harfbuzz

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 29, 2024 License: BSD-3-Clause, Unlicense, MIT Imports: 15 Imported by: 5

Documentation

Overview

Package harfbuzz provides advanced text layout for various scripts and languages, with font-aware substitutions and positionning.

Given a font and an input specified as runes, the package shapes this input and returns a slice of positionned glyphs, identified by their index in the font. See `Buffer` and its methods for more details.

This package is a direct port of the C/C++ library.

Index

Constants

View Source
const (
	// Special setting for `Feature.Start` to apply the feature from the start
	// of the buffer.
	FeatureGlobalStart = 0
	// Special setting for `Feature.End` to apply the feature from to the end
	// of the buffer.
	FeatureGlobalEnd = maxInt
)
View Source
const (
	// Special value for script index indicating unsupported script.
	NoScriptIndex = 0xFFFF
	// Special value for feature index indicating unsupported feature.
	NoFeatureIndex = 0xFFFF
	// Special value for language index indicating default or unsupported language.
	DefaultLanguageIndex = 0xFFFF
)

Variables

View Source
var UniscribeBugCompatible = false

UniscribeBugCompatible alters shaping of indic and khmer scripts:

  • when `false`, it applies the recommended shaping choices
  • when `true`, Uniscribe behavior is reproduced

Functions

func IsDefaultIgnorable

func IsDefaultIgnorable(ch rune) bool

IsDefaultIgnorable returns `true` for codepoints with the Default_Ignorable property (as defined in unicode data DerivedCoreProperties.txt)

func ParseVariation

func ParseVariation(s string) (font.Variation, error)

ParseVariation parse the string representation of a variation of the form tag=value

Types

type Buffer

type Buffer struct {
	// Info is used as internal storage during the shaping,
	// and also exposes the result: the glyph to display
	// and its original Cluster value.
	Info []GlyphInfo

	// Pos gives the position of the glyphs resulting from the shapping
	// It has the same length has `Info`.
	Pos []GlyphPosition

	// Props is required to correctly interpret the input runes.
	Props SegmentProperties
	// Glyph that replaces invisible characters in
	// the shaping result. If set to zero (default), the glyph for the
	// U+0020 SPACE character is used. Otherwise, this value is used
	// verbatim.
	Invisible GID

	// Glyph that replaces characters not found in the font during shaping.
	// The not-found glyph defaults to zero, sometimes knows as the
	// ".notdef" glyph.
	NotFound GID

	// Information about how the text in the buffer should be treated.
	Flags ShappingOptions
	// Precise the cluster handling behavior.
	ClusterLevel ClusterLevel
	// contains filtered or unexported fields
}

Buffer is the main structure holding the input text segment and its properties before shaping, and output glyphs and their information after shaping.

func NewBuffer

func NewBuffer() *Buffer

NewBuffer allocate a storage with default options. It should then be populated with `AddRunes` and shapped with `Shape`.

func (*Buffer) AddRune

func (b *Buffer) AddRune(codepoint rune, cluster int)

AddRune appends a character with the Unicode value of `codepoint` to `b`, and gives it the initial cluster value of `cluster`. Clusters can be any thing the client wants, they are usually used to refer to the index of the character in the input text stream and are output in the `GlyphInfo.Cluster` field. This also clears the posterior context (see `AddRunes`).

func (*Buffer) AddRunes

func (b *Buffer) AddRunes(text []rune, itemOffset, itemLength int)

AddRunes appends characters from `text` array to `b`. `itemOffset` is the position of the first character from `text` that will be appended, and `itemLength` is the number of character to add (-1 means the end of the slice). When shaping part of a larger text (e.g. a run of text from a paragraph), instead of passing just the substring corresponding to the run, it is preferable to pass the whole paragraph and specify the run start and length as `itemOffset` and `itemLength`, respectively, to give HarfBuzz the full context to be able, for example, to do cross-run Arabic shaping or properly handle combining marks at start of run. The cluster value attributed to each rune is the index in the `text` slice.

func (*Buffer) Clear

func (b *Buffer) Clear()

Clear resets `b` to its initial empty state (including user settings). This method should be used to reuse the allocated memory.

func (*Buffer) GuessSegmentProperties

func (b *Buffer) GuessSegmentProperties()

GuessSegmentProperties fills unset buffer segment properties based on buffer Unicode contents and can be used when no other information is available.

If buffer `Props.Script` is zero, it will be set to the Unicode script of the first character in the buffer that has a script other than Common, Inherited, and Unknown.

Next, if buffer `Props.Direction` is zero, it will be set to the natural horizontal direction of the buffer script, defaulting to `LeftToRight`.

Finally, if buffer Props.Language is empty, it will be set to the process's default language.

func (*Buffer) Reverse

func (b *Buffer) Reverse()

Reverse reverses buffer contents, that is the `Info` and `Pos` slices.

func (*Buffer) Shape

func (b *Buffer) Shape(font *Font, features []Feature)

Shape shapes the buffer using `font`, turning its Unicode characters content to positioned glyphs. If `features` is not empty, it will be used to control the features applied during shaping. If two features have the same tag but overlapping ranges the value of the feature with the higher index takes precedence.

The shapping plan depends on the font capabilities. See `NewFont` and `Face` and its extension interfaces for more details.

It also depends on the properties of the segment of text : the `Props` field of the buffer must be set before calling `Shape`.

type ClusterLevel

type ClusterLevel uint8

ClusterLevel allows selecting more fine-grained Cluster handling. It defaults to `MonotoneGraphemes`.

const (
	// Return cluster values grouped by graphemes into monotone order.
	MonotoneGraphemes ClusterLevel = iota
	//  Return cluster values grouped into monotone order.
	MonotoneCharacters
	// Don't group cluster values.
	Characters
)

func (ClusterLevel) String

func (cl ClusterLevel) String() string

type Direction

type Direction uint8

Direction is the text direction. The zero value is the initial, unset, invalid direction.

const (
	LeftToRight Direction = 4 + iota // Text is set horizontally from left to right.
	RightToLeft                      // Text is set horizontally from right to left.
	TopToBottom                      // Text is set vertically from top to bottom.
	BottomToTop                      // Text is set vertically from bottom to top.
)

func (Direction) Reverse

func (dir Direction) Reverse() Direction

Reverses a text direction. Requires that the direction is valid.

type Face

type Face = *font.Face

type Feature

type Feature struct {
	Tag loader.Tag
	// Value of the feature: 0 disables the feature, non-zero (usually
	// 1) enables the feature. For features implemented as lookup type 3 (like
	// 'salt') `Value` is a one-based index into the alternates.
	Value uint32
	// The cluster to Start applying this feature setting (inclusive)
	Start int
	// The cluster to End applying this feature setting (exclusive)
	End int
}

Feature holds information about requested feature application. The feature will be applied with the given value to all glyphs which are in clusters between `start` (inclusive) and `end` (exclusive). Setting start to `FeatureGlobalStart` and end to `FeatureGlobalEnd` specifies that the feature always applies to the entire buffer.

func ParseFeature

func ParseFeature(feature string) (Feature, error)

ParseFeature parses one feature string (usually coming from a comma-separated list of font features).

Features can be enabled or disabled, either globally or limited to
specific character ranges.  The format for specifying feature settings
follows.  All valid CSS font-feature-settings values other than 'normal'
and the global values are also accepted, though not documented below.
CSS string escapes are not supported.

The range indices refer to the positions between Unicode characters,
unless the --utf8-clusters is provided, in which case range indices
refer to UTF-8 byte indices. The position before the first character
is always 0.

The format is Python-esque.  Here is how it all works:

  Syntax:       Value:    Start:    End:

Setting value:
  "kern"        1         0         ∞         // Turn feature on
  "+kern"       1         0         ∞         // Turn feature on
  "-kern"       0         0         ∞         // Turn feature off
  "kern=0"      0         0         ∞         // Turn feature off
  "kern=1"      1         0         ∞         // Turn feature on
  "aalt=2"      2         0         ∞         // Choose 2nd alternate

Setting index:
  "kern[]"      1         0         ∞         // Turn feature on
  "kern[:]"     1         0         ∞         // Turn feature on
  "kern[5:]"    1         5         ∞         // Turn feature on, partial
  "kern[:5]"    1         0         5         // Turn feature on, partial
  "kern[3:5]"   1         3         5         // Turn feature on, range
  "kern[3]"     1         3         3+1       // Turn feature on, single char

Mixing it all:

  "aalt[3:5]=2" 2         3         5         // Turn 2nd alternate on for range

type Font

type Font struct {

	// Point size of the font. Set to zero to unset.
	// This is used in AAT layout, when applying 'trak' table.
	Ptem float32

	// Horizontal and vertical scale of the font.
	//
	// The font scale is a number related to, but not the same as,
	// font size. Typically the client establishes a scale factor
	// to be used between the two. For example, 64, or 256, which
	// would be the fractional-precision part of the font scale.
	// This is necessary because [Position] values are integer
	// types and you need to leave room for fractional values
	// in there.
	//
	// For example, to set the font size to 20, with 64
	// levels of fractional precision you would use a scale of
	// 20 * 64.
	//
	// In the example above, even what font size 20 means is up to
	// you. It might be 20 pixels, or 20 points, or 20 millimeters.
	// HarfBuzz does not care about that. You can set the point
	// size of the font using [Ptem], and the pixel
	// size using [Face.Ppem]
	//
	// The choice of scale is yours but needs to be consistent between
	// what you set here, and what you expect out of [Position]
	// as well has draw / paint API output values.
	//
	// Fonts default to a scale equal to the UPEM value of their face.
	// A font with this setting is sometimes called an "unscaled" font.
	//
	// The resulting positions are computed with: fontUnit * Scale / faceUpem,
	// where faceUpem is given by the face.
	//
	// Given a device resolution (in dpi) and a point size, the scale to
	// get result in pixels is given by : pointSize * dpi / 72
	XScale, YScale int32
	// contains filtered or unexported fields
}

Font is used internally as a wrapper around the provided Face.

Font are constructed with `NewFont` and adjusted by accessing the fields Ptem, XScale, YScale.

Fonts private fields only depend on the provided *font.Font, so a Font object is suitable for caching.

func NewFont

func NewFont(face Face) *Font

NewFont constructs a new font object from the specified face.

The scale is set to the face Upem, meaning that by default the output results will be expressed in font units.

The `face` object should not be modified after this call.

func (*Font) ExtentsForDirection

func (f *Font) ExtentsForDirection(direction Direction) api.FontExtents

ExtentsForDirection fetches the extents for a font in a text segment of the specified direction, applying the scaling.

Calls the appropriate direction-specific variant (horizontal or vertical) depending on the value of `direction`.

func (*Font) Face

func (f *Font) Face() Face

Face returns the underlying face. Note that field is readonly, since some caching may happen in the `NewFont` constructor.

func (*Font) GetOTLigatureCarets

func (f *Font) GetOTLigatureCarets(direction Direction, glyph GID) []Position

GetOTLigatureCarets fetches a list of the caret positions defined for a ligature glyph in the GDEF table of the font (or nil if not found).

func (*Font) GlyphAdvanceForDirection

func (f *Font) GlyphAdvanceForDirection(glyph GID, dir Direction) (x, y Position)

GlyphAdvanceForDirection fetches the advance for a glyph ID from the specified font, in a text segment of the specified direction.

Calls the appropriate direction-specific variant (horizontal or vertical) depending on the value of `dir`.

func (*Font) GlyphExtents

func (f *Font) GlyphExtents(glyph GID) (out GlyphExtents, ok bool)

GlyphExtents fetches the GlyphExtents data for a glyph ID in the specified font, or false if not found

func (*Font) GlyphHAdvance

func (f *Font) GlyphHAdvance(glyph GID) Position

GlyphHAdvance fetches the advance for a glyph ID in the font, for horizontal text segments.

func (*Font) SetVarCoordsDesign

func (f *Font) SetVarCoordsDesign(coords []float32)

SetVarCoordsDesign applies a list of variation coordinates, in design-space units, to the font.

type GID

type GID = api.GID

type GlyphExtents

type GlyphExtents struct {
	XBearing int32
	YBearing int32
	Width    int32
	Height   int32
}

GlyphExtents is the same as fonts.GlyphExtents but with int type

type GlyphInfo

type GlyphInfo struct {
	// Cluster is the index of the character in the original text that corresponds
	// to this `GlyphInfo`, or whatever the client passes to `Buffer.Add()`.
	// More than one glyph can have the same `Cluster` value,
	// if they resulted from the same character (e.g. one to many glyph substitution),
	// and when more than one character gets merged in the same glyph (e.g. many to one glyph substitution)
	// the glyph will have the smallest Cluster value of them.
	// By default some characters are merged into the same Cluster
	// (e.g. combining marks have the same Cluster as their bases)
	// even if they are separate glyphs.
	// See Buffer.ClusterLevel for more fine-grained Cluster handling.
	Cluster int

	// Glyph is the result of the selection of concrete glyph
	// after shaping, and refers to the font used.
	Glyph GID

	// Mask exposes glyph attributes (see the constants).
	// It is also used internally during the shaping.
	Mask GlyphMask
	// contains filtered or unexported fields
}

GlyphInfo holds information about the glyphs and their relation to input text. They are internally created from user input, and the shapping sets the `Glyph` field.

func (GlyphInfo) String

func (info GlyphInfo) String() string

String returns a simple description of the glyph of the form Glyph=Cluster(mask)

type GlyphMask

type GlyphMask = uint32
const (
	// Indicates that if input text is broken at the beginning of the cluster this glyph is part of,
	// then both sides need to be re-shaped, as the result might be different.
	// On the flip side, it means that when this flag is not present,
	// then it's safe to break the glyph-run at the beginning of this cluster,
	// and the two sides represent the exact same result one would get
	// if breaking input text at the beginning of this cluster and shaping the two sides
	// separately.
	// This can be used to optimize paragraph layout, by avoiding re-shaping
	// of each line after line-breaking.
	GlyphUnsafeToBreak GlyphMask = 1 << iota

	// Indicates that if input text is changed on one side of the beginning of the cluster this glyph
	// is part of, then the shaping results for the other side might change.
	// Note that the absence of this flag will NOT by itself mean that it IS safe to concat text.
	// Only two pieces of text both of which clear of this flag can be concatenated safely.
	// This can be used to optimize paragraph layout, by avoiding re-shaping of each line
	// after line-breaking, by limiting the reshaping to a small piece around the
	// breaking positin only, even if the breaking position carries the
	// [GlyphUnsafeToBreak] or when hyphenation or other text transformation
	// happens at line-break position, in the following way:
	// 	1. Iterate back from the line-break position until the first cluster start position that is
	// 		NOT unsafe-to-concat,
	// 	2. Shape the segment from there till the end of line,
	// 	3. Check whether the resulting glyph-run also is clear of the unsafe-to-concat at its start-of-text position;
	// 		if it is, just splice it into place and the line is shaped; If not, move on to a position further
	// 		back that is clear of unsafe-to-concat and retry from there, and repeat.
	// At the start of next line a similar algorithm can be implemented. That is:
	// 	1. Iterate forward from the line-break position until the first cluster start position that is NOT unsafe-to-concat,
	// 	2. Shape the segment from beginning of the line to that position,
	// 	3. Check whether the resulting glyph-run also is clear of the unsafe-to-concat at its end-of-text position;
	// 		if it is, just splice it into place and the beginning is shaped; If not, move on to a position further forward that is clear
	// 	 	of unsafe-to-concat and retry up to there, and repeat.
	// A slight complication will arise in the implementation of the algorithm above, because while our buffer API has a way to
	// return flags for position corresponding to start-of-text, there is currently no position
	// corresponding to end-of-text.  This limitation can be alleviated by shaping more text than needed
	// and looking for unsafe-to-concat flag within text clusters.
	// The [GlyphUnsafeToBreak] flag will always imply this flag.
	// To use this flag, you must enable the buffer flag [ProduceUnsafeToConcat] during
	// shaping, otherwise the buffer flag will not be reliably produced.
	GlyphUnsafeToConcat

	// In scripts that use elongation (Arabic, Mongolian, Syriac, etc.), this flag signifies
	// that it is safe to insert a U+0640 TATWEEL character before this cluster for elongation.
	// This flag does not determine the script-specific elongation places, but only
	// when it is safe to do the elongation without interrupting text shaping.
	GlyphSafeToInsertTatweel
)

type GlyphPosition

type GlyphPosition struct {
	// How much the line advances after drawing this glyph when setting
	// text in horizontal direction.
	XAdvance Position
	// How much the glyph moves on the X-axis before drawing it, this
	// should not affect how much the line advances.
	XOffset Position

	// How much the line advances after drawing this glyph when setting
	// text in vertical direction.
	YAdvance Position
	// How much the glyph moves on the Y-axis before drawing it, this
	// should not affect how much the line advances.
	YOffset Position
	// contains filtered or unexported fields
}

GlyphPosition holds the positions of the glyph in both horizontal and vertical directions. All positions are relative to the current point.

type Position

type Position = int32

Position stores a position, scaled according to the `Font` scale parameters.

type SegmentProperties

type SegmentProperties struct {
	// Languages are crucial for selecting which OpenType feature to apply to the
	// buffer which can result in applying language-specific behaviour. Languages
	// are orthogonal to the scripts, and though they are related, they are
	// different concepts and should not be confused with each other.
	Language language.Language

	// Script is crucial for choosing the proper shaping behaviour for scripts that
	// require it (e.g. Arabic) and the OpenType features defined in the font
	// to be applied.
	//
	// See the package language for predefined values.
	Script language.Script

	// Direction is the text flow direction of the buffer. No shaping can happen without
	// setting direction, and it controls the visual direction for the
	// output glyphs; for RTL direction the glyphs will be reversed. Many layout
	// features depend on the proper setting of the direction, for example,
	// reversing RTL text before shaping, then shaping with LTR direction is not
	// the same as keeping the text in logical order and shaping with RTL
	// direction.
	Direction Direction
}

SegmentProperties holds various text properties of a `Buffer`.

type ShappingOptions

type ShappingOptions uint16

ShappingOptions controls some fine tunning of the shaping (see the constants).

const (
	// Flag indicating that special handling of the beginning
	// of text paragraph can be applied to this buffer. Should usually
	// be set, unless you are passing to the buffer only part
	// of the text without the full context.
	Bot ShappingOptions = 1 << iota
	// Flag indicating that special handling of the end of text
	// paragraph can be applied to this buffer, similar to
	// `Bot`.
	Eot
	// Flag indication that character with Default_Ignorable
	// Unicode property should use the corresponding glyph
	// from the font, instead of hiding them (done by
	// replacing them with the space glyph and zeroing the
	// advance width.)  This flag takes precedence over
	// `RemoveDefaultIgnorables`.
	PreserveDefaultIgnorables
	// Flag indication that character with Default_Ignorable
	// Unicode property should be removed from glyph string
	// instead of hiding them (done by replacing them with the
	// space glyph and zeroing the advance width.)
	// `PreserveDefaultIgnorables` takes
	// precedence over this flag.
	RemoveDefaultIgnorables
	// Flag indicating that a dotted circle should
	// not be inserted in the rendering of incorrect
	// character sequences (such at <0905 093E>).
	DoNotinsertDottedCircle

	// Flag indicating that the [GlyphUnsafeToConcat]
	// glyph-flag should be produced by the shaper. By default
	// it will not be produced since it incurs a cost.
	ProduceUnsafeToConcat

	// Flag indicating that the [GlyphSafeToInsertTatweel]
	// glyph-flag should be produced by the shaper. By default
	// it will not be produced.
	ProduceSafeToInsertTatweel
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL