ot

package
v0.1.0-experimental.3 Latest Latest
Warning

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

Go to latest
Published: Nov 24, 2021 License: BSD-3-Clause Imports: 10 Imported by: 0

README

ot – OpenType Font Tables and Features

Package ot provides access to OpenType font tables and features. The intended audience for this package are:

*︎ text shapers, such as HarfBuzz (https://harfbuzz.github.io/what-does-harfbuzz-do.html)

*︎ glyph rasterizers, such as FreeType (https://github.com/golang/freetype)

*︎ any application needing to have the internal structure of an OpenType font file available, and possibly extending the methods of this module by handling additional font tables

This package is not intended for font manipulation applications. You may check out https://pkg.go.dev/github.com/ConradIrwin/font for this.

Status

This is very much work in progress. Handling fonts is fiddly and fonts have become complex software applications in their own right. I often need a break from the vast desert of bytes (without any sign posts), which is what font data files are at their core. Breaks, where I talk to myself and ask, this is what you do in your spare time? Really?

No font collections nor variable fonts are supported yet.

Other Solutions to Font Parsing

There are (at least) two Go packages around for parsing SFNT fonts:

It’s always a good idea to prefer packages from the Go core team, and the x/image/font/sfnt package is certainly well suited for rasterizing applications (as proven by the test cases). However, it is less well suited as a basis for the task of text-shaping. That task requires access to the tables contained in a font and utilities for navigating them, cross-checking entries, applying different shaping algorithms, etc. Moreover, the API is not intended to be extended by other packages, but has been programmed with a concrete target in mind.

ConradIrwin/font allows access to the font tables it has parsed. However, its focus is on font file manipulation (read in ⇒ manipulate ⇒ export), thus access to tables means more or less access to the tables binaries and doing much of the interpretation on the client side. I started out pursuing this approach, but at the end abondened it. The main reason is that I prefer the approach of the Go core team of keeping the initial font binary in memory, and not copying out too much into separate buffers or data structures. I need to have the binary data in memory anyway, as for complex-script shaping we will rely on HarfBuzz for a long time to come (HarfBuzz receives a font as a byte-blob and does its own font parsing).

A better suited blueprint of what we're trying to accomplish is this implementation in Rust:

Abstractions

Package ot will not provide functions to interpret any table of a font, but rather expose the tables to the client in a semantic way. It is not possible to, for example, ask package ot for a kerning distance between two glyphs. Instead, clients have to check for the availability of kerning tables and consult the appropriate table(s) themselves. From this point of view ot is a low-level package.

The binary data of a font can be thought of as a bunch of structures connected by links. The linking is done by offsets (u16 or u32) from link anchors defined by the spec. Data-structures may be categorized into fields-like, list-like and map-like. The implementation details of these structures vary heavily, and many internal tables combine more than one category, but conceptually it should be possible to navigate the graph, spanned by links and structures, without caring about implementation details. Consider this overview of OpenType Layout tables (GSUB and GPOS):

OpenType structure for layout tables

GSUB is an important table for text shaping, so package ot offers a special semantic type. However, this type is not exposing GSUB in full depth. To find out if the current font contains features applicable for Latin script with Turkish language flavour, type:

langSys := gsub.ScriptList.LookupTag(T("latn")).Navigate().Map().LookupTag(T("TRK")).Navigate().List()
fmt.Println("%d font-features for Turkish", langSys.Len())
// => yields 24 with font 'Calibri'

This is an early draft, not suited to be used by other programs.

Documentation

Overview

Package ot provides access to OpenType font tables and features. Intended audience for this package are:

▪︎ text shapers, such as HarfBuzz (https://harfbuzz.github.io/what-does-harfbuzz-do.html)

▪︎ glyph rasterizers, such as FreeType (https://github.com/golang/freetype)

▪︎ any application needing to have the internal structure of an OpenType font file available, and possibly extending the methods of package `ot` by handling additional font tables

Package `ot` will not provide functions to interpret any table of a font, but rather just expose the tables to the client. For example, it is not possible to ask package `ot` for a kerning distance between two glyphs. Clients have to check for the availability of kerning information and consult the appropriate table(s) themselves. From this point of view, `ot` is a low-level package. Functions for getting kerning values and other layout directives from a font are homed in a sister package. Likewise, this package is not intended for font manipulation applications (you may check out https://pkg.go.dev/github.com/ConradIrwin/font for that).

OpenType fonts contain a whole lot of different tables and sub-tables. This package strives to make the semantics of the tables accessible, thus has a lot of different types for the different kinds of OT tables. This makes `ot` a shallow API, but it will nevertheless abstract away some implementation details of fonts:

▪︎ Format versions: many OT tables may occur in a variety of formats. Tables in `ot` will hide the concrete format and structure of underlying OT tables.

▪︎ Word size: offsets in OT may either be 2-byte or 4-byte values. Package `ot` will hide offset-related details (see section below).

▪︎ Bugs in fonts: many fonts in the wild contain entries that—strictly speaking—infringe upon the OT specification (for example, Calibri has an overflow in a 'kern' table variable), but an application using it should not fail because of recoverable errors. Package `ot` will try to circumvent known bugs in common fonts.

Schrödinger's Cat

OpenType fonts contain quite a multitude of tables, and a package intended to expose the semantics of OT tables ought to wrap each of these into a Go type. However, this would waste both time and space, as the usage of subsets of these tables is mutually exclusive (think 'head' and 'bhea'). And it would make the API of package `ot` even more broad as it already is. We therefore focus on the most important tables to be semantically wrapped in Go types and find a different approach for other tables and their OT data structures.

The binary data of a font can be thought of as a bunch of structures connected by links. The linking is done by offsets (u16 or u32) from link anchors defined by the spec. Data-structures may be categorized into fields-like, list-like and map-like. The implementation details of these structures vary heavily, and many internal tables combine more than one category, but conceptually it should be possible to navigate the graph, spanned by links and structures, without caring about implementation details. This is where the cat comes in.

We design an abstraction resting on chains of navigation items and links. There surely is a fancy name from functional theory on this (monads on functions on font data), but I prefer to think about them as Schrödinger's cat: In the end you have to open the box in order to know if the cat is alive or dead. Before we get too quantum, however, let's consider an example. The OpenType specification flags the 'OS/2' table as mandatory (though unused on Mac platforms), but package `ot` does not offer a type for it. As a client, how do you access, e.g., OS/2.xAvgCharWidth? We start by requesting OS/2 as a vanilla table:

os2 := myfont.Table[T("OS/2")]

This should succeed unless `myfont` is broken. From there on, clients will have to consult the OpenType specification. That will tell them that xAvgCharWidth is the 2nd field (index 1) of table OS/2, right after the version field.

xAvgCharWidth := os2.Fields().Get(1).U16(0)

This will read xAvgCharWidth as an uint16, which is the data type of xAvgCharWidth according to the spec. That sure looks like a complicated way of getting a number out of a struct, but remember that we agreed on having an abstraction on top of field-likes, list-likes and map-likes. You didn't have to think about version differences in OT OS/2-tables or byte-offsets from anchors.

But I promised you a cat, you say? In fact, the example already had one included, but's let's head over to a bigger cat. The most complex OT tables, apart from glyphs themselves, include the so-called “layout-tables”.

calibri := ot.Parse(…)                     // find font 'Calibri' on our system
gsub := calibri.Table(T("GSUB")).Self().AsGSub()            // semantic Go type

GSUB is an important table for text shaping, so package `ot` offers a special type. However, this type is not exposing GSUB in full depth! Thus we type:

feats := gsub.ScriptList.LookupTag(T("latn")).Navigate().Map().LookupTag(T("TRK")).Navigate().List()
fmt.Println("%d features for Turkish", feats.Len())
// => yields 24

If you happen to not know the OpenType specification by heart, I'll help you out: We want to know if the font contains features applicable for Latin script with Turkish language flavour ('Calibri' actually does). The line of code is quite a mouthful, I'll readily concede. However, if you ever wrote code to extract information from a font file, you'd probably be used to a lot of error branches like this:

latinScript, ok := GSUB.lookup("latn")                 // pseudo code
if !ok {
    … // opt out
}
turkishLangRecord, ok := latinScript.lookup("TRK")     // pseudo code
if !ok {
    … // opt out (use default)
}
// etc …

So in effect, we're checking multiple times if the cat is still okay, until we eventually reach the box we're looking for. Package `ot` will let you travel the distance without reboxing the cat and just check once at the end. In other words, it's null-safe (imagine some kind of hidden Maybe-type).

Some problems arise with such an approach:

▪︎ Neither syntax nor type-system do guide you, but clients rather have to consult the OpenType specification (not a fun read).

▪︎ Oftentimes you need some trial-and-error to find the right navigation items. It's hard to completely document every path, because then one would re-write the OT tables' spec.

▪︎ To fit every OT-structure in the mould of the aforementioned three abstractions, some OT tables have to be “bended”. It's sometimes not intuitively clear what abstraction is the best, or which one `ot` would choose.

At the end of the day we will see if this approach does the job when we gain some experience with using it from a client perspective.

Status

Work in progress. Handling fonts is fiddly and fonts have become complex software applications in their own right. I often need a break from the vast desert of bytes (without any sign posts), which is what font data files are at their core. A break where I talk to myself and ask, this is what you do in your spare time? Really?

No font collections nor variable fonts are supported yet, but will be in time.

License

Governed by a 3-Clause BSD license. License file may be found in the root folder of this module.

Copyright © 2017–2021 Norbert Pillmayer <norbert@pillmayer.com>

Some code has originally been copied over from golang.org/x/image/font/sfnt/cmap.go, as the cmap-routines are not accessible through the sfnt package's API. I understand this to be legally okay as long as the Go license information stays intact.

Copyright 2017 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.

The license file mentioned can be found in file GO-LICENSE at the root folder of this module.

Index

Constants

View Source
const (
	GDefGlyphClassDefSection    = "GlyphClassDef"
	GDefAttachListSection       = "AttachList"
	GDefLigCaretListSection     = "LigCaretList"
	GDefMarkAttachClassSection  = "MarkAttachClassDef"
	GDefMarkGlyphSetsDefSection = "MarkGlyphSetsDef"
	GDefItemVarStoreSection     = "ItemVarStore"
)

Sections of a GDEF table.

Variables

View Source
var DFLT = T("DFLT")

Functions

func IsGPosLookupType

func IsGPosLookupType(ltype LayoutTableLookupType) bool

Types

type AttachmentPointList

type AttachmentPointList struct {
	Coverage GlyphRange
	Count    int
	// contains filtered or unexported fields
}

An AttachmentPointList consists of a count of the attachment points on a single glyph (PointCount) and an array of contour indices of those points (PointIndex), listed in increasing numerical order.

type AxisTable

type AxisTable struct {
	// contains filtered or unexported fields
}

type BaseTable

type BaseTable struct {
	// contains filtered or unexported fields
}

BaseTable, the Baseline table (BASE), provides information used to align glyphs of different scripts and sizes in a line of text, whether the glyphs are in the same font or in different fonts. BaseTable, the Glyph Definition (BSE) table, provides various glyph properties used in OpenType Layout processing.

See also https://docs.microsoft.com/en-us/typography/opentype/spec/base

func (*BaseTable) Binary

func (tb *BaseTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*BaseTable) Extent

func (tb *BaseTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*BaseTable) Fields

func (tb *BaseTable) Fields() Navigator

func (*BaseTable) Self

func (tb *BaseTable) Self() TableSelf

type CMapGlyphIndex

type CMapGlyphIndex interface {
	Lookup(rune) GlyphIndex
}

CMapGlyphIndex represents a CMap table index to receive a glyph index from a code-point.

type CMapTable

type CMapTable struct {
	GlyphIndexMap CMapGlyphIndex
	// contains filtered or unexported fields
}

CMapTable represents an OpenType cmap table, i.e. the table to receive glyphs from code-points.

See https://docs.microsoft.com/de-de/typography/opentype/spec/cmap

Consulting the cmap table is a very frequent operation on fonts. We therefore construct an internal representation of the looup table. A cmap table may contain more than one lookup table, but we will only instantiate the most appropriate one. Clients who need access to all the lookup tables will have to parse them themselves.

func (*CMapTable) Binary

func (tb *CMapTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*CMapTable) Extent

func (tb *CMapTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*CMapTable) Fields

func (tb *CMapTable) Fields() Navigator

func (*CMapTable) Self

func (tb *CMapTable) Self() TableSelf

type ClassDefinitions

type ClassDefinitions struct {
	// contains filtered or unexported fields
}

ClassDefinitions groups glyphs into classes, denoted as integer values.

From the spec: For efficiency and ease of representation, a font developer can group glyph indices to form glyph classes. Class assignments vary in meaning from one lookup subtable to another. For example, in the GSUB and GPOS tables, classes are used to describe glyph contexts. GDEF tables also use the idea of glyph classes. (see https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table)

func (*ClassDefinitions) Lookup

func (cdef *ClassDefinitions) Lookup(glyph GlyphIndex) int

Lookup returns the class defined for a glyph, or 0 (= default class).

type Coverage

type Coverage struct {
	GlyphRange GlyphRange
	// contains filtered or unexported fields
}

Covarage denotes an indexed set of glyphs. Each LookupSubtable (except an Extension LookupType subtable) in a lookup references a Coverage table (Coverage), which specifies all the glyphs affected by a substitution or positioning operation described in the subtable. The GSUB, GPOS, and GDEF tables rely on this notion of coverage. If a glyph does not appear in a Coverage table, the client can skip that subtable and move immediately to the next subtable.

type Font

type Font struct {
	F      *font.ScalableFont
	Header *FontHeader
	// contains filtered or unexported fields
}

Font represents the internal structure of an OpenType font. It is used to navigate properties of a font for typesetting tasks.

func Parse

func Parse(font []byte) (*Font, error)

Parse parses an OpenType font from a byte slice. An ot.Font needs ongoing access to the fonts byte-data after the Parse function returns. Its elements are assumed immutable while the ot.Font remains in use.

func (*Font) Table

func (otf *Font) Table(tag Tag) Table

Table returns the font table for a given tag. If a table for a tag cannot be found in the font, nil is returned.

Please note that the current implementation will not interpret every kind of font table, either because there is no need to do so (with regard to text shaping or rasterization), or because implementation is not yet finished. However, `Table` will return at least a generic table type for each table contained in the font, i.e. no table information will be dropped.

For example to receive the `OS/2` and the `loca` table, clients may call

os2  := otf.Table(ot.T("OS/2"))
loca := otf.Table(ot.T("loca")).Self().AsLoca()

Table tag names are case-sensitive, following the names in the OpenType specification, i.e., one of:

avar BASE CBDT CBLC CFF CFF2 cmap COLR CPAL cvar cvt DSIG EBDT EBLC EBSC fpgm fvar gasp GDEF glyf GPOS GSUB gvar hdmx head hhea hmtx HVAR JSTF kern loca LTSH MATH maxp MERG meta MVAR name OS/2 PCLT post prep sbix STAT SVG VDMX vhea vmtx VORG VVAR

func (*Font) TableTags

func (otf *Font) TableTags() []Tag

TableTags returns a list of tags, one for each table contained in the font.

type FontHeader

type FontHeader struct {
	FontType   uint32
	TableCount uint16
}

FontHeader is a directory of the top-level tables in a font. If the font file contains only one font, the table directory will begin at byte 0 of the file. If the font file is an OpenType Font Collection file (see below), the beginning point of the table directory for each font is indicated in the TTCHeader.

OpenType fonts that contain TrueType outlines should use the value of 0x00010000 for the FontType. OpenType fonts containing CFF data (version 1 or 2) should use 0x4F54544F ('OTTO', when re-interpreted as a Tag). The Apple specification for TrueType fonts allows for 'true' and 'typ1', but these version tags should not be used for OpenType fonts.

type GDefHeader

type GDefHeader struct {
	// contains filtered or unexported fields
}

GDefHeader contains general information for a Glyph Definition table (GDEF).

func (GDefHeader) Version

func (h GDefHeader) Version() (int, int)

Version returns major and minor version numbers for this GDef table.

type GDefTable

type GDefTable struct {
	GlyphClassDef          ClassDefinitions
	AttachmentPointList    AttachmentPointList
	MarkAttachmentClassDef ClassDefinitions
	MarkGlyphSets          []GlyphRange
	// contains filtered or unexported fields
}

GDefTable, the Glyph Definition (GDEF) table, provides various glyph properties used in OpenType Layout processing.

See also https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table

func (*GDefTable) Binary

func (tb *GDefTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*GDefTable) Extent

func (tb *GDefTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*GDefTable) Fields

func (tb *GDefTable) Fields() Navigator

func (*GDefTable) Header

func (t *GDefTable) Header() GDefHeader

Header returns the Glyph Definition header for t.

func (*GDefTable) Self

func (tb *GDefTable) Self() TableSelf

type GPosTable

type GPosTable struct {
	LayoutTable
	// contains filtered or unexported fields
}

GPosTable is a type representing an OpenType GPOS table (see https://docs.microsoft.com/en-us/typography/opentype/spec/gsub).

func (*GPosTable) Binary

func (tb *GPosTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*GPosTable) Extent

func (tb *GPosTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*GPosTable) Fields

func (tb *GPosTable) Fields() Navigator

func (*GPosTable) Self

func (tb *GPosTable) Self() TableSelf

type GSubTable

type GSubTable struct {
	LayoutTable
	// contains filtered or unexported fields
}

GSubTable is a type representing an OpenType GSUB table (see https://docs.microsoft.com/en-us/typography/opentype/spec/gpos).

func (*GSubTable) Binary

func (tb *GSubTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*GSubTable) Extent

func (tb *GSubTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*GSubTable) Fields

func (tb *GSubTable) Fields() Navigator

func (*GSubTable) Self

func (tb *GSubTable) Self() TableSelf

type GlyphClassDefEnum

type GlyphClassDefEnum uint16

GlyphClassDefEnum lists the glyph classes for ClassDefinitions ('GlyphClassDef'-table).

const (
	BaseGlyph      GlyphClassDefEnum = iota //single character, spacing glyph
	LigatureGlyph                           //multiple character, spacing glyph
	MarkGlyph                               //non-spacing combining glyph
	ComponentGlyph                          //part of single character, spacing glyph
)

type GlyphIndex

type GlyphIndex uint16

GlyphIndex is a glyph index in a font.

type GlyphRange

type GlyphRange interface {
	Match(g GlyphIndex) (int, bool) // is glyph ID g
	ByteSize() int
}

GlyphRange is a type frequently used by sub-tables of layout tables (GPOS and GSUB). If an input glyph g is contained in the range, and index and true is returned, false otherwise.

type HHeaTable

type HHeaTable struct {
	NumberOfHMetrics int
	// contains filtered or unexported fields
}

HHeaTable contains information for horizontal layout.

func (*HHeaTable) Binary

func (tb *HHeaTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*HHeaTable) Extent

func (tb *HHeaTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*HHeaTable) Fields

func (tb *HHeaTable) Fields() Navigator

func (*HHeaTable) Self

func (tb *HHeaTable) Self() TableSelf

type HMtxTable

type HMtxTable struct {
	NumberOfHMetrics int
	// contains filtered or unexported fields
}

HMtxTable contains metric information for the horizontal layout each of the glyphs in the font. Each element in the contained hMetrics-array has two parts: the advance width and left side bearing. The value NumberOfHMetrics is taken from the `hhea` table. In a monospaced font, only one entry is required but that entry may not be omitted. Optionally, an array of left side bearings follows. The corresponding glyphs are assumed to have the same advance width as that found in the last entry in the hMetrics array. Since there must be a left side bearing and an advance width associated with each glyph in the font, the number of entries in this array is derived from the total number of glyphs in the font minus the value `HHea.NumberOfHMetrics`, which is copied into the HMtxTable for easier access.

func (*HMtxTable) Binary

func (tb *HMtxTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*HMtxTable) Extent

func (tb *HMtxTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*HMtxTable) Fields

func (tb *HMtxTable) Fields() Navigator

func (*HMtxTable) Self

func (tb *HMtxTable) Self() TableSelf

type HeadTable

type HeadTable struct {
	Flags            uint16 // see https://docs.microsoft.com/en-us/typography/opentype/spec/head
	UnitsPerEm       uint16 // values 16 … 16384 are valid
	IndexToLocFormat uint16 // needed to interpret loca table
	// contains filtered or unexported fields
}

HeadTable gives global information about the font. Only a small subset of fields are made public by HeadTable, as they are needed for consistency-checks. To read any of the other fields of table 'head' use:

head   := otf.Table(T("head"))
fields := head.Fields().Get(n)     // get nth field value
fields := head.Fields().All()      // get a slice with all field values

See also type `Navigator`.

func (*HeadTable) Binary

func (tb *HeadTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*HeadTable) Extent

func (tb *HeadTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*HeadTable) Fields

func (tb *HeadTable) Fields() Navigator

func (*HeadTable) Self

func (tb *HeadTable) Self() TableSelf

type KernSubTableInfo

type KernSubTableInfo struct {
	IsHorizontal  bool // kern data may be horizontal or vertical
	IsMinimum     bool // if false, table has kerning values, otherwise has minimum values
	IsOverride    bool // if true, the value in this table should replace the value currently being accumulated
	IsCrossStream bool // if true, kerning is perpendicular to the flow of the text
	Offset        uint16
	Length        uint32
}

KernSubTableInfo contains header information for a kerning sub-table. Currently only format 0 of kerning tables is supported (as does MS Windows).

type KernTable

type KernTable struct {
	// contains filtered or unexported fields
}

KernTable gives information about kerning and kern pairs. The kerning table contains the values that control the inter-character spacing for the glyphs in a font. OpenType™ fonts containing CFF outlines are not supported by the 'kern' table and must use the GPOS OpenType Layout table.

func (*KernTable) Binary

func (tb *KernTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*KernTable) Extent

func (tb *KernTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*KernTable) Fields

func (tb *KernTable) Fields() Navigator

func (*KernTable) Self

func (tb *KernTable) Self() TableSelf

func (*KernTable) SubTableInfo

func (t *KernTable) SubTableInfo(n int) KernSubTableInfo

SubTableInfo returns information about a kerning sub-table. n is 0…N-1.

type LayoutHeader

type LayoutHeader struct {
	// contains filtered or unexported fields
}

LayoutHeader represents header information common to the layout tables.

func (LayoutHeader) Version

func (h LayoutHeader) Version() (int, int)

Version returns major and minor version numbers for this layout table.

type LayoutTable

type LayoutTable struct {
	ScriptList  TagRecordMap
	FeatureList TagRecordMap
	LookupList  LookupList
	// contains filtered or unexported fields
}

LayoutTable is a base type for layout tables. OpenType specifies two such tables–GPOS and GSUB–which share some of their structure.

func (*LayoutTable) Header

func (t *LayoutTable) Header() LayoutHeader

Header returns the layout table header for this GSUB table.

type LayoutTableLookupFlag

type LayoutTableLookupFlag uint16

LayoutTableLookupFlag is a flag type for layout tables (GPOS and GSUB).

const (
	// Note that the RIGHT_TO_LEFT flag is used only for GPOS type 3 lookups and is ignored
	// otherwise. It is not used by client software in determining text direction.
	LOOKUP_FLAG_RIGHT_TO_LEFT             LayoutTableLookupFlag = 0x0001
	LOOKUP_FLAG_IGNORE_BASE_GLYPHS        LayoutTableLookupFlag = 0x0002 // If set, skips over base glyphs
	LOOKUP_FLAG_IGNORE_LIGATURES          LayoutTableLookupFlag = 0x0004 // If set, skips over ligatures
	LOOKUP_FLAG_IGNORE_MARKS              LayoutTableLookupFlag = 0x0008 // If set, skips over all combining marks
	LOOKUP_FLAG_USE_MARK_FILTERING_SET    LayoutTableLookupFlag = 0x0010 // If set, indicates that the lookup table structure is followed by a MarkFilteringSet field.
	LOOKUP_FLAG_reserved                  LayoutTableLookupFlag = 0x00E0 // For future use (Set to zero)
	LOOKUP_FLAG_MARK_ATTACHMENT_TYPE_MASK LayoutTableLookupFlag = 0xFF00 // If not zero, skips over all marks of attachment type different from specified.
)

Lookup flags of layout tables (GPOS and GSUB)

type LayoutTableLookupType

type LayoutTableLookupType uint16

LayoutTableLookupType is a type identifier for layout lookup records (GPOS and GSUB). Enum values are different for GPOS and GSUB.

const (
	GPosLookupTypeSingle            LayoutTableLookupType = 1 // Adjust position of a single glyph
	GPosLookupTypePair              LayoutTableLookupType = 2 // Adjust position of a pair of glyphs
	GPosLookupTypeCursive           LayoutTableLookupType = 3 // Attach cursive glyphs
	GPosLookupTypeMarkToBase        LayoutTableLookupType = 4 // Attach a combining mark to a base glyph
	GPosLookupTypeMarkToLigature    LayoutTableLookupType = 5 // Attach a combining mark to a ligature
	GPosLookupTypeMarkToMark        LayoutTableLookupType = 6 // Attach a combining mark to another mark
	GPosLookupTypeContextPos        LayoutTableLookupType = 7 // Position one or more glyphs in context
	GPosLookupTypeChainedContextPos LayoutTableLookupType = 8 // Position one or more glyphs in chained context
	GPosLookupTypeExtensionPos      LayoutTableLookupType = 9 // Extension mechanism for other positionings
)

GPOS Lookup Type Enumeration

const (
	GSubLookupTypeSingle          LayoutTableLookupType = 1 // Replace one glyph with one glyph
	GSubLookupTypeMultiple        LayoutTableLookupType = 2 // Replace one glyph with more than one glyph
	GSubLookupTypeAlternate       LayoutTableLookupType = 3 // Replace one glyph with one of many glyphs
	GSubLookupTypeLigature        LayoutTableLookupType = 4 // Replace multiple glyphs with one glyph
	GSubLookupTypeContext         LayoutTableLookupType = 5 // Replace one or more glyphs in context
	GSubLookupTypeChainingContext LayoutTableLookupType = 6 // Replace one or more glyphs in chained context
	GSubLookupTypeExtensionSubs   LayoutTableLookupType = 7 // Extension mechanism for other substitutions
	GSubLookupTypeReverseChaining LayoutTableLookupType = 8 // Applied in reverse order, replace single glyph in chaining context
)

GSUB Lookup Type Enumeration

func (LayoutTableLookupType) GPosString

func (lt LayoutTableLookupType) GPosString() string

GPosString interprets a layout table lookup type as a GPOS table type.

func (LayoutTableLookupType) GSubString

func (lt LayoutTableLookupType) GSubString() string

GSubString interprets a layout table lookup type as a GSUB table type.

type LocaTable

type LocaTable struct {
	// contains filtered or unexported fields
}

LocaTable stores the offsets to the locations of the glyphs in the font, relative to the beginning of the glyph data table. By definition, index zero points to the “missing character”, which is the character that appears if a character is not found in the font. The missing character is commonly represented by a blank box or a space.

func (*LocaTable) Binary

func (tb *LocaTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*LocaTable) Extent

func (tb *LocaTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*LocaTable) Fields

func (tb *LocaTable) Fields() Navigator

func (*LocaTable) Self

func (tb *LocaTable) Self() TableSelf

type Lookup

type Lookup struct {
	// contains filtered or unexported fields
}

Lookup tables are contained in a LookupList. A Lookup table defines the specific conditions, type, and results of a substitution or positioning action that is used to implement a feature. For example, a substitution operation requires a list of target glyph indices to be replaced, a list of replacement glyph indices, and a description of the type of substitution action.

Each Lookup table may contain only one type of information (LookupType), determined by whether the lookup is part of a GSUB or GPOS table. GSUB supports eight LookupTypes, and GPOS supports nine LookupTypes

Lookup implements the NavMap interface.

func (Lookup) AsTagRecordMap

func (l Lookup) AsTagRecordMap() TagRecordMap

AsTagRecordMap returns an empty TagRecordMap

func (Lookup) IsTagRecordMap

func (l Lookup) IsTagRecordMap() bool

IsTagRecordMap returns false

func (Lookup) Lookup

func (l Lookup) Lookup(g uint32) NavLocation

Lookup returns a byte segment as output of applying lookup l to input glyph g. g is shortened from 32-bit to 16-bit by using the low bits.

If g is not identified as applicable for the lookup feature, an emtpy byte segment is returned.

func (Lookup) LookupTag

func (l Lookup) LookupTag(tag Tag) NavLink

LookupTag is not defined for Lookup and will return a void link.

func (Lookup) Name

func (l Lookup) Name() string

func (Lookup) Subtable

func (l Lookup) Subtable(i int) *LookupSubtable

type LookupList

type LookupList struct {
	// contains filtered or unexported fields
}

A LookupList table contains an array of offsets to Lookup tables (lookupOffsets). The font developer defines the Lookup sequence in the Lookup array to control the order in which a text-processing client applies lookup data to glyph substitution or positioning operations. (See https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table).

Lookup tables are essential for implementing the various OpenType font features. The details are sometimes tricky and it's often hard to remember how a lookup type works, if you're not doing it on a daily basis. As this is a low-level package, we focus on decoding the sub-tables for lookups and on abstracting the details of the specific variants of GSUB- and GPOS-lookup away, offering a map-like behaviour.

Lookups depend on sub-tables to do the actual work, which in turn may occur in various format versions. This package implements all table/sub-table variants defined by the OT spec, together with the algorithms to access their functionality.

Other packages working on top of `ot` should abstract this further and operate in terms of OT features, hiding altogether the existence of lookup lists and lookups from clients.

LookupList implements the NavList interface.

func (LookupList) All

func (a LookupList) All() []NavLocation

func (LookupList) Get

func (a LookupList) Get(i int) NavLocation

Get returns item #i as a byte location.

func (LookupList) Len

func (a LookupList) Len() int

Len returns the number of entries in the list.

func (LookupList) Navigate

func (ll LookupList) Navigate(i int) Lookup

Navigate will navigate to Lookup i in the list.

func (LookupList) Size

func (a LookupList) Size() int

Size of array a in bytes.

type LookupSubtable

type LookupSubtable struct {
	LookupType LayoutTableLookupType // may differ from Lookup.Type for Type=Extension
	Format     uint16                // lookup subtables may come in more than one format
	Coverage   Coverage              // for which glyphs is this lookup applicable
	Index      VarArray              // Index tables/arrays to lookup up substitutions/positions
	Support    interface{}           // some lookup variants use additional data
}

LookupSubtable is a type for OpenType Lookup Subtables, which are the basis for Lookup operations (see https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table).

“Each LookupType may occur in one or more subtable formats. The ‘best’ format depends on the type of substitution and the resulting storage efficiency. When glyph information is best presented in more than one format, a single lookup may define more than one subtable, as long as all the subtables are for the same LookupType.”

The interpretation of the Index-elements and the Support field depend heavily on the type of the lookup-subtable. For example, for a GSUB lookup of type 'Single Substitution Format 1' Support will be interpreted as a delta and be added to glyph IDs, while lookup type 'Ligature Substitution Format 1' will ignore the Support field and repeatedly descend into the Index tables to match glyph sequences suitable for ligature substitution. (see https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#lookuptype-1-single-substitution-subtable). Package `ot` will not do this interpretation, but rather leave it to higher-protocol packages.

func (LookupSubtable) SequenceRule

func (lksub LookupSubtable) SequenceRule(b fontBinSegm) sequenceRule

TODO Argument should be NavLocation, return value should be []SeqLookupRecord

SequenceRule table: Type Name Description uint16 glyphCount Number of glyphs to be matched uint16 seqLookupCount Number of SequenceLookupRecords uint16 inputSequence[glyphCount-1] Sequence of classes to be matched to the input glyph sequence, beginning with the second glyph position SequenceLookupRecord seqLookupRecords[seqLookupCount] Array of SequenceLookupRecords

type MaxPTable

type MaxPTable struct {
	NumGlyphs int
	// contains filtered or unexported fields
}

MaxPTable establishes the memory requirements for this font. The 'maxp' table contains a count for the number of glyphs in the font. Whenever this value changes, other tables which depend on it should also be updated.

func (*MaxPTable) Binary

func (tb *MaxPTable) Binary() []byte

Binary returns the bytes of this table. Should be treatet as read-only by clients, as it is a view into the original data.

func (*MaxPTable) Extent

func (tb *MaxPTable) Extent() (uint32, uint32)

Offset returns offset and byte size of this table within the OpenType font.

func (*MaxPTable) Fields

func (tb *MaxPTable) Fields() Navigator

func (*MaxPTable) Self

func (tb *MaxPTable) Self() TableSelf
type NavLink interface {
	Base() NavLocation   // source location
	Jump() NavLocation   // destination location
	IsNull() bool        // is this a valid link?
	Navigate() Navigator // interpret destination as an OpenType structure element
	Name() string        // OpenType structure name of destination
}

NavLink is a type to represent the transfer between one Navigator item and another. Clients may use it to either arrive at the binary segment of the destination (call Jump) or to receive the destination as a Navigator item (call Navigate).

Name returns the class name of the link's destination. IsNull is used to check if this NavLink represents a link to a valid destination.

type NavList interface {
	Len() int            // number of items in the list
	Get(int) NavLocation // bytes of entry #n
	All() []NavLocation  // all entries as (possibly variable sized) byte segments
}

NavList represents a sequence of—possibly unequal sized—items, addressable by position.

func ParseList

func ParseList(b fontBinSegm, N int, recordSize int) NavList
type NavLocation interface {
	Size() int                  // size in bytes
	Bytes() []byte              // return as a byte slice
	Slice(int, int) NavLocation // return a sub-segment of this location
	Reader() io.Reader          // return as a Reader
	U16(int) uint16             // convenience access to 16 bit data at byte index
	U32(int) uint32             // convenience access to 32 bit data at byte index
	Glyphs() []GlyphIndex       // convenience conversion to slice of glyphs
}

NavLocation is a position at a byte within a font's binary data. It represents the start of a segment/slice of binary data.

NavLocation is always the final link of a chain of Navigator calls, giving access to underlying (unstructured) font data. It is the client's responsibility to interpret the structure and impose it onto the NavLocation's bytes.

If somewhere along a chain of navigation calls an error occured, the finally resulting NavLocation may be of size 0.

type NavMap interface {
	Lookup(uint32) NavLocation
	LookupTag(Tag) NavLink
	Name() string
	IsTagRecordMap() bool
	AsTagRecordMap() TagRecordMap
}

NavMap wraps OpenType structures which are map-like. Lookup is always done on 32-bit values, even if the map's keys are 16-bit (will be shortened to low bytes in such cases).

TagRecordMap is a special kind of NavMap.

type Navigator interface {
	Name() string  // returns the name of the underlying OpenType table
	Link() NavLink // non-void if Navigator contains a link
	Map() NavMap   // non-void if Navigator contains a map-like
	List() NavList // non-void if Navigator contains a list-like
	IsVoid() bool  // may be true if a previous error in the call chain occured
	Error() error  // previous error in call chain, if any
}

Navigator is an interface type to wrap various kinds of OpenType structure. On any given Navigator item, not all of the functions may result in sensible values returned. For example, OpenType map-like structures will return a map with a call to `Map`, but will return an invalid `Link` and an empty `List`. A Navigator may contain more than one OT structure, thus more than one such call may return a valid non-void entry.

If a previous call in a navigation chain has caused an error, successing Navigator items will remember that error (call to `Error`) and will wrap only void Navigators (nil-safe).

type SequenceContext

type SequenceContext struct {
	BacktrackCoverage []Coverage         // for format 3
	InputCoverage     []Coverage         // for format 3
	LookaheadCoverage []Coverage         // for format 3
	ClassDefs         []ClassDefinitions // for format 2
}

SequenceContext is a type for identifying the input sequence context for contextual lookups (see https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#common-structures-for-contextual-lookup-subtables).

Clients will receive this struct in the `Support` field of a LookupSubtable, whenever it's appropriate:

▪︎ GSUB Lookup Type 5 and 6, format 2 and 3

▪︎ GPOS Lookup Type 5 and 7, format 2 and 3

For type 5, the length of each non-void slice will be exactly 1; for type 6/7 they may be of arbitrary length. Its exact allocation will depend on the type/format combination of the lookup subtable.

type Table

type Table interface {
	Extent() (uint32, uint32) // offset and byte size within the font's binary data
	Binary() []byte           // the bytes of this table; should be treatet as read-only by clients
	Fields() Navigator        // start for navigation calls
	Self() TableSelf          // reference to itself
}

Table represents one of the various OpenType font tables

Required Tables, according to the OpenType specification: 'cmap' (Character to glyph mapping), 'head' (Font header), 'hhea' (Horizontal header), 'hmtx' (Horizontal metrics), 'maxp' (Maximum profile), 'name' (Naming table), 'OS/2' (OS/2 and Windows specific metrics), 'post' (PostScript information).

Advanced Typographic Tables: 'BASE' (Baseline data), 'GDEF' (Glyph definition data), 'GPOS' (Glyph positioning data), 'GSUB' (Glyph substitution data), 'JSTF' (Justification data), 'MATH' (Math layout data).

For TrueType outline fonts: 'cvt ' (Control Value Table, optional), 'fpgm' (Font program, optional), 'glyf' (Glyph data), 'loca' (Index to location), 'prep' (CVT Program, optional), 'gasp' (Grid-fitting/Scan-conversion, optional).

For OpenType fonts based on CFF outlines: 'CFF ' (Compact Font Format 1.0), 'CFF2' (Compact Font Format 2.0), 'VORG' (Vertical Origin, optional).

Currently not used/supported: SVG font table, bitmap glyph tables, color font tables, font variations.

type TableSelf

type TableSelf struct {
	// contains filtered or unexported fields
}

TableSelf is a reference to a table. Its primary use is for converting a generic table to a concrete table flavour, and for reproducing the name tag of a table.

func (TableSelf) AsCMap

func (self TableSelf) AsCMap() *CMapTable

AsCMap returns this table as a cmap table, or nil.

func (TableSelf) AsGDef

func (self TableSelf) AsGDef() *GDefTable

AsGDef returns this table as a GDEF table, or nil.

func (TableSelf) AsGPos

func (self TableSelf) AsGPos() *GPosTable

AsGPos returns this table as a GPOS table, or nil.

func (TableSelf) AsGSub

func (self TableSelf) AsGSub() *GSubTable

AsGSub returns this table as a GSUB table, or nil.

func (TableSelf) AsHHea

func (self TableSelf) AsHHea() *HHeaTable

AsHHea returns this table as a hhea table, or nil.

func (TableSelf) AsHMtx

func (self TableSelf) AsHMtx() *HMtxTable

AsHMtx returns this table as a hmtx table, or nil.

func (TableSelf) AsHead

func (self TableSelf) AsHead() *HeadTable

AsHead returns this table as a head table, or nil.

func (TableSelf) AsKern

func (self TableSelf) AsKern() *KernTable

AsKern returns this table as a kern table, or nil.

func (TableSelf) AsLoca

func (self TableSelf) AsLoca() *LocaTable

AsLoca returns this table as a kern table, or nil.

func (TableSelf) AsMaxP

func (self TableSelf) AsMaxP() *MaxPTable

AsMaxP returns this table as a kern table, or nil.

func (TableSelf) NameTag

func (self TableSelf) NameTag() Tag

NameTag returns the 4-letter name of a table.

type Tag

type Tag uint32

Tag is defined by the spec as: Array of four uint8s (length = 32 bits) used to identify a table, design-variation axis, script, language system, feature, or baseline

func MakeTag

func MakeTag(b []byte) Tag

MakeTag creates a Tag from 4 bytes, e.g., If b is shorter or longer, it will be silently extended or cut as appropriate

MakeTag([]byte("cmap"))

func T

func T(t string) Tag

T returns a Tag from a (4-letter) string. If t is shorter or longer, it will be silently extended or cut as appropriate

func (Tag) String

func (t Tag) String() string

type TagRecordMap

type TagRecordMap interface {
	Name() string           // OpenType specification name of this map
	LookupTag(Tag) NavLink  // returns the link associated with a given tag
	Tags() []Tag            // returns all the tags which the map uses as keys
	Count() int             // number of entries in the map
	Get(int) (Tag, NavLink) // get entry at position n
}

A TagRecordMap is a dict-type (map) to receive a data record (returned as a link) from a given tag. This kind of map is used within OpenType fonts in several instances, e.g. https://docs.microsoft.com/en-us/typography/opentype/spec/base#basescriptlist-table

For some record maps the (tag) keys are not unique (e.g., the feature-list table), so in this case the first matching entry will be returned.

type VarArray

type VarArray interface {
	Get(i int, deep bool) (NavLocation, error) // get record at index i; if deep: query nested arrays
	Size() int                                 // get the number of entries
}

VarArray is a type for arrays of variable length records, which in turn may point to nested arrays of (variable size) records.

func ParseVarArray

func ParseVarArray(loc NavLocation, sizeOffset, arrayDataGap int, name string) VarArray

ParseVarArray interprets a byte sequence as a `VarArray`.

Jump to

Keyboard shortcuts

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