Skip to content

Commit

Permalink
CoreText fallback shaper ex
Browse files Browse the repository at this point in the history
More experimenting on top of https://github.com/rive-app/rive/pull/8556

This breaks some APIs that still need to be fixed up elsewhere.

The basic concept here is that when you request a system font you can tell it whether you're requesting to use it a Harfbuzz shaped system font or a CoreText (System) shaped system font.

We prioritize Harfbuzz first so that we have predictable performance and results across edit and runtime. To do this the fallback process now comes with an index. Iteration will keep happening until no font is returned (or all glyphs are found).

If the registered fallbacks look like this:
```
RiveFont.fallbackFonts = [
  UIFont(name: "PingFangSC-Semibold", size: 12)!,
  UIFont(name: "Hiragino Sans", size: 12)!
]
```

The fallback process will return:
```
iter 0: Ping Fang Harfbuzz Shaped
iter 1: Hiragino San Harfbuzz Shaped
iter 2: Ping Fang Coretext Shaped
iter 3: Hiragino Sans Coretext Shaped
```

We also use Coretext last as usually shaping with Coretext causes Apple's shaper to do its own fallbacks (it calls them cascades like css). So iter 2 (in the example above) will be the final iteration as all glyphs get filled via Apple's own fallbacks.

![CleanShot 2024-11-14 at 21 16 55@2x](https://github.com/user-attachments/assets/c12e158b-5b8e-41d4-8d9b-8184a316a079)

Diffs=
3eefba5039 CoreText fallback shaper ex (#8568)

Co-authored-by: David Skuza <[email protected]>
Co-authored-by: Luigi Rosso <[email protected]>
  • Loading branch information
3 people committed Nov 20, 2024
1 parent c03bfff commit a0e735b
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
807f9b20ac7f040df6646b808bdb70ab84b7db57
3eefba5039d73329b31048b3bd839bfabc177bc0
36 changes: 19 additions & 17 deletions Source/Renderer/RiveFactory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

static NSArray<id<RiveFallbackFontProvider>>* _fallbackFonts = nil;

static rive::rcp<rive::Font> riveFontFromNativeFont(id font)
static rive::rcp<rive::Font> riveFontFromNativeFont(id font,
bool useSystemShaper)
{
uint16_t weight = 400;
if ([font conformsToProtocol:@protocol(RiveWeightProvider)])
Expand All @@ -34,24 +35,25 @@
}

CTFontRef ctFont = (__bridge CTFontRef)font;
return HBFont::FromSystem((void*)ctFont, weight, width);
return HBFont::FromSystem((void*)ctFont, useSystemShaper, weight, width);
}

static rive::rcp<rive::Font> findFallbackFont(
rive::Span<const rive::Unichar> missing)
static rive::rcp<rive::Font> findFallbackFont(const rive::Unichar missing,
const uint32_t fallbackIndex)
{
// For each descriptor…
for (id<RiveFallbackFontProvider> fallback in RiveFont.fallbackFonts)
// Try all the fallback fonts twice, first pass with harfbuzz and the second
// loop uses the system shaper.
if (fallbackIndex / 2 < RiveFont.fallbackFonts.count)
{
auto font = riveFontFromNativeFont(fallback.fallbackFont);
if (font->hasGlyph(missing))
{
rive::rcp<rive::Font> rcFont = rive::rcp<rive::Font>(font);
// because the font was released at load time, we need to give it an
// extra ref whenever we bump it to a reference counted pointer.
rcFont->ref();
return rcFont;
}
auto f =
[RiveFont
.fallbackFonts[fallbackIndex % RiveFont.fallbackFonts.count]
fallbackFont];
auto font = riveFontFromNativeFont(
f, fallbackIndex >= RiveFont.fallbackFonts.count);
rive::rcp<rive::Font> rcFont = rive::rcp<rive::Font>(font);
rcFont->ref();
return rcFont;
}
return nullptr;
}
Expand Down Expand Up @@ -194,12 +196,12 @@ - (RiveFont*)decodeFont:(nonnull NSData*)data
#if TARGET_OS_IPHONE
- (RiveFont*)decodeUIFont:(UIFont*)font
{
return [[RiveFont alloc] initWithFont:riveFontFromNativeFont(font)];
return [[RiveFont alloc] initWithFont:riveFontFromNativeFont(font, true)];
}
#else
- (RiveFont*)decodeNSFont:(NSFont*)font
{
return [[RiveFont alloc] initWithFont:riveFontFromNativeFont(font)];
return [[RiveFont alloc] initWithFont:riveFontFromNativeFont(font, true)];
}
#endif

Expand Down

0 comments on commit a0e735b

Please sign in to comment.