iOS Fabric: fontFamily (PostScript name) + explicit fontWeight resolves to the heaviest face — elvis-operator typo in RCTFontUtils.mm
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 1/5
- Tempo estimado
- Menos de uma hora
- Facilidade para iniciantes
- 85/100
- Tipo de issue
- Bug
- Clareza
- Claramente especificada
- Status de atividade
- Ativa
- Stack de tecnologia
- ios, objective-c, react-native
- Domínio
- mobile-dev
Direção de pesquisa
Comece em ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm por volta da linha 364 e inspecione como os pesos de fonte explícitos são selecionados. Reproduza o problema com os exemplos de Poppins PostScript-name e inspecione os runs de fonte de NSAttributedString renderizados. Está concluído quando pesos explícitos que não são o padrão são resolvidos para a face solicitada, em vez da face mais pesada.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
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
- Bundle a multi-weight custom font family (e.g. Poppins Regular/Medium/SemiBold/Bold) via
UIAppFonts. - Render
<Text style={{ fontFamily: 'Poppins-Medium', fontWeight: '500' }}>test</Text>on 0.86.2 with Fabric. - 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.
- Linguagem predominante
- C++
- Estrelas
- 127k
- Forks
- 25.3k
- Métricas de merge de PRs
- Nenhum PR com merge em 30d
Preparar o ambiente
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de react/react-native
-
Needs: Author Feedback Needs: Repro
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 75/100
react/react-native#58659 · 2 comentários ·
Mantenedores costumam responder em até 1 dia
-
Needs: Author Feedback Needs: Repro
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 92/100
react/react-native#58621 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
Needs: Author Feedback Needs: Repro
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 85/100
react/react-native#58610 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
Needs: Triage :mag:
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
react/react-native#58565 · 1 comentário · 2 reações ·
Mantenedores costumam responder em até 1 dia
-
Needs: Author Feedback Needs: Repro
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 88/100
react/react-native#58555 · 5 comentários · 2 reações ·
Mantenedores costumam responder em até 1 dia
Todas as issues de react/react-native
Issues semelhantes
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
hyprwm/aquamarine#426 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 62/100
amnezia-vpn/amnezia-client#3222 ·
Mantenedores costumam responder em até 2 dias
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
sdatkinson/NeuralAmpModelerCore#342 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 86/100
valkey-io/valkey-search#1465 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
KhronosGroup/Vulkan-Tutorial#524 ·
Mantenedores costumam responder em até 1 dia