typeset

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MPL-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package typeset loads TrueType fonts, shapes and wraps text, and places one text block on a page. It is pure computation: it knows nothing about PDF.

Fonts

A Font is an immutable, validated static TrueType font (glyf outlines). Variable fonts, CFF (OpenType/CFF), collections, fonts whose OS/2 fsType forbids embedding, and malformed files are rejected with an error; loading never panics. A font's identity is the SHA-256 of its bytes. A Font is safe to share between goroutines.

Text

Text is left-to-right Latin, Greek and Cyrillic (script classes Common and Inherited included) with combining marks positioned by the font's GPOS. Text is never normalized: decomposed and precomposed forms stay as given. Every character must have a glyph in the font; a missing glyph is an error, never a substitute box. Right-to-left and complex scripts, control characters (including TAB), and format characters (joiners, bidi controls, soft hyphen) are rejected early with a TextError.

Whitespace

  • CRLF and lone CR are line breaks, equivalent to LF.
  • Every LF ends a paragraph; one final LF adds no empty paragraph. Empty text has no lines.
  • U+0020 is the only breaking and justification space. Runs of spaces are preserved verbatim: leading and interior spaces occupy width. Spaces at a wrap point are consumed by the break. Trailing spaces of a line never count towards its width and are never justified.
  • U+00A0 and every other space character are ordinary glyphs: never a break opportunity, never collapsed, never justified.
  • U+2028 and U+2029 are rejected.

Placement

A text block is as wide as the wrap width (or the widest line when there is no wrap width, or the widest overflowing line) and as high as first-line ascent plus last-line descent plus the line advances. The block is anchored to one of nine points of the page and moved by offsets (+x right, +y up, points); the alignment acts inside the block. The block bounds use font advances, ascent and descent, not glyph ink.

Concurrency

A Shaper holds mutable shaping state and must not be shared between goroutines; use one per goroutine. The returned Placed values are plain data.

Index

Constants

View Source
const (
	// MinFontSize is the smallest font size in points that survives three-decimal output.
	MinFontSize = 0.01
	// MaxFontSize equals the largest generated page side.
	MaxFontSize = 14400.0
	// MinPageSide bounds a generated page side from below, in points.
	MinPageSide = 1.0
	// MaxPageSide bounds a generated page side from above, in points.
	MaxPageSide = 14400.0
	// MaxOffset bounds the absolute x and y offsets and the wrap width in points.
	MaxOffset = 1e6
	// MaxLineSpacing bounds the line spacing multiplier.
	MaxLineSpacing = 100.0

	// AnchorTopLeft places the block's top-left corner on the page's. The nine anchors run row by row from
	// here to AnchorBottomRight; the block's matching point is placed on the page's.
	AnchorTopLeft Anchor = 0
	// AnchorTopCenter anchors the middle of the block's top edge to the middle of the page's.
	AnchorTopCenter Anchor = 1
	// AnchorTopRight anchors the block's top-right corner to the page's.
	AnchorTopRight Anchor = 2
	// AnchorMiddleLeft anchors the middle of the block's left edge to the middle of the page's.
	AnchorMiddleLeft Anchor = 3
	// AnchorCenter anchors the block's center to the page's.
	AnchorCenter Anchor = 4
	// AnchorMiddleRight anchors the middle of the block's right edge to the middle of the page's.
	AnchorMiddleRight Anchor = 5
	// AnchorBottomLeft anchors the block's bottom-left corner to the page's.
	AnchorBottomLeft Anchor = 6
	// AnchorBottomCenter anchors the middle of the block's bottom edge to the middle of the page's.
	AnchorBottomCenter Anchor = 7
	// AnchorBottomRight anchors the block's bottom-right corner to the page's.
	AnchorBottomRight Anchor = 8

	// AlignLeft aligns lines to the block's left edge. The alignments act inside the block.
	AlignLeft Align = 0
	// AlignCenter centers lines in the block.
	AlignCenter Align = 1
	// AlignRight aligns lines to the block's right edge.
	AlignRight Align = 2
	// AlignJustify spreads interior U+0020 spaces so a wrapped line fills the block; the last line of
	// each paragraph stays left-aligned.
	AlignJustify Align = 3

	// OverflowReject turns findings into an error (the plan value "error").
	OverflowReject OverflowPolicy = 0
	// OverflowAllow reports findings and succeeds.
	OverflowAllow OverflowPolicy = 1

	// FindingWordTooWide means a line, necessarily a single unbreakable word, is wider than the wrap width.
	FindingWordTooWide FindingKind = "word-wider-than-box"
	// FindingOutsidePageHorizontal means the block leaves the page on the left or right.
	FindingOutsidePageHorizontal FindingKind = "outside-page-horizontal"
	// FindingOutsidePageVertical means the block leaves the page on the top or bottom (vertical overflow).
	FindingOutsidePageVertical FindingKind = "outside-page-vertical"
)
View Source
const DefaultFontName = "Noto Sans"

DefaultFontName is the plan-level name of the embedded default font.

View Source
const (
	// MaxTextRunes bounds the text of one block, so wrapping and shaping memory stays proportional to it.
	MaxTextRunes = 100_000
)

Variables

View Source
var (
	// ErrMalformedFont is wrapped by every error that reports a font file that is damaged or inconsistent.
	ErrMalformedFont = errors.New("malformed font")
	// ErrUnsupportedFont is wrapped by every error that reports a well-formed font of a kind this package does not embed.
	ErrUnsupportedFont = errors.New("unsupported font")
	// ErrShapingFailed is wrapped by every error that reports a failure of the shaper itself rather than of the text.
	ErrShapingFailed = errors.New("shaping failed")
)

Functions

This section is empty.

Types

type Align

type Align int

Align places lines inside the block.

type Anchor

type Anchor int

Anchor is one of nine points of the page to which the text block is attached.

type Cluster

type Cluster struct {
	Text   string
	Glyphs []Glyph
}

Cluster is the unit that maps glyphs back to source text: the glyphs that one run of source characters shaped to (a base and its marks, a ligature, or a single character).

func (Cluster) IsSpace

func (c Cluster) IsSpace() bool

IsSpace reports whether the cluster is exactly one U+0020, the only breaking and justification space.

type Digest

type Digest [sha256.Size]byte

Digest is a font's identity: the SHA-256 of its file bytes.

type EmbeddingError

type EmbeddingError struct {
	FsType uint16
}

EmbeddingError reports an OS/2 fsType that forbids embedding.

func (*EmbeddingError) Error

func (e *EmbeddingError) Error() string

Error implements error.

type Finding

type Finding struct {
	Kind   FindingKind
	Detail string
	// Line is the zero-based line of a FindingWordTooWide, otherwise -1.
	Line int
}

Finding is one overflow condition.

type FindingKind

type FindingKind string

FindingKind classifies an overflow finding.

type Font

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

Font is a validated, immutable static TrueType font.

func LoadDefaultFont

func LoadDefaultFont() (*Font, error)

LoadDefaultFont parses the embedded default font. Each call returns a new Font with the same identity; callers load it once per job.

func LoadFont

func LoadFont(data []byte) (*Font, error)

LoadFont validates data as an embeddable static TrueType font. It retains data, which the caller must not modify afterwards. It never panics on malformed input; every defect is an error.

func (*Font) Ascent

func (f *Font) Ascent() float64

Ascent returns the typographic ascent in font units.

func (*Font) BBox

func (f *Font) BBox() [4]int

BBox returns the head table's xMin, yMin, xMax, yMax in font units.

func (*Font) Bytes

func (f *Font) Bytes() []byte

Bytes returns the font file. The caller must not modify it.

func (*Font) CapHeight

func (f *Font) CapHeight() float64

CapHeight returns the capital height in font units, or the ascent when the font declares none.

func (*Font) Descent

func (f *Font) Descent() float64

Descent returns the typographic descent in font units; it is negative.

func (*Font) GlyphAdvance

func (f *Font) GlyphAdvance(glyph uint16) int

GlyphAdvance returns the nominal horizontal advance of a glyph in font units, or 0 for an unknown glyph.

func (*Font) GlyphText

func (f *Font) GlyphText(glyph uint16) string

GlyphText returns the text a glyph stands for on its own: the smallest code point the cmap maps to it, or "" when no code point maps to it.

func (*Font) Identity

func (f *Font) Identity() Digest

Identity returns the SHA-256 of the font file.

func (*Font) PostScriptName

func (f *Font) PostScriptName() string

PostScriptName returns the font's name restricted to characters legal in a PDF name.

func (*Font) UnitsPerEm

func (f *Font) UnitsPerEm() int

UnitsPerEm returns the font design units per em.

type Glyph

type Glyph struct {
	ID uint16
	// Advance is the pen advance after the glyph, with kerning applied.
	Advance int
	// XOffset and YOffset move the drawn glyph from the pen; GPOS mark attachment lands here.
	XOffset, YOffset int
}

Glyph is one positioned glyph. All distances are font units.

type InvalidParamError

type InvalidParamError struct {
	Field   string
	Message string
}

InvalidParamError names a Params field outside its domain.

func (*InvalidParamError) Error

func (e *InvalidParamError) Error() string

Error implements error.

type Line

type Line struct {
	Clusters []Cluster
	X        float64
	Baseline float64
	// Width is the advance width without trailing spaces, justification included.
	Width float64
	// ExtraSpace is the justification added to each interior U+0020, in points.
	ExtraSpace float64
}

Line is one positioned line. X and Baseline are the page coordinates of the first glyph's pen.

func (Line) Text

func (l Line) Text() string

Text returns the source text of the line.

type OutlineError

type OutlineError struct {
	// Font is the PostScript name of the font.
	Font string
	// Rune is the first character of the cluster that needs the glyph.
	Rune rune
	// Glyph is the glyph identifier in the font.
	Glyph uint16
}

OutlineError reports a font whose outline for a glyph that the text needs cannot be read, which would render that character blank. The parsing library discards the whole outline table when any glyph of it is damaged, so every glyph of such a font reports this error, not only the damaged one. It matches ErrMalformedFont under errors.Is.

func (*OutlineError) Error

func (e *OutlineError) Error() string

Error implements error.

func (*OutlineError) Unwrap

func (*OutlineError) Unwrap() error

Unwrap lets errors.Is match ErrMalformedFont.

type OverflowError

type OverflowError struct {
	Findings []Finding
	// WrapWidth and PageWidth retain the configured width and authored canvas
	// for diagnostics; glyph-expanded block bounds cannot identify this cause.
	WrapWidth float64
	PageWidth float64
}

OverflowError reports findings under OverflowReject policy.

func (*OverflowError) Error

func (e *OverflowError) Error() string

Error implements error.

func (*OverflowError) FixedWidthExceedsPage added in v0.2.0

func (e *OverflowError) FixedWidthExceedsPage() bool

FixedWidthExceedsPage identifies a configured block that cannot fit even when both horizontal edges receive the existing placement tolerance. It requires an actual horizontal finding and does not classify glyph-expanded widths.

type OverflowPolicy

type OverflowPolicy int

OverflowPolicy decides what a finding means.

type Params

type Params struct {
	Text string
	// Language is an optional BCP-47 tag selecting language-specific glyph forms (for example "lv").
	Language string
	// Size is the font size, MinFontSize through MaxFontSize.
	Size float64
	// PageWidth and PageHeight are the page sides, MinPageSide through MaxPageSide.
	PageWidth, PageHeight float64
	// OffsetX and OffsetY move the anchored block; each is within +-MaxOffset.
	OffsetX, OffsetY float64
	// WrapWidth is the block width; 0 means no wrapping (explicit line breaks only).
	WrapWidth float64
	// LineSpacing is the baseline-to-baseline distance as a multiple of Size; it is greater than 0.
	LineSpacing float64
	Anchor      Anchor
	Align       Align
	Overflow    OverflowPolicy
}

Params describes one text block on one page. Lengths are points; +x is right and +y is up.

type Placed

type Placed struct {
	Font      *Font
	InkBounds *Rect
	Lines     []Line
	Findings  []Finding
	Bounds    Rect
	Size      float64
}

Placed is a laid-out text block positioned on a page.

type Problem

type Problem struct {
	Reason string
	// Offset is the rune offset into the text, or -1 for invalid UTF-8.
	Offset int
	// More counts further consecutive code points rejected for the same reason.
	More int
	Rune rune
}

Problem is one reason text cannot be rendered with a font.

type Rect

type Rect struct {
	X, Y, Width, Height float64
}

Rect is a rectangle in page coordinates: its bottom-left corner and size.

type Shaper

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

Shaper holds reusable shaping state. It is not safe for concurrent use; use one per goroutine. A Font may be shared between Shapers.

go-text's Face carries a mutable glyph cache, so a Face must not be shared between goroutines even though the parsed font is immutable; each Shaper therefore owns a private Face per Font.

func (*Shaper) Place

func (s *Shaper) Place(font *Font, params Params) (*Placed, error)

Place shapes, wraps and positions params.Text with the font. Empty text yields no lines, zero bounds and no findings. A rejected text returns a *TextError and invalid numbers an *InvalidParamError, both with a nil result. When findings exist under OverflowReject policy, Place returns the complete result together with an *OverflowError, so callers can report computed bounds.

func (*Shaper) ValidateText

func (s *Shaper) ValidateText(font *Font, text string) error

ValidateText checks geometry-independent script and glyph availability before source inspection. A missing nominal glyph is checked through shaping, since composition may supply it.

type TextError

type TextError struct {
	Problems []Problem
}

TextError lists the rejected positions of a text, capped at a few.

func (*TextError) Error

func (e *TextError) Error() string

Error implements error.

Jump to

Keyboard shortcuts

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