Skip to content

Commit 5cc89ee

Browse files
hryhoriiK97claude
andcommitted
Cache custom font family resolution on iOS Fabric
Resolving a custom `fontFamily` in `RCTFontWithFontProperties` enumerates the family's faces and instantiates every one of them to pick the closest weight and style, and it ran once per text fragment per attributed string build. Cache the resolved font per family, size, weight and style, cleared when fonts are registered at runtime, as the legacy `RCTFont.mm` already does for its own lookups. Variants and variation settings are applied after the cache as before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 96dddb0 commit 5cc89ee

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

  • packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager

‎packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTFontUtils.mm‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,35 @@ static UIFontDescriptorSystemDesign RCTGetFontDescriptorSystemDesign(NSString *f
385385
return systemDesigns[family];
386386
}
387387

388+
// Resolving a custom family instantiates every face in it to pick the closest
389+
// one, once per text fragment. The resolved font is cached per family, size,
390+
// weight and style; the cache is cleared when fonts are registered at runtime.
391+
static NSCache<NSString *, UIFont *> *RCTCustomFontCache(void)
392+
{
393+
static NSCache<NSString *, UIFont *> *cache;
394+
static dispatch_once_t onceToken;
395+
dispatch_once(&onceToken, ^{
396+
cache = [NSCache new];
397+
[NSNotificationCenter.defaultCenter
398+
addObserverForName:(NSNotificationName)kCTFontManagerRegisteredFontsChangedNotification
399+
object:nil
400+
queue:nil
401+
usingBlock:^(NSNotification *) {
402+
[cache removeAllObjects];
403+
}];
404+
});
405+
return cache;
406+
}
407+
408+
static NSString *RCTCustomFontCacheKey(const RCTFontProperties &fontProperties, CGFloat effectiveFontSize)
409+
{
410+
return [NSString stringWithFormat:@"%@/%.1f/%.2f/%ld",
411+
fontProperties.family,
412+
effectiveFontSize,
413+
fontProperties.weight,
414+
(long)fontProperties.style];
415+
}
416+
388417
UIFont *RCTFontWithFontProperties(RCTFontProperties fontProperties)
389418
{
390419
RCTFontProperties defaultFontProperties = RCTDefaultFontProperties();
@@ -406,6 +435,9 @@ static UIFontDescriptorSystemDesign RCTGetFontDescriptorSystemDesign(NSString *f
406435
// Handle system font as special case. This ensures that we preserve
407436
// the specific metrics of the standard system font as closely as possible.
408437
font = RCTDefaultFontWithFontProperties(fontProperties);
438+
} else if (
439+
(font = [RCTCustomFontCache() objectForKey:RCTCustomFontCacheKey(fontProperties, effectiveFontSize)]) != nil) {
440+
// Resolved before; variants and variation settings are applied below.
409441
} else {
410442
NSArray<NSString *> *fontNames = [UIFont fontNamesForFamilyName:fontProperties.family];
411443
UIFontWeight fontWeight = fontProperties.weight;
@@ -447,6 +479,10 @@ static UIFontDescriptorSystemDesign RCTGetFontDescriptorSystemDesign(NSString *f
447479
font = [UIFont fontWithName:fontNames[0] size:effectiveFontSize];
448480
}
449481
}
482+
483+
if (font != nil) {
484+
[RCTCustomFontCache() setObject:font forKey:RCTCustomFontCacheKey(fontProperties, effectiveFontSize)];
485+
}
450486
}
451487

452488
// Apply font variants to font object.

0 commit comments

Comments
 (0)