Skip to content

Reference ​

Import everything with import sparkles.font;. Fallible operations return FontResult!T, an Expected holding a value or a FontError. Operations on a face are free functions callable as methods (face.charMap).

Errors — sparkles.font.errors ​

SymbolMeaning
FontErrorkind, tag (or none), offset (absolute), tableOffset (inside tag, when readable), limit, limitValue and needed
FontErrorKindnotAFont, truncated, badOffset, badValue, unsupportedVersion, missingTable, limitExceeded, indexOutOfRange, invalidEncoding, unsupportedCapability, and kinds later milestones use
FontLimitthe limits of FTB3: tableRecords (4,096), cmapSubtables (64), variationAxes (64), and the outline and colour limits; callerStorage with needed
Taga four-byte table tag: Tag("head"), .chars

Faces — sparkles.font.face ​

OperationResult
openFace(bytes, index = 0)a Face; checks the container, directory, head, maxp and the cmap header; O(tables)
openCollection(bytes)a Collection: count, face(i); a single font is a collection of one
face.table(tag)the table's bytes, borrowed; missingTable or badOffset
face.unitsPerEm, numGlyphsfrom head and maxp
face.outlinestrueType or cff, from the signature
face.directoryDirectoryEntry per record: tag, offset, length, stored checksum, readable, duplicate
face.computedChecksum(i)the checksum of record i's table
face.searchFields, checksumAdjustmentstored and expected values

Tables — sparkles.font.tables ​

face.head, hhea, maxp, os2, post return structs whose fields carry OpenType's names; has… flags mark fields the stored version lacks. face.hmtx returns a view with advance(gid), lsb(gid) and metric(gid). face.fvar, avar and stat return views whose entries are results. face.spacing classifies the face as mono, dual or proportional.

Character maps — sparkles.font.cmap ​

OperationResult
face.charMapthe first qualifying subtable, in HarfBuzz's order, as a CharMap; unsupportedCapability when none
face.charMapAt(i)encoding record i alone, without fallback
map.glyph(cp)the glyph, or 0; O(log n)
map.rangessorted, merged CodepointRanges of mapped codepoints
map.variant(cp, selector)Variant: none, useDefault or glyph, from format 14
map.platform, encoding, format, lookupthe chosen record and how codepoints become keys
map.rejectedRecords, firstRejection, outOfRangeMappings, unmappedByTargetwhat was skipped or dropped

Names — sparkles.font.names ​

face.name returns a NameTable whose records are FontResult!NameRecord. A NameRecord has platformID, encodingID, languageID, nameID, raw bytes, an optional languageTag, encoding, decodedLength() and decode(char[] destination).

Glyph names ​

face.glyphName(gid) returns a GlyphName (present, text) from post or the CFF charset. To name many glyphs, size and build an index:

d
auto scratch = new uint[face.glyphNameIndexLength.value];
const index = face.glyphNameIndex(scratch).value;
const name = index[gid]; // constant time

The index borrows the face's bytes and scratch.

Units — sparkles.font.units ​

A DesignValue is a signed count of 1/65,536 font units with the face's unitsPerEm; DesignValue.fromUnits(n, upem) holds a stored field exactly.

OperationResult
checkedAdd(a, b), checkedSum(values, upem)the exact sum; arithmeticExhausted on 64-bit overflow
toLayoutUnit(d, em)d · em / (upem · 65,536) rounded once to a tick, ties to even; arithmeticExhausted out of range
Ppem.fromInteger(n), fromRational(r)a positive rational ppem; badValue when not positive
Ppem.fromPhysical(em, dpi)em · dpi / 72 for em in points, exactly; ppem.isInteger for Device tables
toPixels(d, ppem)the exact d · ppem / (upem · 65,536) rounded once to the nearest double

Sum a run's design values before converting it, so the run rounds once.

Variations — sparkles.font.variations ​

NormalizedCoords is a slice of F2Dot14 coordinates, one per fvar axis; allZero(coords) is the default instance, where no store is read and every delta is zero. Views borrow the containing table's bytes and report errors with its tag; a malformed header is recorded at read and returned by every lookup at nonzero coordinates.

OperationResult
ItemVariationStore.read(table, tag, tableStart, offset, fvarAxes)the store view; broken and error when its header, format or region axis count is wrong
store.delta(DeltaSetIndex(outer, inner), coords, upem)the exact DesignValue delta, scalars rounded per axis as fontations does; badValue for a dangling outer, inner or region index
DeltaSetIndexMap.read(table, tag, tableStart, offset), map.map(i)the DeltaSetIndex of item i: past the count the last entry, count 0 the identity; another format unsupportedVersion
deviceDelta(table, tag, tableStart, offset, store, coords, upem, ppem)a DeviceDelta: the VariationIndex variation, and devicePixels with deviceApplied only at an integer ppem in the table's range

DeltaSetIndex.noVariation (0xFFFF, 0xFFFF) has delta zero. Design and physical queries pass no ppem, so a Device table never applies to them.

Instances — sparkles.font.instance ​

An Instance is a copyable value: the face, a unit-tagged InstanceSize, a Synthesis, and per fvar axis the F16.16 user value and the normalized F2Dot14 coordinate. It holds at most 64 axes and allocates nothing.

OperationResult
face.axes, face.namedInstancesrandom-access ranges of FontResult!VariationAxis and NamedInstance; empty without fvar, empty with hasError when it is unreadable
InstanceSize.physical(em), InstanceSize.pixels(ppem)a size in LayoutUnit or Ppem; unit, em, ppem
Synthesis(emboldenStrength, obliqueSlant)F16.16, zero by default; stored, not applied
face.instance(size, [UserCoordinate(tag, value)], synth)an Instance; badValue for a size that is not positive or a value for a badValue axis, limitExceeded past 64 axes
inst.coords, userValue(i), axisCount, allZerothe F2Dot14 coordinates (a NormalizedCoords slice), the user value given or the default
inst.ignoredCoordinatescoordinates whose tag no axis has, or all of them for a face without fvar
inst.avarApplied, recordedErrors, firstRecordedErrorwhether avar was used, and the problems the instance was built around
normalizeAxisValue(axis, user), mapCoordinate(map, v)the F16.16 steps: clamp and divide, ties away from zero; one avar segment map with HarfBuzz's rules
toF2Dot14(x)(x + 2) >> 2, saturated

Of a tag given twice the last value wins; a tag several axes share sets each of them. An avar whose axis count differs from fvar's, or that is unreadable, is left out and recorded; a decreasing segment map leaves only its axis unmapped. Version 2 evaluates its item variation store on the mapped coordinates and clamps each result to ±1.

Metrics — sparkles.font.metrics ​

Every value is a Measurement: the exact design value and the instance's size. m.physical is a LayoutUnit at a physically sized instance; m.pixels is fractional pixels at a pixel-sized one, and m.pixels(dpi) at a physically sized one on a device of dpi (ppem = em · dpi / 72), so the device scale never changes the physical value. A query in a form the instance cannot give is unsupportedCapability. m.pixelsAt(ppem) takes an explicit ppem.

OperationResult
inst.verticalSetsthe hhea, typographic and Windows sets as stored plus MVAR deltas, and useTypoMetrics; a missing table's sets absent (hasHhea, hasOs2)
inst.lineMetricsascender, descender, line gap and the source set, chosen on stored values in FTM2's order; present is false when no set remains
inst.decorationsx-height and cap height (OS/2 v2+), underline (post), strikeout (OS/2), each with a has… flag; a stored zero is a value
inst.advance(gid)the hmtx advance plus the HVAR delta; unsupportedCapability at nonzero coordinates without HVAR; negative results kept
inst.measureRun(gids)the checked design-value sum of the run's advances, converted once by the caller; the first error, arithmeticExhausted on overflow
inst.cellMetrics(cmap, ppem)CellMetrics in whole pixels: width (and widthSource), ascent, descent, line gap, height, baseline, underline
face.hvar(axes), hvar.advanceDelta(gid, …)the HVAR view (major 1; a null advance map is the identity on the glyph ID) and one advance delta
face.mvar(axes), mvar.delta(tag, …)the MVAR view (major 1, valueRecordSize ≥ 8) and one value's delta by binary search; a tag with no record is zero

The hhea and typographic sets take the hasc, hdsc and hlgp deltas; the Windows set takes hcla and hcld only. At all-zero coordinates neither HVAR nor MVAR is read, so a malformed one cannot fail a query there; at nonzero coordinates an unreadable MVAR fails every value that takes a delta, and an unreadable HVAR every varied advance.

cellMetrics takes the face's CharMap, built once by the caller, in addition to the integer ppem of the specification's cellMetrics(ppem): the library keeps no hidden cache, and building a character map is not O(1). It rounds by FTM19's table: width (U+0030's advance, else OS/2.xAvgCharWidth) to nearest with ties to even and at least 1; ascent up; descent (the negated descender) up and at least 0; line gap to nearest even and at least 0; the baseline at ascent + ⌊gap / 2⌋; the underline at baseline − position rounded to nearest even, its thickness at least 1.

Vertical metrics — sparkles.font.vertical ​

Vertical queries take an Instance and return Measurements, like the horizontal ones. Without the tables a result is absent (present false), not an error and never a synthesized value; a stored zero is a value.

OperationResult
face.vheaVhea, version 1.0 or 1.1 (fields as stored), at least 36 bytes; another version unsupportedVersion
face.vmtx, vmtx.metric(gid)VerticalMetric (advance height, top side bearing) with hmtx's leniency: numOfLongVerMetrics capped at numGlyphs, the last advance repeated, truncated per glyph
face.vorg, vorg.originY(gid)VORG 1.0; a glyph's record by binary search, else defaultVertOriginY, with fromRecord
face.vvar(axes), advanceDelta, originDeltathe VVAR view (major 1): advance-height map (null is the identity) and vertical-origin map; side-bearing maps are not read
inst.verticalLineMetricsvhea ascender, descender and line gap plus the vasc, vdsc, vlgp deltas; absent without vhea
inst.verticalAdvance(gid)the vmtx advance plus the VVAR delta; absent without vhea or vmtx; unsupportedCapability at nonzero coordinates without VVAR
inst.verticalOrigin(gid)VerticalOrigin: y, its source (vorgRecord, vorgDefault, or none when absent) and whether a VVAR origin delta was added (varied)

verticalOrigin follows the specification's table: VORG 1.0 answers, plus the VVAR origin delta when VVAR has an origin map; another VORG version is unsupportedVersion; a face without VORG but with vmtx and glyf is unsupportedCapability until outlines give each glyph's yMax; any other face has no origin, and a layout that needs one chooses its own fallback. A caller's glyph ID past numGlyphs is indexOutOfRange for both glyph queries. At all-zero coordinates neither VVAR nor MVAR is read.

Baselines — sparkles.font.baseline ​

BASE major version 1 is read; minor 0 or 1, a later minor as 1, with the item variation store from 1.1. Each axis (BaselineAxis.horizontal, vertical) is optional. A coordinate is a BaseCoord: its format, its coordinate as a Measurement (VariationIndex delta included), a format-2 referenceGlyph and pointIndex with unresolvedPoint set until outlines resolve the point, and a format-3 device adjustment whose whole-pixel delta only BaseCoord.pixels adds, at an instance sized in pixels at an integer ppem inside the table's range.

OperationResult
face.base(axes), base.axis(which)the BASE view and one BaseAxis (present false when its offset is null)
axis.tags, axis.scriptsthe tag list as BaselineTags; the script records as FontResult!Tag entries, badOffset for a record pointing outside the table
inst.baselineTags(axis)BaselineTags, a random-access range of Tag; empty with axisPresent false without the axis
inst.baseline(axis, script, tag)Baseline: which script record answered (requested or defaultScript), defaultIndex, and present with the BaseCoord when one is found
inst.extents(axis, script, language, feature)Extents: the script, the MinMax record (language or scriptDefault), fromFeature, and a min and max Extent, each absent, a value or an error

baseline follows the specification's table: no BASE is missingTable; no axis, no script or DFLT record, no BaseValues, or a tag outside the tag list is absent; a tag index past the coordinates is badValue; a coordinate format other than 1–3 is unsupportedVersion. defaultIndex is reported but never answers another tag, and a zero coordinate is a value. extents takes the language's MinMax record, else the script's default, then the feature's record within it, else the record's own values; a null minimum or maximum is absent, and an offset outside the table is that value's badOffset. Pass Tag.init for no language or feature. At all-zero coordinates the store is not read.

Coverage — sparkles.font.coverage ​

Coverage.read(table, tag, tableStart, offset) views a Coverage table inside MATH, GDEF, GSUB or GPOS. Format 1 (a sorted glyph array) and format 2 (sorted glyph ranges) are read; another format is unsupportedVersion, an array past the table truncated, and an offset past it badOffset. These are recorded at read (broken, error) and returned by the lookups.

OperationResult
coverage.index(gid)a CoverageIndex: covered, and the format-1 position or format-2 startCoverageIndex + gid − start; binary search, O(log n)
coverage.glyphsCoveredGlyphs, a forward range of CoveredGlyph (glyph and coverage index) in coverage order; a range whose end precedes its start is empty

GDEF — sparkles.font.gdef ​

face.gdef(fvarAxes) reads the GDEF header (major version 1; the item variation store from 1.3). face.gdefVariationStore(fvarAxes) is the store MATH and GPOS VariationIndex tables resolve against: not present without GDEF, before 1.3, or with a null offset; any other GDEF problem is recorded as a broken store, so only a delta that reads it at nonzero coordinates reports it.

Math — sparkles.font.math_table ​

The module is math_table so that it never reads as std.math. MATH major version 1 is read, any minor; another major is unsupportedVersion, and without the table every query is missingTable. Values are MathValues: present false when the font has no record (a stored zero is present), a kind of percentage (signed, never scaled), length (a design value with no device: the two minimum heights) or record (a MathValueRecord). A record's value is a Measurement including its VariationIndex delta from GDEF's store (badValue without one, at nonzero coordinates); a Device table's whole-pixel delta stays in device and only MathValue.pixels adds it, at an instance sized in pixels at an integer ppem inside the table's range.

OperationResult
face.mathTablethe MATH header, with majorVersion and minorVersion
inst.mathConstantsMathConstants, indexed by MathConstant (56, in table order); each constant its own FontResult!MathValue, truncated past a short table; present false without a MathConstants table
inst.italicsCorrection(gid)the glyph's MathValueRecord; absent when not covered, badValue when its coverage index is past the value array
inst.topAccentAttachment(gid)as italicsCorrection; an uncovered glyph is absent, never half its advance
inst.isExtendedShape(gid)whether the extended-shape coverage holds the glyph; false without one
inst.mathKernTable(gid, corner)MathKernTable for a MathKernCorner: heightCount, height(i), value(i), heightsAscending and lookup(h); present false when not covered or the corner is null, badValue past the record array
inst.mathKern(gid, corner, h)the kern value at index k, the first height (stored order) greater than h, else heightCount
inst.mathVariants(gid, direction)MathVariants, a random-access range of MathVariant (glyph and advance) for a MathDirection, with minConnectorOverlap; empty without a construction, badValue for a construction index past its array
inst.mathAssemblyLength(gid, direction)MathAssemblyLength: present and partCount
inst.mathAssembly(gid, direction, parts[])MathAssembly: present, the written slice of GlyphParts (glyph, connector lengths, full advance, flags, extender) and the assembly's italicsCorrection

mathKern resolves heights with their variation deltas and no device delta, in stored order, until one is greater than h; a height equal to h selects the value above it, a ppem never changes the step, and the first error met is the result. Unsorted heights are not reordered; heightsAscending reports them. h is a DesignValue in the face's units per em, else badValue. A parts array shorter than the part count is limitExceeded naming callerStorage with the count as needed, and is left unchanged, as on every other error. flags keeps reserved bits as stored. No assembly is composed. At all-zero coordinates the store is not read.

Layout — sparkles.font.layout ​

GSUB and GPOS (a LayoutTable, gsub or gpos) major version 1 are read, any minor; the FeatureVariations table from 1.1. Another major is unsupportedVersion, and without the table every query is missingTable. A null script, feature or lookup list is empty. Every list reports a malformed entry as that entry's error and keeps the others readable, rather than rejecting the whole table as HarfBuzz does: an index read from the font past the array it indexes is badValue, an offset outside the table badOffset, and a caller's index past a list indexOutOfRange.

OperationResult
face.layout(table)the header: majorVersion, minorVersion, scriptCount, featureCount, lookupCount, hasFeatureVariations
face.layoutScripts(table)LayoutScripts, a random-access range of FontResult!LayoutScript with tag(i) readable even for a broken entry
script.defaultLanguage, languages, language(tag)a LangSys (present false when absent; Tag.init names the default), the language systems as a random-access range, and a binary search by tag
langSys.featureIndicesLayoutIndices: each feature index, badValue past the feature list; hasRequiredFeature and requiredFeatureIndex (0xFFFF is none)
face.features(table, script, language)Features, a random-access range of FontResult!Feature (tag, index, required, substituted, lookups as LayoutIndices), the required feature first; found false when the script or language system is not listed
inst.features(table, script, language)as on the face, with the first FeatureVariations record whose condition set holds applied; variation names it as a VariationChoice
face.featureVariationCount(table)the number of FeatureVariations records; 0 before 1.1 or for a null offset
inst.featureVariation(table, r)FeatureVariationRecord: whether record r's condition set holds; unsupportedVersion for a condition of a format other than 1
face.featureSubstitutions(table, r)FeatureSubstitutions, a random-access range of FontResult!FeatureSubstitution (feature index and alternate lookups); badValue for a feature index past the list
face.lookup(table, index)Lookup: type, flag, subtableCount, and markFilteringSet when the flag has useMarkFilteringSet; O(1)
face.substitutions(lookupIndex)Substitutions, a lazy forward range of FontResult!Substitution for a GSUB lookup

A format-1 condition holds when min ≤ coord ≤ max on the F2Dot14 coordinate, an axis past the instance's reading 0; an empty or null condition set holds; any other format never holds. A substitution naming a feature past the list leaves that feature its default lookups. When the FeatureVariations table, or the chosen record's substitution table, cannot be read, every feature at the instance returns that error.

A Substitution has the effective lookupType (never 7; extension says it was wrapped), format, subtable, and input and output as GlyphSequences: an optional leading glyph followed by a borrowed run of big-endian glyph IDs (UInt16Run). Types 1–3 give one glyph in, and its substitute (format 1 as (g + delta) mod 65,536), sequence, or one alternate (alternateIndex) out; type 4 the coverage glyph and its components in, the ligature out. Types 5 and 6 give lookups, the SequenceLookups the rule invokes, never followed, with contextInput saying whether the input holds glyphs (format 1), classes led by the rule set's class (format 2) or only its count (format 3, coverages); type 6 adds backtrack and lookahead. Type 8 gives one glyph in and out with backtrackCount and lookaheadCount. A malformed subtable, a coverage index past its subtable's array, or a record past the table is one error element, and the walk continues; an extension of an extension, or of a type differing from the lookup's first extension, is its subtable's badValue.

Colour — sparkles.font.colour ​

face.colourCapability reports which colour formats a face holds, independent of which the library renders, reading each table's header in O(1). The result has one ColourSupport per format: present when the face has the table, and has, a FontResult!bool that is false for a table holding no data for the format and the table's error when its header cannot be verified (usable is has being true). Support is never claimed for data that was not checked.

Entryhas is true for
colrLayersCOLR version 0 or 1 with base glyph records, whose base glyph and layer arrays fit
colrPaintCOLR version 1 with a non-empty BaseGlyphList (offset at byte 14) whose records fit
cpalCPAL version 0 or 1 with palettes, whose index array and colour records fit
cbdtCBDT with a CBLC holding at least one bitmap size, both of major version 2 or 3
sbixsbix version 1 with strikes
svgSVG version 0 with a non-empty document list

A COLR version above 1 is unsupportedVersion for both COLR entries, where HarfBuzz reads it as version 1; a CBDT without CBLC is missingTable naming CBLC, where HarfBuzz counts it. A truncated header, or an offset outside its table, is that entry's error.