Skip to content

Commit 1d5538f

Browse files
authored
fix(🍏): Add missing system apple fonts in listFontFamilies (#3600)
1 parent e5cb62a commit 1d5538f

File tree

10 files changed

+142
-81
lines changed

10 files changed

+142
-81
lines changed

apps/example/src/Examples/API/FontMgr.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import React from "react";
22
import { ScrollView, useWindowDimensions } from "react-native";
33
import {
44
Canvas,
5-
Skia,
65
Text,
6+
listFontFamilies,
77
matchFont,
88
useFonts,
99
} from "@shopify/react-native-skia";
@@ -16,11 +16,7 @@ const titleText = "Fonts from the System";
1616
const titleY = titleFontSize + PADDING;
1717
const subtitleY = titleY + 14 + PADDING;
1818

19-
const fontMgr = Skia.FontMgr.System();
20-
const familyNames = new Array(fontMgr.countFamilies())
21-
.fill(0)
22-
.map((_, i) => fontMgr.getFamilyName(i));
23-
19+
const familyNames = listFontFamilies();
2420
const title2Y = subtitleY + 16 * familyNames.length + PADDING + titleFontSize;
2521

2622
export const FontMgr = () => {

packages/skia/android/cpp/jni/JniPlatformContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ void JniPlatformContext::notifyTaskReadyExternal() {
207207
jni::ThreadScope ts;
208208

209209
static auto method =
210-
javaPart_->getClass()->getMethod<void()>("notifyTaskReady");
210+
javaPart_->getClass()->getMethod<void()>("notifyTaskReady");
211211
method(javaPart_.get());
212212
}
213213

packages/skia/apple/RNSkApplePlatformContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ class RNSkApplePlatformContext : public RNSkPlatformContext {
7373

7474
sk_sp<SkFontMgr> createFontMgr() override;
7575

76+
std::vector<std::string> getSystemFontFamilies() override;
77+
7678
private:
7779
ViewScreenshotService *_screenshotService;
7880

packages/skia/apple/RNSkApplePlatformContext.mm

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#import <CoreMedia/CMSampleBuffer.h>
44
#include <Metal/Metal.h>
55
#import <React/RCTUtils.h>
6+
#include <set>
67
#include <thread>
78
#include <utility>
89

@@ -300,6 +301,51 @@
300301
return SkFontMgr_New_CoreText(nullptr);
301302
}
302303

304+
std::vector<std::string> RNSkApplePlatformContext::getSystemFontFamilies() {
305+
std::vector<std::string> families;
306+
307+
// System UI fonts (e.g., .AppleSystemUIFont) are not enumerated by Skia's
308+
// font manager. We retrieve them via Core Text's CTFontUIFontType constants.
309+
// This list covers common system font types as of iOS 17 / macOS 14.
310+
// Apple may add new CTFontUIFontType values in future OS versions,
311+
// so this list may need to be updated periodically.
312+
CTFontUIFontType fontTypes[] = {
313+
kCTFontUIFontUser, kCTFontUIFontUserFixedPitch,
314+
kCTFontUIFontSystem, kCTFontUIFontEmphasizedSystem,
315+
kCTFontUIFontSmallSystem, kCTFontUIFontSmallEmphasizedSystem,
316+
kCTFontUIFontMiniSystem, kCTFontUIFontMiniEmphasizedSystem,
317+
kCTFontUIFontLabel, kCTFontUIFontMessage,
318+
kCTFontUIFontToolTip,
319+
};
320+
321+
std::set<std::string> uniqueFamilies;
322+
323+
for (CTFontUIFontType fontType : fontTypes) {
324+
CTFontRef font = CTFontCreateUIFontForLanguage(fontType, 12.0, nullptr);
325+
if (font) {
326+
CFStringRef familyName = CTFontCopyFamilyName(font);
327+
if (familyName) {
328+
const char *cstr =
329+
CFStringGetCStringPtr(familyName, kCFStringEncodingUTF8);
330+
if (cstr) {
331+
uniqueFamilies.insert(std::string(cstr));
332+
} else {
333+
char buffer[256];
334+
if (CFStringGetCString(familyName, buffer, sizeof(buffer),
335+
kCFStringEncodingUTF8)) {
336+
uniqueFamilies.insert(std::string(buffer));
337+
}
338+
}
339+
CFRelease(familyName);
340+
}
341+
CFRelease(font);
342+
}
343+
}
344+
345+
families.assign(uniqueFamilies.begin(), uniqueFamilies.end());
346+
return families;
347+
}
348+
303349
void RNSkApplePlatformContext::runOnMainThread(std::function<void()> func) {
304350
dispatch_async(dispatch_get_main_queue(), ^{
305351
func();

packages/skia/apple/SkiaCVPixelBufferUtils.mm

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@
3030
#include <TargetConditionals.h>
3131
#if TARGET_RT_BIG_ENDIAN
3232
#define FourCC2Str(fourcc) \
33-
(const char[]){*((char *)&fourcc), *(((char *)&fourcc) + 1), \
34-
*(((char *)&fourcc) + 2), *(((char *)&fourcc) + 3), 0}
33+
(const char[]) { \
34+
*((char *)&fourcc), *(((char *)&fourcc) + 1), *(((char *)&fourcc) + 2), \
35+
*(((char *)&fourcc) + 3), 0 \
36+
}
3537
#else
3638
#define FourCC2Str(fourcc) \
37-
(const char[]){*(((char *)&fourcc) + 3), *(((char *)&fourcc) + 2), \
38-
*(((char *)&fourcc) + 1), *(((char *)&fourcc) + 0), 0}
39+
(const char[]) { \
40+
*(((char *)&fourcc) + 3), *(((char *)&fourcc) + 2), \
41+
*(((char *)&fourcc) + 1), *(((char *)&fourcc) + 0), 0 \
42+
}
3943
#endif
4044

4145
// pragma MARK: TextureHolder

packages/skia/cpp/api/JsiSkFontMgr.h

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,32 @@ class JsiSkFontMgr : public JsiSkWrappingSkPtrHostObject<SkFontMgr> {
2727

2828
JsiSkFontMgr(std::shared_ptr<RNSkPlatformContext> context,
2929
sk_sp<SkFontMgr> fontMgr)
30-
: JsiSkWrappingSkPtrHostObject(std::move(context), fontMgr) {}
30+
: JsiSkWrappingSkPtrHostObject(context, fontMgr),
31+
_systemFontFamilies(context->getSystemFontFamilies()) {}
3132

32-
JSI_HOST_FUNCTION(countFamilies) { return getObject()->countFamilies(); }
33+
JSI_HOST_FUNCTION(countFamilies) {
34+
return static_cast<int>(getObject()->countFamilies() +
35+
_systemFontFamilies.size());
36+
}
3337

3438
JSI_HOST_FUNCTION(getFamilyName) {
3539
auto i = static_cast<int>(arguments[0].asNumber());
36-
SkString name;
37-
getObject()->getFamilyName(i, &name);
38-
return jsi::String::createFromUtf8(runtime, name.c_str());
40+
auto baseFamilyCount = getObject()->countFamilies();
41+
if (i < baseFamilyCount) {
42+
SkString name;
43+
getObject()->getFamilyName(i, &name);
44+
return jsi::String::createFromUtf8(runtime, name.c_str());
45+
}
46+
auto systemIndex = i - baseFamilyCount;
47+
if (systemIndex < static_cast<int>(_systemFontFamilies.size())) {
48+
return jsi::String::createFromUtf8(runtime,
49+
_systemFontFamilies[systemIndex]);
50+
}
51+
throw jsi::JSError(runtime, "Font family index out of bounds: " +
52+
std::to_string(i) + " (total families: " +
53+
std::to_string(baseFamilyCount +
54+
_systemFontFamilies.size()) +
55+
")");
3956
}
4057

4158
JSI_HOST_FUNCTION(matchFamilyStyle) {
@@ -55,6 +72,9 @@ class JsiSkFontMgr : public JsiSkWrappingSkPtrHostObject<SkFontMgr> {
5572
JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkFontMgr, countFamilies),
5673
JSI_EXPORT_FUNC(JsiSkFontMgr, getFamilyName),
5774
JSI_EXPORT_FUNC(JsiSkFontMgr, matchFamilyStyle))
75+
76+
private:
77+
std::vector<std::string> _systemFontFamilies;
5878
};
5979

6080
} // namespace RNSkia

packages/skia/cpp/api/JsiSkPictureFactory.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,15 @@ class JsiSkPictureFactory : public JsiSkHostObject {
5050
}
5151
}
5252

53-
// Get ArrayBuffer - try buffer property first (Uint8Array, etc.), then direct ArrayBuffer
54-
jsi::ArrayBuffer buffer = obj.hasProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer"))
55-
? obj.getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer"))
56-
.asObject(runtime)
57-
.getArrayBuffer(runtime)
58-
: obj.getArrayBuffer(runtime);
53+
// Get ArrayBuffer - try buffer property first (Uint8Array, etc.), then
54+
// direct ArrayBuffer
55+
jsi::ArrayBuffer buffer =
56+
obj.hasProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer"))
57+
? obj.getProperty(runtime,
58+
jsi::PropNameID::forAscii(runtime, "buffer"))
59+
.asObject(runtime)
60+
.getArrayBuffer(runtime)
61+
: obj.getArrayBuffer(runtime);
5962

6063
sk_sp<SkData> data =
6164
SkData::MakeWithCopy(buffer.data(runtime), buffer.size(runtime));

0 commit comments

Comments
 (0)