00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "debug.h"
00008 #include "spritecache.h"
00009 #include "fontcache.h"
00010 #include "spriteloader/spriteloader.hpp"
00011 #include "blitter/factory.hpp"
00012 #include "gfx_func.h"
00013 #include "core/alloc_func.hpp"
00014 #include "core/math_func.hpp"
00015
00016 #include "table/sprites.h"
00017 #include "table/control_codes.h"
00018
00019 #ifdef WITH_FREETYPE
00020 #include <ft2build.h>
00021 #include FT_FREETYPE_H
00022 #include FT_GLYPH_H
00023
00024 #ifdef WITH_FONTCONFIG
00025 #include <fontconfig/fontconfig.h>
00026 #endif
00027
00028 static FT_Library _library = NULL;
00029 static FT_Face _face_small = NULL;
00030 static FT_Face _face_medium = NULL;
00031 static FT_Face _face_large = NULL;
00032
00033 FreeTypeSettings _freetype;
00034
00035 enum {
00036 FACE_COLOUR = 1,
00037 SHADOW_COLOUR = 2,
00038 };
00039
00042 #ifdef WIN32
00043 #include <windows.h>
00044 #include <tchar.h>
00045 #include <shlobj.h>
00046 #include "win32.h"
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 #define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
00057 #define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
00058 static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
00059 {
00060 FT_Error err = FT_Err_Cannot_Open_Resource;
00061 HKEY hKey;
00062 LONG ret;
00063 TCHAR vbuffer[MAX_PATH], dbuffer[256];
00064 TCHAR *font_namep;
00065 char *font_path;
00066 uint index;
00067
00068
00069
00070
00071 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
00072 if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
00073
00074 if (ret != ERROR_SUCCESS) {
00075 DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
00076 return err;
00077 }
00078
00079
00080
00081
00082 #if defined(UNICODE)
00083 font_namep = MallocT<TCHAR>(MAX_PATH);
00084 MB_TO_WIDE_BUFFER(font_name, font_namep, MAX_PATH * sizeof(TCHAR));
00085 #else
00086 font_namep = (char*)font_name;
00087 #endif
00088
00089 for (index = 0;; index++) {
00090 TCHAR *s;
00091 DWORD vbuflen = lengthof(vbuffer);
00092 DWORD dbuflen = lengthof(dbuffer);
00093
00094 ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen);
00095 if (ret != ERROR_SUCCESS) goto registry_no_font_found;
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 s = _tcschr(vbuffer, _T('('));
00107 if (s != NULL) s[-1] = '\0';
00108
00109 if (_tcschr(vbuffer, _T('&')) == NULL) {
00110 if (_tcsicmp(vbuffer, font_namep) == 0) break;
00111 } else {
00112 if (_tcsstr(vbuffer, font_namep) != NULL) break;
00113 }
00114 }
00115
00116 if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) {
00117 DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory");
00118 goto folder_error;
00119 }
00120
00121
00122
00123
00124
00125
00126 #if defined(UNICODE)
00127
00128
00129
00130 font_path = (char*)font_namep;
00131 WIDE_TO_MB_BUFFER(vbuffer, font_path, MAX_PATH * sizeof(TCHAR));
00132 #else
00133 font_path = vbuffer;
00134 #endif
00135
00136 ttd_strlcat(font_path, "\\", MAX_PATH * sizeof(TCHAR));
00137 ttd_strlcat(font_path, WIDE_TO_MB(dbuffer), MAX_PATH * sizeof(TCHAR));
00138 index = 0;
00139 do {
00140 err = FT_New_Face(_library, font_path, index, face);
00141 if (err != FT_Err_Ok) break;
00142
00143 if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
00144 err = FT_Err_Cannot_Open_Resource;
00145
00146 } while ((FT_Long)++index != (*face)->num_faces);
00147
00148
00149 folder_error:
00150 registry_no_font_found:
00151 #if defined(UNICODE)
00152 free(font_namep);
00153 #endif
00154 RegCloseKey(hKey);
00155 return err;
00156 }
00157 #else
00158 # ifdef WITH_FONTCONFIG
00159 static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
00160 {
00161 FT_Error err = FT_Err_Cannot_Open_Resource;
00162
00163 if (!FcInit()) {
00164 ShowInfoF("Unable to load font configuration");
00165 } else {
00166 FcPattern *match;
00167 FcPattern *pat;
00168 FcFontSet *fs;
00169 FcResult result;
00170 char *font_style;
00171 char *font_family;
00172
00173
00174 font_family = strdup(font_name);
00175 font_style = strchr(font_family, ',');
00176 if (font_style != NULL) {
00177 font_style[0] = '\0';
00178 font_style++;
00179 while (*font_style == ' ' || *font_style == '\t') font_style++;
00180 }
00181
00182
00183 pat = FcNameParse((FcChar8*)font_family);
00184 if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style);
00185 FcConfigSubstitute(0, pat, FcMatchPattern);
00186 FcDefaultSubstitute(pat);
00187 fs = FcFontSetCreate();
00188 match = FcFontMatch(0, pat, &result);
00189
00190 if (fs != NULL && match != NULL) {
00191 int i;
00192 FcChar8 *family;
00193 FcChar8 *style;
00194 FcChar8 *file;
00195 FcFontSetAdd(fs, match);
00196
00197 for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) {
00198
00199 if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch &&
00200 FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch &&
00201 FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) {
00202
00203
00204 if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue;
00205
00206
00207
00208
00209 if (strcasecmp(font_family, (char*)family) == 0) {
00210 err = FT_New_Face(_library, (char *)file, 0, face);
00211 }
00212 }
00213 }
00214 }
00215
00216 free(font_family);
00217 FcPatternDestroy(pat);
00218 FcFontSetDestroy(fs);
00219 FcFini();
00220 }
00221
00222 return err;
00223 }
00224 # else
00225 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
00226 # endif
00227
00228 #endif
00229
00236 static void LoadFreeTypeFont(const char *font_name, FT_Face *face, const char *type)
00237 {
00238 FT_Error error;
00239
00240 if (StrEmpty(font_name)) return;
00241
00242 error = FT_New_Face(_library, font_name, 0, face);
00243
00244 if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, face);
00245
00246 if (error == FT_Err_Ok) {
00247 DEBUG(freetype, 2, "Requested '%s', using '%s %s'", font_name, (*face)->family_name, (*face)->style_name);
00248
00249
00250 error = FT_Select_Charmap(*face, ft_encoding_unicode);
00251 if (error == FT_Err_Ok) return;
00252
00253 if (error == FT_Err_Invalid_CharMap_Handle) {
00254
00255
00256
00257 FT_CharMap found = (*face)->charmaps[0];
00258 int i;
00259
00260 for (i = 0; i < (*face)->num_charmaps; i++) {
00261 FT_CharMap charmap = (*face)->charmaps[i];
00262 if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
00263 found = charmap;
00264 }
00265 }
00266
00267 if (found != NULL) {
00268 error = FT_Set_Charmap(*face, found);
00269 if (error == FT_Err_Ok) return;
00270 }
00271 }
00272 }
00273
00274 FT_Done_Face(*face);
00275 *face = NULL;
00276
00277 ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name, type, error);
00278 }
00279
00280
00281 void InitFreeType()
00282 {
00283 if (StrEmpty(_freetype.small_font) && StrEmpty(_freetype.medium_font) && StrEmpty(_freetype.large_font)) {
00284 DEBUG(freetype, 1, "No font faces specified, using sprite fonts instead");
00285 return;
00286 }
00287
00288 if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
00289 ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
00290 return;
00291 }
00292
00293 DEBUG(freetype, 2, "Initialized");
00294
00295
00296 LoadFreeTypeFont(_freetype.small_font, &_face_small, "small");
00297 LoadFreeTypeFont(_freetype.medium_font, &_face_medium, "medium");
00298 LoadFreeTypeFont(_freetype.large_font, &_face_large, "large");
00299
00300
00301 if (_face_small != NULL) FT_Set_Pixel_Sizes(_face_small, 0, _freetype.small_size);
00302 if (_face_medium != NULL) FT_Set_Pixel_Sizes(_face_medium, 0, _freetype.medium_size);
00303 if (_face_large != NULL) FT_Set_Pixel_Sizes(_face_large, 0, _freetype.large_size);
00304 }
00305
00306
00307 static FT_Face GetFontFace(FontSize size)
00308 {
00309 switch (size) {
00310 default: NOT_REACHED();
00311 case FS_NORMAL: return _face_medium;
00312 case FS_SMALL: return _face_small;
00313 case FS_LARGE: return _face_large;
00314 }
00315 }
00316
00317
00318 struct GlyphEntry {
00319 Sprite *sprite;
00320 byte width;
00321 };
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 static GlyphEntry **_glyph_ptr[FS_END];
00337
00338
00339 static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
00340 {
00341 if (_glyph_ptr[size] == NULL) return NULL;
00342 if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) return NULL;
00343 return &_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)];
00344 }
00345
00346
00347 static void SetGlyphPtr(FontSize size, WChar key, const GlyphEntry *glyph)
00348 {
00349 if (_glyph_ptr[size] == NULL) {
00350 DEBUG(freetype, 3, "Allocating root glyph cache for size %u", size);
00351 _glyph_ptr[size] = CallocT<GlyphEntry*>(256);
00352 }
00353
00354 if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) {
00355 DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), size);
00356 _glyph_ptr[size][GB(key, 8, 8)] = CallocT<GlyphEntry>(256);
00357 }
00358
00359 DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, size);
00360 _glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
00361 _glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width;
00362 }
00363
00364 void *AllocateFont(size_t size)
00365 {
00366 return MallocT<byte>(size);
00367 }
00368
00369
00370
00371 static bool GetFontAAState(FontSize size)
00372 {
00373
00374 if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
00375
00376 switch (size) {
00377 default: NOT_REACHED();
00378 case FS_NORMAL: return _freetype.medium_aa;
00379 case FS_SMALL: return _freetype.small_aa;
00380 case FS_LARGE: return _freetype.large_aa;
00381 }
00382 }
00383
00384
00385 const Sprite *GetGlyph(FontSize size, WChar key)
00386 {
00387 FT_Face face = GetFontFace(size);
00388 FT_GlyphSlot slot;
00389 GlyphEntry new_glyph;
00390 GlyphEntry *glyph;
00391 SpriteLoader::Sprite sprite;
00392 int width;
00393 int height;
00394 int x;
00395 int y;
00396 int y_adj;
00397
00398 assert(IsPrintable(key));
00399
00400
00401 if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
00402 SpriteID sprite = GetUnicodeGlyph(size, key);
00403 if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
00404 return GetSprite(sprite);
00405 }
00406
00407
00408 glyph = GetGlyphPtr(size, key);
00409 if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
00410
00411 slot = face->glyph;
00412
00413 bool aa = GetFontAAState(size);
00414
00415 FT_Load_Char(face, key, FT_LOAD_DEFAULT);
00416 FT_Render_Glyph(face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
00417
00418
00419 aa = (slot->bitmap.palette_mode == FT_PIXEL_MODE_GRAY);
00420
00421
00422 width = max(1, slot->bitmap.width + (size == FS_NORMAL));
00423 height = max(1, slot->bitmap.rows + (size == FS_NORMAL));
00424
00425
00426 sprite.data = CallocT<SpriteLoader::CommonPixel>(width * height);
00427 sprite.width = width;
00428 sprite.height = height;
00429 sprite.x_offs = slot->bitmap_left;
00430
00431 y_adj = (size == FS_NORMAL) ? 2 : 0;
00432 sprite.y_offs = GetCharacterHeight(size) - slot->bitmap_top - y_adj;
00433
00434
00435 if (size == FS_NORMAL) {
00436 for (y = 0; y < slot->bitmap.rows; y++) {
00437 for (x = 0; x < slot->bitmap.width; x++) {
00438 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
00439 sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR;
00440 sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
00441 }
00442 }
00443 }
00444 }
00445
00446 for (y = 0; y < slot->bitmap.rows; y++) {
00447 for (x = 0; x < slot->bitmap.width; x++) {
00448 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
00449 sprite.data[x + y * sprite.width].m = FACE_COLOUR;
00450 sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
00451 }
00452 }
00453 }
00454
00455 new_glyph.sprite = BlitterFactoryBase::GetCurrentBlitter()->Encode(&sprite, AllocateFont);
00456 free(sprite.data);
00457 new_glyph.width = (slot->advance.x >> 6) + (size != FS_NORMAL);
00458
00459 SetGlyphPtr(size, key, &new_glyph);
00460
00461 return new_glyph.sprite;
00462 }
00463
00464
00465 uint GetGlyphWidth(FontSize size, WChar key)
00466 {
00467 FT_Face face = GetFontFace(size);
00468 GlyphEntry *glyph;
00469
00470 if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
00471 SpriteID sprite = GetUnicodeGlyph(size, key);
00472 if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
00473 return SpriteExists(sprite) ? GetSprite(sprite)->width + (size != FS_NORMAL) : 0;
00474 }
00475
00476 glyph = GetGlyphPtr(size, key);
00477 if (glyph == NULL || glyph->sprite == NULL) {
00478 GetGlyph(size, key);
00479 glyph = GetGlyphPtr(size, key);
00480 }
00481
00482 return glyph->width;
00483 }
00484
00485
00486 #endif
00487
00488
00489
00490 #include "table/unicode.h"
00491
00492 static SpriteID **_unicode_glyph_map[FS_END];
00493
00494
00496 static SpriteID GetFontBase(FontSize size)
00497 {
00498 switch (size) {
00499 default: NOT_REACHED();
00500 case FS_NORMAL: return SPR_ASCII_SPACE;
00501 case FS_SMALL: return SPR_ASCII_SPACE_SMALL;
00502 case FS_LARGE: return SPR_ASCII_SPACE_BIG;
00503 }
00504 }
00505
00506
00507 SpriteID GetUnicodeGlyph(FontSize size, uint32 key)
00508 {
00509 if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) return 0;
00510 return _unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)];
00511 }
00512
00513
00514 void SetUnicodeGlyph(FontSize size, uint32 key, SpriteID sprite)
00515 {
00516 if (_unicode_glyph_map[size] == NULL) _unicode_glyph_map[size] = CallocT<SpriteID*>(256);
00517 if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) _unicode_glyph_map[size][GB(key, 8, 8)] = CallocT<SpriteID>(256);
00518 _unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
00519 }
00520
00521
00522 void InitializeUnicodeGlyphMap()
00523 {
00524 for (FontSize size = FS_NORMAL; size != FS_END; size++) {
00525
00526 if (_unicode_glyph_map[size] != NULL) {
00527 for (uint i = 0; i < 256; i++) {
00528 if (_unicode_glyph_map[size][i] != NULL) free(_unicode_glyph_map[size][i]);
00529 }
00530 free(_unicode_glyph_map[size]);
00531 _unicode_glyph_map[size] = NULL;
00532 }
00533
00534 SpriteID base = GetFontBase(size);
00535
00536 for (uint i = ASCII_LETTERSTART; i < 256; i++) {
00537 SpriteID sprite = base + i - ASCII_LETTERSTART;
00538 if (!SpriteExists(sprite)) continue;
00539 SetUnicodeGlyph(size, i, sprite);
00540 SetUnicodeGlyph(size, i + SCC_SPRITE_START, sprite);
00541 }
00542
00543 for (uint i = 0; i < lengthof(_default_unicode_map); i++) {
00544 byte key = _default_unicode_map[i].key;
00545 if (key == CLRA || key == CLRL) {
00546
00547
00548
00549 if (key == CLRA || size == FS_LARGE) {
00550 SetUnicodeGlyph(size, _default_unicode_map[i].code, 0);
00551 }
00552 } else {
00553 SpriteID sprite = base + key - ASCII_LETTERSTART;
00554 SetUnicodeGlyph(size, _default_unicode_map[i].code, sprite);
00555 }
00556 }
00557 }
00558 }