Add glyph-id rendering, skip-ink decorations, and native font matching#545
Merged
Conversation
Introduces several major features and API additions: - **Glyph-id rendering/measurement**: `TextRenderer.RenderTo(renderer, glyphId, GlyphOptions)`, `GlyphRun`, `GlyphOptions`, and `TextMeasurer` overloads for measuring by glyph id without text layout. - **`FontMetrics` public API**: `TryGetGlyphMetrics(ushort glyphId, ...)`, `TryGetTableData(Tag, ...)`, and `OpenStream()` are now public/abstract members. - **`MemoryFontMetrics`**: Stream-loaded fonts now copy data into owned memory so they remain valid after the source stream is closed. - **`FontSource` abstraction**: Unifies file-backed and memory-backed font data access behind a single type used by `StreamFontMetrics`. - **Text-decoration skip-ink** (`TextDecorationSkipInk.Auto`): Underlines and overlines now break around glyph descenders/ascenders, implemented via `GlyphIntersectionCollector` and `TeeGlyphRenderer`. - **Native OS font matching**: New `DirectWriteSystemFontMatcher`, `CoreTextSystemFontMatcher`, and `FontConfigSystemFontMatcher` replace `MacSystemFontsEnumerator`. `SystemFonts.TryMatchCharacter` and `IReadOnlySystemFontCollection.TryMatchCharacter` provide OS-level font fallback. - **`FontCollectionExtensions`/`FontCollection`**: Support explicit family-name and style overrides when adding metrics, preserving platform family groupings from native matchers. - `TextRenderer.RenderTextTo` renamed to `RenderTo`; old name removed.
Replace the eager COLR v1 paint cache with on-demand paint decoding backed by a snapshot of the raw COLR table data. This avoids walking every color glyph paint graph during font load, reduces startup cost for fonts with many color glyphs, and keeps resolved paints cached by offset for reuse across renders. The loader now also accepts the table length so it can capture the exact COLR table bytes for later resolution.
Improves native font discovery and matching across macOS, Linux, and Windows. On macOS, CoreFoundation interop is corrected for CFNumberType ABI and descriptor trait extraction now reads weight/symbolic traits in one pass with fewer font instantiations. On Linux, Fontconfig calls are conditionally serialized for older non-thread-safe versions, family matching uses weak binding, and matched fonts are validated for actual character coverage. On Windows, non-local DirectWrite loaders are safely skipped and COM wrapper disposal guidance is clarified. The old AppContext switch path that disabled native enumeration was removed, along with its test helper and related test.
Updates the TrueType interpreter to better match FreeType v40 behavior. The class docs now describe backward-compatibility mode as the default and explain how fonts can waive it via INSTCTRL selector 3. INSTCTRL handling now allows selector 3 inside glyph programs (temporarily per glyph, since prep state is restored each run), and GETINFO now reports ClearType/grayscale support by setting bit 19 when selector bit 12 is requested.
Move skip-ink carving responsibility out of `FontGlyphMetrics` by sending full decoration lines plus merged ink intersection ranges through `IGlyphRenderer.SetDecoration(...)`. This updates all renderer implementations/callers to the new signature and simplifies `GlyphIntersectionCollector` to track per-contour band extents. The change also adds `TextDecorationOptions` and `TextRun.GetDecorationOptions(...)` so runs can override decoration thickness (for example, stroke-driven styling) instead of always using font metric thickness.
# Conflicts: # src/SixLabors.Fonts/Tables/Cff/CffGlyphMetrics.cs # src/SixLabors.Fonts/Tables/TrueType/TrueTypeGlyphMetrics.cs
Updated synthetic italic and bold rendering to better match Chromium/SkParagraph and FreeType behavior: switched to 1/4 oblique shear, adjusted bold strength to 1/31 em, unified outline transforms, fixed bounds transforms for rotated/sheared boxes, and avoided synthetic emboldening for painted color glyphs. Reworked emboldening to use a pooled renderer and FreeType-style contour dilation, added painted-glyph bounds support, expanded font synthesis coverage (including emoji and visual/browser comparison cases), and refreshed affected reference images.
Introduce a new FontWeight enum and comprehensive weight resolution system that supports both variable fonts (via wght axis) and static fonts (via synthetic bold). The implementation follows CSS weight semantics with a 600-weight boundary for synthetic bold synthesis. Updates include: - New FontWeight enum (100-900) matching OpenType and CSS standards - Weight property on FontDescription from OS/2 table - TextOptions and TextRun now support FontWeight configuration - Font.WithWeight() method for applying weights to variable fonts - Updated bold synthesis logic to use weight-based approach instead of boolean style flag - Support for weight overrides per text run or globally via TextOptions
Resolve numeric weights through system font families before synthetic bolding, while preserving existing variable-font behavior. Also switch OpenType axis tags to the shared `Tag` type and add browser and unit coverage for Windows system families like Segoe UI and Arial.
Tightens system font discovery and fallback across CoreText, DirectWrite, and Fontconfig so native matches resolve to managed, file-backed fonts more reliably. The change adds explicit face-name tracking, maps CoreText fallback fonts by PostScript name, includes Fontconfig application and localized family aliases, respects sysroot-resolved paths, skips non-loadable variable-instance indexes, and treats OTC files as font collections throughout the managed loader.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prerequisites
Description
This pull request introduces several improvements and refactorings to the font handling and metrics system, focusing on enhanced variable font weight support, more flexible font collection management, and improved glyph lookup performance and clarity. The changes affect core classes such as
Font,FontCollection, andFileFontMetrics, adding new APIs and internal logic to support these features.Variable Font and Weight Support:
Font.WithWeight(FontWeight weight, out bool applied)method, allowing more precise control over font weight selection and fallback to system fonts or synthetic weights when necessary.requestedWeightfield and corresponding constructor inFont, enabling numeric weight lookup and integration with system font collections. TheResolveBaseMetricsmethod now respects this requested weight when resolving metrics. [1] [2] [3]Font Metrics and Glyph Lookup Enhancements:
TryGetGlyphId(CodePoint codePoint, out ushort glyphId)method toFontfor direct glyph ID retrieval, and optimizedTryGetGlyphto use glyph ID lookup before fetching metrics, improving glyph lookup performance. [1] [2]FileFontMetricsto expose underlyingStreamFontMetricspublicly, implement table data and stream access methods, and support glyph metrics lookup by glyph ID, enhancing flexibility for advanced font operations. [1] [2] [3]Font Collection and Metrics Management:
FontCollectionto use a newFontCollectionEntrytype, allowing explicit family name and style overrides when adding metrics. This enables more accurate and flexible font family and style lookups, especially for custom or memory-based fonts. [1] [2] [3] [4]FontCollectionto use the new entry structure, improving culture-aware and style-specific matching.File and Memory Font Metrics Improvements:
FileFontMetricsto internally use aFontSourceabstraction, improving stream handling and table data access, and updated constructors for clarity and encapsulation. [1] [2]FontCollectionto useMemoryFontMetricsinstead ofStreamFontMetrics, unifying font metric handling for in-memory fonts.Other Notable Enhancements:
Bounds.Transformmethod to correctly compute the transformed bounding box by transforming all four corners, ensuring accurate bounds after arbitrary transformations.MemoryFontMetricsin font name resolution logic.These changes collectively improve the flexibility, accuracy, and extensibility of font handling in the codebase, especially for advanced variable font and custom font collection scenarios.