react / react/react-native

iOS Fabric: fontFamily (PostScript name) + explicit fontWeight resolves to the heaviest face — elvis-operator typo in RCTFontUtils.mm

Aperta Adatta ai principianti
#58,176 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Needs: Author Feedback Needs: Repro
Lingua principale
C++
Stelle
127k
Fork
25.3k
Merge medio
1g 23h
PR unite (30g)
4

Descrizione

Description

On iOS/Fabric in React Native 0.86.2, any <Text> style that combines a PostScript-named fontFamily with an explicit non-default fontWeight renders the heaviest face in the family instead of the requested weight.

// Renders Poppins-Medium (correct)
<Text style={{ fontFamily: 'Poppins-Medium' }} />

// Renders Poppins-Bold (bug — expected Poppins-Medium)
<Text style={{ fontFamily: 'Poppins-Medium', fontWeight: '500' }} />

// Renders Poppins-Bold (bug — expected Poppins-SemiBold)
<Text style={{ fontFamily: 'Poppins-SemiBold', fontWeight: '600' }} />

// Bare family name + weight resolves correctly (different code path)
<Text style={{ fontFamily: 'Poppins', fontWeight: '500' }} />  // correct

Verified via the rendered NSAttributedString font runs (not UIFont lookups): the fonts are registered and loadable; the resolver selects the wrong face.

Root cause

ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm (~line 364):

fontWeight = (fontWeight != 0.0) ?: RCTGetFontWeight(font);

The GNU ?: (elvis) operator assigns the boolean result of the comparison — 1.0 — for any explicit nonzero weight, rather than preserving the original fontWeight value. UIFontWeight 1.0 is the heaviest weight, so the subsequent family search selects the boldest face.

Suggested fix

fontWeight = (fontWeight != 0.0) ? fontWeight : RCTGetFontWeight(font);

(Note: this still cannot distinguish an explicit fontWeight: '400' from "no weight," since UIFontWeightRegular == 0.0 — a separate, pre-existing limitation.)

Impact

Any app pairing custom-font PostScript names with explicit weights (a common pattern, and the style many older codebases carry from pre-Fabric versions where the named face won) renders bold text across the board after upgrading. We hit this migrating a production app from 0.81.5 to 0.86.2 — every fontFamily: 'Poppins-<Face>' + matching fontWeight pair (~450 style sites) collapsed to Poppins-Bold. We are carrying a one-line patch-package fix of the ternary, which restores correct resolution for all pairings.

Steps to reproduce

  1. Bundle a multi-weight custom font family (e.g. Poppins Regular/Medium/SemiBold/Bold) via UIAppFonts.
  2. Render <Text style={{ fontFamily: 'Poppins-Medium', fontWeight: '500' }}>test</Text> on 0.86.2 with Fabric.
  3. Inspect the rendered attributed string: the resolved font is Poppins-Bold.

Environment

React Native 0.86.2 (Fabric / new architecture), iOS 26.5 simulator + device, Expo SDK 57 prebuild (bare workflow equivalent). Regression vs 0.81.5 behavior.

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia in ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm intorno alla riga 364 e verifica come vengono selezionati i pesi del font espliciti. Riproduci il problema con gli esempi Poppins PostScript-name e verifica i font run di NSAttributedString renderizzati. Il lavoro è completo quando i pesi espliciti non predefiniti vengono risolti nel face richiesto invece che nel face più pesante.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
ios, objective-c, react-native
Ambito
mobile-dev
Tipo di issue
Bug
Difficoltà
1/5
Tempo stimato
Meno di un'ora
Stato di attività
Attiva
Chiarezza
Specificata chiaramente
Idoneità per principianti
85/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.