Skip to content

fix: respect CSS generic font-family fallback chain#403

Open
wakamex wants to merge 8 commits intothx:mainfrom
wakamex:fix/font-family-fallback-chain
Open

fix: respect CSS generic font-family fallback chain#403
wakamex wants to merge 8 commits intothx:mainfrom
wakamex:fix/font-family-fallback-chain

Conversation

@wakamex
Copy link

@wakamex wakamex commented Mar 2, 2026

Summary

  • set_font_families() now respects the configured generic family options (sansSerifFamily, serifFamily, etc.) instead of setting all generic families to the first font loaded into fontdb — which could be "Font Awesome 6 Brands" or another icon font lacking text glyphs.
  • Probes well-known font names (Liberation Sans, Noto Sans, DejaVu Sans, etc.) when the configured default (e.g. "Arial") isn't installed, matching browser behavior across Windows, macOS, and Linux.
  • Fixes the repro where font-family="'Berkeley Mono', 'Noto Sans', sans-serif" rendered 7.4B as 74B (invisible dot) because sans-serif resolved to an icon font.

Test plan

  • New test: sansSerifFamily option controls sans-serif resolution (pixel-exact match against direct font name)
  • New test: sans-serif renders "." in "7.4B" (compares pixel output of "7.4B" vs "74B" — must differ)
  • All 54 existing tests pass (no regressions)
  • Visual verification: /tmp/repro_fixed.png shows 7.4B with dot

🤖 Generated with Claude Code

wakamex and others added 3 commits March 2, 2026 16:16
set_font_families() ignores the configured generic family options
(sansSerifFamily, serifFamily, etc.) and sets ALL generic families to
the first font loaded into fontdb. On this system that's
"Font Awesome 6 Brands" — an icon font missing text glyphs — causing
font-family chains like "'Berkeley Mono', 'Noto Sans', sans-serif" to
render "7.4B" as "74B" (missing the dot).

This test verifies that sansSerifFamily is respected: font-family="sans-serif"
with sansSerifFamily='Liberation Sans' should render identically to
font-family="Liberation Sans" directly.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
set_font_families() was ignoring the user-configured generic family
options (serifFamily, sansSerifFamily, cursiveFamily, fantasyFamily,
monoSpaceFamily) and blindly setting ALL generic families to
default_font_family — which was often empty ("") or the first font
loaded into fontdb (e.g. "Font Awesome 6 Brands").

This caused font-family fallback chains like
  "'Berkeley Mono', 'Noto Sans', sans-serif"
to resolve sans-serif to an icon font, dropping glyphs for "." ":" etc.

The fix:
- New resolve_generic_family() helper uses the configured value if it
  exists in fontdb, otherwise falls back to the first available font
- set_font_families() and set_wasm_font_families() now use per-generic
  configured values instead of a single default_font_family
- find_and_debug_font_path() no longer overrides generic families

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The previous commit respected user-configured generic family values,
but the defaults (Arial, Times New Roman, etc.) are Windows fonts that
don't exist on Linux. When sans-serif defaulted to "Arial" and Arial
wasn't installed, resolve_generic_family fell back to the first font
in fontdb — still "Font Awesome 6 Brands" on this system.

Now resolve_generic_family tries a list of well-known alternatives for
each generic family (Arial → Liberation Sans → Noto Sans → DejaVu Sans
→ ...) before falling back to the first available font. This mirrors
browser behavior.

Also adds a direct repro test: rendering "7.4B" vs "74B" with
font-family="sans-serif" must produce different pixels (proving the
dot renders).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@vercel
Copy link

vercel bot commented Mar 2, 2026

@wakamex is attempting to deploy a commit to the yisibl's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes generic CSS font-family resolution so sans-serif/serif/etc respect the configured generic-family options and fall back through a browser-like chain of well-known fonts, avoiding cases where a generic family accidentally resolves to an icon font without text glyphs.

Changes:

  • Added generic-family resolution logic that probes configured values, then OS-common fallback families, then the first available font in fontdb.
  • Updated both native and wasm font-family setup to use the generic-family resolver (and reduced default-font debug behavior).
  • Added tests validating sansSerifFamily controls sans-serif resolution and that punctuation like . renders (detects the “7.4B → 74B” regression).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/fonts.rs Introduces generic-family resolver + fallback lists; updates native/wasm family setup to avoid generic families resolving to the first loaded face.
__test__/index.spec.ts Adds regression tests for sans-serif resolution and punctuation rendering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

wakamex and others added 5 commits March 6, 2026 01:08
Address PR review comments:
- Build a HashSet of available family names once instead of scanning
  all fontdb faces per candidate (resolve_generic_family is gone,
  replaced by a closure over the shared set)
- Apply cargo fmt to fix formatting

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Instead of hardcoding "Liberation Sans" (unavailable on macOS/Windows),
probe for an available sans-serif font by comparing against a non-existent
font baseline to detect per-character fallback.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@wakamex
Copy link
Author

wakamex commented Mar 6, 2026

thanks for the review! tests pass on my fork https://github.com/wakamex/resvg-js/actions/runs/22752685120

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants