Repository navigation
Fix #296: variable fonts list and draw every named style - #326
Merged
Merged
Conversation
The font database made one style per font file, so a variable font such as Figtree[wght].ttf listed only its default instance (Light). Faces now also yield their fvar named instances, each a style of the family named by its subfamily name (the default instance is the face itself; unnamed or duplicate instances are left out; axes and instances read are capped). The system font scan reads the fvar table beside the name table, so installed instances are listed before the file is loaded and found by name and by PostScript name. An instance face carries its axis settings: skrifa draws its outlines and reads its metrics and advances at that location, harfrust shapes with a ShaperInstance, so layout, the canvas, Create Outlines and hit testing all use the instance. PDF export embeds it through krilla's Font::new_variable, SVG @font-face through subsetter's subset_with_variations: both write a static font of that instance. Tests build a small variable font in code (test_fonts, via write-fonts; no font file is committed) and check listing, resolving, glyphs and advances, PDF and SVG export and damaged fvar/gvar tables; Bahnschrift and Segoe UI Variable are checked where installed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 7, 2026
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.
Fixes #296.
The font database made one style per font file, from its
nametable. A variable font such as Figtree from Google Fonts (Figtree[wght].ttf,Figtree-Italic[wght].ttf) is one file per family whose default instance is Light, so VectorCraft listed only Light and Light Italic and never read thefvarnamed instances (Regular to Black). Outlines, advances and shaping were also always taken at the default location.What users see
text.fontList/ MCP, sorted bywghtwith italics after. Figtree shows Light to Black with their italics; Bahnschrift shows its 15 styles (Condensed and SemiCondensed included); Segoe UI Variable its 15 (Light to Bold in Display, Small and Text).resolve(family, "Bold")finds the instance, including installed fonts not loaded yet. PostScript names such asFigtree-Boldresolve too (PDF and.aiimport).Font::new_variable(instanced by subsetter, CFF2 turned into TrueType), so the text stays real, selectable text in the instance's glyphs.@font-faceas a static subset of the instance (embedding the variable file would show the default instance in browsers). A licence that forbids subsetting embeds the whole instance; an instance that can't be instanced isn't embedded rather than embedding the wrong one.Tests
crates/text/src/test_fonts.rsbuilds a variable font in code with write-fonts (no font file is committed): the bundled Source Sans 3 plus awghtaxis whosegvarwidensl,Iandnby 25 %, with instances Normal (default), SemiBold, Bold, an unnamed one and a duplicateBOLD. Other crates' tests reach it through the dev-onlytest-fontsfeature.tests_variable.rs:fvar/gvar) with Bold advances;fvartables (huge axis or instance counts, bad record sizes, truncation, 2,000 instances) and 300 rounds of random damage tofvar/gvarof a real font don't panic.land text wider than Light) and Segoe UI Variable.variable_font_instances_are_real_text_in_their_own_glyphs: real text in Regular and Bold re-imports within 0.5 pt of the outlined export, and Bold is wider.variable_font_instances_embed_as_themselves: the@font-facefonts are static, with the instance's advances.Not done yet
font-weight/font-styleonly, so a width instance such as "Bold Condensed" shows as Bold in a browser (as for static fonts today).Dependencies:
subsetter'svariable-fontsfeature invectorcraft-text(krilla already enabled it everywhere, wasm included); write-fonts 0.48 (already in the lock through subsetter) as a dev-dependency and behind the dev-onlytest-fontsfeature.Checks
8e40794(Fix #291: live corners stay circular when a rectangle is scaled unevenly #323, Fix #290: hovering another menu title switches the open menu #325):cargo xtask ci, all 7 steps passed (fmt, clippy, test, assets, brands, layers, wasm), 3,469 tests.--control):text.fontListlists the Bahnschrift and Segoe UI Variable instances;text.createin Bahnschrift Light, Regular, Bold and Bold Condensed and Segoe UI Variable Light Display and Bold Display renders each at its weight and width (ui.render), and the same after a PDF export reopened and a.vectorcraftsave reopened.🤖 Generated with Claude Code