OpenTTD

fontdetection.cpp
Go to the documentation of this file.
1 /* $Id: fontdetection.cpp 26709 2014-07-30 20:19:29Z planetmaker $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 */
9
12 #ifdef WITH_FREETYPE
13
14 #include "stdafx.h"
15 #include "debug.h"
16 #include "fontdetection.h"
17 #include "string_func.h"
18 #include "strings_func.h"
19
20 extern FT_Library _library;
21
27 /* ========================================================================================
28 * Windows support
29 * ======================================================================================== */
30
31 #ifdef WIN32
32 #include "core/alloc_func.hpp"
33 #include "core/math_func.hpp"
34 #include <windows.h>
35 #include <shlobj.h> /* SHGetFolderPath */
36 #include "os/windows/win32.h"
37
38 #include "safeguards.h"
39
50 const char *GetShortPath(const TCHAR *long_path)
51 {
52 static char short_path[MAX_PATH];
53 #ifdef UNICODE
54 WCHAR short_path_w[MAX_PATH];
55 GetShortPathName(long_path, short_path_w, lengthof(short_path_w));
56 WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, lengthof(short_path), NULL, NULL);
57 #else
58 /* Technically not needed, but do it for consistency. */
59 GetShortPathName(long_path, short_path, lengthof(short_path));
60 #endif
61 return short_path;
62 }
63
64 /* Get the font file to be loaded into Freetype by looping the registry
65 * location where windows lists all installed fonts. Not very nice, will
66 * surely break if the registry path changes, but it works. Much better
67 * solution would be to use CreateFont, and extract the font data from it
68 * by GetFontData. The problem with this is that the font file needs to be
69 * kept in memory then until the font is no longer needed. This could mean
70 * an additional memory usage of 30MB (just for fonts!) when using an eastern
71 * font for all font sizes */
72 #define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
73 #define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
74 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
75 {
76 FT_Error err = FT_Err_Cannot_Open_Resource;
77 HKEY hKey;
78 LONG ret;
79 TCHAR vbuffer[MAX_PATH], dbuffer[256];
80 TCHAR *pathbuf;
81 const char *font_path;
82 uint index;
83 size_t path_len;
84
85 /* On windows NT (2000, NT3.5, XP, etc.) the fonts are stored in the
86 * "Windows NT" key, on Windows 9x in the Windows key. To save us having
87 * to retrieve the windows version, we'll just query both */
88 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
89 if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
90
91 if (ret != ERROR_SUCCESS) {
92 DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
93 return err;
94 }
95
96 /* Convert font name to file system encoding. */
97 TCHAR *font_namep = _tcsdup(OTTD2FS(font_name));
98
99 for (index = 0;; index++) {
100 TCHAR *s;
101 DWORD vbuflen = lengthof(vbuffer);
102 DWORD dbuflen = lengthof(dbuffer);
103
104 ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen);
105 if (ret != ERROR_SUCCESS) goto registry_no_font_found;
106
107 /* The font names in the registry are of the following 3 forms:
108 * - ADMUI3.fon
109 * - Book Antiqua Bold (TrueType)
110 * - Batang & BatangChe & Gungsuh & GungsuhChe (TrueType)
111 * We will strip the font-type '()' if any and work with the font name
112 * itself, which must match exactly; if...
113 * TTC files, font files which contain more than one font are separated
114 * by '&'. Our best bet will be to do substr match for the fontname
115 * and then let FreeType figure out which index to load */
116 s = _tcschr(vbuffer, _T('('));
117 if (s != NULL) s[-1] = '\0';
118
119 if (_tcschr(vbuffer, _T('&')) == NULL) {
120 if (_tcsicmp(vbuffer, font_namep) == 0) break;
121 } else {
122 if (_tcsstr(vbuffer, font_namep) != NULL) break;
123 }
124 }
125
126 if (!SUCCEEDED(OTTDSHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) {
127 DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory");
128 goto folder_error;
129 }
130
131 /* Some fonts are contained in .ttc files, TrueType Collection fonts. These
132 * contain multiple fonts inside this single file. GetFontData however
133 * returns the whole file, so we need to check each font inside to get the
134 * proper font. */
135 path_len = _tcslen(vbuffer) + _tcslen(dbuffer) + 2; // '\' and terminating nul.
136 pathbuf = AllocaM(TCHAR, path_len);
137 _sntprintf(pathbuf, path_len, _T("%s\\%s"), vbuffer, dbuffer);
138
139 /* Convert the path into something that FreeType understands. */
140 font_path = GetShortPath(pathbuf);
141
142 index = 0;
143 do {
144 err = FT_New_Face(_library, font_path, index, face);
145 if (err != FT_Err_Ok) break;
146
147 if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
148 /* Try english name if font name failed */
149 if (strncasecmp(font_name + strlen(font_name) + 1, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
150 err = FT_Err_Cannot_Open_Resource;
151
152 } while ((FT_Long)++index != (*face)->num_faces);
153
154
155 folder_error:
156 registry_no_font_found:
157 free(font_namep);
158 RegCloseKey(hKey);
159 return err;
160 }
161
175 static const char *GetEnglishFontName(const ENUMLOGFONTEX *logfont)
176 {
177 static char font_name[MAX_PATH];
178 const char *ret_font_name = NULL;
179 uint pos = 0;
180 HDC dc;
181 HGDIOBJ oldfont;
182 byte *buf;
183 DWORD dw;
184 uint16 format, count, stringOffset, platformId, encodingId, languageId, nameId, length, offset;
185
186 HFONT font = CreateFontIndirect(&logfont->elfLogFont);
187 if (font == NULL) goto err1;
188
189 dc = GetDC(NULL);
190 oldfont = SelectObject(dc, font);
191 dw = GetFontData(dc, 'eman', 0, NULL, 0);
192 if (dw == GDI_ERROR) goto err2;
193
194 buf = MallocT<byte>(dw);
195 dw = GetFontData(dc, 'eman', 0, buf, dw);
196 if (dw == GDI_ERROR) goto err3;
197
198 format = buf[pos++] << 8;
199 format += buf[pos++];
200 assert(format == 0);
201 count = buf[pos++] << 8;
202 count += buf[pos++];
203 stringOffset = buf[pos++] << 8;
204 stringOffset += buf[pos++];
205 for (uint i = 0; i < count; i++) {
206 platformId = buf[pos++] << 8;
207 platformId += buf[pos++];
208 encodingId = buf[pos++] << 8;
209 encodingId += buf[pos++];
210 languageId = buf[pos++] << 8;
211 languageId += buf[pos++];
212 nameId = buf[pos++] << 8;
213 nameId += buf[pos++];
214 if (nameId != 1) {
215 pos += 4; // skip length and offset
216 continue;
217 }
218 length = buf[pos++] << 8;
219 length += buf[pos++];
220 offset = buf[pos++] << 8;
221 offset += buf[pos++];
222
223 /* Don't buffer overflow */
224 length = min(length, MAX_PATH - 1);
225 for (uint j = 0; j < length; j++) font_name[j] = buf[stringOffset + offset + j];
226 font_name[length] = '\0';
227
228 if ((platformId == 1 && languageId == 0) || // Macintosh English
229 (platformId == 3 && languageId == 0x0409)) { // Microsoft English (US)
230 ret_font_name = font_name;
231 break;
232 }
233 }
234
235 err3:
236 free(buf);
237 err2:
238 SelectObject(dc, oldfont);
239 ReleaseDC(NULL, dc);
240 DeleteObject(font);
241 err1:
242 return ret_font_name == NULL ? WIDE_TO_MB((const TCHAR*)logfont->elfFullName) : ret_font_name;
243 }
244
245 class FontList {
246 protected:
247 TCHAR **fonts;
248 uint items;
249 uint capacity;
250
251 public:
252 FontList() : fonts(NULL), items(0), capacity(0) { };
253
254 ~FontList() {
255 if (this->fonts == NULL) return;
256
257 for (uint i = 0; i < this->items; i++) {
258 free(this->fonts[i]);
259 }
260
261 free(this->fonts);
262 }
263
264 bool Add(const TCHAR *font) {
265 for (uint i = 0; i < this->items; i++) {
266 if (_tcscmp(this->fonts[i], font) == 0) return false;
267 }
268
269 if (this->items == this->capacity) {
270 this->capacity += 10;
271 this->fonts = ReallocT(this->fonts, this->capacity);
272 }
273
274 this->fonts[this->items++] = _tcsdup(font);
275
276 return true;
277 }
278 };
279
280 struct EFCParam {
281 FreeTypeSettings *settings;
282 LOCALESIGNATURE locale;
283 MissingGlyphSearcher *callback;
284 FontList fonts;
285 };
286
287 static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
288 {
289 EFCParam *info = (EFCParam *)lParam;
290
291 /* Skip duplicates */
292 if (!info->fonts.Add((const TCHAR*)logfont->elfFullName)) return 1;
293 /* Only use TrueType fonts */
294 if (!(type & TRUETYPE_FONTTYPE)) return 1;
295 /* Don't use SYMBOL fonts */
296 if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET) return 1;
297 /* Use monospaced fonts when asked for it. */
298 if (info->callback->Monospace() && (logfont->elfLogFont.lfPitchAndFamily & (FF_MODERN | FIXED_PITCH)) != (FF_MODERN | FIXED_PITCH)) return 1;
299
300 /* The font has to have at least one of the supported locales to be usable. */
301 if ((metric->ntmFontSig.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) {
302 /* On win9x metric->ntmFontSig seems to contain garbage. */
303 FONTSIGNATURE fs;
304 memset(&fs, 0, sizeof(fs));
305 HFONT font = CreateFontIndirect(&logfont->elfLogFont);
306 if (font != NULL) {
307 HDC dc = GetDC(NULL);
308 HGDIOBJ oldfont = SelectObject(dc, font);
309 GetTextCharsetInfo(dc, &fs, 0);
310 SelectObject(dc, oldfont);
311 ReleaseDC(NULL, dc);
312 DeleteObject(font);
313 }
314 if ((fs.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (fs.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) return 1;
315 }
316
317 char font_name[MAX_PATH];
318 convert_from_fs((const TCHAR *)logfont->elfFullName, font_name, lengthof(font_name));
319
320 /* Add english name after font name */
321 const char *english_name = GetEnglishFontName(logfont);
322 strecpy(font_name + strlen(font_name) + 1, english_name, lastof(font_name));
323
324 /* Check whether we can actually load the font. */
325 bool ft_init = _library != NULL;
326 bool found = false;
327 FT_Face face;
328 /* Init FreeType if needed. */
329 if ((ft_init || FT_Init_FreeType(&_library) == FT_Err_Ok) && GetFontByFaceName(font_name, &face) == FT_Err_Ok) {
330 FT_Done_Face(face);
331 found = true;
332 }
333 if (!ft_init) {
334 /* Uninit FreeType if we did the init. */
335 FT_Done_FreeType(_library);
336 _library = NULL;
337 }
338
339 if (!found) return 1;
340
341 info->callback->SetFontNames(info->settings, font_name);
342 if (info->callback->FindMissingGlyphs(NULL)) return 1;
343 DEBUG(freetype, 1, "Fallback font: %s (%s)", font_name, english_name);
344 return 0; // stop enumerating
345 }
346
347 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
348 {
349 DEBUG(freetype, 1, "Trying fallback fonts");
350 EFCParam langInfo;
351 if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPTSTR)&langInfo.locale, sizeof(langInfo.locale) / sizeof(TCHAR)) == 0) {
352 /* Invalid langid or some other mysterious error, can't determine fallback font. */
353 DEBUG(freetype, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid);
354 return false;
355 }
356 langInfo.settings = settings;
357 langInfo.callback = callback;
358
359 LOGFONT font;
360 /* Enumerate all fonts. */
361 font.lfCharSet = DEFAULT_CHARSET;
362 font.lfFaceName[0] = '\0';
363 font.lfPitchAndFamily = 0;
364
365 HDC dc = GetDC(NULL);
366 int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
367 ReleaseDC(NULL, dc);
368 return ret == 0;
369 }
370
371 #elif defined(__APPLE__) /* end ifdef Win32 */
372 /* ========================================================================================
373 * OSX support
374 * ======================================================================================== */
375
376 #include "os/macosx/macos.h"
377
378 #include "safeguards.h"
379
380 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
381 {
382 FT_Error err = FT_Err_Cannot_Open_Resource;
383
384 /* Get font reference from name. */
385 CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name, kCFStringEncodingUTF8);
386 ATSFontRef font = ATSFontFindFromName(name, kATSOptionFlagsDefault);
387 CFRelease(name);
388 if (font == kInvalidFont) return err;
389
390 /* Get a file system reference for the font. */
391 FSRef ref;
392 OSStatus os_err = -1;
393 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
394 if (MacOSVersionIsAtLeast(10, 5, 0)) {
395 os_err = ATSFontGetFileReference(font, &ref);
396 } else
397 #endif
398 {
399 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !defined(__LP64__)
400 /* This type was introduced with the 10.5 SDK. */
401 #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5)
402 #define ATSFSSpec FSSpec
403 #endif
404 FSSpec spec;
405 os_err = ATSFontGetFileSpecification(font, (ATSFSSpec *)&spec);
406 if (os_err == noErr) os_err = FSpMakeFSRef(&spec, &ref);
407 #endif
408 }
409
410 if (os_err == noErr) {
411 /* Get unix path for file. */
412 UInt8 file_path[PATH_MAX];
413 if (FSRefMakePath(&ref, file_path, sizeof(file_path)) == noErr) {
414 DEBUG(freetype, 3, "Font path for %s: %s", font_name, file_path);
415 err = FT_New_Face(_library, (const char *)file_path, 0, face);
416 }
417 }
418
419 return err;
420 }
421
422 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
423 {
424 bool result = false;
425
426 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
427 if (MacOSVersionIsAtLeast(10, 5, 0)) {
428 /* Determine fallback font using CoreText. This uses the language isocode
429 * to find a suitable font. CoreText is available from 10.5 onwards. */
430 char lang[16];
431 if (strcmp(language_isocode, "zh_TW") == 0) {
432 /* Traditional Chinese */
433 strecpy(lang, "zh-Hant", lastof(lang));
434 } else if (strcmp(language_isocode, "zh_CN") == 0) {
435 /* Simplified Chinese */
436 strecpy(lang, "zh-Hans", lastof(lang));
437 } else {
438 /* Just copy the first part of the isocode. */
439 strecpy(lang, language_isocode, lastof(lang));
440 char *sep = strchr(lang, '_');
441 if (sep != NULL) *sep = '\0';
442 }
443
444 /* Create a font descriptor matching the wanted language and latin (english) glyphs. */
445 CFStringRef lang_codes[2];
446 lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang, kCFStringEncodingUTF8);
447 lang_codes[1] = CFSTR("en");
448 CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks);
449 CFDictionaryRef lang_attribs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&kCTFontLanguagesAttribute, (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
450 CTFontDescriptorRef lang_desc = CTFontDescriptorCreateWithAttributes(lang_attribs);
451 CFRelease(lang_arr);
452 CFRelease(lang_attribs);
453 CFRelease(lang_codes[0]);
454
455 /* Get array of all font descriptors for the wanted language. */
456 CFSetRef mandatory_attribs = CFSetCreate(kCFAllocatorDefault, (const void **)&kCTFontLanguagesAttribute, 1, &kCFTypeSetCallBacks);
457 CFArrayRef descs = CTFontDescriptorCreateMatchingFontDescriptors(lang_desc, mandatory_attribs);
458 CFRelease(mandatory_attribs);
459 CFRelease(lang_desc);
460
461 for (CFIndex i = 0; descs != NULL && i < CFArrayGetCount(descs); i++) {
462 CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs, i);
463
464 /* Get font traits. */
465 CFDictionaryRef traits = (CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute);
466 CTFontSymbolicTraits symbolic_traits;
467 CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits, kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
468 CFRelease(traits);
469
470 /* Skip symbol fonts and vertical fonts. */
471 if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue;
472 /* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
473 if (symbolic_traits & kCTFontBoldTrait) continue;
474 /* Select monospaced fonts if asked for. */
475 if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
476
477 /* Get font name. */
478 char name[128];
479 CFStringRef font_name = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute);
480 CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
481 CFRelease(font_name);
482
483 /* There are some special fonts starting with an '.' and the last
484 * resort font that aren't usable. Skip them. */
485 if (name[0] == '.' || strncmp(name, "LastResort", 10) == 0) continue;
486
487 /* Save result. */
488 callback->SetFontNames(settings, name);
489 if (!callback->FindMissingGlyphs(NULL)) {
490 DEBUG(freetype, 2, "CT-Font for %s: %s", language_isocode, name);
491 result = true;
492 break;
493 }
494 }
495 if (descs != NULL) CFRelease(descs);
496 } else
497 #endif
498 {
499 /* Create a font iterator and iterate over all fonts that
500 * are available to the application. */
501 ATSFontIterator itr;
502 ATSFontRef font;
503 ATSFontIteratorCreate(kATSFontContextLocal, NULL, NULL, kATSOptionFlagsDefaultScope, &itr);
504 while (!result && ATSFontIteratorNext(itr, &font) == noErr) {
505 /* Get font name. */
506 char name[128];
507 CFStringRef font_name;
508 ATSFontGetName(font, kATSOptionFlagsDefault, &font_name);
509 CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
510
511 bool monospace = IsMonospaceFont(font_name);
512 CFRelease(font_name);
513
514 /* Select monospaced fonts if asked for. */
515 if (monospace != callback->Monospace()) continue;
516
517 /* We only want the base font and not bold or italic variants. */
518 if (strstr(name, "Italic") != NULL || strstr(name, "Bold")) continue;
519
520 /* Skip some inappropriate or ugly looking fonts that have better alternatives. */
521 if (name[0] == '.' || strncmp(name, "Apple Symbols", 13) == 0 || strncmp(name, "LastResort", 10) == 0) continue;
522
523 /* Save result. */
524 callback->SetFontNames(settings, name);
525 if (!callback->FindMissingGlyphs(NULL)) {
526 DEBUG(freetype, 2, "ATS-Font for %s: %s", language_isocode, name);
527 result = true;
528 break;
529 }
530 }
531 ATSFontIteratorRelease(&itr);
532 }
533
534 if (!result) {
535 /* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
536 * supports. If we didn't find any other font, just try it, maybe we get lucky. */
537 callback->SetFontNames(settings, "Arial Unicode MS");
538 result = !callback->FindMissingGlyphs(NULL);
539 }
540
541 callback->FindMissingGlyphs(NULL);
542 return result;
543 }
544
545 #elif defined(WITH_FONTCONFIG) /* end ifdef __APPLE__ */
546
547 #include <fontconfig/fontconfig.h>
548
549 #include "safeguards.h"
550
551 /* ========================================================================================
552 * FontConfig (unix) support
553 * ======================================================================================== */
554 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
555 {
556 FT_Error err = FT_Err_Cannot_Open_Resource;
557
558 if (!FcInit()) {
559 ShowInfoF("Unable to load font configuration");
560 } else {
561 FcPattern *match;
562 FcPattern *pat;
563 FcFontSet *fs;
564 FcResult result;
565 char *font_style;
566 char *font_family;
567
568 /* Split & strip the font's style */
569 font_family = stredup(font_name);
570 font_style = strchr(font_family, ',');
571 if (font_style != NULL) {
572 font_style[0] = '\0';
573 font_style++;
574 while (*font_style == ' ' || *font_style == '\t') font_style++;
575 }
576
577 /* Resolve the name and populate the information structure */
578 pat = FcNameParse((FcChar8*)font_family);
579 if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style);
580 FcConfigSubstitute(0, pat, FcMatchPattern);
581 FcDefaultSubstitute(pat);
582 fs = FcFontSetCreate();
583 match = FcFontMatch(0, pat, &result);
584
585 if (fs != NULL && match != NULL) {
586 int i;
587 FcChar8 *family;
588 FcChar8 *style;
589 FcChar8 *file;
590 FcFontSetAdd(fs, match);
591
592 for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) {
593 /* Try the new filename */
594 if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch &&
595 FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch &&
596 FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) {
597
598 /* The correct style? */
599 if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue;
600
601 /* Font config takes the best shot, which, if the family name is spelled
602 * wrongly a 'random' font, so check whether the family name is the
603 * same as the supplied name */
604 if (strcasecmp(font_family, (char*)family) == 0) {
605 err = FT_New_Face(_library, (char *)file, 0, face);
606 }
607 }
608 }
609 }
610
611 free(font_family);
612 FcPatternDestroy(pat);
613 FcFontSetDestroy(fs);
614 FcFini();
615 }
616
617 return err;
618 }
619
620 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
621 {
622 if (!FcInit()) return false;
623
624 bool ret = false;
625
626 /* Fontconfig doesn't handle full language isocodes, only the part
627 * before the _ of e.g. en_GB is used, so "remove" everything after
628 * the _. */
629 char lang[16];
630 seprintf(lang, lastof(lang), ":lang=%s", language_isocode);
631 char *split = strchr(lang, '_');
632 if (split != NULL) *split = '\0';
633
634 /* First create a pattern to match the wanted language. */
635 FcPattern *pat = FcNameParse((FcChar8*)lang);
636 /* We only want to know the filename. */
637 FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_SPACING, FC_SLANT, FC_WEIGHT, NULL);
638 /* Get the list of filenames matching the wanted language. */
639 FcFontSet *fs = FcFontList(NULL, pat, os);
640
641 /* We don't need these anymore. */
642 FcObjectSetDestroy(os);
643 FcPatternDestroy(pat);
644
645 if (fs != NULL) {
646 int best_weight = -1;
647 const char *best_font = NULL;
648
649 for (int i = 0; i < fs->nfont; i++) {
650 FcPattern *font = fs->fonts[i];
651
652 FcChar8 *file = NULL;
653 FcResult res = FcPatternGetString(font, FC_FILE, 0, &file);
654 if (res != FcResultMatch || file == NULL) {
655 continue;
656 }
657
658 /* Get a font with the right spacing .*/
659 int value = 0;
660 FcPatternGetInteger(font, FC_SPACING, 0, &value);
661 if (callback->Monospace() != (value == FC_MONO) && value != FC_DUAL) continue;
662
663 /* Do not use those that explicitly say they're slanted. */
664 FcPatternGetInteger(font, FC_SLANT, 0, &value);
665 if (value != 0) continue;
666
667 /* We want the fatter font as they look better at small sizes. */
668 FcPatternGetInteger(font, FC_WEIGHT, 0, &value);
669 if (value <= best_weight) continue;
670
671 callback->SetFontNames(settings, (const char*)file);
672
673 bool missing = callback->FindMissingGlyphs(NULL);
674 DEBUG(freetype, 1, "Font \"%s\" misses%s glyphs", file, missing ? "" : " no");
675
676 if (!missing) {
677 best_weight = value;
678 best_font = (const char *)file;
679 }
680 }
681
682 if (best_font != NULL) {
683 ret = true;
684 callback->SetFontNames(settings, best_font);
685 InitFreeType(callback->Monospace());
686 }
687
688 /* Clean up the list of filenames. */
689 FcFontSetDestroy(fs);
690 }
691
692 FcFini();
693 return ret;
694 }
695
696 #else /* without WITH_FONTCONFIG */
697 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
698 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback) { return false; }
699 #endif /* WITH_FONTCONFIG */
700
701 #endif /* WITH_FREETYPE */
strings_func.h
Functions related to OTTD&#39;s strings.
seprintf
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Definition: string.cpp:398
debug.h
Functions related to debugging.
OTTDSHGetFolderPath
HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)
Our very own SHGetFolderPath function for support of windows operating systems that don&#39;t have this f...
Definition: win32.cpp:708
MacOSVersionIsAtLeast
static bool MacOSVersionIsAtLeast(long major, long minor, long bugfix)
Check if we are at least running on the specified version of Mac OS.
Definition: macos.h:27
fontdetection.h
Functions related to detecting/finding the right font.
MissingGlyphSearcher::Monospace
virtual bool Monospace()=0
Whether to search for a monospace font or not.
lastof
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:50
AllocaM
#define AllocaM(T, num_elements)
alloca() has to be called in the parent function, so define AllocaM() as a macro
Definition: alloc_func.hpp:134
convert_from_fs
char * convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
Convert to OpenTTD&#39;s encoding from that of the environment in UNICODE.
Definition: win32.cpp:646
FreeTypeSettings
Settings for the freetype fonts.
Definition: fontcache.h:204
InitFreeType
void InitFreeType(bool monospace)
(Re)initialize the freetype related things, i.e.
Definition: fontcache.cpp:643
ShowInfoF
void CDECL ShowInfoF(const char *str,...)
Shows some information on the console/a popup box depending on the OS.
Definition: openttd.cpp:130
string_func.h
Functions related to low-level strings.
alloc_func.hpp
Functions related to the allocation of memory.
MissingGlyphSearcher
A searcher for missing glyphs.
Definition: strings_func.h:246
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
safeguards.h
A number of safeguards to prevent using unsafe methods.
GetFontByFaceName
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
Get the font loaded into a Freetype face by using a font-name.
Definition: fontdetection.cpp:554
stredup
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
Definition: string.cpp:126
ReallocT
static T * ReallocT(T *t_ptr, size_t num_elements)
Simplified reallocation function that allocates the specified number of elements of the given type...
Definition: alloc_func.hpp:113
MissingGlyphSearcher::FindMissingGlyphs
bool FindMissingGlyphs(const char **str)
Check whether there are glyphs missing in the current language.
Definition: strings.cpp:2003
lengthof
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
min
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:42
OTTD2FS
const TCHAR * OTTD2FS(const char *name, bool console_cp)
Convert from OpenTTD&#39;s encoding to that of the local environment.
Definition: win32.cpp:631
math_func.hpp
Integer math functions.
SetFallbackFont
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
We would like to have a fallback font as the current one doesn&#39;t contain all characters we need...
Definition: fontdetection.cpp:620
DEBUG
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:39
strecpy
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
Definition: depend.cpp:68
PATH_MAX
#define PATH_MAX
The maximum length of paths, if we don&#39;t know it.
Definition: depend.cpp:121
MissingGlyphSearcher::SetFontNames
virtual void SetFontNames(struct FreeTypeSettings *settings, const char *font_name)=0
Set the right font names.
macos.h
Functions related to MacOS support.
free
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: depend.cpp:114
win32.h
declarations of functions for MS windows systems