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 const Sprite *SpriteFontCache::GetGlyph(GlyphID key)
00166 {
00167 SpriteID sprite = this->GetUnicodeGlyph(key);
00168 if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
00169 return GetSprite(sprite, ST_FONT);
00170 }
00171
00172 uint SpriteFontCache::GetGlyphWidth(GlyphID key)
00173 {
00174 SpriteID sprite = this->GetUnicodeGlyph(key);
00175 if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
00176 return SpriteExists(sprite) ? GetSprite(sprite, ST_FONT)->width + (this->fs != FS_NORMAL) : 0;
00177 }
00178
00179 bool SpriteFontCache::GetDrawGlyphShadow()
00180 {
00181 return false;
00182 }
00183
00184 FontCache *FontCache::caches[FS_END] = { new SpriteFontCache(FS_NORMAL), new SpriteFontCache(FS_SMALL), new SpriteFontCache(FS_LARGE), new SpriteFontCache(FS_MONO) };
00185
00186 #ifdef WITH_FREETYPE
00187 #include <ft2build.h>
00188 #include FT_FREETYPE_H
00189 #include FT_GLYPH_H
00190 #include FT_TRUETYPE_TABLES_H
00191
00193 class FreeTypeFontCache : public FontCache {
00194 private:
00195 FT_Face face;
00196
00197 typedef SmallMap<uint32, SmallPair<size_t, const void*> > FontTable;
00198 FontTable font_tables;
00199
00201 struct GlyphEntry {
00202 Sprite *sprite;
00203 byte width;
00204 bool duplicate;
00205 };
00206
00220 GlyphEntry **glyph_to_sprite;
00221
00222 GlyphEntry *GetGlyphPtr(GlyphID key);
00223 void SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate = false);
00224
00225 public:
00226 FreeTypeFontCache(FontSize fs, FT_Face face, int pixels);
00227 ~FreeTypeFontCache();
00228 virtual SpriteID GetUnicodeGlyph(WChar key) { return this->parent->GetUnicodeGlyph(key); }
00229 virtual void SetUnicodeGlyph(WChar key, SpriteID sprite) { this->parent->SetUnicodeGlyph(key, sprite); }
00230 virtual void InitializeUnicodeGlyphMap() { this->parent->InitializeUnicodeGlyphMap(); }
00231 virtual void ClearFontCache();
00232 virtual const Sprite *GetGlyph(GlyphID key);
00233 virtual uint GetGlyphWidth(GlyphID key);
00234 virtual bool GetDrawGlyphShadow();
00235 virtual GlyphID MapCharToGlyph(WChar key);
00236 virtual const void *GetFontTable(uint32 tag, size_t &length);
00237 };
00238
00239 FT_Library _library = NULL;
00240
00241 FreeTypeSettings _freetype;
00242
00243 static const byte FACE_COLOUR = 1;
00244 static const byte SHADOW_COLOUR = 2;
00245
00252 FreeTypeFontCache::FreeTypeFontCache(FontSize fs, FT_Face face, int pixels) : FontCache(fs), face(face), glyph_to_sprite(NULL)
00253 {
00254 assert(face != NULL);
00255
00256 if (pixels == 0) {
00257
00258 pixels = _default_font_height[this->fs];
00259
00260 TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head);
00261 if (head != NULL) {
00262
00263
00264 int diff = _default_font_height[this->fs] - _default_font_height[FS_SMALL];
00265 pixels = Clamp(min(head->Lowest_Rec_PPEM, 20) + diff, _default_font_height[this->fs], MAX_FONT_SIZE);
00266 }
00267 }
00268
00269 FT_Error err = FT_Set_Pixel_Sizes(this->face, 0, pixels);
00270 if (err == FT_Err_Invalid_Pixel_Size) {
00271
00272
00273 FT_Bitmap_Size *bs = this->face->available_sizes;
00274 int i = this->face->num_fixed_sizes;
00275 int n = bs->height;
00276 for (; --i; bs++) {
00277 if (abs(pixels - bs->height) < abs(pixels - n)) n = bs->height;
00278 }
00279
00280 FT_Set_Pixel_Sizes(this->face, 0, n);
00281 }
00282
00283 this->units_per_em = this->face->units_per_EM;
00284 this->ascender = this->face->size->metrics.ascender >> 6;
00285 this->descender = this->face->size->metrics.descender >> 6;
00286 this->height = this->ascender - this->descender;
00287 }
00288
00296 static void LoadFreeTypeFont(FontSize fs)
00297 {
00298 FreeTypeSubSetting *settings = NULL;
00299 switch (fs) {
00300 default: NOT_REACHED();
00301 case FS_SMALL: settings = &_freetype.small; break;
00302 case FS_NORMAL: settings = &_freetype.medium; break;
00303 case FS_LARGE: settings = &_freetype.large; break;
00304 case FS_MONO: settings = &_freetype.mono; break;
00305 }
00306
00307 if (StrEmpty(settings->font)) return;
00308
00309 if (_library == NULL) {
00310 if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
00311 ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
00312 return;
00313 }
00314
00315 DEBUG(freetype, 2, "Initialized");
00316 }
00317
00318 FT_Face face = NULL;
00319 FT_Error error = FT_New_Face(_library, settings->font, 0, &face);
00320
00321 if (error != FT_Err_Ok) error = GetFontByFaceName(settings->font, &face);
00322
00323 if (error == FT_Err_Ok) {
00324 DEBUG(freetype, 2, "Requested '%s', using '%s %s'", settings->font, face->family_name, face->style_name);
00325
00326
00327 error = FT_Select_Charmap(face, ft_encoding_unicode);
00328 if (error == FT_Err_Ok) goto found_face;
00329
00330 if (error == FT_Err_Invalid_CharMap_Handle) {
00331
00332
00333
00334 FT_CharMap found = face->charmaps[0];
00335 int i;
00336
00337 for (i = 0; i < face->num_charmaps; i++) {
00338 FT_CharMap charmap = face->charmaps[i];
00339 if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
00340 found = charmap;
00341 }
00342 }
00343
00344 if (found != NULL) {
00345 error = FT_Set_Charmap(face, found);
00346 if (error == FT_Err_Ok) goto found_face;
00347 }
00348 }
00349 }
00350
00351 FT_Done_Face(face);
00352
00353 static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" };
00354 ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings->font, SIZE_TO_NAME[fs], error);
00355 return;
00356
00357 found_face:
00358 new FreeTypeFontCache(fs, face, settings->size);
00359 }
00360
00361
00365 FreeTypeFontCache::~FreeTypeFontCache()
00366 {
00367 FT_Done_Face(this->face);
00368 this->ClearFontCache();
00369
00370 for (FontTable::iterator iter = this->font_tables.Begin(); iter != this->font_tables.End(); iter++) {
00371 free(iter->second.second);
00372 }
00373 }
00374
00378 void FreeTypeFontCache::ClearFontCache()
00379 {
00380 if (this->glyph_to_sprite == NULL) return;
00381
00382 for (int i = 0; i < 256; i++) {
00383 if (this->glyph_to_sprite[i] == NULL) continue;
00384
00385 for (int j = 0; j < 256; j++) {
00386 if (this->glyph_to_sprite[i][j].duplicate) continue;
00387 free(this->glyph_to_sprite[i][j].sprite);
00388 }
00389
00390 free(this->glyph_to_sprite[i]);
00391 }
00392
00393 free(this->glyph_to_sprite);
00394 this->glyph_to_sprite = NULL;
00395 }
00396
00397 FreeTypeFontCache::GlyphEntry *FreeTypeFontCache::GetGlyphPtr(GlyphID key)
00398 {
00399 if (this->glyph_to_sprite == NULL) return NULL;
00400 if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) return NULL;
00401 return &this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)];
00402 }
00403
00404
00405 void FreeTypeFontCache::SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate)
00406 {
00407 if (this->glyph_to_sprite == NULL) {
00408 DEBUG(freetype, 3, "Allocating root glyph cache for size %u", this->fs);
00409 this->glyph_to_sprite = CallocT<GlyphEntry*>(256);
00410 }
00411
00412 if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) {
00413 DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), this->fs);
00414 this->glyph_to_sprite[GB(key, 8, 8)] = CallocT<GlyphEntry>(256);
00415 }
00416
00417 DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, this->fs);
00418 this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
00419 this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width;
00420 this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].duplicate = duplicate;
00421 }
00422
00423 static void *AllocateFont(size_t size)
00424 {
00425 return MallocT<byte>(size);
00426 }
00427
00428
00429
00430 static bool GetFontAAState(FontSize size)
00431 {
00432
00433 if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
00434
00435 switch (size) {
00436 default: NOT_REACHED();
00437 case FS_NORMAL: return _freetype.medium.aa;
00438 case FS_SMALL: return _freetype.small.aa;
00439 case FS_LARGE: return _freetype.large.aa;
00440 case FS_MONO: return _freetype.mono.aa;
00441 }
00442 }
00443
00444
00445 const Sprite *FreeTypeFontCache::GetGlyph(GlyphID key)
00446 {
00447 if ((key & SPRITE_GLYPH) != 0) return parent->GetGlyph(key);
00448
00449
00450 GlyphEntry *glyph = this->GetGlyphPtr(key);
00451 if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
00452
00453 FT_GlyphSlot slot = this->face->glyph;
00454
00455 bool aa = GetFontAAState(this->fs);
00456
00457 GlyphEntry new_glyph;
00458 if (key == 0) {
00459 GlyphID question_glyph = this->MapCharToGlyph('?');
00460 if (question_glyph == 0) {
00461
00462 SpriteID sprite = this->GetUnicodeGlyph(key);
00463 Sprite *spr = (Sprite*)GetRawSprite(sprite, ST_FONT, AllocateFont);
00464 assert(spr != NULL);
00465 new_glyph.sprite = spr;
00466 new_glyph.width = spr->width + (this->fs != FS_NORMAL);
00467 this->SetGlyphPtr(key, &new_glyph, false);
00468 return new_glyph.sprite;
00469 } else {
00470
00471 this->GetGlyph(question_glyph);
00472 glyph = this->GetGlyphPtr(question_glyph);
00473 this->SetGlyphPtr(key, glyph, true);
00474 return glyph->sprite;
00475 }
00476 }
00477 FT_Load_Glyph(this->face, key, FT_LOAD_DEFAULT);
00478 FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
00479
00480
00481 aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
00482
00483
00484 int width = max(1, slot->bitmap.width + (this->fs == FS_NORMAL));
00485 int height = max(1, slot->bitmap.rows + (this->fs == FS_NORMAL));
00486
00487
00488 if (width > 256 || height > 256) usererror("Font glyph is too large");
00489
00490
00491 SpriteLoader::Sprite sprite;
00492 sprite.AllocateData(ZOOM_LVL_NORMAL, width * height);
00493 sprite.type = ST_FONT;
00494 sprite.width = width;
00495 sprite.height = height;
00496 sprite.x_offs = slot->bitmap_left;
00497 sprite.y_offs = this->ascender - slot->bitmap_top;
00498
00499
00500 if (this->fs == FS_NORMAL && !aa) {
00501 for (int y = 0; y < slot->bitmap.rows; y++) {
00502 for (int x = 0; x < slot->bitmap.width; x++) {
00503 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
00504 sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR;
00505 sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
00506 }
00507 }
00508 }
00509 }
00510
00511 for (int y = 0; y < slot->bitmap.rows; y++) {
00512 for (int x = 0; x < slot->bitmap.width; x++) {
00513 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
00514 sprite.data[x + y * sprite.width].m = FACE_COLOUR;
00515 sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
00516 }
00517 }
00518 }
00519
00520 new_glyph.sprite = BlitterFactoryBase::GetCurrentBlitter()->Encode(&sprite, AllocateFont);
00521 new_glyph.width = slot->advance.x >> 6;
00522
00523 this->SetGlyphPtr(key, &new_glyph);
00524
00525 return new_glyph.sprite;
00526 }
00527
00528
00529 bool FreeTypeFontCache::GetDrawGlyphShadow()
00530 {
00531 return this->fs == FS_NORMAL && GetFontAAState(FS_NORMAL);
00532 }
00533
00534
00535 uint FreeTypeFontCache::GetGlyphWidth(GlyphID key)
00536 {
00537 if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyphWidth(key);
00538
00539 GlyphEntry *glyph = this->GetGlyphPtr(key);
00540 if (glyph == NULL || glyph->sprite == NULL) {
00541 this->GetGlyph(key);
00542 glyph = this->GetGlyphPtr(key);
00543 }
00544
00545 return glyph->width;
00546 }
00547
00548 GlyphID FreeTypeFontCache::MapCharToGlyph(WChar key)
00549 {
00550 assert(IsPrintable(key));
00551
00552 if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
00553 return this->parent->MapCharToGlyph(key);
00554 }
00555
00556 return FT_Get_Char_Index(this->face, key);
00557 }
00558
00559 const void *FreeTypeFontCache::GetFontTable(uint32 tag, size_t &length)
00560 {
00561 const FontTable::iterator iter = this->font_tables.Find(tag);
00562 if (iter != this->font_tables.End()) {
00563 length = iter->second.first;
00564 return iter->second.second;
00565 }
00566
00567 FT_ULong len = 0;
00568 FT_Byte *result = NULL;
00569
00570 FT_Load_Sfnt_Table(this->face, tag, 0, NULL, &len);
00571
00572 if (len > 0) {
00573 result = MallocT<FT_Byte>(len);
00574 FT_Load_Sfnt_Table(this->face, tag, 0, result, &len);
00575 }
00576 length = len;
00577
00578 this->font_tables.Insert(tag, SmallPair<size_t, const void *>(length, result));
00579 return result;
00580 }
00581
00582 #endif
00583
00588 void InitFreeType(bool monospace)
00589 {
00590 for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
00591 if (monospace != (fs == FS_MONO)) continue;
00592
00593 FontCache *fc = FontCache::Get(fs);
00594 if (fc->HasParent()) delete fc;
00595
00596 #ifdef WITH_FREETYPE
00597 LoadFreeTypeFont(fs);
00598 #endif
00599 }
00600 }
00601
00605 void UninitFreeType()
00606 {
00607 for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
00608 FontCache *fc = FontCache::Get(fs);
00609 if (fc->HasParent()) delete fc;
00610 }
00611
00612 #ifdef WITH_FREETYPE
00613 FT_Done_FreeType(_library);
00614 _library = NULL;
00615 #endif
00616 }