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 }