00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifdef WITH_FREETYPE
00013
00014 #include "stdafx.h"
00015 #include "debug.h"
00016 #include "fontdetection.h"
00017 #include "string_func.h"
00018 #include "strings_func.h"
00019
00020 extern FT_Library _library;
00021
00027
00028
00029
00030
00031 #ifdef WIN32
00032 #include "core/alloc_func.hpp"
00033 #include "core/math_func.hpp"
00034 #include <windows.h>
00035 #include <shlobj.h>
00036 #include "os/windows/win32.h"
00037
00048 char *GetShortPath(const char *long_path)
00049 {
00050 static char short_path[MAX_PATH];
00051 #ifdef UNICODE
00052
00053
00054
00055 wchar_t long_path_w[MAX_PATH];
00056 MultiByteToWideChar(CP_UTF8, 0, long_path, -1, long_path_w, MAX_PATH);
00057
00058 wchar_t short_path_w[MAX_PATH];
00059 GetShortPathNameW(long_path_w, short_path_w, MAX_PATH);
00060
00061 WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, MAX_PATH, NULL, NULL);
00062 #else
00063
00064 GetShortPathNameA(long_path, short_path, MAX_PATH);
00065 #endif
00066 return short_path;
00067 }
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 #define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
00078 #define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
00079 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
00080 {
00081 FT_Error err = FT_Err_Cannot_Open_Resource;
00082 HKEY hKey;
00083 LONG ret;
00084 TCHAR vbuffer[MAX_PATH], dbuffer[256];
00085 TCHAR *font_namep;
00086 char *font_path;
00087 uint index;
00088
00089
00090
00091
00092 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
00093 if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
00094
00095 if (ret != ERROR_SUCCESS) {
00096 DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
00097 return err;
00098 }
00099
00100
00101
00102
00103 #if defined(UNICODE)
00104 font_namep = MallocT<TCHAR>(MAX_PATH);
00105 MB_TO_WIDE_BUFFER(font_name, font_namep, MAX_PATH * sizeof(TCHAR));
00106 #else
00107 font_namep = const_cast<char *>(font_name);
00108 #endif
00109
00110 for (index = 0;; index++) {
00111 TCHAR *s;
00112 DWORD vbuflen = lengthof(vbuffer);
00113 DWORD dbuflen = lengthof(dbuffer);
00114
00115 ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen);
00116 if (ret != ERROR_SUCCESS) goto registry_no_font_found;
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 s = _tcschr(vbuffer, _T('('));
00128 if (s != NULL) s[-1] = '\0';
00129
00130 if (_tcschr(vbuffer, _T('&')) == NULL) {
00131 if (_tcsicmp(vbuffer, font_namep) == 0) break;
00132 } else {
00133 if (_tcsstr(vbuffer, font_namep) != NULL) break;
00134 }
00135 }
00136
00137 if (!SUCCEEDED(OTTDSHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) {
00138 DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory");
00139 goto folder_error;
00140 }
00141
00142
00143
00144
00145
00146
00147 #if defined(UNICODE)
00148
00149
00150
00151 font_path = (char*)font_namep;
00152 WIDE_TO_MB_BUFFER(vbuffer, font_path, MAX_PATH * sizeof(TCHAR));
00153 #else
00154 font_path = vbuffer;
00155 #endif
00156
00157 ttd_strlcat(font_path, "\\", MAX_PATH * sizeof(TCHAR));
00158 ttd_strlcat(font_path, WIDE_TO_MB(dbuffer), MAX_PATH * sizeof(TCHAR));
00159
00160
00161 font_path = GetShortPath(font_path);
00162
00163 index = 0;
00164 do {
00165 err = FT_New_Face(_library, font_path, index, face);
00166 if (err != FT_Err_Ok) break;
00167
00168 if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
00169
00170 if (strncasecmp(font_name + strlen(font_name) + 1, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
00171 err = FT_Err_Cannot_Open_Resource;
00172
00173 } while ((FT_Long)++index != (*face)->num_faces);
00174
00175
00176 folder_error:
00177 registry_no_font_found:
00178 #if defined(UNICODE)
00179 free(font_namep);
00180 #endif
00181 RegCloseKey(hKey);
00182 return err;
00183 }
00184
00198 static const char *GetEnglishFontName(const ENUMLOGFONTEX *logfont)
00199 {
00200 static char font_name[MAX_PATH];
00201 const char *ret_font_name = NULL;
00202 uint pos = 0;
00203 HDC dc;
00204 HGDIOBJ oldfont;
00205 byte *buf;
00206 DWORD dw;
00207 uint16 format, count, stringOffset, platformId, encodingId, languageId, nameId, length, offset;
00208
00209 HFONT font = CreateFontIndirect(&logfont->elfLogFont);
00210 if (font == NULL) goto err1;
00211
00212 dc = GetDC(NULL);
00213 oldfont = SelectObject(dc, font);
00214 dw = GetFontData(dc, 'eman', 0, NULL, 0);
00215 if (dw == GDI_ERROR) goto err2;
00216
00217 buf = MallocT<byte>(dw);
00218 dw = GetFontData(dc, 'eman', 0, buf, dw);
00219 if (dw == GDI_ERROR) goto err3;
00220
00221 format = buf[pos++] << 8;
00222 format += buf[pos++];
00223 assert(format == 0);
00224 count = buf[pos++] << 8;
00225 count += buf[pos++];
00226 stringOffset = buf[pos++] << 8;
00227 stringOffset += buf[pos++];
00228 for (uint i = 0; i < count; i++) {
00229 platformId = buf[pos++] << 8;
00230 platformId += buf[pos++];
00231 encodingId = buf[pos++] << 8;
00232 encodingId += buf[pos++];
00233 languageId = buf[pos++] << 8;
00234 languageId += buf[pos++];
00235 nameId = buf[pos++] << 8;
00236 nameId += buf[pos++];
00237 if (nameId != 1) {
00238 pos += 4;
00239 continue;
00240 }
00241 length = buf[pos++] << 8;
00242 length += buf[pos++];
00243 offset = buf[pos++] << 8;
00244 offset += buf[pos++];
00245
00246
00247 length = min(length, MAX_PATH - 1);
00248 for (uint j = 0; j < length; j++) font_name[j] = buf[stringOffset + offset + j];
00249 font_name[length] = '\0';
00250
00251 if ((platformId == 1 && languageId == 0) ||
00252 (platformId == 3 && languageId == 0x0409)) {
00253 ret_font_name = font_name;
00254 break;
00255 }
00256 }
00257
00258 err3:
00259 free(buf);
00260 err2:
00261 SelectObject(dc, oldfont);
00262 ReleaseDC(NULL, dc);
00263 DeleteObject(font);
00264 err1:
00265 return ret_font_name == NULL ? WIDE_TO_MB((const TCHAR*)logfont->elfFullName) : ret_font_name;
00266 }
00267
00268 class FontList {
00269 protected:
00270 TCHAR **fonts;
00271 uint items;
00272 uint capacity;
00273
00274 public:
00275 FontList() : fonts(NULL), items(0), capacity(0) { };
00276
00277 ~FontList() {
00278 if (this->fonts == NULL) return;
00279
00280 for (uint i = 0; i < this->items; i++) {
00281 free(this->fonts[i]);
00282 }
00283
00284 free(this->fonts);
00285 }
00286
00287 bool Add(const TCHAR *font) {
00288 for (uint i = 0; i < this->items; i++) {
00289 if (_tcscmp(this->fonts[i], font) == 0) return false;
00290 }
00291
00292 if (this->items == this->capacity) {
00293 this->capacity += 10;
00294 this->fonts = ReallocT(this->fonts, this->capacity);
00295 }
00296
00297 this->fonts[this->items++] = _tcsdup(font);
00298
00299 return true;
00300 }
00301 };
00302
00303 struct EFCParam {
00304 FreeTypeSettings *settings;
00305 LOCALESIGNATURE locale;
00306 MissingGlyphSearcher *callback;
00307 FontList fonts;
00308 };
00309
00310 static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
00311 {
00312 EFCParam *info = (EFCParam *)lParam;
00313
00314
00315 if (!info->fonts.Add((const TCHAR*)logfont->elfFullName)) return 1;
00316
00317 if (!(type & TRUETYPE_FONTTYPE)) return 1;
00318
00319 if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET) return 1;
00320
00321 if (info->callback->Monospace() && (logfont->elfLogFont.lfPitchAndFamily & (FF_MODERN | FIXED_PITCH)) != (FF_MODERN | FIXED_PITCH)) return 1;
00322
00323
00324 if ((metric->ntmFontSig.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) {
00325
00326 FONTSIGNATURE fs;
00327 memset(&fs, 0, sizeof(fs));
00328 HFONT font = CreateFontIndirect(&logfont->elfLogFont);
00329 if (font != NULL) {
00330 HDC dc = GetDC(NULL);
00331 HGDIOBJ oldfont = SelectObject(dc, font);
00332 GetTextCharsetInfo(dc, &fs, 0);
00333 SelectObject(dc, oldfont);
00334 ReleaseDC(NULL, dc);
00335 DeleteObject(font);
00336 }
00337 if ((fs.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (fs.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) return 1;
00338 }
00339
00340 char font_name[MAX_PATH];
00341 #if defined(UNICODE)
00342 WIDE_TO_MB_BUFFER((const TCHAR*)logfont->elfFullName, font_name, lengthof(font_name));
00343 #else
00344 strecpy(font_name, (const TCHAR*)logfont->elfFullName, lastof(font_name));
00345 #endif
00346
00347
00348 const char *english_name = GetEnglishFontName(logfont);
00349 strecpy(font_name + strlen(font_name) + 1, english_name, lastof(font_name));
00350
00351
00352 bool ft_init = _library != NULL;
00353 bool found = false;
00354 FT_Face face;
00355
00356 if ((ft_init || FT_Init_FreeType(&_library) == FT_Err_Ok) && GetFontByFaceName(font_name, &face) == FT_Err_Ok) {
00357 FT_Done_Face(face);
00358 found = true;
00359 }
00360 if (!ft_init) {
00361
00362 FT_Done_FreeType(_library);
00363 _library = NULL;
00364 }
00365
00366 if (!found) return 1;
00367
00368 info->callback->SetFontNames(info->settings, font_name);
00369 if (info->callback->FindMissingGlyphs(NULL)) return 1;
00370 DEBUG(freetype, 1, "Fallback font: %s (%s)", font_name, english_name);
00371 return 0;
00372 }
00373
00374 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
00375 {
00376 DEBUG(freetype, 1, "Trying fallback fonts");
00377 EFCParam langInfo;
00378 if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPTSTR)&langInfo.locale, sizeof(langInfo.locale) / sizeof(TCHAR)) == 0) {
00379
00380 DEBUG(freetype, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid);
00381 return false;
00382 }
00383 langInfo.settings = settings;
00384 langInfo.callback = callback;
00385
00386 LOGFONT font;
00387
00388 font.lfCharSet = DEFAULT_CHARSET;
00389 font.lfFaceName[0] = '\0';
00390 font.lfPitchAndFamily = 0;
00391
00392 HDC dc = GetDC(NULL);
00393 int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
00394 ReleaseDC(NULL, dc);
00395 return ret == 0;
00396 }
00397
00398 #elif defined(__APPLE__)
00399
00400
00401
00402
00403 #include "os/macosx/macos.h"
00404
00405 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
00406 {
00407 FT_Error err = FT_Err_Cannot_Open_Resource;
00408
00409
00410 CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name, kCFStringEncodingUTF8);
00411 ATSFontRef font = ATSFontFindFromName(name, kATSOptionFlagsDefault);
00412 CFRelease(name);
00413 if (font == kInvalidFont) return err;
00414
00415
00416 FSRef ref;
00417 OSStatus os_err = -1;
00418 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
00419 if (MacOSVersionIsAtLeast(10, 5, 0)) {
00420 os_err = ATSFontGetFileReference(font, &ref);
00421 } else
00422 #endif
00423 {
00424 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !__LP64__
00425
00426 #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5)
00427 #define ATSFSSpec FSSpec
00428 #endif
00429 FSSpec spec;
00430 os_err = ATSFontGetFileSpecification(font, (ATSFSSpec *)&spec);
00431 if (os_err == noErr) os_err = FSpMakeFSRef(&spec, &ref);
00432 #endif
00433 }
00434
00435 if (os_err == noErr) {
00436
00437 UInt8 file_path[PATH_MAX];
00438 if (FSRefMakePath(&ref, file_path, sizeof(file_path)) == noErr) {
00439 DEBUG(freetype, 3, "Font path for %s: %s", font_name, file_path);
00440 err = FT_New_Face(_library, (const char *)file_path, 0, face);
00441 }
00442 }
00443
00444 return err;
00445 }
00446
00447 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
00448 {
00449 const char *str;
00450 bool result = false;
00451
00452 callback->FindMissingGlyphs(&str);
00453
00454 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
00455 if (MacOSVersionIsAtLeast(10, 5, 0)) {
00456
00457
00458 char lang[16];
00459 if (strcmp(language_isocode, "zh_TW") == 0) {
00460
00461 strecpy(lang, "zh-Hant", lastof(lang));
00462 } else if (strcmp(language_isocode, "zh_CN") == 0) {
00463
00464 strecpy(lang, "zh-Hans", lastof(lang));
00465 } else if (strncmp(language_isocode, "ur", 2) == 0) {
00466
00467
00468
00469 strecpy(lang, "fa", lastof(lang));
00470 } else {
00471
00472 strecpy(lang, language_isocode, lastof(lang));
00473 char *sep = strchr(lang, '_');
00474 if (sep != NULL) *sep = '\0';
00475 }
00476
00477 CFStringRef lang_code;
00478 lang_code = CFStringCreateWithCString(kCFAllocatorDefault, lang, kCFStringEncodingUTF8);
00479
00480
00481
00482 ATSFontIterator itr;
00483 ATSFontRef font;
00484 ATSFontIteratorCreate(kATSFontContextLocal, NULL, NULL, kATSOptionFlagsUnRestrictedScope, &itr);
00485 while (!result && ATSFontIteratorNext(itr, &font) == noErr) {
00486
00487 CTFontRef font_ref = CTFontCreateWithPlatformFont(font, 0.0, NULL, NULL);
00488 CFArrayRef langs = CTFontCopySupportedLanguages(font_ref);
00489 if (langs != NULL) {
00490
00491 for (CFIndex i = 0; i < CFArrayGetCount(langs); i++) {
00492 CFStringRef lang = (CFStringRef)CFArrayGetValueAtIndex(langs, i);
00493 if (CFStringCompare(lang, lang_code, kCFCompareAnchored) == kCFCompareEqualTo) {
00494
00495 CFStringRef font_name = CTFontCopyFullName(font_ref);
00496 char name[128];
00497 CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
00498 CFRelease(font_name);
00499
00500 if (strncmp(name, "Courier", 7) == 0 || strncmp(name, "Apple Symbols", 13) == 0 ||
00501 strncmp(name, ".Aqua", 5) == 0 || strncmp(name, "LastResort", 10) == 0 ||
00502 strncmp(name, "GB18030 Bitmap", 14) == 0) continue;
00503
00504
00505 callback->SetFontNames(settings, name);
00506 DEBUG(freetype, 2, "CT-Font for %s: %s", language_isocode, name);
00507 result = true;
00508 break;
00509 }
00510 }
00511 CFRelease(langs);
00512 }
00513 CFRelease(font_ref);
00514 }
00515 ATSFontIteratorRelease(&itr);
00516 CFRelease(lang_code);
00517 } else
00518 #endif
00519 {
00520 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !__LP64__
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 char buff[256];
00531 strecpy(buff, str, lastof(buff));
00532 str_validate(buff, lastof(buff), SVS_ALLOW_NEWLINE);
00533
00534
00535 CFStringRef cf_str = CFStringCreateWithCString(kCFAllocatorDefault, buff, kCFStringEncodingUTF8);
00536 if (cf_str == NULL) {
00537
00538 return false;
00539 }
00540 CFIndex str_len = CFStringGetLength(cf_str);
00541 UniChar string[str_len];
00542 CFStringGetCharacters(cf_str, CFRangeMake(0, str_len), string);
00543
00544
00545 ATSUStyle style;
00546 ATSUCreateStyle(&style);
00547
00548
00549 UniCharCount run_len = kATSUToTextEnd;
00550 ATSUTextLayout text_layout;
00551 ATSUCreateTextLayoutWithTextPtr(string, kATSUFromTextBeginning, kATSUToTextEnd, str_len, 1, &run_len, &style, &text_layout);
00552
00553
00554
00555
00556
00557
00558 UniCharArrayOffset offset = kATSUFromTextBeginning;
00559 OSStatus os_err;
00560 do {
00561 ATSUFontID font;
00562 UniCharCount run_len;
00563 os_err = ATSUMatchFontsToText(text_layout, offset, kATSUToTextEnd, &font, &offset, &run_len);
00564 if (os_err == kATSUFontsMatched) {
00565
00566
00567 ATSUAttributeTag tag = kATSUFontTag;
00568 ByteCount size = sizeof(font);
00569 ATSUAttributeValuePtr val = &font;
00570 ATSUSetAttributes(style, 1, &tag, &size, &val);
00571 offset += run_len;
00572 }
00573
00574 } while (os_err == kATSUFontsMatched && offset < (UniCharArrayOffset)str_len);
00575
00576 if (os_err == noErr || os_err == kATSUFontsMatched) {
00577
00578
00579 ATSUFontID font;
00580 ByteCount act_len;
00581 ATSUGetAttribute(style, kATSUFontTag, sizeof(font), &font, &act_len);
00582
00583
00584
00585 char name[128];
00586 ATSUFindFontName(font, kFontUniqueName, kFontNoPlatformCode, kFontNoScriptCode, kFontNoLanguageCode, 127, name, &act_len, NULL);
00587 name[act_len > 127 ? 127 : act_len] = '\0';
00588
00589
00590 callback->SetFontNames(settings, name);
00591 DEBUG(freetype, 2, "ATSUI-Font for %s: %s", language_isocode, name);
00592 result = true;
00593 }
00594
00595 ATSUDisposeTextLayout(text_layout);
00596 ATSUDisposeStyle(style);
00597 CFRelease(cf_str);
00598 #endif
00599 }
00600
00601 if (result && strncmp(settings->medium.font, "Geeza Pro", 9) == 0) {
00602
00603
00604
00605
00606
00607 bool ft_init = _library != NULL;
00608 FT_Face face;
00609
00610 if ((ft_init || FT_Init_FreeType(&_library) == FT_Err_Ok) && GetFontByFaceName("Arial Unicode MS", &face) == FT_Err_Ok) {
00611 FT_Done_Face(face);
00612 callback->SetFontNames(settings, "Arial Unicode MS");
00613 DEBUG(freetype, 1, "Replacing font 'Geeza Pro' with 'Arial Unicode MS'");
00614 }
00615 if (!ft_init) {
00616
00617 FT_Done_FreeType(_library);
00618 _library = NULL;
00619 }
00620 }
00621
00622 callback->FindMissingGlyphs(NULL);
00623 return result;
00624 }
00625
00626 #elif defined(WITH_FONTCONFIG)
00627
00628 #include <fontconfig/fontconfig.h>
00629
00630
00631
00632
00633 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
00634 {
00635 FT_Error err = FT_Err_Cannot_Open_Resource;
00636
00637 if (!FcInit()) {
00638 ShowInfoF("Unable to load font configuration");
00639 } else {
00640 FcPattern *match;
00641 FcPattern *pat;
00642 FcFontSet *fs;
00643 FcResult result;
00644 char *font_style;
00645 char *font_family;
00646
00647
00648 font_family = strdup(font_name);
00649 font_style = strchr(font_family, ',');
00650 if (font_style != NULL) {
00651 font_style[0] = '\0';
00652 font_style++;
00653 while (*font_style == ' ' || *font_style == '\t') font_style++;
00654 }
00655
00656
00657 pat = FcNameParse((FcChar8*)font_family);
00658 if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style);
00659 FcConfigSubstitute(0, pat, FcMatchPattern);
00660 FcDefaultSubstitute(pat);
00661 fs = FcFontSetCreate();
00662 match = FcFontMatch(0, pat, &result);
00663
00664 if (fs != NULL && match != NULL) {
00665 int i;
00666 FcChar8 *family;
00667 FcChar8 *style;
00668 FcChar8 *file;
00669 FcFontSetAdd(fs, match);
00670
00671 for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) {
00672
00673 if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch &&
00674 FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch &&
00675 FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) {
00676
00677
00678 if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue;
00679
00680
00681
00682
00683 if (strcasecmp(font_family, (char*)family) == 0) {
00684 err = FT_New_Face(_library, (char *)file, 0, face);
00685 }
00686 }
00687 }
00688 }
00689
00690 free(font_family);
00691 FcPatternDestroy(pat);
00692 FcFontSetDestroy(fs);
00693 FcFini();
00694 }
00695
00696 return err;
00697 }
00698
00699 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
00700 {
00701 if (!FcInit()) return false;
00702
00703 bool ret = false;
00704
00705
00706
00707
00708 char lang[16];
00709 seprintf(lang, lastof(lang), ":lang=%s", language_isocode);
00710 char *split = strchr(lang, '_');
00711 if (split != NULL) *split = '\0';
00712
00713
00714 FcPattern *pat = FcNameParse((FcChar8*)lang);
00715
00716 FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_SPACING, FC_SLANT, FC_WEIGHT, NULL);
00717
00718 FcFontSet *fs = FcFontList(NULL, pat, os);
00719
00720
00721 FcObjectSetDestroy(os);
00722 FcPatternDestroy(pat);
00723
00724 if (fs != NULL) {
00725 int best_weight = -1;
00726 const char *best_font = NULL;
00727
00728 for (int i = 0; i < fs->nfont; i++) {
00729 FcPattern *font = fs->fonts[i];
00730
00731 FcChar8 *file = NULL;
00732 FcResult res = FcPatternGetString(font, FC_FILE, 0, &file);
00733 if (res != FcResultMatch || file == NULL) {
00734 continue;
00735 }
00736
00737
00738 int value = 0;
00739 FcPatternGetInteger(font, FC_SPACING, 0, &value);
00740 if (callback->Monospace() != (value == FC_MONO) && value != FC_DUAL) continue;
00741
00742
00743 FcPatternGetInteger(font, FC_SLANT, 0, &value);
00744 if (value != 0) continue;
00745
00746
00747 FcPatternGetInteger(font, FC_WEIGHT, 0, &value);
00748 if (value <= best_weight) continue;
00749
00750 callback->SetFontNames(settings, (const char*)file);
00751
00752 bool missing = callback->FindMissingGlyphs(NULL);
00753 DEBUG(freetype, 1, "Font \"%s\" misses%s glyphs", file, missing ? "" : " no");
00754
00755 if (!missing) {
00756 best_weight = value;
00757 best_font = (const char *)file;
00758 }
00759 }
00760
00761 if (best_font != NULL) {
00762 ret = true;
00763 callback->SetFontNames(settings, best_font);
00764 InitFreeType(callback->Monospace());
00765 }
00766
00767
00768 FcFontSetDestroy(fs);
00769 }
00770
00771 FcFini();
00772 return ret;
00773 }
00774
00775 #else
00776 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
00777 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback) { return false; }
00778 #endif
00779
00780 #endif