text

package
v0.18.1 Latest Latest
Warning

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

Go to latest
Published: Jan 16, 2026 License: MIT Imports: 18 Imported by: 0

README

text — GPU Text Pipeline for gg

Status: v0.13.0 (Released)

This package implements a modern GPU-ready text pipeline for gogpu/gg, inspired by Ebitengine text/v2, go-text/typesetting, and vello.

Architecture

FontSource (heavyweight, shared)
    ↓
Face (lightweight, per-size)
    ↓
Segmenter → Shaper → Layout → GlyphRenderer
    │           │        │          │
Bidi/Script  Cache    Lines    ┌────┴────┐
                               │         │
                          Vector Path  MSDF
                          (quality)   (perf)
                               │         │
                               └────┬────┘
                                    ↓
                              GPU Rendering

Features

Pluggable Shaper (v0.10.0)
  • Shaper interface — Converts text to positioned glyphs
  • BuiltinShaper — Default using golang.org/x/image
  • Custom shapers — Plug in go-text/typesetting or HarfBuzz
Bidi/Script Segmentation (v0.10.0)
  • 25+ Unicode scripts — Latin, Arabic, Hebrew, Han, Cyrillic, Thai, etc.
  • Full Unicode Bidi Algorithm — Via golang.org/x/text/unicode/bidi
  • Script inheritance — Common/Inherited characters resolved from context
Multi-line Layout (v0.10.0+)
  • Alignment — Left, Center, Right, Justify (placeholder)
  • Line wrapping — At MaxWidth with word boundaries
  • Line spacing — Configurable multiplier
  • Bidi-aware — Proper RTL/LTR segment ordering
Unicode Text Wrapping (v0.13.0)
  • WrapMode enum — WrapWordChar (default), WrapNone, WrapWord, WrapChar
  • UAX #14 simplified — Break classification (Space, Zero, Open, Close, Hyphen, Ideographic)
  • CJK support — Break opportunities at ideograph boundaries
  • Performance — 1,185 ns/op FindBreakOpportunities, 0 allocs
Shaping Cache (v0.10.0)
  • 16-shard LRU — Concurrent access without lock contention
  • 16K total entries — 1024 per shard
  • Zero-allocation hot path — Pre-allocated result storage

Usage

Basic Text Drawing
// Load font (heavyweight, do once)
source, err := text.NewFontSourceFromFile("Roboto-Regular.ttf")
if err != nil {
    log.Fatal(err)
}
defer source.Close()

// Create face at specific size (lightweight)
face := source.Face(24)

// Use with gg.Context (dc = drawing context)
dc := gg.NewContext(800, 600)
dc.SetFont(face)
dc.DrawString("Hello, GoGPU!", 100, 100)
Text Shaping
// Shape text to positioned glyphs
glyphs := text.Shape("Hello", face, 24)
for _, g := range glyphs {
    fmt.Printf("GID=%d X=%.1f Y=%.1f\n", g.GID, g.X, g.Y)
}
Bidi/Script Segmentation
// Segment mixed-direction text
segments := text.SegmentText("Hello שלום مرحبا")
for _, seg := range segments {
    fmt.Printf("'%s' Dir=%s Script=%s\n",
        seg.Text, seg.Direction, seg.Script)
}

// RTL base direction
segments = text.SegmentTextRTL("مرحبا Hello")
Multi-line Layout
// Layout with options
opts := text.LayoutOptions{
    MaxWidth:    400,
    LineSpacing: 1.2,
    Alignment:   text.AlignCenter,
    Direction:   text.DirectionLTR,
    WrapMode:    text.WrapWordChar, // Word-first, char fallback (default)
}
layout := text.LayoutText(longText, face, 16, opts)

// Access lines
for _, line := range layout.Lines {
    fmt.Printf("Y=%.1f Width=%.1f Glyphs=%d\n",
        line.Y, line.Width, len(line.Glyphs))
}

// Simple layout (no wrapping)
layout = text.LayoutTextSimple("Hello\nWorld", face, 16)
Text Wrapping Modes
// WrapWordChar (default) — Word boundaries first, character fallback for long words
opts := text.LayoutOptions{
    MaxWidth: 200,
    WrapMode: text.WrapWordChar,
}

// WrapWord — Word boundaries only, long words overflow
opts.WrapMode = text.WrapWord

// WrapChar — Character boundaries, any character can break
opts.WrapMode = text.WrapChar

// WrapNone — No wrapping, text may exceed MaxWidth
opts.WrapMode = text.WrapNone

// Standalone wrapping API
results := text.WrapText("Hello World", face, 16, 100, text.WrapWordChar)
for _, r := range results {
    fmt.Printf("Line: '%s' (%d-%d)\n", r.Text, r.Start, r.End)
}

// Measure text width
width := text.MeasureText("Hello World", face, 16)
Custom Shaper
// Implement custom shaper (e.g., go-text/typesetting)
type MyShaper struct {
    // ...
}

func (s *MyShaper) Shape(text string, face text.Face, size float64) []text.ShapedGlyph {
    // Custom shaping logic
}

// Set as global shaper
text.SetShaper(&MyShaper{})
defer text.SetShaper(nil) // Reset to default

Types

ShapedGlyph
type ShapedGlyph struct {
    GID      GlyphID  // Glyph index in font
    Cluster  int      // Source character index
    X, Y     float64  // Position relative to origin
    XAdvance float64  // Horizontal advance
    YAdvance float64  // Vertical advance (for TTB)
}
Segment
type Segment struct {
    Text      string    // Segment text
    Start     int       // Byte offset in original text
    End       int       // End byte offset
    Direction Direction // LTR or RTL
    Script    Script    // Unicode script
    Level     int       // Bidi embedding level
}
Layout
type Layout struct {
    Lines  []Line   // Positioned lines
    Width  float64  // Maximum line width
    Height float64  // Total height
}

type Line struct {
    Runs    []ShapedRun   // Runs with uniform style
    Glyphs  []ShapedGlyph // All positioned glyphs
    Width   float64       // Line width
    Ascent  float64       // Max ascent
    Descent float64       // Max descent
    Y       float64       // Baseline Y position
}

Dependencies

  • golang.org/x/image/font/opentype — TTF/OTF parsing
  • golang.org/x/text/unicode/bidi — Unicode Bidirectional Algorithm

Subpackages

text/cache

LRU caching infrastructure for shaping results.

text/msdf (v0.11.0)

Multi-channel Signed Distance Field generation for GPU text rendering.

  • Generator — Pure Go MSDF with edge coloring algorithm
  • AtlasManager — Multi-atlas management with shelf packing
  • ConcurrentAtlasManager — High-throughput sharded variant
text/emoji (v0.11.0)

Emoji and color font support.

  • Detection — IsEmoji, IsZWJ, IsRegionalIndicator
  • Sequences — ZWJ, flags, skin tones, keycaps
  • COLRv0/v1 — Color glyph parsing and rendering
  • sbix/CBDT — Bitmap emoji (PNG, JPEG, TIFF)

Test Coverage

  • text package: 87.6%
  • text/cache package: 93.7%
  • text/msdf package: 87.0%
  • text/emoji package: 85.0%
  • 0 linter issues

Versions

v0.13.0 (Current)
  • WrapMode enum — WrapWordChar, WrapNone, WrapWord, WrapChar
  • BreakClass — UAX #14 simplified line breaking
  • WrapText() — Standalone wrapping API
  • MeasureText() — Measure text advance width
  • CJK support — Ideograph break opportunities
  • context.Context — LayoutTextWithContext() cancellation
v0.11.0
  • Glyph-as-Path rendering (OutlineExtractor)
  • GlyphCache LRU (16-shard, <50ns hit)
  • MSDF generator (Pure Go)
  • MSDF atlas with shelf packing
  • Emoji support (COLRv1, sbix, ZWJ)
  • Subpixel positioning (4/10 levels)
v0.10.0
  • Pluggable Shaper interface
  • Extended shaping types
  • Sharded LRU shaping cache
  • Bidi/Script segmentation
  • Multi-line Layout Engine

Documentation

Overview

Package text provides text rendering for gg. It implements a modern text API inspired by Ebitengine text/v2.

The text rendering pipeline follows a separation of concerns:

  • FontSource: Heavyweight, shared font resource (parses TTF/OTF files)
  • Face: Lightweight font instance at a specific size
  • FontParser: Pluggable font parsing backend (default: golang.org/x/image)

Example usage

// Load font (do once, share across application)
source, err := text.NewFontSourceFromFile("Roboto-Regular.ttf")
if err != nil {
    log.Fatal(err)
}
defer source.Close()

// Create face at specific size (lightweight)
face := source.Face(24)

// Use with gg.Context
ctx := gg.NewContext(800, 600)
ctx.SetFont(face)
ctx.DrawString("Hello, GoGPU!", 100, 100)

Pluggable Parser Backend

The font parsing is abstracted through the FontParser interface. By default, golang.org/x/image/font/opentype is used. Custom parsers can be registered for alternative implementations:

// Register a custom parser
text.RegisterParser("myparser", myCustomParser)

// Use the custom parser
source, err := text.NewFontSource(data, text.WithParser("myparser"))

This design allows:

  • Easy migration to different font libraries
  • Pure Go implementations without external dependencies
  • Custom font formats or optimized parsers

Package text provides GPU text rendering infrastructure.

Package text provides GPU text rendering infrastructure.

Package text provides GPU text rendering infrastructure.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrEmptyFontData is returned when font data is empty.
	ErrEmptyFontData = errors.New("text: empty font data")

	// ErrEmptyFaces is returned when no faces are provided to MultiFace.
	ErrEmptyFaces = errors.New("text: faces cannot be empty")
)

Sentinel errors for text package.

View Source
var (
	// Latin Scripts
	RangeBasicLatin = UnicodeRange{0x0000, 0x007F} // ASCII
	RangeLatin1Sup  = UnicodeRange{0x0080, 0x00FF} // Latin-1 Supplement
	RangeLatinExtA  = UnicodeRange{0x0100, 0x017F} // Latin Extended-A
	RangeLatinExtB  = UnicodeRange{0x0180, 0x024F} // Latin Extended-B

	// Cyrillic Scripts
	RangeCyrillic = UnicodeRange{0x0400, 0x04FF} // Cyrillic

	// Greek Scripts
	RangeGreek = UnicodeRange{0x0370, 0x03FF} // Greek and Coptic

	// Middle Eastern Scripts
	RangeArabic = UnicodeRange{0x0600, 0x06FF} // Arabic
	RangeHebrew = UnicodeRange{0x0590, 0x05FF} // Hebrew

	// CJK Scripts
	RangeCJKUnified = UnicodeRange{0x4E00, 0x9FFF} // CJK Unified Ideographs
	RangeHiragana   = UnicodeRange{0x3040, 0x309F} // Hiragana
	RangeKatakana   = UnicodeRange{0x30A0, 0x30FF} // Katakana
	RangeHangul     = UnicodeRange{0xAC00, 0xD7AF} // Hangul Syllables

	// Emoji
	RangeEmoji        = UnicodeRange{0x1F600, 0x1F64F} // Emoticons
	RangeEmojiMisc    = UnicodeRange{0x1F300, 0x1F5FF} // Miscellaneous Symbols and Pictographs
	RangeEmojiSymbols = UnicodeRange{0x1F680, 0x1F6FF} // Transport and Map Symbols
	RangeEmojiFlags   = UnicodeRange{0x1F1E0, 0x1F1FF} // Regional Indicator Symbols (Flags)
)

Common Unicode ranges for filtering faces.

View Source
var ErrUnsupportedFontType = &FontError{Reason: "unsupported font type for outline extraction"}

ErrUnsupportedFontType is returned when the font type is not supported.

Functions

func Draw

func Draw(dst draw.Image, text string, face Face, x, y float64, col color.Color)

Draw renders text to a destination image. Position (x, y) is the baseline origin. Supports sourceFace, MultiFace, and FilteredFace.

func IsPunctuation added in v0.10.0

func IsPunctuation(r rune) bool

func IsWhitespace added in v0.10.0

func IsWhitespace(r rune) bool

func Measure

func Measure(text string, face Face) (width, height float64)

Measure returns the dimensions of text. Width is the horizontal advance, height is the font's line height.

func MeasureText added in v0.13.0

func MeasureText(text string, face Face, size float64) float64

MeasureText measures the total advance width of text.

func Quantize added in v0.11.0

func Quantize(pos float64, mode SubpixelMode) (intPos int, subPos uint8)

Quantize converts a fractional position to quantized subpixel offset. Returns the integer position and subpixel key component.

For example, with Subpixel4 mode:

  • pos=10.0 returns (10, 0)
  • pos=10.25 returns (10, 1)
  • pos=10.5 returns (10, 2)
  • pos=10.75 returns (10, 3)
  • pos=10.99 returns (10, 3) // quantized to nearest

func QuantizePoint added in v0.11.0

func QuantizePoint(x, y float64, config SubpixelConfig) (intX, intY int, subX, subY uint8)

QuantizePoint quantizes both X and Y positions. Returns integer positions and subpixel key components.

func RegisterParser

func RegisterParser(name string, parser FontParser)

RegisterParser registers a custom font parser. This allows users to provide their own parsing implementation.

func SetShaper added in v0.10.0

func SetShaper(s Shaper)

SetShaper sets the global shaper used by Shape(). Pass nil to reset to the default BuiltinShaper.

Example usage with a custom shaper:

text.SetShaper(myHarfBuzzShaper)
defer text.SetShaper(nil) // Reset to default

func SubpixelOffset added in v0.11.0

func SubpixelOffset(subPos uint8, mode SubpixelMode) float64

SubpixelOffset returns the rendering offset for a subpixel position. For Subpixel4 mode: 0 -> 0.0, 1 -> 0.25, 2 -> 0.5, 3 -> 0.75 For Subpixel10 mode: 0 -> 0.0, 1 -> 0.1, ..., 9 -> 0.9

func SubpixelOffsets added in v0.11.0

func SubpixelOffsets(subX, subY uint8, config SubpixelConfig) (offsetX, offsetY float64)

SubpixelOffsets returns both X and Y rendering offsets.

Types

type AffineTransform added in v0.11.0

type AffineTransform struct {
	A, B, C, D float32 // Matrix coefficients
	Tx, Ty     float32 // Translation
}

AffineTransform represents a 2D affine transformation matrix. The matrix is:

[A B Tx]
[C D Ty]
[0 0 1 ]

func IdentityTransform added in v0.11.0

func IdentityTransform() *AffineTransform

IdentityTransform returns the identity transformation.

func RotateTransform added in v0.11.0

func RotateTransform(angle float32) *AffineTransform

RotateTransform creates a rotation transformation (angle in radians).

func ScaleTransform added in v0.11.0

func ScaleTransform(sx, sy float32) *AffineTransform

ScaleTransform returns a scaling transformation.

func ScaleTransformXY added in v0.11.0

func ScaleTransformXY(sx, sy float32) *AffineTransform

ScaleTransformXY creates a non-uniform scaling transformation.

func TranslateTransform added in v0.11.0

func TranslateTransform(tx, ty float32) *AffineTransform

TranslateTransform returns a translation transformation.

func (*AffineTransform) Multiply added in v0.11.0

func (m *AffineTransform) Multiply(other *AffineTransform) *AffineTransform

Multiply returns the composition of two transformations.

func (*AffineTransform) TransformPoint added in v0.11.0

func (m *AffineTransform) TransformPoint(x, y float32) (float32, float32)

TransformPoint applies the transformation to a point.

type Alignment added in v0.10.0

type Alignment int

Alignment specifies text horizontal alignment within the layout width.

const (
	// AlignLeft aligns text to the left edge (default).
	AlignLeft Alignment = iota
	// AlignCenter centers text horizontally.
	AlignCenter
	// AlignRight aligns text to the right edge.
	AlignRight
	// AlignJustify distributes text evenly (future implementation).
	AlignJustify
)

func (Alignment) String added in v0.10.0

func (a Alignment) String() string

String returns the string representation of the alignment.

type BreakClass added in v0.13.0

type BreakClass uint8

BreakClass represents Unicode line breaking classes (UAX #14 simplified).

type BreakOpportunity added in v0.13.0

type BreakOpportunity uint8

BreakOpportunity represents a line break opportunity.

const (
	// BreakNo means no break allowed here.
	BreakNo BreakOpportunity = iota
	// BreakAllowed means break is allowed here.
	BreakAllowed
	// BreakMandatory means break is required here (newline).
	BreakMandatory
)

type BuiltinSegmenter added in v0.10.0

type BuiltinSegmenter struct {
	BaseDirection Direction
}

func NewBuiltinSegmenter added in v0.10.0

func NewBuiltinSegmenter() *BuiltinSegmenter

func NewBuiltinSegmenterWithDirection added in v0.10.0

func NewBuiltinSegmenterWithDirection(dir Direction) *BuiltinSegmenter

func (*BuiltinSegmenter) Segment added in v0.10.0

func (s *BuiltinSegmenter) Segment(text string) []Segment

type BuiltinShaper added in v0.10.0

type BuiltinShaper struct{}

BuiltinShaper provides text shaping using golang.org/x/image/font. It supports Latin, Cyrillic, Greek, CJK, and other scripts that don't require complex text shaping (ligatures, contextual forms, etc.).

For complex scripts like Arabic, Hebrew, or Indic languages that require advanced shaping features (GSUB/GPOS tables), use SetShaper() with a HarfBuzz-compatible implementation such as go-text/typesetting.

BuiltinShaper is stateless and safe for concurrent use.

func (*BuiltinShaper) Shape added in v0.10.0

func (s *BuiltinShaper) Shape(text string, face Face, size float64) []ShapedGlyph

Shape implements the Shaper interface. It converts text to positioned glyphs using the font's glyph metrics.

The shaping is simple left-to-right positioning without:

  • Ligature substitution (fi, fl, etc.)
  • Kerning pairs
  • Contextual alternates
  • Right-to-left reordering

For these features, use a full shaper like go-text/typesetting.

type Cache deprecated

type Cache[K comparable, V any] struct {
	// contains filtered or unexported fields
}

Cache is a generic thread-safe LRU cache with soft limit.

Deprecated: For new code, use github.com/gogpu/gg/cache.Cache or cache.ShardedCache which offer better performance and more features. When the cache exceeds softLimit, oldest entries are evicted.

Cache is safe for concurrent use. Cache must not be copied after creation (has mutex).

func NewCache

func NewCache[K comparable, V any](softLimit int) *Cache[K, V]

NewCache creates a new cache with the given soft limit. A softLimit of 0 means unlimited.

func (*Cache[K, V]) Clear

func (c *Cache[K, V]) Clear()

Clear removes all entries from the cache.

func (*Cache[K, V]) Get

func (c *Cache[K, V]) Get(key K) (V, bool)

Get retrieves a value from the cache. Returns (value, true) if found, (zero, false) otherwise.

func (*Cache[K, V]) GetOrCreate

func (c *Cache[K, V]) GetOrCreate(key K, create func() V) V

GetOrCreate returns cached value or creates it. Thread-safe: create is called under lock to prevent duplicate creation.

func (*Cache[K, V]) Len

func (c *Cache[K, V]) Len() int

Len returns the number of entries in the cache.

func (*Cache[K, V]) Set

func (c *Cache[K, V]) Set(key K, value V)

Set stores a value in the cache. If the cache exceeds softLimit after insertion, oldest entries are evicted.

type Direction

type Direction int

Direction specifies text direction.

const (
	// DirectionLTR is left-to-right text (English, French, etc.)
	DirectionLTR Direction = iota
	// DirectionRTL is right-to-left text (Arabic, Hebrew)
	DirectionRTL
	// DirectionTTB is top-to-bottom text (traditional Chinese, Japanese)
	DirectionTTB
	// DirectionBTT is bottom-to-top text (rare)
	DirectionBTT
)

func (Direction) IsHorizontal added in v0.10.0

func (d Direction) IsHorizontal() bool

IsHorizontal returns true if the direction is horizontal (LTR or RTL).

func (Direction) IsVertical added in v0.10.0

func (d Direction) IsVertical() bool

IsVertical returns true if the direction is vertical (TTB or BTT).

func (Direction) String

func (d Direction) String() string

String returns the string representation of the direction.

type DirectionMismatchError added in v0.12.0

type DirectionMismatchError struct {
	Index    int
	Got      Direction
	Expected Direction
}

DirectionMismatchError is returned when faces have different directions.

func (*DirectionMismatchError) Error added in v0.12.0

func (e *DirectionMismatchError) Error() string

type DrawOptions

type DrawOptions struct {
	// Color for the text (default: black)
	Color color.Color
}

DrawOptions provides advanced options for text drawing. Reserved for future enhancements.

type Face

type Face interface {
	// Metrics returns the font metrics at this face's size.
	Metrics() Metrics

	// Advance returns the total advance width of the text in pixels.
	// This is the sum of all glyph advances.
	Advance(text string) float64

	// HasGlyph reports whether the font has a glyph for the given rune.
	HasGlyph(r rune) bool

	// Glyphs returns an iterator over all glyphs in the text.
	// The glyphs are positioned relative to the origin (0, 0).
	// Uses Go 1.25+ iter.Seq for zero-allocation iteration.
	Glyphs(text string) iter.Seq[Glyph]

	// AppendGlyphs appends glyphs for the text to dst and returns the extended slice.
	// This is useful for building glyph slices without allocation.
	AppendGlyphs(dst []Glyph, text string) []Glyph

	// Direction returns the text direction for this face.
	Direction() Direction

	// Source returns the FontSource this face was created from.
	Source() *FontSource

	// Size returns the size of this face in points.
	Size() float64
	// contains filtered or unexported methods
}

Face represents a font face at a specific size. This is a lightweight object that can be created from a FontSource. Face is safe for concurrent use.

type FaceOption

type FaceOption func(*faceConfig)

FaceOption configures Face creation.

func WithDirection

func WithDirection(d Direction) FaceOption

WithDirection sets the text direction for the face.

func WithHinting

func WithHinting(h Hinting) FaceOption

WithHinting sets the hinting mode for the face.

func WithLanguage

func WithLanguage(lang string) FaceOption

WithLanguage sets the language tag for the face (e.g., "en", "ja", "ar").

type FilteredFace

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

FilteredFace wraps a face and restricts it to specific Unicode ranges. Only glyphs in the specified ranges are considered available. FilteredFace is safe for concurrent use.

func NewFilteredFace

func NewFilteredFace(face Face, ranges ...UnicodeRange) *FilteredFace

NewFilteredFace creates a FilteredFace. Only glyphs in the specified ranges are considered available. If no ranges are specified, all glyphs are available (no filtering).

func (*FilteredFace) Advance

func (f *FilteredFace) Advance(text string) float64

Advance implements Face.Advance. Only includes runes that are in the allowed ranges.

func (*FilteredFace) AppendGlyphs

func (f *FilteredFace) AppendGlyphs(dst []Glyph, text string) []Glyph

AppendGlyphs implements Face.AppendGlyphs. Only appends glyphs for runes in the allowed ranges.

func (*FilteredFace) Direction

func (f *FilteredFace) Direction() Direction

Direction implements Face.Direction.

func (*FilteredFace) Glyphs

func (f *FilteredFace) Glyphs(text string) iter.Seq[Glyph]

Glyphs implements Face.Glyphs. Only yields glyphs for runes in the allowed ranges.

func (*FilteredFace) HasGlyph

func (f *FilteredFace) HasGlyph(r rune) bool

HasGlyph implements Face.HasGlyph. Returns true only if the rune is in the allowed ranges and the wrapped face has it.

func (*FilteredFace) Metrics

func (f *FilteredFace) Metrics() Metrics

Metrics implements Face.Metrics.

func (*FilteredFace) Size

func (f *FilteredFace) Size() float64

Size implements Face.Size.

func (*FilteredFace) Source

func (f *FilteredFace) Source() *FontSource

Source implements Face.Source.

type FontError added in v0.11.0

type FontError struct {
	Reason string
}

FontError represents a font-related error.

func (*FontError) Error added in v0.11.0

func (e *FontError) Error() string

type FontMetrics

type FontMetrics struct {
	// Ascent is the distance from the baseline to the top of the font (positive).
	Ascent float64

	// Descent is the distance from the baseline to the bottom of the font (negative).
	Descent float64

	// LineGap is the recommended line gap between lines.
	LineGap float64

	// XHeight is the height of lowercase letters (like 'x').
	XHeight float64

	// CapHeight is the height of uppercase letters.
	CapHeight float64
}

FontMetrics holds font-level metrics at a specific size.

func (FontMetrics) Height

func (m FontMetrics) Height() float64

Height returns the total line height (ascent - descent + line gap).

type FontParser

type FontParser interface {
	// Parse parses font data (TTF or OTF) and returns a ParsedFont.
	Parse(data []byte) (ParsedFont, error)
}

FontParser is an interface for font parsing backends. This abstraction allows swapping the font parsing library (e.g., golang.org/x/image/font/opentype vs a pure Go implementation).

The default implementation uses golang.org/x/image/font/opentype.

type FontSource

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

FontSource represents a loaded font file. One FontSource can create multiple Face instances at different sizes. FontSource is heavyweight and should be shared across the application.

FontSource is safe for concurrent use. FontSource must not be copied after creation (enforced by copyCheck).

func NewFontSource

func NewFontSource(data []byte, opts ...SourceOption) (*FontSource, error)

NewFontSource creates a FontSource from font data (TTF or OTF). The data slice is copied internally and can be reused after this call.

Options can be used to configure caching and parser backend.

func NewFontSourceFromFile

func NewFontSourceFromFile(path string, opts ...SourceOption) (*FontSource, error)

NewFontSourceFromFile loads a FontSource from a font file path.

func (*FontSource) Close

func (s *FontSource) Close() error

Close releases resources associated with the FontSource. All faces created from this source become invalid after Close.

func (*FontSource) Face

func (s *FontSource) Face(size float64, opts ...FaceOption) Face

Face creates a Face at the specified size (in points). Multiple faces can be created from the same FontSource.

Face is a lightweight object that shares caches with the FontSource.

func (*FontSource) Name

func (s *FontSource) Name() string

Name returns the font name.

func (*FontSource) Parsed

func (s *FontSource) Parsed() ParsedFont

Parsed returns the parsed font for advanced operations. This is primarily used by Face implementations.

type Glyph

type Glyph struct {
	// Rune is the Unicode character this glyph represents.
	// For ligatures, this may be the first character of the ligature.
	Rune rune

	// GID is the glyph index in the font.
	GID GlyphID

	// X, Y are the position of the glyph relative to the text origin.
	// The origin is at the baseline of the first character.
	X, Y float64

	// OriginX, OriginY are the absolute position of the glyph's origin point.
	// This is where the glyph should be drawn from.
	OriginX float64
	OriginY float64

	// Advance is the horizontal advance width of the glyph.
	// This is how much the cursor moves after drawing this glyph.
	Advance float64

	// Bounds is the bounding box of the glyph.
	// This defines the area the glyph occupies.
	Bounds Rect

	// Index is the byte position in the original string where this glyph starts.
	Index int

	// Cluster is the character cluster index.
	// Multiple glyphs can belong to the same cluster (e.g., ligatures).
	Cluster int
}

Glyph represents a single shaped glyph with its position and metrics. This is the output of text shaping and is ready for rendering.

type GlyphCache added in v0.11.0

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

GlyphCache is a thread-safe LRU cache for glyph outlines. It provides fast lookups with automatic eviction of least recently used entries.

The cache is sharded to reduce lock contention in concurrent access patterns. It supports both capacity-based eviction (when MaxEntries is reached) and frame-based eviction (during Maintain() calls).

GlyphCache is safe for concurrent use.

func GetGlobalGlyphCache added in v0.11.0

func GetGlobalGlyphCache() *GlyphCache

GetGlobalGlyphCache returns the global shared glyph cache.

func NewGlyphCache added in v0.11.0

func NewGlyphCache() *GlyphCache

NewGlyphCache creates a new glyph cache with default configuration.

func NewGlyphCacheWithConfig added in v0.11.0

func NewGlyphCacheWithConfig(config GlyphCacheConfig) *GlyphCache

NewGlyphCacheWithConfig creates a new glyph cache with the given configuration.

func SetGlobalGlyphCache added in v0.11.0

func SetGlobalGlyphCache(cache *GlyphCache) *GlyphCache

SetGlobalGlyphCache replaces the global glyph cache. The old cache is returned for cleanup if needed.

func (*GlyphCache) Clear added in v0.11.0

func (c *GlyphCache) Clear()

Clear removes all entries from the cache.

func (*GlyphCache) CurrentFrame added in v0.11.0

func (c *GlyphCache) CurrentFrame() uint64

CurrentFrame returns the current frame number.

func (*GlyphCache) Delete added in v0.11.0

func (c *GlyphCache) Delete(key OutlineCacheKey)

Delete removes an entry from the cache.

func (*GlyphCache) Get added in v0.11.0

Get retrieves a cached glyph outline. Returns nil if not found.

func (*GlyphCache) GetOrCreate added in v0.11.0

func (c *GlyphCache) GetOrCreate(key OutlineCacheKey, create func() *GlyphOutline) *GlyphOutline

GetOrCreate retrieves a cached outline or creates one using the provided function. This is an atomic operation that avoids redundant creation.

func (*GlyphCache) HitRate added in v0.11.0

func (c *GlyphCache) HitRate() float64

HitRate returns the cache hit rate as a percentage. Returns 0 if there are no accesses.

func (*GlyphCache) Len added in v0.11.0

func (c *GlyphCache) Len() int

Len returns the total number of cached entries.

func (*GlyphCache) Maintain added in v0.11.0

func (c *GlyphCache) Maintain()

Maintain performs periodic maintenance on the cache. It evicts entries that haven't been accessed for FrameLifetime frames. Call this once per frame for frame-based eviction.

func (*GlyphCache) ResetStats added in v0.11.0

func (c *GlyphCache) ResetStats()

ResetStats resets the cache statistics.

func (*GlyphCache) Set added in v0.11.0

func (c *GlyphCache) Set(key OutlineCacheKey, outline *GlyphOutline)

Set stores a glyph outline in the cache. If the cache is full, the least recently used entry is evicted.

func (*GlyphCache) Stats added in v0.11.0

func (c *GlyphCache) Stats() (hits, misses, evictions, insertions uint64)

Stats returns cache statistics.

type GlyphCacheConfig added in v0.11.0

type GlyphCacheConfig struct {
	// MaxEntries is the maximum number of cached glyph outlines.
	// Default: 4096
	MaxEntries int

	// FrameLifetime is the number of frames an entry can be unused
	// before being eligible for eviction during Maintain().
	// Default: 64
	FrameLifetime int
}

GlyphCacheConfig holds configuration for GlyphCache.

func DefaultGlyphCacheConfig added in v0.11.0

func DefaultGlyphCacheConfig() GlyphCacheConfig

DefaultGlyphCacheConfig returns the default cache configuration.

type GlyphCachePool added in v0.11.0

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

GlyphCachePool manages a pool of GlyphCaches for per-thread usage. This can further reduce contention in highly concurrent scenarios.

func NewGlyphCachePool added in v0.11.0

func NewGlyphCachePool() *GlyphCachePool

NewGlyphCachePool creates a new pool of glyph caches.

func (*GlyphCachePool) Get added in v0.11.0

func (p *GlyphCachePool) Get() *GlyphCache

Get retrieves a cache from the pool.

func (*GlyphCachePool) Put added in v0.11.0

func (p *GlyphCachePool) Put(c *GlyphCache)

Put returns a cache to the pool.

type GlyphCacheStats added in v0.11.0

type GlyphCacheStats struct {
	Hits       atomic.Uint64
	Misses     atomic.Uint64
	Evictions  atomic.Uint64
	Insertions atomic.Uint64
}

GlyphCacheStats holds cache statistics.

type GlyphFlags added in v0.10.0

type GlyphFlags uint8

GlyphFlags provides additional glyph information for rendering.

const (
	// GlyphFlagLigature indicates this glyph is the first in a ligature.
	// The following glyphs with zero advance are part of the same ligature.
	GlyphFlagLigature GlyphFlags = 1 << iota

	// GlyphFlagMark indicates this glyph is a combining mark.
	// Marks are positioned relative to their base glyph.
	GlyphFlagMark

	// GlyphFlagSafeToBreak indicates this is a safe line break point.
	// Used by the layout engine for word wrapping.
	GlyphFlagSafeToBreak

	// GlyphFlagClusterStart indicates this glyph starts a new cluster.
	// Clusters are groups of glyphs that map to one or more characters.
	GlyphFlagClusterStart
)

func (GlyphFlags) Has added in v0.10.0

func (f GlyphFlags) Has(flag GlyphFlags) bool

Has returns true if the flags contain the specified flag.

func (GlyphFlags) String added in v0.10.0

func (f GlyphFlags) String() string

String returns a human-readable representation of the flags.

type GlyphID

type GlyphID uint16

GlyphID is a unique identifier for a glyph within a font. The glyph ID is assigned by the font file and is font-specific.

type GlyphImage

type GlyphImage struct {
	// Mask is the alpha mask (grayscale image).
	// This represents the glyph's shape.
	Mask *image.Alpha

	// Bounds relative to glyph origin.
	// The origin is typically on the baseline at the left edge.
	Bounds image.Rectangle

	// Advance width in pixels.
	// This is how far the cursor should move after drawing this glyph.
	Advance float64
}

GlyphImage represents a rasterized glyph. This contains the alpha mask and positioning information.

func RasterizeGlyph

func RasterizeGlyph(parsed ParsedFont, glyphID GlyphID, ppem float64) *GlyphImage

RasterizeGlyph renders a glyph to an alpha mask. Uses golang.org/x/image/font for rasterization.

This function is primarily intended for future caching implementations and advanced use cases. For normal text drawing, use the Draw function instead.

Parameters:

  • parsed: The parsed font (must be *ximageParsedFont)
  • glyphID: The glyph index to rasterize
  • ppem: Pixels per em (font size)

Returns:

  • *GlyphImage with the rasterized glyph, or nil if rasterization fails

type GlyphKey

type GlyphKey struct {
	GID  GlyphID
	Size float64
}

GlyphKey identifies a rasterized glyph in the glyph cache.

type GlyphOutline added in v0.11.0

type GlyphOutline struct {
	// Segments is the list of path segments that make up the outline.
	Segments []OutlineSegment

	// Bounds is the bounding box of the outline in scaled units.
	Bounds Rect

	// Advance is the horizontal advance width of the glyph.
	Advance float32

	// LSB is the left side bearing.
	LSB float32

	// GID is the glyph ID this outline represents.
	GID GlyphID

	// Type indicates the type of glyph (outline, bitmap, COLR).
	Type GlyphType
}

GlyphOutline represents the vector outline of a glyph. The outline consists of one or more closed contours.

func (*GlyphOutline) Clone added in v0.11.0

func (o *GlyphOutline) Clone() *GlyphOutline

Clone creates a deep copy of the outline.

func (*GlyphOutline) IsEmpty added in v0.11.0

func (o *GlyphOutline) IsEmpty() bool

IsEmpty returns true if the outline has no segments.

func (*GlyphOutline) Scale added in v0.11.0

func (o *GlyphOutline) Scale(factor float32) *GlyphOutline

Scale returns a new outline with all coordinates scaled by the given factor.

func (*GlyphOutline) SegmentCount added in v0.11.0

func (o *GlyphOutline) SegmentCount() int

SegmentCount returns the number of segments in the outline.

func (*GlyphOutline) Transform added in v0.11.0

func (o *GlyphOutline) Transform(m *AffineTransform) *GlyphOutline

Transform returns a new outline with all coordinates transformed.

func (*GlyphOutline) Translate added in v0.11.0

func (o *GlyphOutline) Translate(dx, dy float32) *GlyphOutline

Translate returns a new outline with all coordinates translated by (dx, dy).

type GlyphRenderer added in v0.11.0

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

GlyphRenderer converts shaped glyphs to outline paths. It uses the GlyphCache for efficient outline caching and OutlineExtractor for extracting glyph outlines from fonts.

GlyphRenderer is safe for concurrent use.

func NewGlyphRenderer added in v0.11.0

func NewGlyphRenderer() *GlyphRenderer

NewGlyphRenderer creates a new glyph renderer with the global cache.

func NewGlyphRendererWithCache added in v0.11.0

func NewGlyphRendererWithCache(cache *GlyphCache) *GlyphRenderer

NewGlyphRendererWithCache creates a new glyph renderer with a custom cache.

func (*GlyphRenderer) Cache added in v0.11.0

func (r *GlyphRenderer) Cache() *GlyphCache

Cache returns the glyph cache used by this renderer.

func (*GlyphRenderer) RenderGlyph added in v0.11.0

func (r *GlyphRenderer) RenderGlyph(
	glyph *ShapedGlyph,
	font ParsedFont,
	size float64,
	params RenderParams,
) *GlyphOutline

RenderGlyph renders a single glyph to an outline. Returns the glyph outline with positioning applied.

Parameters:

  • glyph: The shaped glyph to render
  • font: The parsed font to use for outline extraction
  • size: Font size in pixels (ppem)
  • params: Rendering parameters

Returns the transformed outline, or nil if the glyph has no outline.

func (*GlyphRenderer) RenderGlyphs added in v0.11.0

func (r *GlyphRenderer) RenderGlyphs(
	glyphs []ShapedGlyph,
	font ParsedFont,
	size float64,
	params RenderParams,
) []*GlyphOutline

RenderGlyphs renders multiple glyphs to outlines. Returns a slice of outlines corresponding to each input glyph. Glyphs with no outline (e.g., spaces) will have nil entries.

func (*GlyphRenderer) RenderLayout added in v0.11.0

func (r *GlyphRenderer) RenderLayout(layout *Layout, params RenderParams) [][]*GlyphOutline

RenderLayout renders a complete layout to outlines. Returns a 2D slice where [line][glyph] contains the outlines.

func (*GlyphRenderer) RenderRun added in v0.11.0

func (r *GlyphRenderer) RenderRun(run *ShapedRun, params RenderParams) []*GlyphOutline

RenderRun renders a shaped run to outlines.

func (*GlyphRenderer) SetCache added in v0.11.0

func (r *GlyphRenderer) SetCache(cache *GlyphCache)

SetCache sets the glyph cache used by this renderer.

type GlyphType added in v0.10.0

type GlyphType uint8

GlyphType indicates how to render a glyph.

const (
	// GlyphTypeOutline is a vector path glyph (default).
	// Rendered via sparse strips or MSDF.
	GlyphTypeOutline GlyphType = iota

	// GlyphTypeBitmap is an embedded bitmap glyph.
	// Found in sbix (Apple) or CBDT/CBLC (Google) tables.
	// Used for color emoji.
	GlyphTypeBitmap

	// GlyphTypeCOLR is a color layers glyph.
	// Uses COLRv0 or COLRv1 tables for layered color glyphs.
	GlyphTypeCOLR

	// GlyphTypeSVG is an SVG document glyph.
	// Found in SVG table, used for complex color glyphs.
	GlyphTypeSVG
)

func (GlyphType) String added in v0.10.0

func (t GlyphType) String() string

String returns the string representation of the glyph type.

type Hinting

type Hinting int

Hinting specifies font hinting mode.

const (
	// HintingNone disables hinting.
	HintingNone Hinting = iota
	// HintingVertical applies vertical hinting only.
	HintingVertical
	// HintingFull applies full hinting.
	HintingFull
)

func (Hinting) String

func (h Hinting) String() string

String returns the string representation of the hinting.

type Layout added in v0.10.0

type Layout struct {
	// Lines contains all lines of laid out text.
	Lines []Line

	// Width is the maximum width among all lines.
	Width float64

	// Height is the total height of all lines.
	Height float64
}

Layout represents the result of text layout.

func LayoutText added in v0.10.0

func LayoutText(text string, face Face, size float64, opts LayoutOptions) *Layout

LayoutText performs text layout with the given options. It segments text by direction/script, shapes each segment, wraps lines if MaxWidth > 0, and positions lines with alignment.

For cancellable layout, use LayoutTextWithContext.

func LayoutTextSimple added in v0.10.0

func LayoutTextSimple(text string, face Face, size float64) *Layout

LayoutTextSimple is a convenience wrapper with default options.

func LayoutTextWithContext added in v0.13.0

func LayoutTextWithContext(ctx context.Context, text string, face Face, size float64, opts LayoutOptions) (*Layout, error)

LayoutTextWithContext performs text layout with the given options and cancellation support. It segments text by direction/script, shapes each segment, wraps lines if MaxWidth > 0, and positions lines with alignment.

The context can be used to cancel long-running layout operations. When canceled, returns nil and ctx.Err().

type LayoutOptions added in v0.10.0

type LayoutOptions struct {
	// MaxWidth is the maximum line width in pixels.
	// If 0, no line wrapping is performed (single-line paragraphs).
	MaxWidth float64

	// LineSpacing is a multiplier for line height.
	// 1.0 uses the font's natural line height; 1.5 adds 50% extra space.
	LineSpacing float64

	// Alignment specifies horizontal text alignment.
	Alignment Alignment

	// Direction is the base text direction (LTR or RTL).
	// Used for paragraph-level direction when no strong directional text is present.
	Direction Direction

	// WrapMode specifies how text is wrapped when it exceeds MaxWidth.
	// Default is WrapWordChar which breaks at word boundaries first,
	// then falls back to character boundaries for long words.
	WrapMode WrapMode
}

LayoutOptions configures text layout behavior.

func DefaultLayoutOptions added in v0.10.0

func DefaultLayoutOptions() LayoutOptions

DefaultLayoutOptions returns sensible default layout options.

type Line added in v0.10.0

type Line struct {
	// Runs contains the shaped runs that make up this line.
	// Multiple runs occur with mixed scripts or directions.
	Runs []ShapedRun

	// Glyphs contains all glyphs from Runs, positioned for rendering.
	// Glyph X positions are absolute within the layout.
	Glyphs []ShapedGlyph

	// Width is the total advance width of all glyphs in this line.
	Width float64

	// Ascent is the maximum ascent of all runs (distance above baseline).
	Ascent float64

	// Descent is the maximum descent of all runs (distance below baseline).
	Descent float64

	// Y is the baseline Y position of this line within the layout.
	Y float64
}

Line represents a positioned line of text ready for rendering.

func (*Line) Height added in v0.10.0

func (l *Line) Height() float64

Height returns the total height of the line (ascent + descent).

type Metrics

type Metrics struct {
	// Ascent is the distance from the baseline to the top of the font (positive).
	// This is the maximum height a glyph can reach above the baseline.
	Ascent float64

	// Descent is the distance from the baseline to the bottom of the font (positive, below baseline).
	// This is the maximum depth a glyph can reach below the baseline.
	// Note: Unlike FontMetrics.Descent, this is stored as a positive value.
	Descent float64

	// LineGap is the recommended gap between lines.
	LineGap float64

	// XHeight is the height of lowercase letters (like 'x').
	XHeight float64

	// CapHeight is the height of uppercase letters.
	CapHeight float64
}

Metrics holds font metrics at a specific size. These metrics are derived from the font file and scaled to the face size.

func (Metrics) LineHeight

func (m Metrics) LineHeight() float64

LineHeight returns the total line height (ascent + descent + line gap). This is the recommended vertical distance between baselines of consecutive lines.

type MultiFace

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

MultiFace combines multiple faces with fallback. When rendering, it uses the first face that has the glyph. MultiFace is safe for concurrent use.

func NewMultiFace

func NewMultiFace(faces ...Face) (*MultiFace, error)

NewMultiFace creates a MultiFace from faces. All faces must have the same direction. Returns error if faces is empty or directions don't match.

func (*MultiFace) Advance

func (m *MultiFace) Advance(text string) float64

Advance implements Face.Advance. Calculates total advance using the appropriate face for each rune.

func (*MultiFace) AppendGlyphs

func (m *MultiFace) AppendGlyphs(dst []Glyph, text string) []Glyph

AppendGlyphs implements Face.AppendGlyphs. Appends glyphs using the appropriate face for each rune.

func (*MultiFace) Direction

func (m *MultiFace) Direction() Direction

Direction implements Face.Direction.

func (*MultiFace) Glyphs

func (m *MultiFace) Glyphs(text string) iter.Seq[Glyph]

Glyphs implements Face.Glyphs. Returns an iterator over all glyphs, using the appropriate face for each rune.

func (*MultiFace) HasGlyph

func (m *MultiFace) HasGlyph(r rune) bool

HasGlyph implements Face.HasGlyph. Returns true if any face has the glyph.

func (*MultiFace) Metrics

func (m *MultiFace) Metrics() Metrics

Metrics implements Face.Metrics. Returns metrics from the first face.

func (*MultiFace) Size

func (m *MultiFace) Size() float64

Size implements Face.Size. Returns the size from the first face.

func (*MultiFace) Source

func (m *MultiFace) Source() *FontSource

Source implements Face.Source. Returns nil since MultiFace is a composite face.

type OutlineCacheKey added in v0.11.0

type OutlineCacheKey struct {
	// FontID is a unique identifier for the font.
	FontID uint64

	// GID is the glyph index within the font.
	GID GlyphID

	// Size is the font size in ppem (pixels per em).
	// We use int16 for efficiency; sizes above 32K are rare.
	Size int16

	// Hinting indicates the hinting mode used.
	Hinting Hinting
}

OutlineCacheKey uniquely identifies a cached glyph outline.

type OutlineExtractor added in v0.11.0

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

OutlineExtractor extracts glyph outlines from fonts. It uses a buffer pool internally for efficiency.

func NewOutlineExtractor added in v0.11.0

func NewOutlineExtractor() *OutlineExtractor

NewOutlineExtractor creates a new outline extractor.

func (*OutlineExtractor) ExtractOutline added in v0.11.0

func (e *OutlineExtractor) ExtractOutline(font ParsedFont, gid GlyphID, size float64) (*GlyphOutline, error)

ExtractOutline extracts the outline for a glyph at the given size. The size is in pixels (ppem - pixels per em). Returns nil if the glyph has no outline (e.g., space character).

type OutlineOp added in v0.11.0

type OutlineOp uint8

OutlineOp is the type of path operation.

const (
	// OutlineOpMoveTo moves to a new point without drawing.
	OutlineOpMoveTo OutlineOp = iota

	// OutlineOpLineTo draws a line to the target point.
	OutlineOpLineTo

	// OutlineOpQuadTo draws a quadratic bezier curve.
	OutlineOpQuadTo

	// OutlineOpCubicTo draws a cubic bezier curve.
	OutlineOpCubicTo
)

func (OutlineOp) String added in v0.11.0

func (op OutlineOp) String() string

String returns a string representation of the operation.

type OutlinePoint added in v0.11.0

type OutlinePoint struct {
	X, Y float32
}

OutlinePoint represents a point in a glyph outline. All coordinates are in font units and should be scaled by size/unitsPerEm.

type OutlineSegment added in v0.11.0

type OutlineSegment struct {
	// Op is the segment operation type.
	Op OutlineOp

	// Points contains the control and end points for this segment.
	// - MoveTo: Points[0] is the target point
	// - LineTo: Points[0] is the target point
	// - QuadTo: Points[0] is control, Points[1] is target
	// - CubicTo: Points[0], Points[1] are controls, Points[2] is target
	Points [3]OutlinePoint
}

OutlineSegment represents a segment of a glyph outline.

type ParsedFont

type ParsedFont interface {
	// Name returns the font family name.
	// Returns empty string if not available.
	Name() string

	// FullName returns the full font name.
	// Returns empty string if not available.
	FullName() string

	// NumGlyphs returns the number of glyphs in the font.
	NumGlyphs() int

	// UnitsPerEm returns the units per em for the font.
	UnitsPerEm() int

	// GlyphIndex returns the glyph index for a rune.
	// Returns 0 if the glyph is not found.
	GlyphIndex(r rune) uint16

	// GlyphAdvance returns the advance width for a glyph at the given size (in points).
	// The ppem (pixels per em) is derived from size and DPI.
	GlyphAdvance(glyphIndex uint16, ppem float64) float64

	// GlyphBounds returns the bounding box for a glyph at the given size.
	GlyphBounds(glyphIndex uint16, ppem float64) Rect

	// Metrics returns the font metrics at the given size.
	Metrics(ppem float64) FontMetrics
}

ParsedFont represents a parsed font file. This interface abstracts the underlying font representation.

type Rect

type Rect struct {
	// Min is the top-left corner
	MinX, MinY float64
	// Max is the bottom-right corner
	MaxX, MaxY float64
}

Rect represents a rectangle for glyph bounds.

func (Rect) Empty

func (r Rect) Empty() bool

Empty reports whether the rectangle is empty.

func (Rect) Height

func (r Rect) Height() float64

Height returns the height of the rectangle.

func (Rect) Width

func (r Rect) Width() float64

Width returns the width of the rectangle.

type RenderParams added in v0.11.0

type RenderParams struct {
	// Transform is an optional affine transformation to apply to all glyphs.
	// If nil, identity transform is used.
	Transform *AffineTransform

	// Color is the fill color for glyphs.
	Color color.RGBA

	// Opacity is the overall opacity [0, 1].
	// 1.0 means fully opaque, 0.0 means fully transparent.
	Opacity float64
}

RenderParams holds parameters for glyph rendering.

func DefaultRenderParams added in v0.11.0

func DefaultRenderParams() RenderParams

DefaultRenderParams returns default rendering parameters.

func (RenderParams) WithColor added in v0.11.0

func (p RenderParams) WithColor(c color.RGBA) RenderParams

WithColor returns a copy of params with the given color.

func (RenderParams) WithOpacity added in v0.11.0

func (p RenderParams) WithOpacity(opacity float64) RenderParams

WithOpacity returns a copy of params with the given opacity.

func (RenderParams) WithTransform added in v0.11.0

func (p RenderParams) WithTransform(t *AffineTransform) RenderParams

WithTransform returns a copy of params with the given transform.

type RuneToBoolMap

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

RuneToBoolMap is a memory-efficient map from rune to bool. Uses 2 bits per rune: (checked, hasGlyph). Optimized for sparse access patterns in Unicode space.

Each block covers 256 runes (512 bits = 64 bytes). Blocks are allocated on-demand only when a rune in that range is accessed.

RuneToBoolMap is safe for concurrent use. RuneToBoolMap must not be copied after creation (has mutex).

func NewRuneToBoolMap

func NewRuneToBoolMap() *RuneToBoolMap

NewRuneToBoolMap creates a new rune-to-bool map.

func (*RuneToBoolMap) Clear

func (m *RuneToBoolMap) Clear()

Clear removes all entries from the map.

func (*RuneToBoolMap) Get

func (m *RuneToBoolMap) Get(r rune) (hasGlyph, checked bool)

Get returns (hasGlyph, checked). If checked is false, the rune hasn't been queried yet.

func (*RuneToBoolMap) Set

func (m *RuneToBoolMap) Set(r rune, hasGlyph bool)

Set stores the hasGlyph value for a rune. Marks the rune as checked.

type Script added in v0.10.0

type Script uint32

Script represents a Unicode script for text segmentation. Scripts are used to identify runs of text that should be shaped together.

const (
	// ScriptCommon is used for punctuation, numbers, and symbols shared across scripts.
	ScriptCommon Script = iota
	// ScriptInherited is used for combining marks that inherit the script of the base character.
	ScriptInherited
	// ScriptLatin is used for Latin-based scripts (English, French, German, etc.)
	ScriptLatin
	// ScriptCyrillic is used for Cyrillic script (Russian, Ukrainian, Bulgarian, etc.)
	ScriptCyrillic
	// ScriptGreek is used for Greek script.
	ScriptGreek
	// ScriptArabic is used for Arabic script (Arabic, Persian, Urdu, etc.)
	ScriptArabic
	// ScriptHebrew is used for Hebrew script.
	ScriptHebrew
	// ScriptHan is used for Chinese/Japanese Kanji characters.
	ScriptHan
	// ScriptHiragana is used for Japanese Hiragana.
	ScriptHiragana
	// ScriptKatakana is used for Japanese Katakana.
	ScriptKatakana
	// ScriptHangul is used for Korean script.
	ScriptHangul
	// ScriptDevanagari is used for Devanagari script (Hindi, Sanskrit, etc.)
	ScriptDevanagari
	// ScriptThai is used for Thai script.
	ScriptThai
	// ScriptGeorgian is used for Georgian script.
	ScriptGeorgian
	// ScriptArmenian is used for Armenian script.
	ScriptArmenian
	// ScriptBengali is used for Bengali script.
	ScriptBengali
	// ScriptTamil is used for Tamil script.
	ScriptTamil
	// ScriptTelugu is used for Telugu script.
	ScriptTelugu
	// ScriptKannada is used for Kannada script.
	ScriptKannada
	// ScriptMalayalam is used for Malayalam script.
	ScriptMalayalam
	// ScriptGujarati is used for Gujarati script.
	ScriptGujarati
	// ScriptOriya is used for Oriya script.
	ScriptOriya
	// ScriptGurmukhi is used for Gurmukhi script (Punjabi).
	ScriptGurmukhi
	// ScriptSinhala is used for Sinhala script.
	ScriptSinhala
	// ScriptKhmer is used for Khmer script (Cambodian).
	ScriptKhmer
	// ScriptLao is used for Lao script.
	ScriptLao
	// ScriptMyanmar is used for Myanmar (Burmese) script.
	ScriptMyanmar
	// ScriptTibetan is used for Tibetan script.
	ScriptTibetan
	// ScriptEthiopic is used for Ethiopic script.
	ScriptEthiopic
	// ScriptUnknown is used for unrecognized scripts.
	ScriptUnknown
)

Script constants for common Unicode scripts. The values are based on Unicode script codes but simplified for our use case.

func DetectScript added in v0.10.0

func DetectScript(r rune) Script

DetectScript returns the Unicode script for a given rune. This uses hardcoded Unicode ranges for common scripts to avoid external dependencies.

For characters that appear in multiple scripts or are shared (like punctuation and numbers), ScriptCommon is returned. For combining marks, ScriptInherited is returned.

func (Script) IsRTL added in v0.10.0

func (s Script) IsRTL() bool

IsRTL returns true if the script is typically written right-to-left.

func (Script) RequiresComplexShaping added in v0.10.0

func (s Script) RequiresComplexShaping() bool

RequiresComplexShaping returns true if the script typically needs advanced shaping features (ligatures, contextual forms, etc.) that are not supported by BuiltinShaper.

func (Script) String added in v0.10.0

func (s Script) String() string

String returns the name of the script.

type Segment added in v0.10.0

type Segment struct {
	Text      string
	Start     int
	End       int
	Direction Direction
	Script    Script
	Level     int
}

Segment represents a contiguous run of text with the same direction and script.

func SegmentText added in v0.10.0

func SegmentText(text string) []Segment

func SegmentTextRTL added in v0.10.0

func SegmentTextRTL(text string) []Segment

func (Segment) RuneCount added in v0.10.0

func (s Segment) RuneCount() int

type Segmenter added in v0.10.0

type Segmenter interface {
	Segment(text string) []Segment
}

type ShapedGlyph added in v0.10.0

type ShapedGlyph struct {
	// GID is the glyph index in the font.
	GID GlyphID

	// Cluster is the source character index in the original text.
	// Used for hit testing and cursor positioning.
	Cluster int

	// X is the horizontal position relative to the text origin.
	X float64

	// Y is the vertical position relative to the baseline.
	Y float64

	// XAdvance is the horizontal advance to the next glyph.
	XAdvance float64

	// YAdvance is the vertical advance (for vertical text).
	YAdvance float64
}

ShapedGlyph represents a positioned glyph ready for GPU rendering. Unlike Glyph which contains CPU rasterization data (Mask), ShapedGlyph is minimal and designed for efficient GPU text rendering pipelines.

func Shape added in v0.10.0

func Shape(text string, face Face, size float64) []ShapedGlyph

Shape is a convenience function that uses the global shaper. It converts text to positioned glyphs using the given face and size.

type ShapedRun added in v0.10.0

type ShapedRun struct {
	// Glyphs is the sequence of positioned glyphs.
	Glyphs []ShapedGlyph

	// Advance is the total advance of all glyphs.
	// For horizontal text, this is width; for vertical, height.
	Advance float64

	// Ascent is the maximum ascent above the baseline.
	Ascent float64

	// Descent is the maximum descent below the baseline (positive value).
	Descent float64

	// Direction is the text direction for this run.
	Direction Direction

	// Face is the font face used for this run.
	Face Face

	// Size is the font size in pixels.
	Size float64
}

ShapedRun is a sequence of shaped glyphs with uniform style. Used by the Layout Engine for multi-line and multi-style text rendering.

func (*ShapedRun) Bounds added in v0.10.0

func (r *ShapedRun) Bounds() (x, y, width, height float64)

Bounds returns the bounding rectangle of the run. The origin is at the baseline start.

func (*ShapedRun) Height added in v0.10.0

func (r *ShapedRun) Height() float64

Height returns the total height of the run. For horizontal text, this is Ascent + Descent. For vertical text, this equals Advance.

func (*ShapedRun) LineHeight added in v0.10.0

func (r *ShapedRun) LineHeight() float64

LineHeight returns the recommended line height for this run.

func (*ShapedRun) Width added in v0.10.0

func (r *ShapedRun) Width() float64

Width returns the total width of the run. For horizontal text, this equals Advance. For vertical text, this is based on glyph widths.

type Shaper added in v0.10.0

type Shaper interface {
	// Shape converts text into positioned glyphs using the given face and size.
	// The returned ShapedGlyph slice is ready for GPU rendering.
	Shape(text string, face Face, size float64) []ShapedGlyph
}

Shaper converts text to positioned glyphs. Implementations provide different levels of text shaping support:

  • BuiltinShaper: Uses golang.org/x/image/font for Latin, Cyrillic, Greek, CJK
  • HarfBuzz-compatible: Use SetShaper() with a go-text/typesetting implementation

func GetShaper added in v0.10.0

func GetShaper() Shaper

GetShaper returns the current global shaper.

type ShapingKey

type ShapingKey struct {
	Text      string
	Size      float64
	Direction Direction
}

ShapingKey identifies shaped text in the shaping cache.

type SourceOption

type SourceOption func(*sourceConfig)

SourceOption configures FontSource creation.

func WithCacheLimit

func WithCacheLimit(n int) SourceOption

WithCacheLimit sets the maximum number of cached glyphs. A value of 0 disables the cache limit.

func WithParser

func WithParser(name string) SourceOption

WithParser specifies the font parser backend. The default is "ximage" which uses golang.org/x/image/font/opentype.

Custom parsers can be registered with RegisterParser. This allows using alternative font parsing libraries or a pure Go implementation in the future.

type SubpixelCache added in v0.11.0

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

SubpixelCache wraps GlyphCache with subpixel awareness. It provides the same interface as GlyphCache but uses SubpixelKey to differentiate between the same glyph at different subpixel offsets.

SubpixelCache is safe for concurrent use.

func GetGlobalSubpixelCache added in v0.11.0

func GetGlobalSubpixelCache() *SubpixelCache

GetGlobalSubpixelCache returns the global shared subpixel cache.

func NewSubpixelCache added in v0.11.0

func NewSubpixelCache(config SubpixelConfig) *SubpixelCache

NewSubpixelCache creates a cache with subpixel support.

func NewSubpixelCacheWithConfig added in v0.11.0

func NewSubpixelCacheWithConfig(config SubpixelConfig, glyphConfig GlyphCacheConfig) *SubpixelCache

NewSubpixelCacheWithConfig creates a cache with custom glyph cache config.

func SetGlobalSubpixelCache added in v0.11.0

func SetGlobalSubpixelCache(cache *SubpixelCache) *SubpixelCache

SetGlobalSubpixelCache replaces the global subpixel cache. The old cache is returned for cleanup if needed.

func (*SubpixelCache) Clear added in v0.11.0

func (c *SubpixelCache) Clear()

Clear removes all entries from the cache.

func (*SubpixelCache) Config added in v0.11.0

func (c *SubpixelCache) Config() SubpixelConfig

Config returns the subpixel configuration.

func (*SubpixelCache) Delete added in v0.11.0

func (c *SubpixelCache) Delete(key SubpixelKey)

Delete removes an entry from the cache.

func (*SubpixelCache) Get added in v0.11.0

func (c *SubpixelCache) Get(key SubpixelKey) *GlyphOutline

Get retrieves a glyph at the specified subpixel position. Returns nil if not found.

func (*SubpixelCache) GetOrCreate added in v0.11.0

func (c *SubpixelCache) GetOrCreate(
	key SubpixelKey,
	create func(offsetX, offsetY float64) *GlyphOutline,
) *GlyphOutline

GetOrCreate retrieves or creates a glyph at subpixel position. The create function receives the subpixel offsets to apply during rasterization.

func (*SubpixelCache) HitRate added in v0.11.0

func (c *SubpixelCache) HitRate() float64

HitRate returns the cache hit rate as a percentage.

func (*SubpixelCache) Len added in v0.11.0

func (c *SubpixelCache) Len() int

Len returns the total number of cached entries.

func (*SubpixelCache) Maintain added in v0.11.0

func (c *SubpixelCache) Maintain()

Maintain performs periodic maintenance on the cache.

func (*SubpixelCache) ResetStats added in v0.11.0

func (c *SubpixelCache) ResetStats()

ResetStats resets the cache statistics.

func (*SubpixelCache) Set added in v0.11.0

func (c *SubpixelCache) Set(key SubpixelKey, outline *GlyphOutline)

Set stores a glyph outline at the specified subpixel position.

func (*SubpixelCache) SetConfig added in v0.11.0

func (c *SubpixelCache) SetConfig(config SubpixelConfig)

SetConfig updates the subpixel configuration. Note: This clears the cache as existing entries may be invalid.

func (*SubpixelCache) Stats added in v0.11.0

func (c *SubpixelCache) Stats() SubpixelCacheStats

Stats returns subpixel cache statistics.

type SubpixelCacheStats added in v0.11.0

type SubpixelCacheStats struct {
	// Hits is the number of cache hits
	Hits uint64

	// Misses is the number of cache misses
	Misses uint64

	// SubpixelHits is hits where subpixel position matched
	SubpixelHits uint64

	// SubpixelCreates is glyphs created for subpixel positions
	SubpixelCreates uint64
}

SubpixelCacheStats holds subpixel cache statistics.

type SubpixelConfig added in v0.11.0

type SubpixelConfig struct {
	// Mode determines the number of subpixel positions.
	Mode SubpixelMode

	// Horizontal enables subpixel positioning on X axis.
	Horizontal bool

	// Vertical enables subpixel positioning on Y axis (rarely needed).
	Vertical bool
}

SubpixelConfig holds subpixel positioning configuration.

func DefaultSubpixelConfig added in v0.11.0

func DefaultSubpixelConfig() SubpixelConfig

DefaultSubpixelConfig returns default configuration. Uses 4 horizontal subpixel positions.

func HighQualitySubpixelConfig added in v0.11.0

func HighQualitySubpixelConfig() SubpixelConfig

HighQualitySubpixelConfig returns a configuration with maximum subpixel quality. Uses 10 horizontal subpixel positions.

func NoSubpixelConfig added in v0.11.0

func NoSubpixelConfig() SubpixelConfig

NoSubpixelConfig returns a configuration with subpixel positioning disabled.

func (SubpixelConfig) CacheMultiplier added in v0.11.0

func (c SubpixelConfig) CacheMultiplier() int

CacheMultiplier returns the factor by which cache size increases. For Subpixel4 with horizontal only: 4x For Subpixel10 with both: 100x

func (SubpixelConfig) IsEnabled added in v0.11.0

func (c SubpixelConfig) IsEnabled() bool

IsEnabled returns true if any subpixel positioning is enabled.

type SubpixelKey added in v0.11.0

type SubpixelKey struct {
	OutlineCacheKey

	// SubX is the quantized horizontal subpixel position (0 to Mode-1).
	SubX uint8

	// SubY is the quantized vertical subpixel position (0 to Mode-1).
	SubY uint8
}

SubpixelKey extends OutlineCacheKey with subpixel offset. This allows caching separate rasterized glyphs for each subpixel position.

func MakeSubpixelKey added in v0.11.0

func MakeSubpixelKey(baseKey OutlineCacheKey, x, y float64, config SubpixelConfig) SubpixelKey

MakeSubpixelKey creates a SubpixelKey from glyph position and base cache key.

type SubpixelMode added in v0.11.0

type SubpixelMode int

SubpixelMode controls subpixel text positioning. Subpixel positioning improves text quality by allowing glyphs to be rendered at fractional pixel positions. This is especially important for small text where the difference between whole pixel positions is noticeable.

const (
	// SubpixelNone disables subpixel positioning.
	// Glyphs snap to whole pixels. Fastest but lower quality.
	SubpixelNone SubpixelMode = 0

	// Subpixel4 uses 4 subpixel positions (0.0, 0.25, 0.5, 0.75).
	// Good balance of quality and cache size.
	Subpixel4 SubpixelMode = 4

	// Subpixel10 uses 10 subpixel positions (0.0, 0.1, ..., 0.9).
	// Highest quality but 10x cache entries per glyph.
	Subpixel10 SubpixelMode = 10
)

func (SubpixelMode) Divisions added in v0.11.0

func (m SubpixelMode) Divisions() int

Divisions returns the number of subpixel divisions. Returns 1 for SubpixelNone (no divisions).

func (SubpixelMode) IsEnabled added in v0.11.0

func (m SubpixelMode) IsEnabled() bool

IsEnabled returns true if subpixel positioning is enabled.

func (SubpixelMode) String added in v0.11.0

func (m SubpixelMode) String() string

String returns the string representation of the subpixel mode.

type TextRenderer added in v0.11.0

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

TextRenderer provides a high-level API for text rendering. It combines shaping and glyph outline extraction.

Note: For rendering to a scene.Scene, use scene.TextRenderer instead, which provides direct scene integration.

func GetGlobalTextRenderer added in v0.11.0

func GetGlobalTextRenderer() *TextRenderer

GetGlobalTextRenderer returns the global shared text renderer.

func NewTextRenderer added in v0.11.0

func NewTextRenderer() *TextRenderer

NewTextRenderer creates a new text renderer.

func (*TextRenderer) GlyphRenderer added in v0.11.0

func (tr *TextRenderer) GlyphRenderer() *GlyphRenderer

GlyphRenderer returns the underlying glyph renderer.

func (*TextRenderer) SetDefaultColor added in v0.11.0

func (tr *TextRenderer) SetDefaultColor(c color.RGBA)

SetDefaultColor sets the default text color.

func (*TextRenderer) SetDefaultFace added in v0.11.0

func (tr *TextRenderer) SetDefaultFace(face Face)

SetDefaultFace sets the default font face for rendering.

func (*TextRenderer) SetDefaultSize added in v0.11.0

func (tr *TextRenderer) SetDefaultSize(size float64)

SetDefaultSize sets the default font size.

func (*TextRenderer) ShapeAndRender added in v0.11.0

func (tr *TextRenderer) ShapeAndRender(text string) ([]*GlyphOutline, error)

ShapeAndRender shapes text and returns the glyph outlines.

func (*TextRenderer) ShapeAndRenderAt added in v0.11.0

func (tr *TextRenderer) ShapeAndRenderAt(text string, x, y float64) ([]*GlyphOutline, error)

ShapeAndRenderAt shapes text and returns outlines at the specified position.

type UnicodeRange

type UnicodeRange struct {
	Start rune
	End   rune
}

UnicodeRange represents a contiguous range of code points.

func (UnicodeRange) Contains

func (ur UnicodeRange) Contains(r rune) bool

Contains reports whether the rune is in the range.

type WrapMode added in v0.13.0

type WrapMode uint8

WrapMode specifies how text is wrapped when it exceeds the maximum width.

const (
	// WrapWordChar breaks at word boundaries first,
	// then falls back to character boundaries for long words.
	// This is the default and most common mode (zero value for backward compatibility).
	WrapWordChar WrapMode = iota

	// WrapNone disables text wrapping; text may exceed MaxWidth.
	WrapNone

	// WrapWord breaks at word boundaries only.
	// Long words that exceed MaxWidth will overflow.
	WrapWord

	// WrapChar breaks at character boundaries.
	// Any character can be a break point.
	WrapChar
)

func (WrapMode) String added in v0.13.0

func (m WrapMode) String() string

String returns the string representation of the wrap mode.

type WrapResult added in v0.13.0

type WrapResult struct {
	// Text is the content of this line.
	Text string
	// Start is the byte offset in the original text.
	Start int
	// End is the byte offset in the original text.
	End int
}

WrapResult represents a wrapped line of text.

func WrapText added in v0.13.0

func WrapText(text string, face Face, size float64, maxWidth float64, mode WrapMode) []WrapResult

WrapText wraps text to fit within maxWidth using the specified face and options. Returns a slice of wrapped line results.

Directories

Path Synopsis
Package cache provides high-performance caching for text shaping and rendering.
Package cache provides high-performance caching for text shaping and rendering.
Package emoji provides emoji and color font support for text rendering.
Package emoji provides emoji and color font support for text rendering.
Package msdf provides Multi-channel Signed Distance Field generation for high-quality, scalable text rendering on GPU.
Package msdf provides Multi-channel Signed Distance Field generation for high-quality, scalable text rendering on GPU.

Jump to

Keyboard shortcuts

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