fix(ios): don't apply .weight() to a resolved custom font - #105
Open
adamjmarshall wants to merge 1 commit into
Open
adamjmarshall wants to merge 1 commit into
adamjmarshall wants to merge 1 commit into
Conversation
NUIScaledFontModifier.body chained .weight(weight) onto every custom Font
NativeUIFontResolver returned, defaulting to .regular whenever a caller
didn't request a specific weight. But every font token this resolver
resolves names one specific bundled static face — one .ttf/.otf per weight,
registered and referenced by its own PostScript name (see
NativeUIFontResolver's own doc comment) — never a variable-font family with
sibling weights for SwiftUI to select between.
Asking CoreText to synthesize a different weight for a name that already
identifies one exact static face has nothing to draw from, and on iOS it
silently drops the custom font in favor of the system font. Colors and
everything else stay correct (separate modifiers), so the only visible
symptom is the requested custom font quietly not applying — e.g. a
NavBar::titleView() with Text::make(...)->font('Montserrat-Bold') renders
in the plain system font instead of Montserrat Bold.
Confirmed in a consuming app via the iOS Simulator: toggling this exact
`.weight()` call off/on reproduces and fixes the issue, deterministically,
across Debug and Release configurations. This repo has no Swift-level test
harness to pin the regression (tests/ only covers the PHP wire-props layer),
so I'm not able to add automated coverage for it here.
The system-font fallback branch is untouched — `weight` is still meaningful
there, since there's no named face to lose.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Summary
On iOS, a custom named font resolved by
NativeUIFontResolver(e.g.Text::make(...)->font('Montserrat-Bold')) can silently render as the plain system font instead — colors and everything else stay correct, only the font is wrong. Most visible onNavBar::titleView(), since that's the one place a caller in my app requested a specific bold static font without also requesting a matching->weight().Root cause
NUIScaledFontModifier.body(resources/ios/NativeUITheme.swift) chains.weight(weight)onto every customFontNativeUIFontResolverreturns —weightdefaults to.regularwhen a caller doesn't request one explicitly.Every font token this resolver resolves names one specific static bundled face — one
.ttf/.otfper weight, registered viaCTFontManagerRegisterFontsForURLand referenced by its own PostScript name (perNativeUIFontResolver's own doc comment: "Fonts are bundled into the app's Resources by this plugin'scopy_assetshook... filename... is the token"). It's never a variable-font family with sibling weights for SwiftUI/CoreText to select between under that name.Chaining
.weight()onto aFont.custom(name:)built from that exact PostScript name asks CoreText to synthesize a different weight it has nothing else to draw from — and on iOS that silently drops the custom font entirely in favor of the system font, rather than erroring or ignoring the modifier..foregroundColor(a separate modifier) is unaffected, which is why only the font — not the color — looks wrong.Fix
Drop the
.weight(weight)call for a resolved custom font (both the italic-with-synthesized-oblique branch and the plain branch). The system-font fallback branch is untouched —weightis still meaningful there, since there's no named face to lose.Verification
Reproduced and fixed in a consuming app (
NavBar::titleView()with twoText::make(...)->font('Montserrat-Bold')elements) via the iOS Simulator: toggling this exact.weight()call off/on reproduces and fixes the issue deterministically, independent of build configuration (confirmed against both a Debug and a Release-configuration local build). I wasn't able to find a Swift-level test harness in this repo (tests/only covers the PHP wire-props/serialization layer, not actual SwiftUI rendering), so I don't have an automated regression test to add here — happy to add one if you can point me at a pattern for testing actual font resolution/rendering.🤖 Generated with Claude Code