| 260 | } |
| 261 | |
| 262 | bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback) const override |
| 263 | { |
| 264 | /* Determine fallback font using CoreText. This uses the language isocode |
| 265 | * to find a suitable font. CoreText is available from 10.5 onwards. */ |
| 266 | std::string lang; |
| 267 | if (language_isocode == "zh_TW") { |
| 268 | /* Traditional Chinese */ |
| 269 | lang = "zh-Hant"; |
| 270 | } else if (language_isocode == "zh_CN") { |
| 271 | /* Simplified Chinese */ |
| 272 | lang = "zh-Hans"; |
| 273 | } else { |
| 274 | /* Just copy the first part of the isocode. */ |
| 275 | lang = language_isocode.substr(0, language_isocode.find('_')); |
| 276 | } |
| 277 | |
| 278 | /* Create a font descriptor matching the wanted language and latin (english) glyphs. |
| 279 | * Can't use CFAutoRelease here for everything due to the way the dictionary has to be created. */ |
| 280 | CFStringRef lang_codes[2]; |
| 281 | lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang.c_str(), kCFStringEncodingUTF8); |
| 282 | lang_codes[1] = CFSTR("en"); |
| 283 | CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks); |
| 284 | CFAutoRelease<CFDictionaryRef> lang_attribs(CFDictionaryCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); |
| 285 | CFAutoRelease<CTFontDescriptorRef> lang_desc(CTFontDescriptorCreateWithAttributes(lang_attribs.get())); |
| 286 | CFRelease(lang_arr); |
| 287 | CFRelease(lang_codes[0]); |
| 288 | |
| 289 | /* Get array of all font descriptors for the wanted language. */ |
| 290 | CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks)); |
| 291 | CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get())); |
| 292 | |
| 293 | bool result = false; |
| 294 | for (int tries = 0; tries < 2; tries++) { |
| 295 | for (CFIndex i = 0; descs.get() != nullptr && i < CFArrayGetCount(descs.get()); i++) { |
| 296 | CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i); |
| 297 | |
| 298 | /* Get font traits. */ |
| 299 | CFAutoRelease<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute)); |
| 300 | CTFontSymbolicTraits symbolic_traits; |
| 301 | CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits); |
| 302 | |
| 303 | /* Skip symbol fonts and vertical fonts. */ |
| 304 | if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue; |
| 305 | /* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */ |
| 306 | if (symbolic_traits & kCTFontBoldTrait) continue; |
| 307 | /* Select monospaced fonts if asked for. */ |
| 308 | if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue; |
| 309 | |
| 310 | /* Get font name. */ |
| 311 | char buffer[128]; |
| 312 | CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute)); |
| 313 | CFStringGetCString(font_name.get(), buffer, std::size(buffer), kCFStringEncodingUTF8); |
| 314 | |
| 315 | /* Serif fonts usually look worse on-screen with only small |
| 316 | * font sizes. As such, we try for a sans-serif font first. |
| 317 | * If we can't find one in the first try, try all fonts. */ |
| 318 | if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) continue; |
| 319 |
nothing calls this directly
no test coverage detected