fontcache.cpp

Go to the documentation of this file.
00001 /* $Id: fontcache.cpp 26209 2014-01-02 22:41:58Z 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   virtual const char *GetFontName() { return "sprite"; }
00085 };
00086 
00091 SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid_map(NULL)
00092 {
00093   this->InitializeUnicodeGlyphMap();
00094 }
00095 
00099 SpriteFontCache::~SpriteFontCache()
00100 {
00101   this->ClearGlyphToSpriteMap();
00102 }
00103 
00104 SpriteID SpriteFontCache::GetUnicodeGlyph(GlyphID key)
00105 {
00106   if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == NULL) return 0;
00107   return this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)];
00108 }
00109 
00110 void SpriteFontCache::SetUnicodeGlyph(GlyphID key, SpriteID sprite)
00111 {
00112   if (this->glyph_to_spriteid_map == NULL) this->glyph_to_spriteid_map = CallocT<SpriteID*>(256);
00113   if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == NULL) this->glyph_to_spriteid_map[GB(key, 8, 8)] = CallocT<SpriteID>(256);
00114   this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
00115 }
00116 
00117 void SpriteFontCache::InitializeUnicodeGlyphMap()
00118 {
00119   /* Clear out existing glyph map if it exists */
00120   this->ClearGlyphToSpriteMap();
00121 
00122   SpriteID base;
00123   switch (this->fs) {
00124     default: NOT_REACHED();
00125     case FS_MONO:   // Use normal as default for mono spaced font, i.e. FALL THROUGH
00126     case FS_NORMAL: base = SPR_ASCII_SPACE;       break;
00127     case FS_SMALL:  base = SPR_ASCII_SPACE_SMALL; break;
00128     case FS_LARGE:  base = SPR_ASCII_SPACE_BIG;   break;
00129   }
00130 
00131   for (uint i = ASCII_LETTERSTART; i < 256; i++) {
00132     SpriteID sprite = base + i - ASCII_LETTERSTART;
00133     if (!SpriteExists(sprite)) continue;
00134     this->SetUnicodeGlyph(i, sprite);
00135     this->SetUnicodeGlyph(i + SCC_SPRITE_START, sprite);
00136   }
00137 
00138   for (uint i = 0; i < lengthof(_default_unicode_map); i++) {
00139     byte key = _default_unicode_map[i].key;
00140     if (key == CLRA) {
00141       /* Clear the glyph. This happens if the glyph at this code point
00142         * is non-standard and should be accessed by an SCC_xxx enum
00143         * entry only. */
00144       this->SetUnicodeGlyph(_default_unicode_map[i].code, 0);
00145     } else {
00146       SpriteID sprite = base + key - ASCII_LETTERSTART;
00147       this->SetUnicodeGlyph(_default_unicode_map[i].code, sprite);
00148     }
00149   }
00150 }
00151 
00155 void SpriteFontCache::ClearGlyphToSpriteMap()
00156 {
00157   if (this->glyph_to_spriteid_map == NULL) return;
00158 
00159   for (uint i = 0; i < 256; i++) {
00160     free(this->glyph_to_spriteid_map[i]);
00161   }
00162   free(this->glyph_to_spriteid_map);
00163   this->glyph_to_spriteid_map = NULL;
00164 }
00165 
00166 void SpriteFontCache::ClearFontCache()
00167 {
00168   Layouter::ResetFontCache(this->fs);
00169 }
00170 
00171 const Sprite *SpriteFontCache::GetGlyph(GlyphID key)
00172 {
00173   SpriteID sprite = this->GetUnicodeGlyph(key);
00174   if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
00175   return GetSprite(sprite, ST_FONT);
00176 }
00177 
00178 uint SpriteFontCache::GetGlyphWidth(GlyphID key)
00179 {
00180   SpriteID sprite = this->GetUnicodeGlyph(key);
00181   if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
00182   return SpriteExists(sprite) ? GetSprite(sprite, ST_FONT)->width + (this->fs != FS_NORMAL) : 0;
00183 }
00184 
00185 bool SpriteFontCache::GetDrawGlyphShadow()
00186 {
00187   return false;
00188 }
00189 
00190 /*static */ FontCache *FontCache::caches[FS_END] = { new SpriteFontCache(FS_NORMAL), new SpriteFontCache(FS_SMALL), new SpriteFontCache(FS_LARGE), new SpriteFontCache(FS_MONO) };
00191 
00192 #ifdef WITH_FREETYPE
00193 #include <ft2build.h>
00194 #include FT_FREETYPE_H
00195 #include FT_GLYPH_H
00196 #include FT_TRUETYPE_TABLES_H
00197 
00199 class FreeTypeFontCache : public FontCache {
00200 private:
00201   FT_Face face;  
00202 
00203   typedef SmallMap<uint32, SmallPair<size_t, const void*> > FontTable; 
00204   FontTable font_tables; 
00205 
00207   struct GlyphEntry {
00208     Sprite *sprite; 
00209     byte width;     
00210     bool duplicate; 
00211   };
00212 
00226   GlyphEntry **glyph_to_sprite;
00227 
00228   GlyphEntry *GetGlyphPtr(GlyphID key);
00229   void SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate = false);
00230 
00231 public:
00232   FreeTypeFontCache(FontSize fs, FT_Face face, int pixels);
00233   ~FreeTypeFontCache();
00234   virtual SpriteID GetUnicodeGlyph(WChar key) { return this->parent->GetUnicodeGlyph(key); }
00235   virtual void SetUnicodeGlyph(WChar key, SpriteID sprite) { this->parent->SetUnicodeGlyph(key, sprite); }
00236   virtual void InitializeUnicodeGlyphMap() { this->parent->InitializeUnicodeGlyphMap(); }
00237   virtual void ClearFontCache();
00238   virtual const Sprite *GetGlyph(GlyphID key);
00239   virtual uint GetGlyphWidth(GlyphID key);
00240   virtual bool GetDrawGlyphShadow();
00241   virtual GlyphID MapCharToGlyph(WChar key);
00242   virtual const void *GetFontTable(uint32 tag, size_t &length);
00243   virtual const char *GetFontName() { return face->family_name; }
00244 };
00245 
00246 FT_Library _library = NULL;
00247 
00248 FreeTypeSettings _freetype;
00249 
00250 static const byte FACE_COLOUR   = 1;
00251 static const byte SHADOW_COLOUR = 2;
00252 
00259 FreeTypeFontCache::FreeTypeFontCache(FontSize fs, FT_Face face, int pixels) : FontCache(fs), face(face), glyph_to_sprite(NULL)
00260 {
00261   assert(face != NULL);
00262 
00263   if (pixels == 0) {
00264     /* Try to determine a good height based on the minimal height recommended by the font. */
00265     pixels = _default_font_height[this->fs];
00266 
00267     TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head);
00268     if (head != NULL) {
00269       /* Font height is minimum height plus the difference between the default
00270        * height for this font size and the small size. */
00271       int diff = _default_font_height[this->fs] - _default_font_height[FS_SMALL];
00272       pixels = Clamp(min(head->Lowest_Rec_PPEM, 20) + diff, _default_font_height[this->fs], MAX_FONT_SIZE);
00273     }
00274   }
00275 
00276   FT_Error err = FT_Set_Pixel_Sizes(this->face, 0, pixels);
00277   if (err == FT_Err_Invalid_Pixel_Size) {
00278 
00279     /* Find nearest size to that requested */
00280     FT_Bitmap_Size *bs = this->face->available_sizes;
00281     int i = this->face->num_fixed_sizes;
00282     int n = bs->height;
00283     for (; --i; bs++) {
00284       if (abs(pixels - bs->height) < abs(pixels - n)) n = bs->height;
00285     }
00286 
00287     FT_Set_Pixel_Sizes(this->face, 0, n);
00288   }
00289 
00290   this->units_per_em = this->face->units_per_EM;
00291   this->ascender     = this->face->size->metrics.ascender >> 6;
00292   this->descender    = this->face->size->metrics.descender >> 6;
00293   this->height       = this->ascender - this->descender;
00294 }
00295 
00303 static void LoadFreeTypeFont(FontSize fs)
00304 {
00305   FreeTypeSubSetting *settings = NULL;
00306   switch (fs) {
00307     default: NOT_REACHED();
00308     case FS_SMALL:  settings = &_freetype.small;  break;
00309     case FS_NORMAL: settings = &_freetype.medium; break;
00310     case FS_LARGE:  settings = &_freetype.large;  break;
00311     case FS_MONO:   settings = &_freetype.mono;   break;
00312   }
00313 
00314   if (StrEmpty(settings->font)) return;
00315 
00316   if (_library == NULL) {
00317     if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
00318       ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
00319       return;
00320     }
00321 
00322     DEBUG(freetype, 2, "Initialized");
00323   }
00324 
00325   FT_Face face = NULL;
00326   FT_Error error = FT_New_Face(_library, settings->font, 0, &face);
00327 
00328   if (error != FT_Err_Ok) error = GetFontByFaceName(settings->font, &face);
00329 
00330   if (error == FT_Err_Ok) {
00331     DEBUG(freetype, 2, "Requested '%s', using '%s %s'", settings->font, face->family_name, face->style_name);
00332 
00333     /* Attempt to select the unicode character map */
00334     error = FT_Select_Charmap(face, ft_encoding_unicode);
00335     if (error == FT_Err_Ok) goto found_face; // Success
00336 
00337     if (error == FT_Err_Invalid_CharMap_Handle) {
00338       /* Try to pick a different character map instead. We default to
00339        * the first map, but platform_id 0 encoding_id 0 should also
00340        * be unicode (strange system...) */
00341       FT_CharMap found = face->charmaps[0];
00342       int i;
00343 
00344       for (i = 0; i < face->num_charmaps; i++) {
00345         FT_CharMap charmap = face->charmaps[i];
00346         if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
00347           found = charmap;
00348         }
00349       }
00350 
00351       if (found != NULL) {
00352         error = FT_Set_Charmap(face, found);
00353         if (error == FT_Err_Ok) goto found_face;
00354       }
00355     }
00356   }
00357 
00358   FT_Done_Face(face);
00359 
00360   static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" };
00361   ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings->font, SIZE_TO_NAME[fs], error);
00362   return;
00363 
00364 found_face:
00365   new FreeTypeFontCache(fs, face, settings->size);
00366 }
00367 
00368 
00372 FreeTypeFontCache::~FreeTypeFontCache()
00373 {
00374   FT_Done_Face(this->face);
00375   this->ClearFontCache();
00376 
00377   for (FontTable::iterator iter = this->font_tables.Begin(); iter != this->font_tables.End(); iter++) {
00378     free(iter->second.second);
00379   }
00380 }
00381 
00385 void FreeTypeFontCache::ClearFontCache()
00386 {
00387   if (this->glyph_to_sprite == NULL) return;
00388 
00389   for (int i = 0; i < 256; i++) {
00390     if (this->glyph_to_sprite[i] == NULL) continue;
00391 
00392     for (int j = 0; j < 256; j++) {
00393       if (this->glyph_to_sprite[i][j].duplicate) continue;
00394       free(this->glyph_to_sprite[i][j].sprite);
00395     }
00396 
00397     free(this->glyph_to_sprite[i]);
00398   }
00399 
00400   free(this->glyph_to_sprite);
00401   this->glyph_to_sprite = NULL;
00402 
00403   Layouter::ResetFontCache(this->fs);
00404 }
00405 
00406 FreeTypeFontCache::GlyphEntry *FreeTypeFontCache::GetGlyphPtr(GlyphID key)
00407 {
00408   if (this->glyph_to_sprite == NULL) return NULL;
00409   if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) return NULL;
00410   return &this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)];
00411 }
00412 
00413 
00414 void FreeTypeFontCache::SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate)
00415 {
00416   if (this->glyph_to_sprite == NULL) {
00417     DEBUG(freetype, 3, "Allocating root glyph cache for size %u", this->fs);
00418     this->glyph_to_sprite = CallocT<GlyphEntry*>(256);
00419   }
00420 
00421   if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) {
00422     DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), this->fs);
00423     this->glyph_to_sprite[GB(key, 8, 8)] = CallocT<GlyphEntry>(256);
00424   }
00425 
00426   DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, this->fs);
00427   this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].sprite    = glyph->sprite;
00428   this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].width     = glyph->width;
00429   this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].duplicate = duplicate;
00430 }
00431 
00432 static void *AllocateFont(size_t size)
00433 {
00434   return MallocT<byte>(size);
00435 }
00436 
00437 
00438 /* Check if a glyph should be rendered with antialiasing */
00439 static bool GetFontAAState(FontSize size)
00440 {
00441   /* AA is only supported for 32 bpp */
00442   if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
00443 
00444   switch (size) {
00445     default: NOT_REACHED();
00446     case FS_NORMAL: return _freetype.medium.aa;
00447     case FS_SMALL:  return _freetype.small.aa;
00448     case FS_LARGE:  return _freetype.large.aa;
00449     case FS_MONO:   return _freetype.mono.aa;
00450   }
00451 }
00452 
00453 
00454 const Sprite *FreeTypeFontCache::GetGlyph(GlyphID key)
00455 {
00456   if ((key & SPRITE_GLYPH) != 0) return parent->GetGlyph(key);
00457 
00458   /* Check for the glyph in our cache */
00459   GlyphEntry *glyph = this->GetGlyphPtr(key);
00460   if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
00461 
00462   FT_GlyphSlot slot = this->face->glyph;
00463 
00464   bool aa = GetFontAAState(this->fs);
00465 
00466   GlyphEntry new_glyph;
00467   if (key == 0) {
00468     GlyphID question_glyph = this->MapCharToGlyph('?');
00469     if (question_glyph == 0) {
00470       /* The font misses the '?' character. Use built-in sprite.
00471        * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */
00472 #define CPSET { 0, 0, 0, 0, 1 }
00473 #define CP___ { 0, 0, 0, 0, 0 }
00474       static SpriteLoader::CommonPixel builtin_questionmark_data[10 * 8] = {
00475         CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___,
00476         CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___,
00477         CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___,
00478         CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___,
00479         CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
00480         CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
00481         CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
00482         CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___,
00483         CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
00484         CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
00485       };
00486 #undef CPSET
00487 #undef CP___
00488       static const SpriteLoader::Sprite builtin_questionmark = {
00489         10, // height
00490         8,  // width
00491         0,  // x_offs
00492         0,  // y_offs
00493         ST_FONT,
00494         builtin_questionmark_data
00495       };
00496 
00497       Sprite *spr = BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark, AllocateFont);
00498       assert(spr != NULL);
00499       new_glyph.sprite = spr;
00500       new_glyph.width  = spr->width + (this->fs != FS_NORMAL);
00501       this->SetGlyphPtr(key, &new_glyph, false);
00502       return new_glyph.sprite;
00503     } else {
00504       /* Use '?' for missing characters. */
00505       this->GetGlyph(question_glyph);
00506       glyph = this->GetGlyphPtr(question_glyph);
00507       this->SetGlyphPtr(key, glyph, true);
00508       return glyph->sprite;
00509     }
00510   }
00511   FT_Load_Glyph(this->face, key, FT_LOAD_DEFAULT);
00512   FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
00513 
00514   /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
00515   aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
00516 
00517   /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
00518   int width  = max(1, slot->bitmap.width + (this->fs == FS_NORMAL));
00519   int height = max(1, slot->bitmap.rows  + (this->fs == FS_NORMAL));
00520 
00521   /* Limit glyph size to prevent overflows later on. */
00522   if (width > 256 || height > 256) usererror("Font glyph is too large");
00523 
00524   /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
00525   SpriteLoader::Sprite sprite;
00526   sprite.AllocateData(ZOOM_LVL_NORMAL, width * height);
00527   sprite.type = ST_FONT;
00528   sprite.width = width;
00529   sprite.height = height;
00530   sprite.x_offs = slot->bitmap_left;
00531   sprite.y_offs = this->ascender - slot->bitmap_top;
00532 
00533   /* Draw shadow for medium size */
00534   if (this->fs == FS_NORMAL && !aa) {
00535     for (int y = 0; y < slot->bitmap.rows; y++) {
00536       for (int x = 0; x < slot->bitmap.width; x++) {
00537         if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
00538           sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR;
00539           sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
00540         }
00541       }
00542     }
00543   }
00544 
00545   for (int y = 0; y < slot->bitmap.rows; y++) {
00546     for (int x = 0; x < slot->bitmap.width; x++) {
00547       if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
00548         sprite.data[x + y * sprite.width].m = FACE_COLOUR;
00549         sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
00550       }
00551     }
00552   }
00553 
00554   new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, AllocateFont);
00555   new_glyph.width  = slot->advance.x >> 6;
00556 
00557   this->SetGlyphPtr(key, &new_glyph);
00558 
00559   return new_glyph.sprite;
00560 }
00561 
00562 
00563 bool FreeTypeFontCache::GetDrawGlyphShadow()
00564 {
00565   return this->fs == FS_NORMAL && GetFontAAState(FS_NORMAL);
00566 }
00567 
00568 
00569 uint FreeTypeFontCache::GetGlyphWidth(GlyphID key)
00570 {
00571   if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyphWidth(key);
00572 
00573   GlyphEntry *glyph = this->GetGlyphPtr(key);
00574   if (glyph == NULL || glyph->sprite == NULL) {
00575     this->GetGlyph(key);
00576     glyph = this->GetGlyphPtr(key);
00577   }
00578 
00579   return glyph->width;
00580 }
00581 
00582 GlyphID FreeTypeFontCache::MapCharToGlyph(WChar key)
00583 {
00584   assert(IsPrintable(key));
00585 
00586   if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
00587     return this->parent->MapCharToGlyph(key);
00588   }
00589 
00590   return FT_Get_Char_Index(this->face, key);
00591 }
00592 
00593 const void *FreeTypeFontCache::GetFontTable(uint32 tag, size_t &length)
00594 {
00595   const FontTable::iterator iter = this->font_tables.Find(tag);
00596   if (iter != this->font_tables.End()) {
00597     length = iter->second.first;
00598     return iter->second.second;
00599   }
00600 
00601   FT_ULong len = 0;
00602   FT_Byte *result = NULL;
00603 
00604   FT_Load_Sfnt_Table(this->face, tag, 0, NULL, &len);
00605 
00606   if (len > 0) {
00607     result = MallocT<FT_Byte>(len);
00608     FT_Load_Sfnt_Table(this->face, tag, 0, result, &len);
00609   }
00610   length = len;
00611 
00612   this->font_tables.Insert(tag, SmallPair<size_t, const void *>(length, result));
00613   return result;
00614 }
00615 
00616 #endif /* WITH_FREETYPE */
00617 
00622 void InitFreeType(bool monospace)
00623 {
00624   for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
00625     if (monospace != (fs == FS_MONO)) continue;
00626 
00627     FontCache *fc = FontCache::Get(fs);
00628     if (fc->HasParent()) delete fc;
00629 
00630 #ifdef WITH_FREETYPE
00631     LoadFreeTypeFont(fs);
00632 #endif
00633   }
00634 }
00635 
00639 void UninitFreeType()
00640 {
00641   for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
00642     FontCache *fc = FontCache::Get(fs);
00643     if (fc->HasParent()) delete fc;
00644   }
00645 
00646 #ifdef WITH_FREETYPE
00647   FT_Done_FreeType(_library);
00648   _library = NULL;
00649 #endif /* WITH_FREETYPE */
00650 }