Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[ios, macos] Choose fonts from font stack that match local fonts
Browse files Browse the repository at this point in the history
Prefer local fonts that match the names specified in the font stack (from the text-font layout property), except for the last resort fonts that mbgl hard-codes. Fall back to the list of fallback CJK fonts in user defaults, then the fonts passed in through the platform-agnostic interface (that come from Info.plist). Explicitly use the first font descriptor in the cascade list instead of the system default of Helvetica.

Since the font stack can vary from one rasterization operation to the next, avoid caching the resolved font for now. Removed null checks that are unrealistic given the Core Text API contract.
  • Loading branch information
1ec5 committed Mar 30, 2020
1 parent 3b05fbf commit 93809da
Showing 1 changed file with 51 additions and 47 deletions.
98 changes: 51 additions & 47 deletions platform/darwin/src/local_glyph_rasterizer.mm
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <mbgl/text/local_glyph_rasterizer.hpp>
#include <mbgl/util/i18n.hpp>
#include <mbgl/util/platform.hpp>
#include <mbgl/util/constants.hpp>

#include <unordered_map>

Expand Down Expand Up @@ -54,60 +55,63 @@ CTFontDescriptor configuration option (although we'd have to override font size
class LocalGlyphRasterizer::Impl {
public:
Impl(const optional<std::string> fontFamily_)
: fontFamily(fontFamily_)
, fontHandle(NULL)
{}
{
fallbackFontNames = [[NSUserDefaults standardUserDefaults] stringArrayForKey:@"MGLIdeographicFontFamilyName"];
if (fontFamily_) {
fallbackFontNames = [fallbackFontNames ?: @[] arrayByAddingObjectsFromArray:[@(fontFamily_->c_str()) componentsSeparatedByString:@"\n"]];
}
}

~Impl() {
if (fontHandle) {
CFRelease(fontHandle);
}
}

CTFontRef getFont() {
if (!fontHandle) {
NSArray<NSString *> *fontFamilyNames = [[NSUserDefaults standardUserDefaults] stringArrayForKey:@"MGLIdeographicFontFamilyName"] ?: @[];
if (fontFamily) {
fontFamilyNames = [fontFamilyNames arrayByAddingObjectsFromArray:[@(fontFamily->c_str()) componentsSeparatedByString:@"\n"]];
}
if (!fontFamilyNames.count) {
return NULL;

bool isEnabled() { return fallbackFontNames; }

CTFontDescriptorRef createFontDescriptor(const FontStack& fontStack) {
NSMutableArray *fontNames = [NSMutableArray arrayWithCapacity:fontStack.size() + fallbackFontNames.count];
for (auto& fontName : fontStack) {
if (fontName != util::LAST_RESORT_ALPHABETIC_FONT && fontName != util::LAST_RESORT_PAN_UNICODE_FONT) {
[fontNames addObject:@(fontName.c_str())];
}
}
[fontNames addObjectsFromArray:fallbackFontNames];

CFMutableArrayRefHandle fontDescriptors(CFArrayCreateMutable(kCFAllocatorDefault, fontNames.count, &kCFTypeArrayCallBacks));
for (NSString *name in fontNames) {
NSDictionary *fontAttributes = @{
(NSString *)kCTFontSizeAttribute: @(24.0),
(NSString *)kCTFontNameAttribute: name,
(NSString *)kCTFontDisplayNameAttribute: name,
(NSString *)kCTFontFamilyNameAttribute: name,
};

CFMutableArrayRefHandle fontDescriptors(CFArrayCreateMutable(kCFAllocatorDefault, fontFamilyNames.count, &kCFTypeArrayCallBacks));
for (NSString *name in fontFamilyNames) {
NSDictionary *fontAttributes = @{
(NSString *)kCTFontSizeAttribute: @(24.0),
(NSString *)kCTFontNameAttribute: name,
(NSString *)kCTFontDisplayNameAttribute: name,
(NSString *)kCTFontFamilyNameAttribute: name,
};

CTFontDescriptorRefHandle descriptor(CTFontDescriptorCreateWithAttributes((CFDictionaryRef)fontAttributes));
CFArrayAppendValue(*fontDescriptors, *descriptor);
}

CFStringRef keys[] = { kCTFontSizeAttribute, kCTFontCascadeListAttribute };
CFTypeRef values[] = { (__bridge CFNumberRef)@(24.0), *fontDescriptors };
CTFontDescriptorRefHandle descriptor(CTFontDescriptorCreateWithAttributes((CFDictionaryRef)fontAttributes));
CFArrayAppendValue(*fontDescriptors, *descriptor);
}

CFDictionaryRefHandle attributes(
CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
(const void**)&values, sizeof(keys) / sizeof(keys[0]),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));

CTFontDescriptorRefHandle descriptor(CTFontDescriptorCreateWithAttributes(*attributes));
fontHandle = CTFontCreateWithFontDescriptor(*descriptor, 0.0, NULL);
if (!fontHandle) {
throw std::runtime_error("CTFontCreateWithFontDescriptor failed");
}
CFStringRef keys[] = { kCTFontSizeAttribute, kCTFontCascadeListAttribute };
CFTypeRef values[] = { (__bridge CFNumberRef)@(24.0), *fontDescriptors };

CFDictionaryRefHandle attributes(
CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys,
(const void**)&values, sizeof(keys) / sizeof(keys[0]),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
if (CFArrayGetCount(*fontDescriptors)) {
CTFontDescriptorRef firstDescriptor = (CTFontDescriptorRef)CFArrayGetValueAtIndex(*fontDescriptors, 0);
return CTFontDescriptorCreateCopyWithAttributes(firstDescriptor, *attributes);
} else {
return CTFontDescriptorCreateWithAttributes(*attributes);
}
return fontHandle;
}

CTFontRef createFont(const FontStack& fontStack) {
CTFontDescriptorRefHandle descriptor(createFontDescriptor(fontStack));
return CTFontCreateWithFontDescriptor(*descriptor, 0.0, NULL);
}

private:
optional<std::string> fontFamily;
CTFontRef fontHandle;
NSArray<NSString *> *fallbackFontNames;
};

LocalGlyphRasterizer::LocalGlyphRasterizer(const optional<std::string>& fontFamily)
Expand All @@ -118,7 +122,7 @@ CFDictionaryRefHandle attributes(
{}

bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID) {
return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->getFont();
return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->isEnabled();
}

PremultipliedImage drawGlyphBitmap(GlyphID glyphID, CTFontRef font, Size size) {
Expand Down Expand Up @@ -166,9 +170,9 @@ CFDictionaryRefHandle attributes(
return rgbaBitmap;
}

Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack&, GlyphID glyphID) {
Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack& fontStack, GlyphID glyphID) {
Glyph fixedMetrics;
CTFontRef font = impl->getFont();
CTFontRef font = impl->createFont(fontStack);
if (!font) {
return fixedMetrics;
}
Expand Down

0 comments on commit 93809da

Please sign in to comment.