Skip to content

Alter font loading code to support fallback fonts in fontFamily #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Nov 15, 2022

Conversation

stevenpetryk
Copy link

@stevenpetryk stevenpetryk commented Nov 14, 2022

This is some pre-work to improving how non-latin scripts render. On the web, one can declare fallback fonts easily:

font-family: "Comic Sans MS", "Noto Sans", system-ui;

And that'll attempt to use those fonts, in that order, falling back to the next font whenever a character can't be rendered by the given font.

React Native doesn't support this, and issues asking for support have been closed as stale by a bot. This adds some sliiiightly jank code to support it. I originally wanted to do something like this:

// ❗️ (just an example, not what this PR actually enables)
const styles = StyleSheet.create({
  fontFamily: ['Font One', 'Font Two', 'Font Three', 'sans-serif']
})

But I settled for this to minimize the diff size compared to upstream:

// ✅ what this PR actually enables (not as cool, but easier to implement)
const styles = StyleSheet.create({
  fontFamily: 'Font One, Font Two, Font Three'
})

The native code now just splits fontFamily names by commas and uses that to construct fallback-filled UIFont/Typeface instances.

@stevenpetryk stevenpetryk changed the base branch from master to 0.68-discord-1 November 14, 2022 18:57
@stevenpetryk stevenpetryk force-pushed the i18n-fallback-testing branch 3 times, most recently from ec024e0 to 767848d Compare November 14, 2022 18:59
@@ -192,14 +192,50 @@ - (NSParagraphStyle *)effectiveParagraphStyle

- (UIFont *)effectiveFont
{
// FIXME: RCTFont has thread-safety issues and must be rewritten.
Copy link
Author

Choose a reason for hiding this comment

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

confidence inspiring

Comment on lines 143 to 155
String[] fontFamilyNames = fontFamilyName != null ? fontFamilyName.split(",") : null;
if (fontFamilyNames != null) {
for (int i = 0; i < fontFamilyNames.length; i++) {
fontFamilyNames[i] = fontFamilyNames[i].trim();
}
}
if (fontFamilyNames != null && fontFamilyNames.length > 1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return createAssetTypefaceWithFallbacks(fontFamilyNames, style, assetManager);
} else {
fontFamilyName = fontFamilyNames[0];
}
}
Copy link
Author

Choose a reason for hiding this comment

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

A few checks happening here:

  1. First we really carefully try to see whether a comma-separated list was passed to fontFamilyName
  2. If it was, we split it and trim whitespace off each entry (to allow folks to put spaces around commas)
  3. Finally, iff that list has more than one thing and we're on a high enough version of Android, we use the fallback font creation code. If we're on an older version of Android, we just ignore the fallbacks and proceed wit the original logic.

@stevenpetryk stevenpetryk marked this pull request as ready for review November 15, 2022 18:33
@discord discord deleted a comment from github-actions bot Nov 15, 2022
@stevenpetryk stevenpetryk changed the title i18n fallback testing Alter font loading code to support comma-separated values for fontFamily Nov 15, 2022
@stevenpetryk stevenpetryk changed the title Alter font loading code to support comma-separated values for fontFamily Alter font loading code to support fallback fonts in fontFamily Nov 15, 2022
Comment on lines 110 to 115
private boolean getIsReduceMotionEnabledValue() {
float defaultAnimationScale = Float.parseFloat(Settings.Global.TRANSITION_ANIMATION_SCALE);
float animationScale = Settings.Global.getFloat(mContentResolver, defaultAnimationScale);
return animationScale == 0f;
String value =
Settings.Global.getString(mContentResolver, Settings.Global.TRANSITION_ANIMATION_SCALE);

return value != null && value.equals("0.0");
}
Copy link
Author

Choose a reason for hiding this comment

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

These changes are unrelated to the PR but they're necessary to get RN to compile locally

@stevenpetryk stevenpetryk merged commit 5e1d210 into 0.68-discord-1 Nov 15, 2022
hannomargelo pushed a commit that referenced this pull request May 20, 2025
…tion for existing view (facebook#51294)

Summary:
Pull Request resolved: facebook#51294

changelog: [internal]

Fix a crash where a node that is supposed to be culled doesn't get visited because culling context is not updated.
The differentiator would generate a create instruction for a view that already exists.

Stack trace for the crash:
```
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
  * frame #0: 0x0000000111740874 libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x00000001117aa2ec libsystem_pthread.dylib`pthread_kill + 264
    frame #2: 0x0000000180171ea8 libsystem_c.dylib`abort + 100
    frame #3: 0x00000001802b0144 libc++abi.dylib`abort_message + 128
    frame #4: 0x000000018029fe4c libc++abi.dylib`demangling_terminate_handler() + 296
    frame #5: 0x000000018006f220 libobjc.A.dylib`_objc_terminate() + 124
    frame #6: 0x00000001375d1964 INFRAFramework`meta_terminate() + 5468
    frame #7: 0x00000001802af570 libc++abi.dylib`std::__terminate(void (*)()) + 12
    frame #8: 0x00000001802b2498 libc++abi.dylib`__cxxabiv1::failed_throw(__cxxabiv1::__cxa_exception*) + 32
    frame #9: 0x00000001802b2478 libc++abi.dylib`__cxa_throw + 88
    frame #10: 0x0000000180093904 libobjc.A.dylib`objc_exception_throw + 384
    frame #11: 0x0000000180e6999c Foundation`-[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 268
    frame #12: 0x000000031a3bcfc8 XPLAT_6_Framework`-[RCTComponentViewRegistry dequeueComponentViewWithComponentHandle:tag:] + 528
    frame #13: 0x000000031a3ccdec XPLAT_6_Framework`RCTPerformMountInstructions(std::__1::vector<facebook::react::ShadowViewMutation, std::__1::allocator<facebook::react::ShadowViewMutation>> const&, RCTComponentViewRegistry*, RCTMountingTransactionObserverCoordinator&, int) + 356
    frame #14: 0x000000031a3ccc7c XPLAT_6_Framework`-[RCTMountingManager performTransaction:]::$_1::operator()(facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&) const + 80
    frame #15: 0x000000031a3ccc20 XPLAT_6_Framework`decltype(std::declval<-[RCTMountingManager performTransaction:]::$_1&>()(std::declval<facebook::react::MountingTransaction const&>(), std::declval<facebook::react::SurfaceTelemetry const&>())) std::__1::__invoke[abi:ne190102]<-[RCTMountingManager performTransaction:]::$_1&, facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&>(-[RCTMountingManager performTransaction:]::$_1&, facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&) + 40
    frame #16: 0x000000031a3ccbc8 XPLAT_6_Framework`void std::__1::__invoke_void_return_wrapper<void, true>::__call[abi:ne190102]<-[RCTMountingManager performTransaction:]::$_1&, facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&>(-[RCTMountingManager performTransaction:]::$_1&, facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&) + 40
    frame #17: 0x000000031a3ccb94 XPLAT_6_Framework`std::__1::__function::__alloc_func<-[RCTMountingManager performTransaction:]::$_1, std::__1::allocator<-[RCTMountingManager performTransaction:]::$_1>, void (facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&)>::operator()[abi:ne190102](facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&) + 44
    frame #18: 0x000000031a3cba1c XPLAT_6_Framework`std::__1::__function::__func<-[RCTMountingManager performTransaction:]::$_1, std::__1::allocator<-[RCTMountingManager performTransaction:]::$_1>, void (facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&)>::operator()(facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&) + 44
    frame #20: 0x000000032f219804 XPLAT_1_Framework`std::__1::function<void (facebook::react::MountingTransaction const&, facebook::react::SurfaceTelemetry const&)>::operator()(this=0x000000016d4f0c78, __arg=0x000000016d4f0a10, __arg=0x000000016d4f0978) const at function.h:989:10
    frame #21: 0x000000032f219668 XPLAT_1_Framework`facebook::react::TelemetryController::pullTransaction(this=0x00000003f4680f00, willMount=0x000000016d4f0c98, doMount=0x000000016d4f0c78, didMount=0x000000016d4f0c58) const at TelemetryController.cpp:39:3
    frame #22: 0x000000031a3c5b28 XPLAT_6_Framework`-[RCTMountingManager performTransaction:] + 544
    frame #23: 0x000000031a3c5864 XPLAT_6_Framework`-[RCTMountingManager initiateTransaction:] + 456
    frame #24: 0x000000031a3c5240 XPLAT_6_Framework`__42-[RCTMountingManager scheduleTransaction:]_block_invoke + 308
    frame #25: 0x0000000131f81b84 BOTTOMFramework`__RCTExecuteOnMainQueue_block_invoke + 40
    frame #26: 0x000000018017c788 libdispatch.dylib`_dispatch_call_block_and_release + 24
    frame #27: 0x0000000180197278 libdispatch.dylib`_dispatch_client_callout + 12
    frame #28: 0x00000001801b2fcc libdispatch.dylib`_dispatch_main_queue_drain.cold.7 + 24
    frame #29: 0x000000018018c1c4 libdispatch.dylib`_dispatch_main_queue_drain + 1184
    frame #30: 0x000000018018bd14 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 40
    frame #31: 0x0000000180427fec CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
    frame #32: 0x00000001804229f8 CoreFoundation`__CFRunLoopRun + 1920
    frame #33: 0x0000000180421e3c CoreFoundation`CFRunLoopRunSpecific + 536
    frame #34: 0x0000000190f62d00 GraphicsServices`GSEventRunModal + 164
    frame #35: 0x0000000185bcec98 UIKitCore`-[UIApplication _run] + 796
    frame #36: 0x0000000185bd3064 UIKitCore`UIApplicationMain + 124
    frame #37: 0x0000000115fbf0bc PRODUCTFramework`main + 200
    frame #38: 0x00000001114293d8 dyld_sim`start_sim + 20
    frame #39: 0x0000000111506b4c dyld`start + 6000
```

Reviewed By: rubennorte

Differential Revision: D74654157

fbshipit-source-id: 9181bcd28524c71d0ca4620bd630dc0baa172386
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.

1 participant