# fontcache.cpp

Go to the documentation of this file.

    00001 /* $Id: fontcache.cpp 25987 2013-11-13 21:53:40Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    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   /* Clear out existing glyph map if it exists */
    00119   this->ClearGlyphToSpriteMap();
    00120
    00121   SpriteID base;
    00122   switch (this->fs) {
    00123     default: NOT_REACHED();
    00124     case FS_MONO:   // Use normal as default for mono spaced font, i.e. FALL THROUGH
    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       /* Clear the glyph. This happens if the glyph at this code point
    00141         * is non-standard and should be accessed by an SCC_xxx enum
    00142         * entry only. */
    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 /*static */ 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     /* Try to determine a good height based on the minimal height recommended by the font. */
    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       /* Font height is minimum height plus the difference between the default
    00268        * height for this font size and the small size. */
    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     /* Find nearest size to that requested */
    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     /* Attempt to select the unicode character map */
    00332     error = FT_Select_Charmap(face, ft_encoding_unicode);
    00333     if (error == FT_Err_Ok) goto found_face; // Success
    00334
    00335     if (error == FT_Err_Invalid_CharMap_Handle) {
    00336       /* Try to pick a different character map instead. We default to
    00337        * the first map, but platform_id 0 encoding_id 0 should also
    00338        * be unicode (strange system...) */
    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 /* Check if a glyph should be rendered with antialiasing */
    00437 static bool GetFontAAState(FontSize size)
    00438 {
    00439   /* AA is only supported for 32 bpp */
    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   /* Check for the glyph in our cache */
    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       /* The font misses the '?' character. Use built-in sprite.
    00469        * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */
    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, // height
    00488         8,  // width
    00489         0,  // x_offs
    00490         0,  // y_offs
    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       /* Use '?' for missing characters. */
    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   /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
    00513   aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
    00514
    00515   /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
    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   /* Limit glyph size to prevent overflows later on. */
    00520   if (width > 256 || height > 256) usererror("Font glyph is too large");
    00521
    00522   /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
    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   /* Draw shadow for medium size */
    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 /* WITH_FREETYPE */
    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 /* WITH_FREETYPE */
    00648 }