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