mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-17 21:25:40 +00:00
(svn r25661) -Fix [FS#4847]: [OSX] Rework font detection to work even if no default font sprites are present.
This commit is contained in:
parent
f673278cbf
commit
6c1444b992
@ -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)
|
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
|
||||||
{
|
{
|
||||||
const char *str;
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
callback->FindMissingGlyphs(&str);
|
|
||||||
|
|
||||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||||
if (MacOSVersionIsAtLeast(10, 5, 0)) {
|
if (MacOSVersionIsAtLeast(10, 5, 0)) {
|
||||||
/* Determine fallback font using CoreText. This uses the language isocode
|
/* 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) {
|
} else if (strcmp(language_isocode, "zh_CN") == 0) {
|
||||||
/* Simplified Chinese */
|
/* Simplified Chinese */
|
||||||
strecpy(lang, "zh-Hans", lastof(lang));
|
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 {
|
} else {
|
||||||
/* Just copy the first part of the isocode. */
|
/* Just copy the first part of the isocode. */
|
||||||
strecpy(lang, language_isocode, lastof(lang));
|
strecpy(lang, language_isocode, lastof(lang));
|
||||||
@ -474,28 +466,32 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
|
|||||||
if (sep != NULL) *sep = '\0';
|
if (sep != NULL) *sep = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
CFStringRef lang_code;
|
/* Create a font descriptor matching the wanted language and latin (english) glyphs. */
|
||||||
lang_code = CFStringCreateWithCString(kCFAllocatorDefault, lang, kCFStringEncodingUTF8);
|
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]);
|
||||||
|
|
||||||
/* Create a font iterator and iterate over all fonts that
|
/* Get array of all font descriptors for the wanted language. */
|
||||||
* are available to the application. */
|
CFSetRef mandatory_attribs = CFSetCreate(kCFAllocatorDefault, (const void **)&kCTFontLanguagesAttribute, 1, &kCFTypeSetCallBacks);
|
||||||
ATSFontIterator itr;
|
CFArrayRef descs = CTFontDescriptorCreateMatchingFontDescriptors(lang_desc, mandatory_attribs);
|
||||||
ATSFontRef font;
|
CFRelease(mandatory_attribs);
|
||||||
ATSFontIteratorCreate(kATSFontContextLocal, NULL, NULL, kATSOptionFlagsUnRestrictedScope, &itr);
|
CFRelease(lang_desc);
|
||||||
while (!result && ATSFontIteratorNext(itr, &font) == noErr) {
|
|
||||||
/* Get CoreText font handle. */
|
for (CFIndex i = 0; descs != NULL && i < CFArrayGetCount(descs); i++) {
|
||||||
CTFontRef font_ref = CTFontCreateWithPlatformFont(font, 0.0, NULL, NULL);
|
CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs, i);
|
||||||
CFArrayRef langs = CTFontCopySupportedLanguages(font_ref);
|
|
||||||
if (langs != NULL) {
|
/* Get font name. */
|
||||||
/* 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];
|
char name[128];
|
||||||
|
CFStringRef font_name = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute);
|
||||||
CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
|
CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
|
||||||
CFRelease(font_name);
|
CFRelease(font_name);
|
||||||
|
|
||||||
/* Skip some inappropriate or ugly looking fonts that have better alternatives. */
|
/* Skip some inappropriate or ugly looking fonts that have better alternatives. */
|
||||||
if (strncmp(name, "Courier", 7) == 0 || strncmp(name, "Apple Symbols", 13) == 0 ||
|
if (strncmp(name, "Courier", 7) == 0 || strncmp(name, "Apple Symbols", 13) == 0 ||
|
||||||
strncmp(name, ".Aqua", 5) == 0 || strncmp(name, "LastResort", 10) == 0 ||
|
strncmp(name, ".Aqua", 5) == 0 || strncmp(name, "LastResort", 10) == 0 ||
|
||||||
@ -503,120 +499,53 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
|
|||||||
|
|
||||||
/* Save result. */
|
/* Save result. */
|
||||||
callback->SetFontNames(settings, name);
|
callback->SetFontNames(settings, name);
|
||||||
|
if (!callback->FindMissingGlyphs(NULL)) {
|
||||||
DEBUG(freetype, 2, "CT-Font for %s: %s", language_isocode, name);
|
DEBUG(freetype, 2, "CT-Font for %s: %s", language_isocode, name);
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CFRelease(langs);
|
if (descs != NULL) CFRelease(descs);
|
||||||
}
|
|
||||||
CFRelease(font_ref);
|
|
||||||
}
|
|
||||||
ATSFontIteratorRelease(&itr);
|
|
||||||
CFRelease(lang_code);
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !__LP64__
|
/* Create a font iterator and iterate over all fonts that
|
||||||
/* Determine fallback font using ATSUI. This uses a string sample with
|
* are available to the application. */
|
||||||
* missing characters. This is not failure-proof, but a better way like
|
ATSFontIterator itr;
|
||||||
* using the isocode as in the CoreText code path is not available.
|
ATSFontRef font;
|
||||||
* ATSUI was deprecated with 10.6 and is only partially available in
|
ATSFontIteratorCreate(kATSFontContextLocal, NULL, NULL, kATSOptionFlagsDefaultScope, &itr);
|
||||||
* 64-bit mode. */
|
while (!result && ATSFontIteratorNext(itr, &font) == noErr) {
|
||||||
|
/* Get font name. */
|
||||||
/* 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. */
|
|
||||||
char name[128];
|
char name[128];
|
||||||
ATSUFindFontName(font, kFontUniqueName, kFontNoPlatformCode, kFontNoScriptCode, kFontNoLanguageCode, 127, name, &act_len, NULL);
|
CFStringRef font_name;
|
||||||
name[act_len > 127 ? 127 : act_len] = '\0';
|
ATSFontGetName(font, kATSOptionFlagsDefault, &font_name);
|
||||||
|
CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
|
||||||
|
CFRelease(font_name);
|
||||||
|
|
||||||
/* Save Result. */
|
/* 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. */
|
||||||
callback->SetFontNames(settings, name);
|
callback->SetFontNames(settings, name);
|
||||||
DEBUG(freetype, 2, "ATSUI-Font for %s: %s", language_isocode, name);
|
if (!callback->FindMissingGlyphs(NULL)) {
|
||||||
|
DEBUG(freetype, 2, "ATS-Font for %s: %s", language_isocode, name);
|
||||||
result = true;
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ATSFontIteratorRelease(&itr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ATSUDisposeTextLayout(text_layout);
|
if (!result) {
|
||||||
ATSUDisposeStyle(style);
|
/* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
|
||||||
CFRelease(cf_str);
|
* supports. If we didn't find any other font, just try it, maybe we get lucky. */
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
callback->SetFontNames(settings, "Arial Unicode MS");
|
||||||
DEBUG(freetype, 1, "Replacing font 'Geeza Pro' with 'Arial Unicode MS'");
|
result = !callback->FindMissingGlyphs(NULL);
|
||||||
}
|
|
||||||
if (!ft_init) {
|
|
||||||
/* Uninit FreeType if we did the init. */
|
|
||||||
FT_Done_FreeType(_library);
|
|
||||||
_library = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callback->FindMissingGlyphs(NULL);
|
callback->FindMissingGlyphs(NULL);
|
||||||
|
Loading…
Reference in New Issue
Block a user