# fontcache.cpp

Go to the documentation of this file.

    00001 /* $Id: fontcache.cpp 25528 2013-06-30 08:58:35Z 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
    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   /* Clear out existing glyph map if it exists */
    00116   this->ClearGlyphToSpriteMap();
    00117
    00118   SpriteID base;
    00119   switch (this->fs) {
    00120     default: NOT_REACHED();
    00121     case FS_MONO:   // Use normal as default for mono spaced font, i.e. FALL THROUGH
    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       /* Clear the glyph. This happens if the glyph at this code point
    00138         * is non-standard and should be accessed by an SCC_xxx enum
    00139         * entry only. */
    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 /*static */ 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     /* Try to determine a good height based on the minimal height recommended by the font. */
    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       /* Font height is minimum height plus the difference between the default
    00260        * height for this font size and the small size. */
    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     /* Find nearest size to that requested */
    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     /* Attempt to select the unicode character map */
    00324     error = FT_Select_Charmap(face, ft_encoding_unicode);
    00325     if (error == FT_Err_Ok) goto found_face; // Success
    00326
    00327     if (error == FT_Err_Invalid_CharMap_Handle) {
    00328       /* Try to pick a different character map instead. We default to
    00329        * the first map, but platform_id 0 encoding_id 0 should also
    00330        * be unicode (strange system...) */
    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 /* Check if a glyph should be rendered with antialiasing */
    00427 static bool GetFontAAState(FontSize size)
    00428 {
    00429   /* AA is only supported for 32 bpp */
    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   /* Check for the glyph in our cache */
    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       /* The font misses the '?' character. Use sprite font. */
    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       /* Use '?' for missing characters. */
    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   /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
    00478   aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
    00479
    00480   /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
    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   /* Limit glyph size to prevent overflows later on. */
    00485   if (width > 256 || height > 256) usererror("Font glyph is too large");
    00486
    00487   /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
    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   /* Draw shadow for medium size */
    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 /* WITH_FREETYPE */
    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 /* WITH_FREETYPE */
    00613 }