# fontcache.cpp

Go to the documentation of this file.

    00001 /* $Id: fontcache.cpp 26389 2014-03-03 21:34:36Z fonsinchen $ */
    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_Ok) {
    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     if (i > 0) { // In pathetic cases one might get no fixed sizes at all.
    00283       int n = bs->height;
    00284       FT_Int chosen = 0;
    00285       for (; --i; bs++) {
    00286         if (abs(pixels - bs->height) >= abs(pixels - n)) continue;
    00287         n = bs->height;
    00288         chosen = this->face->num_fixed_sizes - i;
    00289       }
    00290
    00291       /* Don't use FT_Set_Pixel_Sizes here - it might give us another
    00292        * error, even though the size is available (FS#5885). */
    00293       err = FT_Select_Size(this->face, chosen);
    00294     }
    00295   }
    00296
    00297   if (err == FT_Err_Ok) {
    00298     this->units_per_em = this->face->units_per_EM;
    00299     this->ascender     = this->face->size->metrics.ascender >> 6;
    00300     this->descender    = this->face->size->metrics.descender >> 6;
    00301     this->height       = this->ascender - this->descender;
    00302   } else {
    00303     /* Both FT_Set_Pixel_Sizes and FT_Select_Size failed. */
    00304     DEBUG(freetype, 0, "Font size selection failed. Using FontCache defaults.");
    00305   }
    00306 }
    00307
    00315 static void LoadFreeTypeFont(FontSize fs)
    00316 {
    00317   FreeTypeSubSetting *settings = NULL;
    00318   switch (fs) {
    00319     default: NOT_REACHED();
    00320     case FS_SMALL:  settings = &_freetype.small;  break;
    00321     case FS_NORMAL: settings = &_freetype.medium; break;
    00322     case FS_LARGE:  settings = &_freetype.large;  break;
    00323     case FS_MONO:   settings = &_freetype.mono;   break;
    00324   }
    00325
    00326   if (StrEmpty(settings->font)) return;
    00327
    00328   if (_library == NULL) {
    00329     if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
    00330       ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
    00331       return;
    00332     }
    00333
    00334     DEBUG(freetype, 2, "Initialized");
    00335   }
    00336
    00337   FT_Face face = NULL;
    00338   FT_Error error = FT_New_Face(_library, settings->font, 0, &face);
    00339
    00340   if (error != FT_Err_Ok) error = GetFontByFaceName(settings->font, &face);
    00341
    00342   if (error == FT_Err_Ok) {
    00343     DEBUG(freetype, 2, "Requested '%s', using '%s %s'", settings->font, face->family_name, face->style_name);
    00344
    00345     /* Attempt to select the unicode character map */
    00346     error = FT_Select_Charmap(face, ft_encoding_unicode);
    00347     if (error == FT_Err_Ok) goto found_face; // Success
    00348
    00349     if (error == FT_Err_Invalid_CharMap_Handle) {
    00350       /* Try to pick a different character map instead. We default to
    00351        * the first map, but platform_id 0 encoding_id 0 should also
    00352        * be unicode (strange system...) */
    00353       FT_CharMap found = face->charmaps[0];
    00354       int i;
    00355
    00356       for (i = 0; i < face->num_charmaps; i++) {
    00357         FT_CharMap charmap = face->charmaps[i];
    00358         if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
    00359           found = charmap;
    00360         }
    00361       }
    00362
    00363       if (found != NULL) {
    00364         error = FT_Set_Charmap(face, found);
    00365         if (error == FT_Err_Ok) goto found_face;
    00366       }
    00367     }
    00368   }
    00369
    00370   FT_Done_Face(face);
    00371
    00372   static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" };
    00373   ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings->font, SIZE_TO_NAME[fs], error);
    00374   return;
    00375
    00376 found_face:
    00377   new FreeTypeFontCache(fs, face, settings->size);
    00378 }
    00379
    00380
    00384 FreeTypeFontCache::~FreeTypeFontCache()
    00385 {
    00386   FT_Done_Face(this->face);
    00387   this->ClearFontCache();
    00388
    00389   for (FontTable::iterator iter = this->font_tables.Begin(); iter != this->font_tables.End(); iter++) {
    00390     free(iter->second.second);
    00391   }
    00392 }
    00393
    00397 void FreeTypeFontCache::ClearFontCache()
    00398 {
    00399   if (this->glyph_to_sprite == NULL) return;
    00400
    00401   for (int i = 0; i < 256; i++) {
    00402     if (this->glyph_to_sprite[i] == NULL) continue;
    00403
    00404     for (int j = 0; j < 256; j++) {
    00405       if (this->glyph_to_sprite[i][j].duplicate) continue;
    00406       free(this->glyph_to_sprite[i][j].sprite);
    00407     }
    00408
    00409     free(this->glyph_to_sprite[i]);
    00410   }
    00411
    00412   free(this->glyph_to_sprite);
    00413   this->glyph_to_sprite = NULL;
    00414
    00415   Layouter::ResetFontCache(this->fs);
    00416 }
    00417
    00418 FreeTypeFontCache::GlyphEntry *FreeTypeFontCache::GetGlyphPtr(GlyphID key)
    00419 {
    00420   if (this->glyph_to_sprite == NULL) return NULL;
    00421   if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) return NULL;
    00422   return &this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)];
    00423 }
    00424
    00425
    00426 void FreeTypeFontCache::SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate)
    00427 {
    00428   if (this->glyph_to_sprite == NULL) {
    00429     DEBUG(freetype, 3, "Allocating root glyph cache for size %u", this->fs);
    00430     this->glyph_to_sprite = CallocT<GlyphEntry*>(256);
    00431   }
    00432
    00433   if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) {
    00434     DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), this->fs);
    00435     this->glyph_to_sprite[GB(key, 8, 8)] = CallocT<GlyphEntry>(256);
    00436   }
    00437
    00438   DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, this->fs);
    00439   this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].sprite    = glyph->sprite;
    00440   this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].width     = glyph->width;
    00441   this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].duplicate = duplicate;
    00442 }
    00443
    00444 static void *AllocateFont(size_t size)
    00445 {
    00446   return MallocT<byte>(size);
    00447 }
    00448
    00449
    00450 /* Check if a glyph should be rendered with antialiasing */
    00451 static bool GetFontAAState(FontSize size)
    00452 {
    00453   /* AA is only supported for 32 bpp */
    00454   if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
    00455
    00456   switch (size) {
    00457     default: NOT_REACHED();
    00458     case FS_NORMAL: return _freetype.medium.aa;
    00459     case FS_SMALL:  return _freetype.small.aa;
    00460     case FS_LARGE:  return _freetype.large.aa;
    00461     case FS_MONO:   return _freetype.mono.aa;
    00462   }
    00463 }
    00464
    00465
    00466 const Sprite *FreeTypeFontCache::GetGlyph(GlyphID key)
    00467 {
    00468   if ((key & SPRITE_GLYPH) != 0) return parent->GetGlyph(key);
    00469
    00470   /* Check for the glyph in our cache */
    00471   GlyphEntry *glyph = this->GetGlyphPtr(key);
    00472   if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
    00473
    00474   FT_GlyphSlot slot = this->face->glyph;
    00475
    00476   bool aa = GetFontAAState(this->fs);
    00477
    00478   GlyphEntry new_glyph;
    00479   if (key == 0) {
    00480     GlyphID question_glyph = this->MapCharToGlyph('?');
    00481     if (question_glyph == 0) {
    00482       /* The font misses the '?' character. Use built-in sprite.
    00483        * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */
    00484 #define CPSET { 0, 0, 0, 0, 1 }
    00485 #define CP___ { 0, 0, 0, 0, 0 }
    00486       static SpriteLoader::CommonPixel builtin_questionmark_data[10 * 8] = {
    00487         CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___,
    00488         CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___,
    00489         CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___,
    00490         CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___,
    00491         CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
    00492         CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
    00493         CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
    00494         CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___,
    00495         CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
    00496         CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
    00497       };
    00498 #undef CPSET
    00499 #undef CP___
    00500       static const SpriteLoader::Sprite builtin_questionmark = {
    00501         10, // height
    00502         8,  // width
    00503         0,  // x_offs
    00504         0,  // y_offs
    00505         ST_FONT,
    00506         builtin_questionmark_data
    00507       };
    00508
    00509       Sprite *spr = BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark, AllocateFont);
    00510       assert(spr != NULL);
    00511       new_glyph.sprite = spr;
    00512       new_glyph.width  = spr->width + (this->fs != FS_NORMAL);
    00513       this->SetGlyphPtr(key, &new_glyph, false);
    00514       return new_glyph.sprite;
    00515     } else {
    00516       /* Use '?' for missing characters. */
    00517       this->GetGlyph(question_glyph);
    00518       glyph = this->GetGlyphPtr(question_glyph);
    00519       this->SetGlyphPtr(key, glyph, true);
    00520       return glyph->sprite;
    00521     }
    00522   }
    00523   FT_Load_Glyph(this->face, key, FT_LOAD_DEFAULT);
    00524   FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
    00525
    00526   /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
    00527   aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
    00528
    00529   /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
    00530   int width  = max(1, slot->bitmap.width + (this->fs == FS_NORMAL));
    00531   int height = max(1, slot->bitmap.rows  + (this->fs == FS_NORMAL));
    00532
    00533   /* Limit glyph size to prevent overflows later on. */
    00534   if (width > 256 || height > 256) usererror("Font glyph is too large");
    00535
    00536   /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
    00537   SpriteLoader::Sprite sprite;
    00538   sprite.AllocateData(ZOOM_LVL_NORMAL, width * height);
    00539   sprite.type = ST_FONT;
    00540   sprite.width = width;
    00541   sprite.height = height;
    00542   sprite.x_offs = slot->bitmap_left;
    00543   sprite.y_offs = this->ascender - slot->bitmap_top;
    00544
    00545   /* Draw shadow for medium size */
    00546   if (this->fs == FS_NORMAL && !aa) {
    00547     for (int y = 0; y < slot->bitmap.rows; y++) {
    00548       for (int x = 0; x < slot->bitmap.width; x++) {
    00549         if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
    00550           sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR;
    00551           sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
    00552         }
    00553       }
    00554     }
    00555   }
    00556
    00557   for (int y = 0; y < slot->bitmap.rows; y++) {
    00558     for (int x = 0; x < slot->bitmap.width; x++) {
    00559       if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
    00560         sprite.data[x + y * sprite.width].m = FACE_COLOUR;
    00561         sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
    00562       }
    00563     }
    00564   }
    00565
    00566   new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, AllocateFont);
    00567   new_glyph.width  = slot->advance.x >> 6;
    00568
    00569   this->SetGlyphPtr(key, &new_glyph);
    00570
    00571   return new_glyph.sprite;
    00572 }
    00573
    00574
    00575 bool FreeTypeFontCache::GetDrawGlyphShadow()
    00576 {
    00577   return this->fs == FS_NORMAL && GetFontAAState(FS_NORMAL);
    00578 }
    00579
    00580
    00581 uint FreeTypeFontCache::GetGlyphWidth(GlyphID key)
    00582 {
    00583   if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyphWidth(key);
    00584
    00585   GlyphEntry *glyph = this->GetGlyphPtr(key);
    00586   if (glyph == NULL || glyph->sprite == NULL) {
    00587     this->GetGlyph(key);
    00588     glyph = this->GetGlyphPtr(key);
    00589   }
    00590
    00591   return glyph->width;
    00592 }
    00593
    00594 GlyphID FreeTypeFontCache::MapCharToGlyph(WChar key)
    00595 {
    00596   assert(IsPrintable(key));
    00597
    00598   if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
    00599     return this->parent->MapCharToGlyph(key);
    00600   }
    00601
    00602   return FT_Get_Char_Index(this->face, key);
    00603 }
    00604
    00605 const void *FreeTypeFontCache::GetFontTable(uint32 tag, size_t &length)
    00606 {
    00607   const FontTable::iterator iter = this->font_tables.Find(tag);
    00608   if (iter != this->font_tables.End()) {
    00609     length = iter->second.first;
    00610     return iter->second.second;
    00611   }
    00612
    00613   FT_ULong len = 0;
    00614   FT_Byte *result = NULL;
    00615
    00616   FT_Load_Sfnt_Table(this->face, tag, 0, NULL, &len);
    00617
    00618   if (len > 0) {
    00619     result = MallocT<FT_Byte>(len);
    00620     FT_Load_Sfnt_Table(this->face, tag, 0, result, &len);
    00621   }
    00622   length = len;
    00623
    00624   this->font_tables.Insert(tag, SmallPair<size_t, const void *>(length, result));
    00625   return result;
    00626 }
    00627
    00628 #endif /* WITH_FREETYPE */
    00629
    00634 void InitFreeType(bool monospace)
    00635 {
    00636   for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
    00637     if (monospace != (fs == FS_MONO)) continue;
    00638
    00639     FontCache *fc = FontCache::Get(fs);
    00640     if (fc->HasParent()) delete fc;
    00641
    00642 #ifdef WITH_FREETYPE
    00643     LoadFreeTypeFont(fs);
    00644 #endif
    00645   }
    00646 }
    00647
    00651 void UninitFreeType()
    00652 {
    00653   for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
    00654     FontCache *fc = FontCache::Get(fs);
    00655     if (fc->HasParent()) delete fc;
    00656   }
    00657
    00658 #ifdef WITH_FREETYPE
    00659   FT_Done_FreeType(_library);
    00660   _library = NULL;
    00661 #endif /* WITH_FREETYPE */
    00662 }