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