00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "fontcache.h"
00014 #include "fontdetection.h"
00015 #include "blitter/factory.hpp"
00016 #include "core/math_func.hpp"
00017 #include "core/smallmap_type.hpp"
00018 #include "strings_func.h"
00019 #include "zoom_type.h"
00020 #include "gfx_layout.h"
00021
00022 #include "table/sprites.h"
00023 #include "table/control_codes.h"
00024 #include "table/unicode.h"
00025
00026 static const int ASCII_LETTERSTART = 32;
00027 static const int MAX_FONT_SIZE = 72;
00028
00030 static const int _default_font_height[FS_END] = {10, 6, 18, 10};
00031 static const int _default_font_ascender[FS_END] = { 8, 5, 15, 8};
00032
00037 FontCache::FontCache(FontSize fs) : parent(FontCache::Get(fs)), fs(fs), height(_default_font_height[fs]),
00038 ascender(_default_font_ascender[fs]), descender(_default_font_ascender[fs] - _default_font_height[fs]),
00039 units_per_em(1)
00040 {
00041 assert(parent == NULL || this->fs == parent->fs);
00042 FontCache::caches[this->fs] = this;
00043 Layouter::ResetFontCache(this->fs);
00044 }
00045
00047 FontCache::~FontCache()
00048 {
00049 assert(this->fs == parent->fs);
00050 FontCache::caches[this->fs] = this->parent;
00051 Layouter::ResetFontCache(this->fs);
00052 }
00053
00054
00060 int GetCharacterHeight(FontSize size)
00061 {
00062 return FontCache::Get(size)->GetHeight();
00063 }
00064
00065
00067 class SpriteFontCache : public FontCache {
00068 private:
00069 SpriteID **glyph_to_spriteid_map;
00070
00071 void ClearGlyphToSpriteMap();
00072 public:
00073 SpriteFontCache(FontSize fs);
00074 ~SpriteFontCache();
00075 virtual SpriteID GetUnicodeGlyph(WChar key);
00076 virtual void SetUnicodeGlyph(WChar key, SpriteID sprite);
00077 virtual void InitializeUnicodeGlyphMap();
00078 virtual void ClearFontCache();
00079 virtual const Sprite *GetGlyph(GlyphID key);
00080 virtual uint GetGlyphWidth(GlyphID key);
00081 virtual bool GetDrawGlyphShadow();
00082 virtual GlyphID MapCharToGlyph(WChar key) { assert(IsPrintable(key)); return SPRITE_GLYPH | key; }
00083 virtual const void *GetFontTable(uint32 tag, size_t &length) { length = 0; return NULL; }
00084 virtual const char *GetFontName() { return "sprite"; }
00085 };
00086
00091 SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid_map(NULL)
00092 {
00093 this->InitializeUnicodeGlyphMap();
00094 }
00095
00099 SpriteFontCache::~SpriteFontCache()
00100 {
00101 this->ClearGlyphToSpriteMap();
00102 }
00103
00104 SpriteID SpriteFontCache::GetUnicodeGlyph(GlyphID key)
00105 {
00106 if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == NULL) return 0;
00107 return this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)];
00108 }
00109
00110 void SpriteFontCache::SetUnicodeGlyph(GlyphID key, SpriteID sprite)
00111 {
00112 if (this->glyph_to_spriteid_map == NULL) this->glyph_to_spriteid_map = CallocT<SpriteID*>(256);
00113 if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == NULL) this->glyph_to_spriteid_map[GB(key, 8, 8)] = CallocT<SpriteID>(256);
00114 this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
00115 }
00116
00117 void SpriteFontCache::InitializeUnicodeGlyphMap()
00118 {
00119
00120 this->ClearGlyphToSpriteMap();
00121
00122 SpriteID base;
00123 switch (this->fs) {
00124 default: NOT_REACHED();
00125 case FS_MONO:
00126 case FS_NORMAL: base = SPR_ASCII_SPACE; break;
00127 case FS_SMALL: base = SPR_ASCII_SPACE_SMALL; break;
00128 case FS_LARGE: base = SPR_ASCII_SPACE_BIG; break;
00129 }
00130
00131 for (uint i = ASCII_LETTERSTART; i < 256; i++) {
00132 SpriteID sprite = base + i - ASCII_LETTERSTART;
00133 if (!SpriteExists(sprite)) continue;
00134 this->SetUnicodeGlyph(i, sprite);
00135 this->SetUnicodeGlyph(i + SCC_SPRITE_START, sprite);
00136 }
00137
00138 for (uint i = 0; i < lengthof(_default_unicode_map); i++) {
00139 byte key = _default_unicode_map[i].key;
00140 if (key == CLRA) {
00141
00142
00143
00144 this->SetUnicodeGlyph(_default_unicode_map[i].code, 0);
00145 } else {
00146 SpriteID sprite = base + key - ASCII_LETTERSTART;
00147 this->SetUnicodeGlyph(_default_unicode_map[i].code, sprite);
00148 }
00149 }
00150 }
00151
00155 void SpriteFontCache::ClearGlyphToSpriteMap()
00156 {
00157 if (this->glyph_to_spriteid_map == NULL) return;
00158
00159 for (uint i = 0; i < 256; i++) {
00160 free(this->glyph_to_spriteid_map[i]);
00161 }
00162 free(this->glyph_to_spriteid_map);
00163 this->glyph_to_spriteid_map = NULL;
00164 }
00165
00166 void SpriteFontCache::ClearFontCache()
00167 {
00168 Layouter::ResetFontCache(this->fs);
00169 }
00170
00171 const Sprite *SpriteFontCache::GetGlyph(GlyphID key)
00172 {
00173 SpriteID sprite = this->GetUnicodeGlyph(key);
00174 if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
00175 return GetSprite(sprite, ST_FONT);
00176 }
00177
00178 uint SpriteFontCache::GetGlyphWidth(GlyphID key)
00179 {
00180 SpriteID sprite = this->GetUnicodeGlyph(key);
00181 if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
00182 return SpriteExists(sprite) ? GetSprite(sprite, ST_FONT)->width + (this->fs != FS_NORMAL) : 0;
00183 }
00184
00185 bool SpriteFontCache::GetDrawGlyphShadow()
00186 {
00187 return false;
00188 }
00189
00190 FontCache *FontCache::caches[FS_END] = { new SpriteFontCache(FS_NORMAL), new SpriteFontCache(FS_SMALL), new SpriteFontCache(FS_LARGE), new SpriteFontCache(FS_MONO) };
00191
00192 #ifdef WITH_FREETYPE
00193 #include <ft2build.h>
00194 #include FT_FREETYPE_H
00195 #include FT_GLYPH_H
00196 #include FT_TRUETYPE_TABLES_H
00197
00199 class FreeTypeFontCache : public FontCache {
00200 private:
00201 FT_Face face;
00202
00203 typedef SmallMap<uint32, SmallPair<size_t, const void*> > FontTable;
00204 FontTable font_tables;
00205
00207 struct GlyphEntry {
00208 Sprite *sprite;
00209 byte width;
00210 bool duplicate;
00211 };
00212
00226 GlyphEntry **glyph_to_sprite;
00227
00228 GlyphEntry *GetGlyphPtr(GlyphID key);
00229 void SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate = false);
00230
00231 public:
00232 FreeTypeFontCache(FontSize fs, FT_Face face, int pixels);
00233 ~FreeTypeFontCache();
00234 virtual SpriteID GetUnicodeGlyph(WChar key) { return this->parent->GetUnicodeGlyph(key); }
00235 virtual void SetUnicodeGlyph(WChar key, SpriteID sprite) { this->parent->SetUnicodeGlyph(key, sprite); }
00236 virtual void InitializeUnicodeGlyphMap() { this->parent->InitializeUnicodeGlyphMap(); }
00237 virtual void ClearFontCache();
00238 virtual const Sprite *GetGlyph(GlyphID key);
00239 virtual uint GetGlyphWidth(GlyphID key);
00240 virtual bool GetDrawGlyphShadow();
00241 virtual GlyphID MapCharToGlyph(WChar key);
00242 virtual const void *GetFontTable(uint32 tag, size_t &length);
00243 virtual const char *GetFontName() { return face->family_name; }
00244 };
00245
00246 FT_Library _library = NULL;
00247
00248 FreeTypeSettings _freetype;
00249
00250 static const byte FACE_COLOUR = 1;
00251 static const byte SHADOW_COLOUR = 2;
00252
00259 FreeTypeFontCache::FreeTypeFontCache(FontSize fs, FT_Face face, int pixels) : FontCache(fs), face(face), glyph_to_sprite(NULL)
00260 {
00261 assert(face != NULL);
00262
00263 if (pixels == 0) {
00264
00265 pixels = _default_font_height[this->fs];
00266
00267 TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head);
00268 if (head != NULL) {
00269
00270
00271 int diff = _default_font_height[this->fs] - _default_font_height[FS_SMALL];
00272 pixels = Clamp(min(head->Lowest_Rec_PPEM, 20) + diff, _default_font_height[this->fs], MAX_FONT_SIZE);
00273 }
00274 }
00275
00276 FT_Error err = FT_Set_Pixel_Sizes(this->face, 0, pixels);
00277 if (err == FT_Err_Invalid_Pixel_Size) {
00278
00279
00280 FT_Bitmap_Size *bs = this->face->available_sizes;
00281 int i = this->face->num_fixed_sizes;
00282 int n = bs->height;
00283 for (; --i; bs++) {
00284 if (abs(pixels - bs->height) < abs(pixels - n)) n = bs->height;
00285 }
00286
00287 FT_Set_Pixel_Sizes(this->face, 0, n);
00288 }
00289
00290 this->units_per_em = this->face->units_per_EM;
00291 this->ascender = this->face->size->metrics.ascender >> 6;
00292 this->descender = this->face->size->metrics.descender >> 6;
00293 this->height = this->ascender - this->descender;
00294 }
00295
00303 static void LoadFreeTypeFont(FontSize fs)
00304 {
00305 FreeTypeSubSetting *settings = NULL;
00306 switch (fs) {
00307 default: NOT_REACHED();
00308 case FS_SMALL: settings = &_freetype.small; break;
00309 case FS_NORMAL: settings = &_freetype.medium; break;
00310 case FS_LARGE: settings = &_freetype.large; break;
00311 case FS_MONO: settings = &_freetype.mono; break;
00312 }
00313
00314 if (StrEmpty(settings->font)) return;
00315
00316 if (_library == NULL) {
00317 if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
00318 ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
00319 return;
00320 }
00321
00322 DEBUG(freetype, 2, "Initialized");
00323 }
00324
00325 FT_Face face = NULL;
00326 FT_Error error = FT_New_Face(_library, settings->font, 0, &face);
00327
00328 if (error != FT_Err_Ok) error = GetFontByFaceName(settings->font, &face);
00329
00330 if (error == FT_Err_Ok) {
00331 DEBUG(freetype, 2, "Requested '%s', using '%s %s'", settings->font, face->family_name, face->style_name);
00332
00333
00334 error = FT_Select_Charmap(face, ft_encoding_unicode);
00335 if (error == FT_Err_Ok) goto found_face;
00336
00337 if (error == FT_Err_Invalid_CharMap_Handle) {
00338
00339
00340
00341 FT_CharMap found = face->charmaps[0];
00342 int i;
00343
00344 for (i = 0; i < face->num_charmaps; i++) {
00345 FT_CharMap charmap = face->charmaps[i];
00346 if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
00347 found = charmap;
00348 }
00349 }
00350
00351 if (found != NULL) {
00352 error = FT_Set_Charmap(face, found);
00353 if (error == FT_Err_Ok) goto found_face;
00354 }
00355 }
00356 }
00357
00358 FT_Done_Face(face);
00359
00360 static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" };
00361 ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings->font, SIZE_TO_NAME[fs], error);
00362 return;
00363
00364 found_face:
00365 new FreeTypeFontCache(fs, face, settings->size);
00366 }
00367
00368
00372 FreeTypeFontCache::~FreeTypeFontCache()
00373 {
00374 FT_Done_Face(this->face);
00375 this->ClearFontCache();
00376
00377 for (FontTable::iterator iter = this->font_tables.Begin(); iter != this->font_tables.End(); iter++) {
00378 free(iter->second.second);
00379 }
00380 }
00381
00385 void FreeTypeFontCache::ClearFontCache()
00386 {
00387 if (this->glyph_to_sprite == NULL) return;
00388
00389 for (int i = 0; i < 256; i++) {
00390 if (this->glyph_to_sprite[i] == NULL) continue;
00391
00392 for (int j = 0; j < 256; j++) {
00393 if (this->glyph_to_sprite[i][j].duplicate) continue;
00394 free(this->glyph_to_sprite[i][j].sprite);
00395 }
00396
00397 free(this->glyph_to_sprite[i]);
00398 }
00399
00400 free(this->glyph_to_sprite);
00401 this->glyph_to_sprite = NULL;
00402
00403 Layouter::ResetFontCache(this->fs);
00404 }
00405
00406 FreeTypeFontCache::GlyphEntry *FreeTypeFontCache::GetGlyphPtr(GlyphID key)
00407 {
00408 if (this->glyph_to_sprite == NULL) return NULL;
00409 if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) return NULL;
00410 return &this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)];
00411 }
00412
00413
00414 void FreeTypeFontCache::SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate)
00415 {
00416 if (this->glyph_to_sprite == NULL) {
00417 DEBUG(freetype, 3, "Allocating root glyph cache for size %u", this->fs);
00418 this->glyph_to_sprite = CallocT<GlyphEntry*>(256);
00419 }
00420
00421 if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) {
00422 DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), this->fs);
00423 this->glyph_to_sprite[GB(key, 8, 8)] = CallocT<GlyphEntry>(256);
00424 }
00425
00426 DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, this->fs);
00427 this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
00428 this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width;
00429 this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].duplicate = duplicate;
00430 }
00431
00432 static void *AllocateFont(size_t size)
00433 {
00434 return MallocT<byte>(size);
00435 }
00436
00437
00438
00439 static bool GetFontAAState(FontSize size)
00440 {
00441
00442 if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
00443
00444 switch (size) {
00445 default: NOT_REACHED();
00446 case FS_NORMAL: return _freetype.medium.aa;
00447 case FS_SMALL: return _freetype.small.aa;
00448 case FS_LARGE: return _freetype.large.aa;
00449 case FS_MONO: return _freetype.mono.aa;
00450 }
00451 }
00452
00453
00454 const Sprite *FreeTypeFontCache::GetGlyph(GlyphID key)
00455 {
00456 if ((key & SPRITE_GLYPH) != 0) return parent->GetGlyph(key);
00457
00458
00459 GlyphEntry *glyph = this->GetGlyphPtr(key);
00460 if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
00461
00462 FT_GlyphSlot slot = this->face->glyph;
00463
00464 bool aa = GetFontAAState(this->fs);
00465
00466 GlyphEntry new_glyph;
00467 if (key == 0) {
00468 GlyphID question_glyph = this->MapCharToGlyph('?');
00469 if (question_glyph == 0) {
00470
00471
00472 #define CPSET { 0, 0, 0, 0, 1 }
00473 #define CP___ { 0, 0, 0, 0, 0 }
00474 static SpriteLoader::CommonPixel builtin_questionmark_data[10 * 8] = {
00475 CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___,
00476 CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___,
00477 CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___,
00478 CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___,
00479 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
00480 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
00481 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
00482 CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___,
00483 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
00484 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
00485 };
00486 #undef CPSET
00487 #undef CP___
00488 static const SpriteLoader::Sprite builtin_questionmark = {
00489 10,
00490 8,
00491 0,
00492 0,
00493 ST_FONT,
00494 builtin_questionmark_data
00495 };
00496
00497 Sprite *spr = BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark, AllocateFont);
00498 assert(spr != NULL);
00499 new_glyph.sprite = spr;
00500 new_glyph.width = spr->width + (this->fs != FS_NORMAL);
00501 this->SetGlyphPtr(key, &new_glyph, false);
00502 return new_glyph.sprite;
00503 } else {
00504
00505 this->GetGlyph(question_glyph);
00506 glyph = this->GetGlyphPtr(question_glyph);
00507 this->SetGlyphPtr(key, glyph, true);
00508 return glyph->sprite;
00509 }
00510 }
00511 FT_Load_Glyph(this->face, key, FT_LOAD_DEFAULT);
00512 FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
00513
00514
00515 aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
00516
00517
00518 int width = max(1, slot->bitmap.width + (this->fs == FS_NORMAL));
00519 int height = max(1, slot->bitmap.rows + (this->fs == FS_NORMAL));
00520
00521
00522 if (width > 256 || height > 256) usererror("Font glyph is too large");
00523
00524
00525 SpriteLoader::Sprite sprite;
00526 sprite.AllocateData(ZOOM_LVL_NORMAL, width * height);
00527 sprite.type = ST_FONT;
00528 sprite.width = width;
00529 sprite.height = height;
00530 sprite.x_offs = slot->bitmap_left;
00531 sprite.y_offs = this->ascender - slot->bitmap_top;
00532
00533
00534 if (this->fs == FS_NORMAL && !aa) {
00535 for (int y = 0; y < slot->bitmap.rows; y++) {
00536 for (int x = 0; x < slot->bitmap.width; x++) {
00537 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
00538 sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR;
00539 sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
00540 }
00541 }
00542 }
00543 }
00544
00545 for (int y = 0; y < slot->bitmap.rows; y++) {
00546 for (int x = 0; x < slot->bitmap.width; x++) {
00547 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
00548 sprite.data[x + y * sprite.width].m = FACE_COLOUR;
00549 sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
00550 }
00551 }
00552 }
00553
00554 new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, AllocateFont);
00555 new_glyph.width = slot->advance.x >> 6;
00556
00557 this->SetGlyphPtr(key, &new_glyph);
00558
00559 return new_glyph.sprite;
00560 }
00561
00562
00563 bool FreeTypeFontCache::GetDrawGlyphShadow()
00564 {
00565 return this->fs == FS_NORMAL && GetFontAAState(FS_NORMAL);
00566 }
00567
00568
00569 uint FreeTypeFontCache::GetGlyphWidth(GlyphID key)
00570 {
00571 if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyphWidth(key);
00572
00573 GlyphEntry *glyph = this->GetGlyphPtr(key);
00574 if (glyph == NULL || glyph->sprite == NULL) {
00575 this->GetGlyph(key);
00576 glyph = this->GetGlyphPtr(key);
00577 }
00578
00579 return glyph->width;
00580 }
00581
00582 GlyphID FreeTypeFontCache::MapCharToGlyph(WChar key)
00583 {
00584 assert(IsPrintable(key));
00585
00586 if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
00587 return this->parent->MapCharToGlyph(key);
00588 }
00589
00590 return FT_Get_Char_Index(this->face, key);
00591 }
00592
00593 const void *FreeTypeFontCache::GetFontTable(uint32 tag, size_t &length)
00594 {
00595 const FontTable::iterator iter = this->font_tables.Find(tag);
00596 if (iter != this->font_tables.End()) {
00597 length = iter->second.first;
00598 return iter->second.second;
00599 }
00600
00601 FT_ULong len = 0;
00602 FT_Byte *result = NULL;
00603
00604 FT_Load_Sfnt_Table(this->face, tag, 0, NULL, &len);
00605
00606 if (len > 0) {
00607 result = MallocT<FT_Byte>(len);
00608 FT_Load_Sfnt_Table(this->face, tag, 0, result, &len);
00609 }
00610 length = len;
00611
00612 this->font_tables.Insert(tag, SmallPair<size_t, const void *>(length, result));
00613 return result;
00614 }
00615
00616 #endif
00617
00622 void InitFreeType(bool monospace)
00623 {
00624 for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
00625 if (monospace != (fs == FS_MONO)) continue;
00626
00627 FontCache *fc = FontCache::Get(fs);
00628 if (fc->HasParent()) delete fc;
00629
00630 #ifdef WITH_FREETYPE
00631 LoadFreeTypeFont(fs);
00632 #endif
00633 }
00634 }
00635
00639 void UninitFreeType()
00640 {
00641 for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
00642 FontCache *fc = FontCache::Get(fs);
00643 if (fc->HasParent()) delete fc;
00644 }
00645
00646 #ifdef WITH_FREETYPE
00647 FT_Done_FreeType(_library);
00648 _library = NULL;
00649 #endif
00650 }