Documentation
¶
Overview ¶
Package fonts embeds font programs into a PDF and answers the measurement questions laying text out asks.
It is the other half of drawing text. The content package writes the operators; this decides what bytes those operators show and puts the font program in the file so a reader can render them.
Composite fonts only, deliberately ¶
A face is embedded as a Type0 font with Identity-H encoding and a CIDFontType2 descendant (ISO 32000-2 9.7). The alternative — a simple font with a single-byte encoding — is limited to 256 codes and to the glyphs a standard encoding names, which rules out most of Unicode. Anything laying out real text needs the composite form, so that is the only form here rather than a choice to get wrong.
The practical consequence is in the encoding: a character code is two bytes, big-endian, and equals the glyph index. Encode does that mapping; the bytes it returns are what content.Builder.ShowText takes.
Subsetting, and the ordering it imposes ¶
Only the glyphs a face has been asked to encode are embedded, so Embed must come after the drawing that uses the font. Embedding first produces a font carrying .notdef alone, and every glyph the document goes on to show is one the program does not define; Embed refuses that rather than writing it.
Shaping ¶
Shape applies the font's own kerning and ligatures and returns spans ready for a text operator; Encode is the plain path that maps runes to glyphs one at a time. ShapeGlyphs is the full pipeline, which also attaches marks and joins cursive forms.
The rules applied are those the font declares for the run's own script, and for the language system named by SetLanguage. The syllabic scripts are also reordered: their characters are not stored in the order they are drawn, and ShapeGlyphs puts them right. Nine Indic scripts share one model (indic.go), and Khmer (khmer.go) and Myanmar (myanmar.go) each have their own. The scripts the Universal Shaping Engine covers — Tibetan, Javanese, Balinese, Sinhala and a long tail — are not reordered, so text in them is still not correctly set by this package. See layout.go for exactly what is read and each shaper's own file for what it covers.
What it does not do ¶
Both glyf and CFF outlines are subsetted, by the same rule: glyph indices are retained and a dropped glyph becomes an empty one.
A CID-keyed CFF is refused outright. Its CIDs are not glyph indices, and everything here assumes they are.
Index ¶
- func CharStringsForTest(cff []byte) ([][]byte, error)
- func MeasureGlyphs(glyphs []Glyph, size float64) float64
- func MeasureRuns(runs []Run, size float64) float64
- func PrivateDictForTest(cff []byte) ([]byte, error)
- func StandardNames() []string
- type Axis
- type Descriptor
- type Face
- func (f *Face) Advance(r rune) (float64, bool)
- func (f *Face) Axes() []Axis
- func (f *Face) Clone() *Face
- func (f *Face) Cmap() map[rune]int
- func (f *Face) Descriptor() Descriptor
- func (f *Face) Encode(s string) (codes []byte, missing int)
- func (f *Face) Features() []string
- func (f *Face) GlyphAdvance(gid int) float64
- func (f *Face) GlyphAdvances() []float64
- func (f *Face) GlyphID(r rune) (int, bool)
- func (f *Face) GlyphIDForTest(r rune) (int, bool)
- func (f *Face) HasJoiningForms() bool
- func (f *Face) HasKerning() bool
- func (f *Face) HasLigatures() bool
- func (f *Face) HasScript(tag string) bool
- func (f *Face) InkExtent(s string, size float64) (above, below float64, ok bool)
- func (f *Face) IsCFF() bool
- func (f *Face) IsSimple() bool
- func (f *Face) IsStandard() bool
- func (f *Face) IsVariable() bool
- func (f *Face) Language() string
- func (f *Face) Measure(s string, size float64) float64
- func (f *Face) MeasureShaped(s string, size float64) float64
- func (f *Face) Name() string
- func (f *Face) NumGlyphs() int
- func (f *Face) Scripts() []string
- func (f *Face) SetLanguage(tag string)
- func (f *Face) ShapeGlyphs(s string) ([]Glyph, int)
- func (f *Face) ShapeGlyphsWith(s string, features ...string) ([]Glyph, int)
- func (f *Face) Subset() ([]byte, error)
- func (f *Face) SubsetGlyphs() (program []byte, kept []int, err error)
- func (f *Face) UnitsPerEm() int
- func (f *Face) Used() []int
- type Glyph
- type Metric
- type Run
- type Stack
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CharStringsForTest ¶
CharStringsForTest returns the charstrings of a CFF program.
It exists so that a test in another package can look at what the subsetter wrote — that a dropped glyph became an endchar and a kept one did not — which is the property the saving depends on and which nothing else observes. There is no other caller, and the name says so.
func MeasureGlyphs ¶
MeasureGlyphs is the width a shaped run occupies at a given size, which is the sum of its advances — offsets displace glyphs without moving the pen and so contribute nothing.
func MeasureRuns ¶
MeasureRuns is the width a set of runs occupies at a given size.
func PrivateDictForTest ¶
PrivateDictForTest returns a CFF program's Private DICT bytes, as its Top DICT locates them.
It exists so a test can compare the region across a subsetting round trip. The size and offset are copied through rather than recomputed, so nothing in the writer can drift them — but "nothing can drift it" is an argument, and a comparison is a check.
func StandardNames ¶
func StandardNames() []string
StandardNames lists the fourteen faces, as a document names them.
Types ¶
type Axis ¶
type Axis struct {
// Tag is the four-character axis tag: wght, wdth, opsz, slnt, ital, or one
// of the many a foundry may define for itself.
Tag string
// Min, Default and Max are the range the axis offers and where it rests.
Min, Default, Max float64
}
An Axis is one of a variable font's variation axes, in user coordinates.
type Descriptor ¶
type Descriptor struct {
// Ascent and Descent are the font's own, from hhea. Descent is negative.
Ascent, Descent int
// CapHeight is the height of a capital letter, from OS/2, and is zero for a
// font that declares none.
CapHeight int
// BBox is the box enclosing every glyph: xMin, yMin, xMax, yMax.
BBox [4]int
// ItalicAngle is degrees clockwise from vertical, so an italic is negative.
ItalicAngle float64
// StemV is the width of a vertical stem, estimated from the weight the font
// declares because it cannot be measured without rasterising: no table
// states it, and the outlines that would show it are the thing being
// described.
StemV int
// Flags is the bit set PDF's FontDescriptor uses — fixed pitch, serif,
// symbolic and the rest. It is here because it is derived from the font and
// nowhere else, and a caller that wants the bits individually can take them
// apart more easily than it can work them out.
Flags int
// LineGap is the leading hhea asks for between one line's descent and the
// next line's ascent. Ascent + Descent alone is not the height of a line:
// CSS calls the third term line-height: normal and every browser takes it
// from the font, so a formula without it is not a stricter reading of the
// face but the right formula with a term missing.
LineGap int
// TypoAscent, TypoDescent and TypoLineGap are OS/2's sTypo* trio, which many
// fonts disagree with hhea about. UseTypoMetrics carries OS/2 fsSelection
// bit 7, which is the font saying which of the two it means. A consumer that
// honours it is following the font's own instruction rather than guessing;
// one that does not should stay with the hhea three above, which is what
// this module's Ascent and Descent are.
TypoAscent, TypoDescent, TypoLineGap int
UseTypoMetrics bool
// XHeight is OS/2 sxHeight, the height of a lowercase x. CSS's ex unit is
// defined against it, and vertical-align: middle against half of it; the
// half-em both fall back to is the specified fallback and not the answer.
// For a standard face it is the AFM's XHeight, which twelve of the fourteen
// publish — Symbol and ZapfDingbats have no lowercase to measure.
XHeight int
// UnderlinePosition and UnderlineThickness are post's, in font units, with
// the position the distance from the baseline to the *top* of the stroke and
// so negative for a rule drawn below it. StrikeoutPosition and StrikeoutSize
// are OS/2's equivalent for a line through the middle.
//
// A standard face's underline comes from its AFM, converted: PostScript
// measures to the centre of the stroke and post to its top, so the position
// reported is half a thickness above the number Adobe published. The field
// means one thing whichever kind of face answered it. An AFM carries no
// strikeout, so the fourteen state none.
UnderlinePosition, UnderlineThickness int
StrikeoutPosition, StrikeoutSize int
// Weight is OS/2 usWeightClass: 100 for Thin, 400 for Regular, 700 for Bold.
//
// It is worth more than it looks on a variable font. Load hands back the
// outlines as they are stored, which is the face's default instance, and a
// quarter of the variable faces published under the OFL default to something
// lighter than Regular. The name is no guide: the legacy name records can
// spell only four styles, so a face whose default is Thin is commonly still
// called Regular there, and several are. This is the number that says what
// was actually drawn — LoadInstance rewrites it from the location it cut the
// face at, so it says that for an instance too.
Weight int
// Declared is the set of the above the font actually states.
//
// Zero and unknown are different answers and a consumer has to tell them
// apart: a font may legitimately declare a line gap of nothing, and the
// fourteen standard faces have no hhea, OS/2 or post table to declare one
// in — so they state no line gap, no strikeout and no typographic trio, and
// only the x-height and underline their AFM publishes. Every field above
// that can be absent has a bit here, and the bit is the only way to know.
Declared Metric
}
Descriptor is a face's own metrics: what a reader needs to set the text when the font is not available to it.
Lengths are in font units. Divide by UnitsPerEm for fractions of an em, which is what most formats state them in.
func (Descriptor) Has ¶
func (d Descriptor) Has(m Metric) bool
Has reports whether the font stated a metric, as against leaving it zero.
type Face ¶
type Face struct {
// contains filtered or unexported fields
}
Face is a loaded font program: its metrics, its character-to-glyph mapping, and the bytes to embed.
It is not safe for concurrent use. Encode records which glyphs a document used, so two goroutines encoding through one Face race on that record; and shaping caches the font's layout tables as each script selects them, so two goroutines merely *measuring* shaped text race on that cache.
func Load ¶
Load parses an sfnt font program — TrueType or OpenType — and prepares it for embedding. The bytes are retained and written into the PDF as they are.
A variable font loads at its default instance, which is what its glyf outlines already are. LoadInstance is the way to ask for any other point in its design space; see instance.go for why the default is rarely the one that was wanted.
func LoadInstance ¶
LoadInstance parses a variable font and prepares the face it draws at one point in its design space, ready to embed like any other.
The coordinates are in user space and named by axis tag, so a Regular weight at three-quarter width is map[string]float64{"wght": 400, "wdth": 75}. An axis the caller does not name stays at its own default. An axis the *font* does not have is an error rather than a value ignored: a caller asking for a weight from a font with no weight axis has asked for something it will not get, and would otherwise get the default silently — which is the whole problem this exists to fix.
A value outside its axis's range is clamped to the range, as the specification requires of any tool that reads a location. Asking for weight 700 from a face that stops at 600 gets the boldest it has.
The face this returns is static: its outlines are the ones drawn at that location, and it carries no variation tables. Load remains the way to read a font as it stands, which for a variable font is its default instance.
func LoadSimple ¶
LoadSimple parses an sfnt font program and prepares it to be embedded as a simple font with WinAnsiEncoding.
It refuses a program that cannot serve as one: a face is only usable here if its character map covers the encoding, and one that covers almost none of it would produce a document of blanks.
func Standard ¶
Standard returns a face for one of the fourteen standard fonts, by the name a PDF uses for it: "Helvetica", "Times-Roman", "Courier-Bold" and so on. StandardNames lists them all.
The face carries metrics and no program. It measures text and it embeds as a reference rather than a font, which is what makes it free and what makes it unusable in a conforming PDF/A.
func (*Face) Advance ¶
Advance is the horizontal advance of a rune in thousandths of an em, the unit PDF text space uses. It reports whether the font maps the rune at all; for one it does not, the advance is .notdef's.
func (*Face) Axes ¶
Axes are the variation axes the face declares, empty for a static font.
A face from Load carries the outlines as they are stored, which is the default instance, with every axis at its Default below. Axes is how a caller reads which design space it is in and where it was taken, so it can say "this face is variable and was taken at wght=100" rather than discovering it from the shape of the letters — and it is what a caller reads before naming a point to LoadInstance, which is the way to be handed another one.
A face from LoadInstance has no axes. It was cut at one location and is a static font, which is what a design point is once it has been chosen; what it was cut at is in Descriptor().Weight and in Name.
func (*Face) Clone ¶
forDocument returns a face that shares this one's parsing but keeps its own record of what a document used.
The split is between what the *font* says and what a *document* did with it. The program, the tables and the rules read out of them are facts about the font: reading them again for a second document produces the same answer at the same cost, and for a face of any size that cost is most of what loading one comes to. A layout is built by its readers and never written to afterwards, so sharing it is sharing a value, not a variable.
The set of glyphs encoded is the opposite. It is what the subset is computed from, so two documents sharing one would each embed a font carrying the other's glyphs — and, worse, a /CIDSet describing a set neither of them has. That one is always fresh.
The per-script layout caches are fresh too. They are lazily filled, so sharing them across faces would be a write from two goroutines to one map; the alternative is a lock on a path taken once per script per document, and the reading they save is small beside the reading forDocument already avoids. Clone returns a face that shares this one's reading of the font and records its own glyphs.
A face remembers which glyphs it was asked to set, because that is what a subset is computed from — so one face used for two outputs puts each one's glyphs into the other. Reading the font again instead costs milliseconds and megabytes for an answer that cannot differ. Share the parse, not the face.
func (*Face) Cmap ¶
Cmap is the face's character-to-glyph mapping, copied.
It is the way back: a format that wants the text extractable has to say which character each glyph came from, and shaping has long since stopped tracking that. A glyph reachable from several characters appears several times, and choosing between them is the caller's — the choices are not equivalent and depend on what the mapping is for.
func (*Face) Descriptor ¶
func (f *Face) Descriptor() Descriptor
Descriptor returns the face's metrics.
func (*Face) Encode ¶
Encode maps a string to the character codes a Type0/Identity-H font expects: two bytes per glyph, big-endian, each equal to the glyph index. The result is what content.Builder.ShowText takes.
A rune the font does not map encodes as glyph 0, which renders as .notdef — the visible "this font has no glyph for that" box. That is deliberate: an error here would mean a caller could not lay out text containing one stray character, and silently dropping it would lose content. The second result reports how many runes were missing so a caller that cares can react.
func (*Face) Features ¶
Features lists the substitution features this face offers by name, sorted. A caller can present them, or check one before asking for it.
func (*Face) GlyphAdvance ¶
GlyphAdvance is how far the pen moves after a glyph, in font units.
It is the font's own advance and not the one shaping decided: a kern or a mark attachment changes what a *run* does without changing what the glyph says about itself, and a width table describes the glyph.
func (*Face) GlyphAdvances ¶
GlyphAdvances is the advance of every glyph, indexed by glyph id.
The whole table at once, because a format that states widths states them for a range and has to see which are alike.
func (*Face) GlyphID ¶
GlyphID maps a rune to the number the content stream will carry for it, reporting whether the font covers it.
For an embedded face that number is a glyph index, because the encoding is Identity-H. For a standard face it is the WinAnsiEncoding byte, because the encoding is a character encoding — the two are different kinds of number and the only thing they have in common is that Encode writes them.
func (*Face) GlyphIDForTest ¶
GlyphIDForTest returns the glyph index a character maps to in the font program, whatever encoding the face will be embedded with.
GlyphID answers a different question — the number the *content stream* will carry, which for a simple font is a character code and not a glyph index — so a test checking what the subsetter kept needs this one. There is no other caller, and the name says so.
func (*Face) HasJoiningForms ¶
HasJoiningForms reports whether the font carries the positional forms a cursive script needs. A caller can use it to tell a face that can set Arabic from one that merely has the letters.
func (*Face) HasKerning ¶
HasKerning reports whether the font carries pair kerning this package could read. A caller laying out text can use it to decide whether shaping is worth the extra spans, and a test can use it to notice a font whose kerning went unread.
func (*Face) HasLigatures ¶
HasLigatures reports whether the font carries ligature substitutions this package could read.
func (*Face) InkExtent ¶
InkExtent is how far the glyphs of s reach above and below the baseline, at the given size, and whether the face can say.
A tighter answer than the ascent and descent, and a different kind of answer. Ascent and descent describe the *face* — how much room a line of it needs, including for the tallest accent and the deepest tail it has — and every run set in it is given that much whether or not it uses any. This describes the text in hand: an ellipsis is three dots on the baseline however deep the face's descenders go, and a row of capitals has nothing below the baseline at all.
The caller that needs the difference is one deciding whether some rectangle cuts the text: a box that ends just under the baseline does not clip a line of capitals, and answering from the face's descent says it does. For deciding how much room to *give* a line the face's own metrics remain the right numbers, because the next run set in it may be the one with the tail.
It is the vertical extent alone. The horizontal one a caller already has a better answer to in Measure, which is the advance the text was laid out to; glyphs may overhang it slightly and none of this is precise enough to matter there.
ok is false when the face cannot answer — a CFF-flavoured font, whose glyph extents are in the charstrings and cannot be had without interpreting them — and a caller should fall back to the face's ascent and descent. It is also false for a string with nothing in it that draws.
The numbers come from what the font states: the glyph header for a glyf-based face, and Adobe's published per-character boxes for the fourteen standard ones. Neither is verified against the outline, and a font that overstates a glyph's box makes this overstate the run's — which is the safe direction for the question it exists to answer.
func (*Face) IsCFF ¶
IsCFF reports whether the outlines are CFF rather than glyf, which decides how a format has to carry the program and what it may say about it.
func (*Face) IsSimple ¶
IsSimple reports whether the face will be embedded as a simple font — one byte per character — rather than as a composite one.
func (*Face) IsStandard ¶
IsStandard reports whether the face is one of the fourteen rather than an embedded program. A caller that must produce a conforming PDF/A can check it before drawing rather than after validating.
func (*Face) IsVariable ¶
IsVariable reports whether the face declares variation axes.
func (*Face) Measure ¶
Measure is the width of a string set at the given size, in user-space units. Runes the font does not map contribute .notdef's advance, which is what a renderer will draw.
func (*Face) MeasureShaped ¶
MeasureShaped is the width of a shaped string at the given size, in user-space units.
It is what the text will occupy on the page: the same shaping Shape and DrawShaped do, measured rather than drawn. That is the whole contract, and it is the reason this measures by shaping rather than by a cheaper approximation of it. A layout engine measures a word to decide whether it fits the line and then draws it; if the two disagree the line is filled to one width and painted at another, and nothing in either call's own output shows it.
This used to sum a flattened ligature table and a kerning map, which is most of shaping and not all of it — no contextual substitution, no syllabic reordering, no positioning beyond pair kerning. Over the HarfBuzz corpus that was wrong for 1920 of 5911 strings, by up to 17% on a Devanagari conjunct.
func (*Face) Name ¶
Name is the font's PostScript name, which becomes /BaseFont.
It is the name for embedding and not a description of what was drawn. On a variable face the two can differ: the legacy name records spell only four styles, so a face whose default instance is Thin is commonly still named Regular there, and several published under the OFL are. Descriptor().Weight is what says which.
func (*Face) NumGlyphs ¶
NumGlyphs is the number of glyphs the font program declares, including .notdef. It is unchanged by subsetting, which retains glyph indices. A standard face has no program, and reports zero.
func (*Face) Scripts ¶
Scripts lists the OpenType script tags the face declares layout rules for, in sorted order — "latn", "cyrl", "deva" and so on, plus "DFLT" where the font names a default.
It is the question a caller asks when assembling a fallback stack: a face may have the *glyphs* for a script and none of the rules that make it legible, and for Devanagari or Arabic the difference between the two is a row of unjoined letters. Covers answers the first question; this answers the second.
A face whose tables name no scripts at all returns nothing, which is not the same as covering nothing: such a font's features apply to everything.
func (*Face) SetLanguage ¶
SetLanguage names the OpenType language system to shape in: "TRK " for Turkish, "ROM " for Romanian, and so on — four bytes, space-padded, as the OpenType language system registry spells them.
It matters because a font states some rules per language. The same letters are drawn differently in Romanian and in French, and a font that knows the difference says so through a language system; without one it is set the default way, which is right for most text and wrong for the text the font went to the trouble of correcting.
The empty string, the initial value, means the default language system. A language the font does not declare falls back to it too, so a caller may name one without first checking that the face has it.
func (*Face) ShapeGlyphs ¶
ShapeGlyphs turns a string into positioned glyphs, applying everything this package reads: ligatures, contextual substitution, kerning, mark attachment, and the direction each part of the text runs in.
The glyphs come back in *visual* order — the order the pen draws them, left to right — so a caller can draw them as they are, at a pen that only moves forward, whatever scripts the string mixes. That is not the order the string is written in: Hebrew and Arabic read the other way, and a PDF text-showing operator has no way to say so. bidi.go decides where each stretch belongs.
It is the full result. Shape is the same pipeline with the vertical part dropped, and is enough whenever the text carries no marks.
func (*Face) ShapeGlyphsWith ¶
ShapeGlyphsWith is ShapeGlyphs with extra features named by the caller: the optional ones a font offers and nothing turns on by itself, small capitals or oldstyle figures. A tag the font does not declare is ignored rather than refused, because a caller asking for small capitals of a face that has none wants the text, not an error.
func (*Face) Subset ¶
Subset returns a font program carrying only the glyphs this face has encoded, together with .notdef and the components any kept composite glyph needs.
It reports an error when the original font cannot be taken apart — a truncated loca, a glyf that does not agree with it — rather than emitting a program that claims glyphs it does not have.
func (*Face) SubsetGlyphs ¶
SubsetGlyphs is Subset, also reporting which glyphs the subset kept.
A format that names the subset needs them: PDF writes a tag derived from the set so that two subsets of one face can be told apart, and a bitmap of it so a reader can check the program against what the file claims. Both have to be computed from what the subsetter actually kept rather than from what was asked for, since keeping one glyph can require keeping another.
func (*Face) UnitsPerEm ¶
UnitsPerEm is the font's own coordinate grid: how many units make one em.
A caller working in the thousandths of an em this package reports needs it only to convert back — to compare against a tool that reports font units, or to read a value out of the font's own tables. Almost nothing does.
type Glyph ¶
type Glyph struct {
// GID is the glyph to draw.
GID int
// Cluster is the byte offset, in the input string, of the first character
// this glyph came from. Several glyphs may share a cluster — a letter and
// its accent — and one glyph may stand for several characters, as a
// ligature does. It is what maps a position in the text to a position on
// the page, for selection, search and hit-testing.
Cluster int
// XAdvance is how far the pen moves after this glyph is drawn. It starts as
// the font's own advance and is what kerning changes. A mark's is zero,
// which is what makes it sit on the glyph before it rather than after.
XAdvance float64
// XOffset and YOffset displace the glyph from the pen without moving the
// pen. This is how a mark is placed over its base.
XOffset, YOffset float64
// contains filtered or unexported fields
}
Glyph is one positioned glyph of a shaped run. Distances are in thousandths of an em, the unit the font's own metrics are in, so they are independent of the size the text is finally set at.
type Metric ¶
type Metric uint32
Metric names a metric a font may or may not state, for Descriptor.Declared.
type Run ¶
type Run struct {
// Face is what this piece was set in.
Face *Face
// Glyphs are the positioned glyphs, in the order they are drawn. Their
// Cluster values are byte offsets into the *whole* string that was shaped,
// not into this run — a caller mapping a glyph back to the text should not
// have to know that runs exist.
Glyphs []Glyph
// Start is the byte offset in the input where this run begins — where it
// begins in the text, that is, which in a right-to-left run is where the
// *last* glyph drawn came from.
Start int
// Level is the run's bidirectional embedding level: even runs left to
// right, odd right to left. A caller drawing the runs in the order they are
// returned does not need it; one aligning a line, or hit-testing a click
// back to a character, does.
Level int
}
Run is a piece of text set in one face.
type Stack ¶
type Stack struct {
// contains filtered or unexported fields
}
Stack is an ordered list of faces. Each piece of text is set in the first face that has the characters for it.
func NewStack ¶
NewStack builds a fallback list. The order is the priority: the first face is the one text is set in wherever it can be, and the rest are what it falls back to. A nil face is ignored, so a caller assembling a list from optional sources need not filter it.
func (*Stack) Covers ¶
Covers reports whether any face in the stack has a glyph for a character. It is what a caller asks before deciding to add another fallback.
func (*Stack) Faces ¶
Faces returns the faces in priority order. A caller needs them to embed each one that was actually used and to name it in the page's resources.
func (*Stack) Measure ¶
Measure is the width the stack sets a string in, at a given size. It shapes the text to answer, because the width of text with fallback is not the sum of its characters' widths in any one font.
func (*Stack) ShapeRuns ¶
ShapeRuns sets a string across the stack, returning one run per stretch of text that shares a face, a script and a direction, and the number of characters no face could set.
The runs are in *visual* order — the order they are drawn, left to right — and cover the input exactly, so drawing them in order at a continuing pen position sets the text. That is not the order they are written in whenever the text is not all one direction, and neither is the order of the glyphs within a right-to-left run: this is where UAX #9 is applied, and where the reversal that makes Arabic and Hebrew legible happens.
Why script cuts a run as much as face does ¶
A font that covers several scripts states different rules for each, and the rules it states for one are wrong for another: a Greek word given the substitutions a font declares for Arabic is not merely unkerned but misspelt. So a run is a stretch that shares both — one face, one script — and each is shaped with what that font declares for that script.
Characters that are in no script of their own — a space, a digit, a comma, a combining accent — take the script of what they are written among, so the space in the middle of a sentence does not cut it in two.
And why direction cuts one too ¶
A run is shaped by one call into one font, and a call sets one direction: the positioning pass has to know which way the pen will meet the glyphs it is placing. A stretch of Latin inside a Hebrew sentence is a run of its own for the same reason a stretch of Greek inside it would be.
Source Files
¶
- arabic.go
- bidishim.go
- canonical.go
- cff.go
- cffsubset.go
- context.go
- contextpos.go
- embedding.go
- face.go
- glyfpoints.go
- glyphbuf.go
- gvar.go
- ignorable.go
- ignorabletable.go
- indic.go
- indiccategory.go
- indicmatra.go
- indicsyllable.go
- indicvowel.go
- instance.go
- joining.go
- khmer.go
- layout.go
- myanmar.go
- normalize.go
- position.go
- script.go
- scripts.go
- shape.go
- simple.go
- stack.go
- standard.go
- standard14.go
- subset.go
- syllabic.go
- use.go
- usetable.go
- varstore.go