Commit 918fb15
Fix custom font weight rendering heaviest face on iOS Fabric (#57483)
Summary:
On the New Architecture (Fabric), a custom font referenced by its PostScript / full font name (e.g. `fontFamily: "Foo-Medium"`) combined with an explicit non-regular `fontWeight` renders at the heaviest available face (bold/black) instead of the requested weight. This is an iOS-only regression introduced in 0.83; 0.82 was correct. Android is unaffected.
**Root cause.** In `RCTFontUtils.mm`, `RCTFontWithFontProperties()` handles the case where the given `fontFamily` is actually a font name rather than a family name (`fontNames.count == 0`) and resolves the effective weight with:
```objc
fontWeight = (fontWeight != 0.0) ?: RCTGetFontWeight(font);
```
`fontWeight` is a `UIFontWeight` (a `double`: Regular = 0.0, Medium = 0.23, Bold = 0.4, Black = 0.62). The Objective-C "Elvis" operator `A ?: B` evaluates to **`A` itself** when `A` is truthy — and here `A` is the *comparison* `(fontWeight != 0.0)`, a `BOOL`. So whenever a weight was set (e.g. 0.23), `fontWeight` was reassigned to `1.0` (heavier than Black), and the subsequent "closest weight in the family" search always picked the heaviest face.
This was introduced by the automated implicit-bool-conversion sweep in #53591 (D81571883), which rewrote the original correct line `fontWeight ?: RCTGetFontWeight(font)` into `(fontWeight != 0.0) ?: …`. Making the truthiness check explicit is fine as a *condition*, but with `?:` the left-hand side is also the *returned value*, so the numeric weight got replaced by the boolean.
**Fix.**
```objc
fontWeight = (fontWeight != 0.0) ? fontWeight : RCTGetFontWeight(font);
```
For a `double`, `(A != 0.0) ? A : B` is exactly equivalent to the original `A ?: B`, so this restores the 0.81/0.82 behavior while keeping the explicit `!= 0.0` form used elsewhere in the file. The no-weight case is unchanged: `RCTResolveFontProperties` fills an unspecified weight with `UIFontWeightRegular` (0.0), so the weight is still inferred from the font name via `RCTGetFontWeight(font)` in that case. The legacy (Paper) path in `React/Views/RCTFont.mm` uses a different construct and is not affected — consistent with his only reproducing on the New Architecture.
## Changelog:
[iOS] [Fixed] - Custom fonts with an explicit fontWeight no longer render at the heaviest weight on the New Architecture
Pull Request resolved: #57483
Test Plan:
Fixes #54934.
New Architecture, iOS, with a custom font bundled and referenced by its PostScript name,
e.g. `<Text style={{ fontFamily: 'Foo-Medium', fontWeight: '500' }}>`:
| Version | Result |
| --- | --- |
| 0.82 | renders at the requested medium weight ✅ |
| 0.83 / `main` (before fix) | renders bold/black ❌ |
| removing `fontWeight` on 0.83 | renders correctly ✅ (confirms the weight branch is the culprit) |
After this change the text renders at the requested weight on both the old and new architecture.
Reviewed By: cortinico
Differential Revision: D111217210
Pulled By: javache
fbshipit-source-id: 76858e1b83f8f1032cb599aec6c4b0d49a6a74271 parent eb987ef commit 918fb15
1 file changed
Lines changed: 1 addition & 1 deletion
File tree
- packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
361 | 361 | | |
362 | 362 | | |
363 | 363 | | |
364 | | - | |
| 364 | + | |
365 | 365 | | |
366 | 366 | | |
367 | 367 | | |
| |||
0 commit comments