summaryrefslogtreecommitdiff
path: root/src/fontdetection.cpp
diff options
context:
space:
mode:
authormichi_cc <michi_cc@openttd.org>2013-08-05 20:35:59 +0000
committermichi_cc <michi_cc@openttd.org>2013-08-05 20:35:59 +0000
commitd5681d7f6da296aaf33621db2285fee7869849d9 (patch)
treef5594066a4fd0c8e041f9f323cc923566ca06516 /src/fontdetection.cpp
parent4ec314989dfe9e64af015df65f24ce521e6e4320 (diff)
downloadopenttd-d5681d7f6da296aaf33621db2285fee7869849d9.tar.xz
(svn r25661) -Fix [FS#4847]: [OSX] Rework font detection to work even if no default font sprites are present.
Diffstat (limited to 'src/fontdetection.cpp')
-rw-r--r--src/fontdetection.cpp209
1 files changed, 69 insertions, 140 deletions
diff --git a/src/fontdetection.cpp b/src/fontdetection.cpp
index 306426863..943254ab3 100644
--- a/src/fontdetection.cpp
+++ b/src/fontdetection.cpp
@@ -446,11 +446,8 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
{
- const char *str;
bool result = false;
- callback->FindMissingGlyphs(&str);
-
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
if (MacOSVersionIsAtLeast(10, 5, 0)) {
/* Determine fallback font using CoreText. This uses the language isocode
@@ -462,11 +459,6 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
} else if (strcmp(language_isocode, "zh_CN") == 0) {
/* Simplified Chinese */
strecpy(lang, "zh-Hans", lastof(lang));
- } else if (strncmp(language_isocode, "ur", 2) == 0) {
- /* The urdu alphabet is variant of persian. As OS X has no default
- * font that advertises an urdu language code, search for persian
- * support instead. */
- strecpy(lang, "fa", lastof(lang));
} else {
/* Just copy the first part of the isocode. */
strecpy(lang, language_isocode, lastof(lang));
@@ -474,150 +466,87 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
if (sep != NULL) *sep = '\0';
}
- CFStringRef lang_code;
- lang_code = CFStringCreateWithCString(kCFAllocatorDefault, lang, kCFStringEncodingUTF8);
+ /* Create a font descriptor matching the wanted language and latin (english) glyphs. */
+ CFStringRef lang_codes[2];
+ lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang, kCFStringEncodingUTF8);
+ lang_codes[1] = CFSTR("en");
+ CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks);
+ CFDictionaryRef lang_attribs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&kCTFontLanguagesAttribute, (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CTFontDescriptorRef lang_desc = CTFontDescriptorCreateWithAttributes(lang_attribs);
+ CFRelease(lang_arr);
+ CFRelease(lang_attribs);
+ CFRelease(lang_codes[0]);
+
+ /* Get array of all font descriptors for the wanted language. */
+ CFSetRef mandatory_attribs = CFSetCreate(kCFAllocatorDefault, (const void **)&kCTFontLanguagesAttribute, 1, &kCFTypeSetCallBacks);
+ CFArrayRef descs = CTFontDescriptorCreateMatchingFontDescriptors(lang_desc, mandatory_attribs);
+ CFRelease(mandatory_attribs);
+ CFRelease(lang_desc);
+
+ for (CFIndex i = 0; descs != NULL && i < CFArrayGetCount(descs); i++) {
+ CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs, i);
+
+ /* Get font name. */
+ char name[128];
+ CFStringRef font_name = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute);
+ CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
+ CFRelease(font_name);
- /* Create a font iterator and iterate over all fonts that
- * are available to the application. */
- ATSFontIterator itr;
- ATSFontRef font;
- ATSFontIteratorCreate(kATSFontContextLocal, NULL, NULL, kATSOptionFlagsUnRestrictedScope, &itr);
- while (!result && ATSFontIteratorNext(itr, &font) == noErr) {
- /* Get CoreText font handle. */
- CTFontRef font_ref = CTFontCreateWithPlatformFont(font, 0.0, NULL, NULL);
- CFArrayRef langs = CTFontCopySupportedLanguages(font_ref);
- if (langs != NULL) {
- /* Font has a list of supported languages. */
- for (CFIndex i = 0; i < CFArrayGetCount(langs); i++) {
- CFStringRef lang = (CFStringRef)CFArrayGetValueAtIndex(langs, i);
- if (CFStringCompare(lang, lang_code, kCFCompareAnchored) == kCFCompareEqualTo) {
- /* Lang code is supported by font, get full font name. */
- CFStringRef font_name = CTFontCopyFullName(font_ref);
- char name[128];
- CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
- CFRelease(font_name);
- /* Skip some inappropriate or ugly looking fonts that have better alternatives. */
- if (strncmp(name, "Courier", 7) == 0 || strncmp(name, "Apple Symbols", 13) == 0 ||
- strncmp(name, ".Aqua", 5) == 0 || strncmp(name, "LastResort", 10) == 0 ||
- strncmp(name, "GB18030 Bitmap", 14) == 0) continue;
-
- /* Save result. */
- callback->SetFontNames(settings, name);
- DEBUG(freetype, 2, "CT-Font for %s: %s", language_isocode, name);
- result = true;
- break;
- }
- }
- CFRelease(langs);
+ /* Skip some inappropriate or ugly looking fonts that have better alternatives. */
+ if (strncmp(name, "Courier", 7) == 0 || strncmp(name, "Apple Symbols", 13) == 0 ||
+ strncmp(name, ".Aqua", 5) == 0 || strncmp(name, "LastResort", 10) == 0 ||
+ strncmp(name, "GB18030 Bitmap", 14) == 0) continue;
+
+ /* Save result. */
+ callback->SetFontNames(settings, name);
+ if (!callback->FindMissingGlyphs(NULL)) {
+ DEBUG(freetype, 2, "CT-Font for %s: %s", language_isocode, name);
+ result = true;
+ break;
}
- CFRelease(font_ref);
}
- ATSFontIteratorRelease(&itr);
- CFRelease(lang_code);
+ if (descs != NULL) CFRelease(descs);
} else
#endif
{
-#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !__LP64__
- /* Determine fallback font using ATSUI. This uses a string sample with
- * missing characters. This is not failure-proof, but a better way like
- * using the isocode as in the CoreText code path is not available.
- * ATSUI was deprecated with 10.6 and is only partially available in
- * 64-bit mode. */
-
- /* Remove all control characters in the range from SCC_CONTROL_START to
- * SCC_CONTROL_END as well as all ASCII < 0x20 from the string as it will
- * mess with the automatic font detection */
- char buff[256]; // This length is enough to find a suitable replacement font
- strecpy(buff, str, lastof(buff));
- str_validate(buff, lastof(buff), SVS_ALLOW_NEWLINE);
-
- /* Extract a UniChar representation of the sample string. */
- CFStringRef cf_str = CFStringCreateWithCString(kCFAllocatorDefault, buff, kCFStringEncodingUTF8);
- if (cf_str == NULL) {
- /* Something went wrong. Corrupt/invalid sample string? */
- return false;
- }
- CFIndex str_len = CFStringGetLength(cf_str);
- UniChar string[str_len];
- CFStringGetCharacters(cf_str, CFRangeMake(0, str_len), string);
-
- /* Create a default text style with the default font. */
- ATSUStyle style;
- ATSUCreateStyle(&style);
-
- /* Create a text layout object from the sample string using the text style. */
- UniCharCount run_len = kATSUToTextEnd;
- ATSUTextLayout text_layout;
- ATSUCreateTextLayoutWithTextPtr(string, kATSUFromTextBeginning, kATSUToTextEnd, str_len, 1, &run_len, &style, &text_layout);
-
- /* Try to match a font for the sample text. ATSUMatchFontsToText stops after
- * it finds the first continuous character run not renderable with the currently
- * selected font starting at offset. The matching needs to be repeated until
- * the end of the string is reached to make sure the fallback font matches for
- * all characters in the string and not only the first run. */
- UniCharArrayOffset offset = kATSUFromTextBeginning;
- OSStatus os_err;
- do {
- ATSUFontID font;
- UniCharCount run_len;
- os_err = ATSUMatchFontsToText(text_layout, offset, kATSUToTextEnd, &font, &offset, &run_len);
- if (os_err == kATSUFontsMatched) {
- /* Found a better fallback font. Update the text layout
- * object with the new font. */
- ATSUAttributeTag tag = kATSUFontTag;
- ByteCount size = sizeof(font);
- ATSUAttributeValuePtr val = &font;
- ATSUSetAttributes(style, 1, &tag, &size, &val);
- offset += run_len;
- }
- /* Exit if the end of the string is reached or some other error occurred. */
- } while (os_err == kATSUFontsMatched && offset < (UniCharArrayOffset)str_len);
-
- if (os_err == noErr || os_err == kATSUFontsMatched) {
- /* ATSUMatchFontsToText exited normally. Extract font
- * out of the text layout object. */
- ATSUFontID font;
- ByteCount act_len;
- ATSUGetAttribute(style, kATSUFontTag, sizeof(font), &font, &act_len);
-
- /* Get unique font name. The result is not a c-string, we have
- * to leave space for a \0 and terminate it ourselves. */
+ /* Create a font iterator and iterate over all fonts that
+ * are available to the application. */
+ ATSFontIterator itr;
+ ATSFontRef font;
+ ATSFontIteratorCreate(kATSFontContextLocal, NULL, NULL, kATSOptionFlagsDefaultScope, &itr);
+ while (!result && ATSFontIteratorNext(itr, &font) == noErr) {
+ /* Get font name. */
char name[128];
- ATSUFindFontName(font, kFontUniqueName, kFontNoPlatformCode, kFontNoScriptCode, kFontNoLanguageCode, 127, name, &act_len, NULL);
- name[act_len > 127 ? 127 : act_len] = '\0';
+ CFStringRef font_name;
+ ATSFontGetName(font, kATSOptionFlagsDefault, &font_name);
+ CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
+ CFRelease(font_name);
+
+ /* We only want the base font and not bold or italic variants. */
+ if (strstr(name, "Italic") != NULL || strstr(name, "Bold")) continue;
+
+ /* Skip some inappropriate or ugly looking fonts that have better alternatives. */
+ if (strncmp(name, "Courier", 7) == 0 || strncmp(name, "Apple Symbols", 13) == 0 ||
+ strncmp(name, ".Aqua", 5) == 0 || strncmp(name, "LastResort", 10) == 0 ||
+ strncmp(name, "GB18030 Bitmap", 14) == 0) continue;
- /* Save Result. */
+ /* Save result. */
callback->SetFontNames(settings, name);
- DEBUG(freetype, 2, "ATSUI-Font for %s: %s", language_isocode, name);
- result = true;
+ if (!callback->FindMissingGlyphs(NULL)) {
+ DEBUG(freetype, 2, "ATS-Font for %s: %s", language_isocode, name);
+ result = true;
+ break;
+ }
}
-
- ATSUDisposeTextLayout(text_layout);
- ATSUDisposeStyle(style);
- CFRelease(cf_str);
-#endif
+ ATSFontIteratorRelease(&itr);
}
- if (result && strncmp(settings->medium.font, "Geeza Pro", 9) == 0) {
- /* The font 'Geeza Pro' is often found for arabic characters, but
- * it has the 'tiny' problem of not having any latin characters.
- * 'Arial Unicode MS' on the other hand has arabic and latin glyphs,
- * but seems to 'forget' to inform the OS about this fact. Manually
- * substitute the latter for the former if it is loadable. */
- bool ft_init = _library != NULL;
- FT_Face face;
- /* Init FreeType if needed. */
- if ((ft_init || FT_Init_FreeType(&_library) == FT_Err_Ok) && GetFontByFaceName("Arial Unicode MS", &face) == FT_Err_Ok) {
- FT_Done_Face(face);
- callback->SetFontNames(settings, "Arial Unicode MS");
- DEBUG(freetype, 1, "Replacing font 'Geeza Pro' with 'Arial Unicode MS'");
- }
- if (!ft_init) {
- /* Uninit FreeType if we did the init. */
- FT_Done_FreeType(_library);
- _library = NULL;
- }
- }
+ if (!result) {
+ /* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
+ * supports. If we didn't find any other font, just try it, maybe we get lucky. */
+ callback->SetFontNames(settings, "Arial Unicode MS");
+ result = !callback->FindMissingGlyphs(NULL);
+ }
callback->FindMissingGlyphs(NULL);
return result;