00001
00002
00005 #include "stdafx.h"
00006 #include "spritecache.h"
00007 #include "fontcache.h"
00008 #include "blitter/factory.hpp"
00009 #include "gfx_func.h"
00010 #include "core/alloc_func.hpp"
00011 #include "core/math_func.hpp"
00012
00013 #include "table/sprites.h"
00014 #include "table/control_codes.h"
00015
00016 #ifdef WITH_FREETYPE
00017 #include <ft2build.h>
00018 #include FT_FREETYPE_H
00019 #include FT_GLYPH_H
00020
00021 #ifdef WITH_FONTCONFIG
00022 #include <fontconfig/fontconfig.h>
00023 #endif
00024
00025 static FT_Library _library = NULL;
00026 static FT_Face _face_small = NULL;
00027 static FT_Face _face_medium = NULL;
00028 static FT_Face _face_large = NULL;
00029
00030 FreeTypeSettings _freetype;
00031
00032 enum {
00033 FACE_COLOUR = 1,
00034 SHADOW_COLOUR = 2,
00035 };
00036
00039 #ifdef WIN32
00040 #include <windows.h>
00041 #include <tchar.h>
00042 #include <shlobj.h>
00043 #include "win32.h"
00044
00055 char *GetShortPath(const char *long_path)
00056 {
00057 static char short_path[MAX_PATH];
00058 #ifdef UNICODE
00059
00060
00061
00062 wchar_t long_path_w[MAX_PATH];
00063 MultiByteToWideChar(CP_UTF8, 0, long_path, -1, long_path_w, MAX_PATH);
00064
00065 wchar_t short_path_w[MAX_PATH];
00066 GetShortPathNameW(long_path_w, short_path_w, MAX_PATH);
00067
00068 WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, MAX_PATH, NULL, NULL);
00069 #else
00070
00071 GetShortPathNameA(long_path, short_path, MAX_PATH);
00072 #endif
00073 return short_path;
00074 }
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 #define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
00085 #define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
00086 static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
00087 {
00088 FT_Error err = FT_Err_Cannot_Open_Resource;
00089 HKEY hKey;
00090 LONG ret;
00091 TCHAR vbuffer[MAX_PATH], dbuffer[256];
00092 TCHAR *font_namep;
00093 char *font_path;
00094 uint index;
00095
00096
00097
00098
00099 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
00100 if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
00101
00102 if (ret != ERROR_SUCCESS) {
00103 DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
00104 return err;
00105 }
00106
00107
00108
00109
00110 #if defined(UNICODE)
00111 font_namep = MallocT<TCHAR>(MAX_PATH);
00112 MB_TO_WIDE_BUFFER(font_name, font_namep, MAX_PATH * sizeof(TCHAR));
00113 #else
00114 font_namep = (char*)font_name;
00115 #endif
00116
00117 for (index = 0;; index++) {
00118 TCHAR *s;
00119 DWORD vbuflen = lengthof(vbuffer);
00120 DWORD dbuflen = lengthof(dbuffer);
00121
00122 ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen);
00123 if (ret != ERROR_SUCCESS) goto registry_no_font_found;
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134 s = _tcschr(vbuffer, _T('('));
00135 if (s != NULL) s[-1] = '\0';
00136
00137 if (_tcschr(vbuffer, _T('&')) == NULL) {
00138 if (_tcsicmp(vbuffer, font_namep) == 0) break;
00139 } else {
00140 if (_tcsstr(vbuffer, font_namep) != NULL) break;
00141 }
00142 }
00143
00144 if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) {
00145 DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory");
00146 goto folder_error;
00147 }
00148
00149
00150
00151
00152
00153
00154 #if defined(UNICODE)
00155
00156
00157
00158 font_path = (char*)font_namep;
00159 WIDE_TO_MB_BUFFER(vbuffer, font_path, MAX_PATH * sizeof(TCHAR));
00160 #else
00161 font_path = vbuffer;
00162 #endif
00163
00164 ttd_strlcat(font_path, "\\", MAX_PATH * sizeof(TCHAR));
00165 ttd_strlcat(font_path, WIDE_TO_MB(dbuffer), MAX_PATH * sizeof(TCHAR));
00166
00167
00168 font_path = GetShortPath(font_path);
00169
00170 index = 0;
00171 do {
00172 err = FT_New_Face(_library, font_path, index, face);
00173 if (err != FT_Err_Ok) break;
00174
00175 if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
00176 err = FT_Err_Cannot_Open_Resource;
00177
00178 } while ((FT_Long)++index != (*face)->num_faces);
00179
00180
00181 folder_error:
00182 registry_no_font_found:
00183 #if defined(UNICODE)
00184 free(font_namep);
00185 #endif
00186 RegCloseKey(hKey);
00187 return err;
00188 }
00189
00203 static const char *GetEnglishFontName(const ENUMLOGFONTEX *logfont)
00204 {
00205 static char font_name[MAX_PATH];
00206 const char *ret_font_name = NULL;
00207 uint pos = 0;
00208
00209 HFONT font = CreateFontIndirect(&logfont->elfLogFont);
00210 if (font == NULL) goto err1;
00211
00212 HDC dc = GetDC(NULL);
00213 HGDIOBJ oldfont = SelectObject(dc, font);
00214 DWORD dw = GetFontData(dc, 'eman', 0, NULL, 0);
00215 if (dw == GDI_ERROR) goto err2;
00216
00217 byte *buf = MallocT<byte>(dw);
00218 dw = GetFontData(dc, 'eman', 0, buf, dw);
00219 if (dw == GDI_ERROR) goto err3;
00220
00221 uint16 format = buf[pos++] << 8;
00222 format += buf[pos++];
00223 assert(format == 0);
00224 uint16 count = buf[pos++] << 8;
00225 count += buf[pos++];
00226 uint16 stringOffset = buf[pos++] << 8;
00227 stringOffset += buf[pos++];
00228 for (uint i = 0; i < count; i++) {
00229 uint16 platformId = buf[pos++] << 8;
00230 platformId += buf[pos++];
00231 uint16 encodingId = buf[pos++] << 8;
00232 encodingId += buf[pos++];
00233 uint16 languageId = buf[pos++] << 8;
00234 languageId += buf[pos++];
00235 uint16 nameId = buf[pos++] << 8;
00236 nameId += buf[pos++];
00237 if (nameId != 1) {
00238 pos += 4;
00239 continue;
00240 }
00241 uint16 length = buf[pos++] << 8;
00242 length += buf[pos++];
00243 uint16 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 err1:
00264 DeleteObject(font);
00265
00266 return ret_font_name == NULL ? WIDE_TO_MB((const TCHAR*)logfont->elfFullName) : ret_font_name;
00267 }
00268
00269 struct EFCParam {
00270 FreeTypeSettings *settings;
00271 LOCALESIGNATURE locale;
00272 };
00273
00274 static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
00275 {
00276 EFCParam *info = (EFCParam *)lParam;
00277
00278
00279 if (!(type & TRUETYPE_FONTTYPE)) return 1;
00280
00281 if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET) return 1;
00282
00283
00284 if ((metric->ntmFontSig.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) {
00285
00286 FONTSIGNATURE fs;
00287 memset(&fs, 0, sizeof(fs));
00288 HFONT font = CreateFontIndirect(&logfont->elfLogFont);
00289 if (font != NULL) {
00290 HDC dc = GetDC(NULL);
00291 HGDIOBJ oldfont = SelectObject(dc, font);
00292 GetTextCharsetInfo(dc, &fs, 0);
00293 SelectObject(dc, oldfont);
00294 ReleaseDC(NULL, dc);
00295 DeleteObject(font);
00296 }
00297 if ((fs.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (fs.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) return 1;
00298 }
00299
00300 const char *font_name = GetEnglishFontName(logfont);
00301 DEBUG(freetype, 1, "Fallback font: %s", font_name);
00302
00303 strecpy(info->settings->small_font, font_name, lastof(info->settings->small_font));
00304 strecpy(info->settings->medium_font, font_name, lastof(info->settings->medium_font));
00305 strecpy(info->settings->large_font, font_name, lastof(info->settings->large_font));
00306 return 0;
00307 }
00308
00309 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid)
00310 {
00311 EFCParam langInfo;
00312 if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPTSTR)&langInfo.locale, sizeof(langInfo.locale) / sizeof(TCHAR)) == 0) {
00313
00314 DEBUG(freetype, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid);
00315 return false;
00316 }
00317 langInfo.settings = settings;
00318
00319 LOGFONT font;
00320
00321 font.lfCharSet = DEFAULT_CHARSET;
00322 font.lfFaceName[0] = '\0';
00323 font.lfPitchAndFamily = 0;
00324
00325 HDC dc = GetDC(NULL);
00326 int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
00327 ReleaseDC(NULL, dc);
00328 return ret == 0;
00329 }
00330
00331 #elif defined(WITH_FONTCONFIG)
00332 static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
00333 {
00334 FT_Error err = FT_Err_Cannot_Open_Resource;
00335
00336 if (!FcInit()) {
00337 ShowInfoF("Unable to load font configuration");
00338 } else {
00339 FcPattern *match;
00340 FcPattern *pat;
00341 FcFontSet *fs;
00342 FcResult result;
00343 char *font_style;
00344 char *font_family;
00345
00346
00347 font_family = strdup(font_name);
00348 font_style = strchr(font_family, ',');
00349 if (font_style != NULL) {
00350 font_style[0] = '\0';
00351 font_style++;
00352 while (*font_style == ' ' || *font_style == '\t') font_style++;
00353 }
00354
00355
00356 pat = FcNameParse((FcChar8*)font_family);
00357 if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style);
00358 FcConfigSubstitute(0, pat, FcMatchPattern);
00359 FcDefaultSubstitute(pat);
00360 fs = FcFontSetCreate();
00361 match = FcFontMatch(0, pat, &result);
00362
00363 if (fs != NULL && match != NULL) {
00364 int i;
00365 FcChar8 *family;
00366 FcChar8 *style;
00367 FcChar8 *file;
00368 FcFontSetAdd(fs, match);
00369
00370 for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) {
00371
00372 if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch &&
00373 FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch &&
00374 FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) {
00375
00376
00377 if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue;
00378
00379
00380
00381
00382 if (strcasecmp(font_family, (char*)family) == 0) {
00383 err = FT_New_Face(_library, (char *)file, 0, face);
00384 }
00385 }
00386 }
00387 }
00388
00389 free(font_family);
00390 FcPatternDestroy(pat);
00391 FcFontSetDestroy(fs);
00392 FcFini();
00393 }
00394
00395 return err;
00396 }
00397
00398 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid)
00399 {
00400 if (!FcInit()) return false;
00401
00402 bool ret = false;
00403
00404
00405
00406
00407 char lang[16];
00408 strecpy(lang, language_isocode, lastof(lang));
00409 char *split = strchr(lang, '_');
00410 if (split != NULL) *split = '\0';
00411
00412 FcPattern *pat;
00413 FcPattern *match;
00414 FcResult result;
00415 FcChar8 *file;
00416 FcFontSet *fs;
00417 FcValue val;
00418 val.type = FcTypeString;
00419 val.u.s = (FcChar8*)lang;
00420
00421
00422 pat = FcPatternCreate();
00423
00424 if (pat == NULL ||
00425 !FcPatternAdd(pat, "lang", val, false) ||
00426 !FcConfigSubstitute(0, pat, FcMatchPattern)) {
00427 goto error_pattern;
00428 }
00429
00430 FcDefaultSubstitute(pat);
00431
00432
00433 match = FcFontMatch(0, pat, &result);
00434
00435 if (match == NULL) {
00436 goto error_pattern;
00437 }
00438
00439
00440 fs = FcFontSetCreate();
00441 FcFontSetAdd(fs, match);
00442
00443
00444 if (fs->nfont <= 0 || FcPatternGetString(fs->fonts[0], FC_FILE, 0, &file)) {
00445 goto error_fontset;
00446 }
00447
00448 strecpy(settings->small_font, (const char*)file, lastof(settings->small_font));
00449 strecpy(settings->medium_font, (const char*)file, lastof(settings->medium_font));
00450 strecpy(settings->large_font, (const char*)file, lastof(settings->large_font));
00451
00452 ret = true;
00453
00454 error_fontset:
00455 FcFontSetDestroy(fs);
00456 error_pattern:
00457 if (pat != NULL) FcPatternDestroy(pat);
00458 FcFini();
00459 return ret;
00460 }
00461
00462 #else
00463 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
00464 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid) { return false; }
00465 #endif
00466
00473 static void LoadFreeTypeFont(const char *font_name, FT_Face *face, const char *type)
00474 {
00475 FT_Error error;
00476
00477 if (StrEmpty(font_name)) return;
00478
00479 error = FT_New_Face(_library, font_name, 0, face);
00480
00481 if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, face);
00482
00483 if (error == FT_Err_Ok) {
00484 DEBUG(freetype, 2, "Requested '%s', using '%s %s'", font_name, (*face)->family_name, (*face)->style_name);
00485
00486
00487 error = FT_Select_Charmap(*face, ft_encoding_unicode);
00488 if (error == FT_Err_Ok) return;
00489
00490 if (error == FT_Err_Invalid_CharMap_Handle) {
00491
00492
00493
00494 FT_CharMap found = (*face)->charmaps[0];
00495 int i;
00496
00497 for (i = 0; i < (*face)->num_charmaps; i++) {
00498 FT_CharMap charmap = (*face)->charmaps[i];
00499 if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
00500 found = charmap;
00501 }
00502 }
00503
00504 if (found != NULL) {
00505 error = FT_Set_Charmap(*face, found);
00506 if (error == FT_Err_Ok) return;
00507 }
00508 }
00509 }
00510
00511 FT_Done_Face(*face);
00512 *face = NULL;
00513
00514 ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name, type, error);
00515 }
00516
00517
00518 void InitFreeType()
00519 {
00520 if (StrEmpty(_freetype.small_font) && StrEmpty(_freetype.medium_font) && StrEmpty(_freetype.large_font)) {
00521 DEBUG(freetype, 1, "No font faces specified, using sprite fonts instead");
00522 return;
00523 }
00524
00525 if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
00526 ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
00527 return;
00528 }
00529
00530 DEBUG(freetype, 2, "Initialized");
00531
00532
00533 LoadFreeTypeFont(_freetype.small_font, &_face_small, "small");
00534 LoadFreeTypeFont(_freetype.medium_font, &_face_medium, "medium");
00535 LoadFreeTypeFont(_freetype.large_font, &_face_large, "large");
00536
00537
00538 if (_face_small != NULL) FT_Set_Pixel_Sizes(_face_small, 0, _freetype.small_size);
00539 if (_face_medium != NULL) FT_Set_Pixel_Sizes(_face_medium, 0, _freetype.medium_size);
00540 if (_face_large != NULL) FT_Set_Pixel_Sizes(_face_large, 0, _freetype.large_size);
00541 }
00542
00543 static void ResetGlyphCache();
00544
00549 static void UnloadFace(FT_Face *face)
00550 {
00551 if (*face == NULL) return;
00552
00553 FT_Done_Face(*face);
00554 *face = NULL;
00555 }
00556
00560 void UninitFreeType()
00561 {
00562 ResetGlyphCache();
00563
00564 UnloadFace(&_face_small);
00565 UnloadFace(&_face_medium);
00566 UnloadFace(&_face_large);
00567
00568 FT_Done_FreeType(_library);
00569 _library = NULL;
00570 }
00571
00572
00573 static FT_Face GetFontFace(FontSize size)
00574 {
00575 switch (size) {
00576 default: NOT_REACHED();
00577 case FS_NORMAL: return _face_medium;
00578 case FS_SMALL: return _face_small;
00579 case FS_LARGE: return _face_large;
00580 }
00581 }
00582
00583
00584 struct GlyphEntry {
00585 Sprite *sprite;
00586 byte width;
00587 };
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 static GlyphEntry **_glyph_ptr[FS_END];
00603
00605 static void ResetGlyphCache()
00606 {
00607 for (int i = 0; i < FS_END; i++) {
00608 if (_glyph_ptr[i] == NULL) continue;
00609
00610 for (int j = 0; j < 256; j++) {
00611 if (_glyph_ptr[i][j] == NULL) continue;
00612
00613 for (int k = 0; k < 256; k++) {
00614 if (_glyph_ptr[i][j][k].sprite == NULL) continue;
00615 free(_glyph_ptr[i][j][k].sprite);
00616 }
00617
00618 free(_glyph_ptr[i][j]);
00619 }
00620
00621 free(_glyph_ptr[i]);
00622 _glyph_ptr[i] = NULL;
00623 }
00624 }
00625
00626 static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
00627 {
00628 if (_glyph_ptr[size] == NULL) return NULL;
00629 if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) return NULL;
00630 return &_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)];
00631 }
00632
00633
00634 static void SetGlyphPtr(FontSize size, WChar key, const GlyphEntry *glyph)
00635 {
00636 if (_glyph_ptr[size] == NULL) {
00637 DEBUG(freetype, 3, "Allocating root glyph cache for size %u", size);
00638 _glyph_ptr[size] = CallocT<GlyphEntry*>(256);
00639 }
00640
00641 if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) {
00642 DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), size);
00643 _glyph_ptr[size][GB(key, 8, 8)] = CallocT<GlyphEntry>(256);
00644 }
00645
00646 DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, size);
00647 _glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
00648 _glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width;
00649 }
00650
00651 void *AllocateFont(size_t size)
00652 {
00653 return MallocT<byte>(size);
00654 }
00655
00656
00657
00658 static bool GetFontAAState(FontSize size)
00659 {
00660
00661 if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
00662
00663 switch (size) {
00664 default: NOT_REACHED();
00665 case FS_NORMAL: return _freetype.medium_aa;
00666 case FS_SMALL: return _freetype.small_aa;
00667 case FS_LARGE: return _freetype.large_aa;
00668 }
00669 }
00670
00671
00672 const Sprite *GetGlyph(FontSize size, WChar key)
00673 {
00674 FT_Face face = GetFontFace(size);
00675 FT_GlyphSlot slot;
00676 GlyphEntry new_glyph;
00677 GlyphEntry *glyph;
00678 SpriteLoader::Sprite sprite;
00679 int width;
00680 int height;
00681 int x;
00682 int y;
00683 int y_adj;
00684
00685 assert(IsPrintable(key));
00686
00687
00688 if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
00689 SpriteID sprite = GetUnicodeGlyph(size, key);
00690 if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
00691 return GetSprite(sprite, ST_FONT);
00692 }
00693
00694
00695 glyph = GetGlyphPtr(size, key);
00696 if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
00697
00698 slot = face->glyph;
00699
00700 bool aa = GetFontAAState(size);
00701
00702 FT_Load_Char(face, key, FT_LOAD_DEFAULT);
00703 FT_Render_Glyph(face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
00704
00705
00706 aa = (slot->bitmap.palette_mode == FT_PIXEL_MODE_GRAY);
00707
00708
00709 width = max(1, slot->bitmap.width + (size == FS_NORMAL));
00710 height = max(1, slot->bitmap.rows + (size == FS_NORMAL));
00711
00712
00713 sprite.AllocateData(width * height);
00714 sprite.width = width;
00715 sprite.height = height;
00716 sprite.x_offs = slot->bitmap_left;
00717
00718 y_adj = (size == FS_NORMAL) ? 2 : 0;
00719 sprite.y_offs = GetCharacterHeight(size) - slot->bitmap_top - y_adj;
00720
00721
00722 if (size == FS_NORMAL) {
00723 for (y = 0; y < slot->bitmap.rows; y++) {
00724 for (x = 0; x < slot->bitmap.width; x++) {
00725 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
00726 sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR;
00727 sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
00728 }
00729 }
00730 }
00731 }
00732
00733 for (y = 0; y < slot->bitmap.rows; y++) {
00734 for (x = 0; x < slot->bitmap.width; x++) {
00735 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
00736 sprite.data[x + y * sprite.width].m = FACE_COLOUR;
00737 sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
00738 }
00739 }
00740 }
00741
00742 new_glyph.sprite = BlitterFactoryBase::GetCurrentBlitter()->Encode(&sprite, AllocateFont);
00743 new_glyph.width = (slot->advance.x >> 6) + (size != FS_NORMAL);
00744
00745 SetGlyphPtr(size, key, &new_glyph);
00746
00747 return new_glyph.sprite;
00748 }
00749
00750
00751 uint GetGlyphWidth(FontSize size, WChar key)
00752 {
00753 FT_Face face = GetFontFace(size);
00754 GlyphEntry *glyph;
00755
00756 if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
00757 SpriteID sprite = GetUnicodeGlyph(size, key);
00758 if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
00759 return SpriteExists(sprite) ? GetSprite(sprite, ST_FONT)->width + (size != FS_NORMAL) : 0;
00760 }
00761
00762 glyph = GetGlyphPtr(size, key);
00763 if (glyph == NULL || glyph->sprite == NULL) {
00764 GetGlyph(size, key);
00765 glyph = GetGlyphPtr(size, key);
00766 }
00767
00768 return glyph->width;
00769 }
00770
00771
00772 #endif
00773
00774
00775
00776 #include "table/unicode.h"
00777
00778 static SpriteID **_unicode_glyph_map[FS_END];
00779
00780
00782 static SpriteID GetFontBase(FontSize size)
00783 {
00784 switch (size) {
00785 default: NOT_REACHED();
00786 case FS_NORMAL: return SPR_ASCII_SPACE;
00787 case FS_SMALL: return SPR_ASCII_SPACE_SMALL;
00788 case FS_LARGE: return SPR_ASCII_SPACE_BIG;
00789 }
00790 }
00791
00792
00793 SpriteID GetUnicodeGlyph(FontSize size, uint32 key)
00794 {
00795 if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) return 0;
00796 return _unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)];
00797 }
00798
00799
00800 void SetUnicodeGlyph(FontSize size, uint32 key, SpriteID sprite)
00801 {
00802 if (_unicode_glyph_map[size] == NULL) _unicode_glyph_map[size] = CallocT<SpriteID*>(256);
00803 if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) _unicode_glyph_map[size][GB(key, 8, 8)] = CallocT<SpriteID>(256);
00804 _unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
00805 }
00806
00807
00808 void InitializeUnicodeGlyphMap()
00809 {
00810 for (FontSize size = FS_NORMAL; size != FS_END; size++) {
00811
00812 if (_unicode_glyph_map[size] != NULL) {
00813 for (uint i = 0; i < 256; i++) {
00814 if (_unicode_glyph_map[size][i] != NULL) free(_unicode_glyph_map[size][i]);
00815 }
00816 free(_unicode_glyph_map[size]);
00817 _unicode_glyph_map[size] = NULL;
00818 }
00819
00820 SpriteID base = GetFontBase(size);
00821
00822 for (uint i = ASCII_LETTERSTART; i < 256; i++) {
00823 SpriteID sprite = base + i - ASCII_LETTERSTART;
00824 if (!SpriteExists(sprite)) continue;
00825 SetUnicodeGlyph(size, i, sprite);
00826 SetUnicodeGlyph(size, i + SCC_SPRITE_START, sprite);
00827 }
00828
00829 for (uint i = 0; i < lengthof(_default_unicode_map); i++) {
00830 byte key = _default_unicode_map[i].key;
00831 if (key == CLRA || key == CLRL) {
00832
00833
00834
00835 if (key == CLRA || size == FS_LARGE) {
00836 SetUnicodeGlyph(size, _default_unicode_map[i].code, 0);
00837 }
00838 } else {
00839 SpriteID sprite = base + key - ASCII_LETTERSTART;
00840 SetUnicodeGlyph(size, _default_unicode_map[i].code, sprite);
00841 }
00842 }
00843 }
00844 }