Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 61 additions & 19 deletions third_party/txt/src/txt/platform_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@

// Apple system font larger than size 29 returns SFProDisplay typeface.
static const CGFloat kSFProDisplayBreakPoint = 29;
// Apple system font smaller than size 16 returns SFProText typeface.
static const CGFloat kSFProTextBreakPoint = 16;
// Font name represents the "SF Pro Display" system font on Apple platforms.
static const std::string kSFProDisplayName = "CupertinoSystemDisplay";
// Font name represents the "SF Pro Text" system font on Apple platforms.
static const std::string kSFProTextName = "CupertinoSystemText";
// Font weight representing Regular
float kNormalWeightValue = 400;

namespace txt {

const FourCharCode kWeightTag = 'wght';

std::vector<std::string> GetDefaultFontFamilies() {
if (fml::IsPlatformVersionAtLeast(9)) {
return {[FONT_CLASS systemFontOfSize:14].familyName.UTF8String};
Expand All @@ -42,34 +42,76 @@
return mgr;
}

CTFontRef MatchSystemUIFont(float desired_weight, float size) {
CTFontRef ct_font(
CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, size, nullptr));

if (desired_weight == kNormalWeightValue) {
return ct_font;
}

CFMutableDictionaryRef variations(CFDictionaryCreateMutable(
kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));

auto add_axis_to_variations = [&variations](const FourCharCode tag,
float desired_value,
float normal_value) {
if (desired_value != normal_value) {
CFNumberRef tag_number(
CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &tag));
CFNumberRef value_number(CFNumberCreate(
kCFAllocatorDefault, kCFNumberFloatType, &desired_value));
CFDictionarySetValue(variations, tag_number, value_number);
}
};
add_axis_to_variations(kWeightTag, desired_weight, kNormalWeightValue);

CFMutableDictionaryRef attributes(CFDictionaryCreateMutable(
kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
CFDictionarySetValue(attributes, kCTFontVariationAttribute, variations);

CTFontDescriptorRef var_font_desc(
CTFontDescriptorCreateWithAttributes(attributes));

return CTFontCreateCopyWithAttributes(ct_font, size, nullptr, var_font_desc);
}

Copy link
Member

Choose a reason for hiding this comment

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

I was profiling allocations - and this seems to be leaking the CFNumbers, CFMutableDictionary and CTFontDescriptor. I don't see CFRelease calls anywhere? I don't think there's a ScopedCFTypeRef in fml so this will need to be released manually.

Copy link
Member

Choose a reason for hiding this comment

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

@knopp could you file an issue for that so it doesn't get lost?

Copy link
Member

Choose a reason for hiding this comment

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

I think this has been already fixed when clang tidy started complaining about missing CFRelease.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you know which release will contain the memory leak fix?

void RegisterSystemFonts(const DynamicFontManager& dynamic_font_manager) {
// iOS loads different system fonts when size is greater than 28 or lower
// than 17. The "familyName" property returned from CoreText stays the same
// despite the typeface is different.
//
// Below code manually loads and registers them as two different fonts
// so Flutter app can access them on macOS and iOS.
// Below code manually loads and registers the larger font. The existing
// fallback correctly loads the smaller font. The code also iterates through
// the possible font weights from 100 - 900 to correctly load all of them, as
// a CTFont object for the large system font does not include all of the font
// weights by default.
//
// Darwin system fonts from 17 to 28 also have dynamic spacing based on sizes.
// These two fonts do not match the spacings when sizes are from 17 to 28.
// The spacing should be handled by the app or the framework.
//
// See https://www.wwdcnotes.com/notes/wwdc20/10175/ for Apple's document on
// this topic.
sk_sp<SkTypeface> large_system_font = SkMakeTypefaceFromCTFont(
(CTFontRef)CFAutorelease(CTFontCreateUIFontForLanguage(
kCTFontUIFontSystem, kSFProDisplayBreakPoint, NULL)));
if (large_system_font) {
dynamic_font_manager.font_provider().RegisterTypeface(large_system_font,
kSFProDisplayName);
}
sk_sp<SkTypeface> regular_system_font = SkMakeTypefaceFromCTFont(
(CTFontRef)CFAutorelease(CTFontCreateUIFontForLanguage(
kCTFontUIFontSystem, kSFProTextBreakPoint, NULL)));
if (regular_system_font) {
dynamic_font_manager.font_provider().RegisterTypeface(regular_system_font,
kSFProTextName);
auto register_weighted_font = [&dynamic_font_manager](const int weight) {
sk_sp<SkTypeface> large_system_font_weighted =
SkMakeTypefaceFromCTFont((CTFontRef)CFAutorelease(
MatchSystemUIFont(weight, kSFProDisplayBreakPoint)));
if (large_system_font_weighted) {
dynamic_font_manager.font_provider().RegisterTypeface(
large_system_font_weighted, kSFProDisplayName);
}
};
for (int i = 0; i < 8; i++) {
const int font_weight = i * 100;
register_weighted_font(font_weight);
}
// The value 780 returns a font weight of 800.
register_weighted_font(780);
// The value of 810 returns a font weight of 900.
register_weighted_font(810);
}

} // namespace txt
9 changes: 5 additions & 4 deletions third_party/txt/tests/platform_mac_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ class PlatformMacTests : public ::testing::Test {
TEST_F(PlatformMacTests, RegisterSystemFonts) {
DynamicFontManager dynamic_font_manager;
RegisterSystemFonts(dynamic_font_manager);
ASSERT_EQ(dynamic_font_manager.font_provider().GetFamilyCount(), 2ul);
ASSERT_EQ(dynamic_font_manager.font_provider().GetFamilyCount(), 1ul);
ASSERT_NE(dynamic_font_manager.font_provider().MatchFamily(
"CupertinoSystemDisplay"),
nullptr);
ASSERT_NE(
dynamic_font_manager.font_provider().MatchFamily("CupertinoSystemText"),
nullptr);
ASSERT_EQ(dynamic_font_manager.font_provider()
.MatchFamily("CupertinoSystemDisplay")
->count(),
10);
}

} // namespace testing
Expand Down