ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

ttf.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 // Since FreeType2 includes files, which contain forbidden symbols, we need to
00024 // allow all symbols here.
00025 #define FORBIDDEN_SYMBOL_ALLOW_ALL
00026 
00027 #include "common/scummsys.h"
00028 #ifdef USE_FREETYPE2
00029 
00030 #include "graphics/fonts/ttf.h"
00031 #include "graphics/font.h"
00032 #include "graphics/surface.h"
00033 
00034 #include "common/file.h"
00035 #include "common/config-manager.h"
00036 #include "common/singleton.h"
00037 #include "common/stream.h"
00038 #include "common/memstream.h"
00039 #include "common/hashmap.h"
00040 #include "common/ptr.h"
00041 #include "common/unzip.h"
00042 
00043 #include <ft2build.h>
00044 #include FT_FREETYPE_H
00045 #include FT_GLYPH_H
00046 #include FT_TRUETYPE_TABLES_H
00047 #include FT_TRUETYPE_TAGS_H
00048 
00049 // ResidualVM specific
00050 #if FREETYPE_MAJOR > 2 || ( FREETYPE_MAJOR == 2 &&  FREETYPE_MINOR >= 9)
00051 #include FT_TRUETYPE_DRIVER_H
00052 #endif
00053 
00054 namespace Graphics {
00055 
00056 namespace {
00057 
00058 inline int ftCeil26_6(FT_Pos x) {
00059     return (x + 63) / 64;
00060 }
00061 
00062 inline int divRoundToNearest(int dividend, int divisor) {
00063     return (dividend + (divisor / 2)) / divisor;
00064 }
00065 
00066 } // End of anonymous namespace
00067 
00068 class TTFLibrary : public Common::Singleton<TTFLibrary> {
00069 public:
00070     TTFLibrary();
00071     ~TTFLibrary();
00072 
00076     bool isInitialized() const { return _initialized; }
00077 
00078     bool loadFont(const uint8 *file, const uint32 size, FT_Face &face);
00079     void closeFont(FT_Face &face);
00080 private:
00081     FT_Library _library;
00082     bool _initialized;
00083 };
00084 
00085 void shutdownTTF() {
00086     TTFLibrary::destroy();
00087 }
00088 
00089 #define g_ttf ::Graphics::TTFLibrary::instance()
00090 
00091 TTFLibrary::TTFLibrary() : _library(), _initialized(false) {
00092     if (!FT_Init_FreeType(&_library))
00093         _initialized = true;
00094 }
00095 
00096 TTFLibrary::~TTFLibrary() {
00097     if (_initialized) {
00098         FT_Done_FreeType(_library);
00099         _initialized = false;
00100     }
00101 }
00102 
00103 bool TTFLibrary::loadFont(const uint8 *file, const uint32 size, FT_Face &face) {
00104     assert(_initialized);
00105 
00106     return (FT_New_Memory_Face(_library, file, size, 0, &face) == 0);
00107 }
00108 
00109 void TTFLibrary::closeFont(FT_Face &face) {
00110     assert(_initialized);
00111 
00112     FT_Done_Face(face);
00113 }
00114 
00115 class TTFFont : public Font {
00116 public:
00117     TTFFont();
00118     virtual ~TTFFont();
00119 
00120     bool load(Common::SeekableReadStream &stream, int size, TTFSizeMode sizeMode, uint dpi, TTFRenderMode renderMode, const uint32 *mapping, bool stemDarkening);
00121 
00122     virtual int getFontHeight() const;
00123 
00124     virtual int getMaxCharWidth() const;
00125 
00126     virtual int getCharWidth(uint32 chr) const;
00127 
00128     virtual int getKerningOffset(uint32 left, uint32 right) const;
00129 
00130     virtual Common::Rect getBoundingBox(uint32 chr) const;
00131 
00132     virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const;
00133 private:
00134     bool _initialized;
00135     FT_Face _face;
00136 
00137     uint8 *_ttfFile;
00138     uint32 _size;
00139 
00140     int _width, _height;
00141     int _ascent, _descent;
00142 
00143     struct Glyph {
00144         Surface image;
00145         int xOffset, yOffset;
00146         int advance;
00147         FT_UInt slot;
00148     };
00149 
00150     bool cacheGlyph(Glyph &glyph, uint32 chr) const;
00151     typedef Common::HashMap<uint32, Glyph> GlyphCache;
00152     mutable GlyphCache _glyphs;
00153     bool _allowLateCaching;
00154     void assureCached(uint32 chr) const;
00155 
00156     Common::SeekableReadStream *readTTFTable(FT_ULong tag) const;
00157 
00158     int computePointSize(int size, TTFSizeMode sizeMode) const;
00159     int readPointSizeFromVDMXTable(int height) const;
00160     int computePointSizeFromHeaders(int height) const;
00161 
00162     FT_Int32 _loadFlags;
00163     FT_Render_Mode _renderMode;
00164     bool _hasKerning;
00165 };
00166 
00167 TTFFont::TTFFont()
00168     : _initialized(false), _face(), _ttfFile(0), _size(0), _width(0), _height(0), _ascent(0),
00169       _descent(0), _glyphs(), _loadFlags(FT_LOAD_TARGET_NORMAL), _renderMode(FT_RENDER_MODE_NORMAL),
00170       _hasKerning(false), _allowLateCaching(false) {
00171 }
00172 
00173 TTFFont::~TTFFont() {
00174     if (_initialized) {
00175         g_ttf.closeFont(_face);
00176 
00177         delete[] _ttfFile;
00178         _ttfFile = 0;
00179 
00180         for (GlyphCache::iterator i = _glyphs.begin(), end = _glyphs.end(); i != end; ++i)
00181             i->_value.image.free();
00182 
00183         _initialized = false;
00184     }
00185 }
00186 
00187 bool TTFFont::load(Common::SeekableReadStream &stream, int size, TTFSizeMode sizeMode, uint dpi, TTFRenderMode renderMode, const uint32 *mapping, bool stemDarkening) {
00188     if (!g_ttf.isInitialized())
00189         return false;
00190 
00191     _size = stream.size();
00192     if (!_size)
00193         return false;
00194 
00195     _ttfFile = new uint8[_size];
00196     assert(_ttfFile);
00197 
00198     if (stream.read(_ttfFile, _size) != _size) {
00199         delete[] _ttfFile;
00200         _ttfFile = 0;
00201 
00202         return false;
00203     }
00204 
00205     if (!g_ttf.loadFont(_ttfFile, _size, _face)) {
00206         delete[] _ttfFile;
00207         _ttfFile = 0;
00208 
00209         return false;
00210     }
00211 
00212     // We only support scalable fonts.
00213     if (!FT_IS_SCALABLE(_face)) {
00214         delete[] _ttfFile;
00215         _ttfFile = 0;
00216 
00217         g_ttf.closeFont(_face);
00218 
00219         return false;
00220     }
00221 
00222     // RedisualVM specific
00223     if (stemDarkening) {
00224 #if FREETYPE_MAJOR > 2 || ( FREETYPE_MAJOR == 2 &&  FREETYPE_MINOR >= 9)
00225         FT_Parameter param;
00226         param.tag = FT_PARAM_TAG_STEM_DARKENING;
00227         param.data = &stemDarkening;
00228         FT_Face_Properties(_face, 1, &param);
00229 #else
00230         warning("Stem darkening is not available with this version of FreeType");
00231 #endif
00232     }
00233 
00234     // Check whether we have kerning support
00235     _hasKerning = (FT_HAS_KERNING(_face) != 0);
00236 
00237     if (FT_Set_Char_Size(_face, 0, computePointSize(size, sizeMode) * 64, dpi, dpi)) {
00238         delete[] _ttfFile;
00239         _ttfFile = 0;
00240 
00241         return false;
00242     }
00243 
00244     switch (renderMode) {
00245     case kTTFRenderModeNormal:
00246         _loadFlags = FT_LOAD_TARGET_NORMAL;
00247         _renderMode = FT_RENDER_MODE_NORMAL;
00248         break;
00249 
00250     case kTTFRenderModeLight:
00251         _loadFlags = FT_LOAD_TARGET_LIGHT;
00252         _renderMode = FT_RENDER_MODE_LIGHT;
00253         break;
00254 
00255     case kTTFRenderModeMonochrome:
00256         _loadFlags = FT_LOAD_TARGET_MONO;
00257         _renderMode = FT_RENDER_MODE_MONO;
00258         break;
00259     }
00260 
00261     FT_Fixed yScale = _face->size->metrics.y_scale;
00262     _ascent = ftCeil26_6(FT_MulFix(_face->ascender, yScale));
00263     _descent = ftCeil26_6(FT_MulFix(_face->descender, yScale));
00264 
00265     _width = ftCeil26_6(FT_MulFix(_face->max_advance_width, _face->size->metrics.x_scale));
00266     _height = _ascent - _descent + 1;
00267 
00268     if (!mapping) {
00269         // Allow loading of all unicode characters.
00270         _allowLateCaching = true;
00271 
00272         // Load all ISO-8859-1 characters.
00273         for (uint i = 0; i < 256; ++i) {
00274             if (!cacheGlyph(_glyphs[i], i)) {
00275                 _glyphs.erase(i);
00276             }
00277         }
00278     } else {
00279         // We have a fixed map of characters do not load more later.
00280         _allowLateCaching = false;
00281 
00282         for (uint i = 0; i < 256; ++i) {
00283             const uint32 unicode = mapping[i] & 0x7FFFFFFF;
00284             const bool isRequired = (mapping[i] & 0x80000000) != 0;
00285             // Check whether loading an important glyph fails and error out if
00286             // that is the case.
00287             if (!cacheGlyph(_glyphs[i], unicode)) {
00288                 _glyphs.erase(i);
00289                 if (isRequired)
00290                     return false;
00291             }
00292         }
00293     }
00294 
00295     _initialized = (_glyphs.size() != 0);
00296     return _initialized;
00297 }
00298 
00299 int TTFFont::computePointSize(int size, TTFSizeMode sizeMode) const {
00300     int ptSize = 0;
00301     switch (sizeMode) {
00302     case kTTFSizeModeCell: {
00303         ptSize = readPointSizeFromVDMXTable(size);
00304 
00305         if (ptSize == 0) {
00306             ptSize = computePointSizeFromHeaders(size);
00307         }
00308 
00309         if (ptSize == 0) {
00310             warning("Unable to compute point size for font '%s'", _face->family_name);
00311             ptSize = 1;
00312         }
00313         break;
00314     }
00315     case kTTFSizeModeCharacter:
00316         ptSize = size;
00317         break;
00318     }
00319 
00320     return ptSize;
00321 }
00322 
00323 Common::SeekableReadStream *TTFFont::readTTFTable(FT_ULong tag) const {
00324     // Find the required buffer size by calling the load function with nullptr
00325     FT_ULong size = 0;
00326     FT_Error err = FT_Load_Sfnt_Table(_face, tag, 0, nullptr, &size);
00327     if (err) {
00328         return nullptr;
00329     }
00330 
00331     byte *buf = (byte *)malloc(size);
00332     if (!buf) {
00333         return nullptr;
00334     }
00335 
00336     err = FT_Load_Sfnt_Table(_face, tag, 0, buf, &size);
00337     if (err) {
00338         free(buf);
00339         return nullptr;
00340     }
00341 
00342     return new Common::MemoryReadStream(buf, size, DisposeAfterUse::YES);
00343 }
00344 
00345 int TTFFont::readPointSizeFromVDMXTable(int height) const {
00346     // The Vertical Device Metrics table matches font heights with point sizes.
00347     // FreeType does not expose it, we have to parse it ourselves.
00348     // See https://www.microsoft.com/typography/otspec/vdmx.htm
00349 
00350     Common::ScopedPtr<Common::SeekableReadStream> vdmxBuf(readTTFTable(TTAG_VDMX));
00351     if (!vdmxBuf) {
00352         return 0;
00353     }
00354 
00355     // Read the main header
00356     vdmxBuf->skip(4); // Skip the version
00357     uint16 numRatios = vdmxBuf->readUint16BE();
00358 
00359     // Compute the starting position for the group table positions table
00360     int32 offsetTableStart = vdmxBuf->pos() + 4 * numRatios;
00361 
00362     // Search the ratio table for the 1:1 ratio, or the default record (0, 0, 0)
00363     int32 selectedRatio = -1;
00364     for (uint16 i = 0; i < numRatios; i++) {
00365         vdmxBuf->skip(1); // Skip the charset subset
00366         uint8 xRatio = vdmxBuf->readByte();
00367         uint8 yRatio1 = vdmxBuf->readByte();
00368         uint8 yRatio2 = vdmxBuf->readByte();
00369 
00370         if ((xRatio == 1 && yRatio1 <= 1 && yRatio2 >= 1)
00371             || (xRatio == 0 && yRatio1 == 0 && yRatio2 == 0)) {
00372             selectedRatio = i;
00373             break;
00374         }
00375     }
00376     if (selectedRatio < 0) {
00377         return 0;
00378     }
00379 
00380     // Read from group table positions table to get the group table offset
00381     vdmxBuf->seek(offsetTableStart + sizeof(uint16) * selectedRatio);
00382     uint16 groupOffset = vdmxBuf->readUint16BE();
00383 
00384     // Read the group table header
00385     vdmxBuf->seek(groupOffset);
00386     uint16 numRecords = vdmxBuf->readUint16BE();
00387     vdmxBuf->skip(2); // Skip the table bounds
00388 
00389     // Search a record matching the required height
00390     for (uint16 i = 0; i < numRecords; i++) {
00391         uint16 pointSize = vdmxBuf->readUint16BE();
00392         int16 yMax = vdmxBuf->readSint16BE();
00393         int16 yMin = vdmxBuf->readSint16BE();
00394 
00395         if (yMax + -yMin > height) {
00396             return 0;
00397         }
00398         if (yMax + -yMin == height) {
00399             return pointSize;
00400         }
00401     }
00402 
00403     return 0;
00404 }
00405 
00406 int TTFFont::computePointSizeFromHeaders(int height) const {
00407     TT_OS2 *os2Header = (TT_OS2 *)FT_Get_Sfnt_Table(_face, ft_sfnt_os2);
00408     TT_HoriHeader *horiHeader = (TT_HoriHeader *)FT_Get_Sfnt_Table(_face, ft_sfnt_hhea);
00409 
00410     if (os2Header && (os2Header->usWinAscent + os2Header->usWinDescent != 0)) {
00411         return divRoundToNearest(_face->units_per_EM * height, os2Header->usWinAscent + os2Header->usWinDescent);
00412     } else if (horiHeader && (horiHeader->Ascender + horiHeader->Descender != 0)) {
00413         return divRoundToNearest(_face->units_per_EM * height, horiHeader->Ascender + horiHeader->Descender);
00414     }
00415 
00416     return 0;
00417 }
00418 
00419 int TTFFont::getFontHeight() const {
00420     return _height;
00421 }
00422 
00423 int TTFFont::getMaxCharWidth() const {
00424     return _width;
00425 }
00426 
00427 int TTFFont::getCharWidth(uint32 chr) const {
00428     assureCached(chr);
00429     GlyphCache::const_iterator glyphEntry = _glyphs.find(chr);
00430     if (glyphEntry == _glyphs.end())
00431         return 0;
00432     else
00433         return glyphEntry->_value.advance;
00434 }
00435 
00436 int TTFFont::getKerningOffset(uint32 left, uint32 right) const {
00437     if (!_hasKerning)
00438         return 0;
00439 
00440     assureCached(left);
00441     assureCached(right);
00442 
00443     FT_UInt leftGlyph, rightGlyph;
00444     GlyphCache::const_iterator glyphEntry;
00445 
00446     glyphEntry = _glyphs.find(left);
00447     if (glyphEntry != _glyphs.end()) {
00448         leftGlyph = glyphEntry->_value.slot;
00449     } else {
00450         return 0;
00451     }
00452 
00453     glyphEntry = _glyphs.find(right);
00454     if (glyphEntry != _glyphs.end()) {
00455         rightGlyph = glyphEntry->_value.slot;
00456     } else {
00457         return 0;
00458     }
00459 
00460     if (!leftGlyph || !rightGlyph)
00461         return 0;
00462 
00463     FT_Vector kerningVector;
00464     FT_Get_Kerning(_face, leftGlyph, rightGlyph, FT_KERNING_DEFAULT, &kerningVector);
00465     return (kerningVector.x / 64);
00466 }
00467 
00468 Common::Rect TTFFont::getBoundingBox(uint32 chr) const {
00469     assureCached(chr);
00470     GlyphCache::const_iterator glyphEntry = _glyphs.find(chr);
00471     if (glyphEntry == _glyphs.end()) {
00472         return Common::Rect();
00473     } else {
00474         const int xOffset = glyphEntry->_value.xOffset;
00475         const int yOffset = glyphEntry->_value.yOffset;
00476         const Graphics::Surface &image = glyphEntry->_value.image;
00477         return Common::Rect(xOffset, yOffset, xOffset + image.w, yOffset + image.h);
00478     }
00479 }
00480 
00481 namespace {
00482 
00483 template<typename ColorType>
00484 void renderGlyph(uint8 *dstPos, const int dstPitch, const uint8 *srcPos, const int srcPitch, const int w, const int h, ColorType color, const PixelFormat &dstFormat) {
00485     uint8 sR, sG, sB;
00486     dstFormat.colorToRGB(color, sR, sG, sB);
00487 
00488     for (int y = 0; y < h; ++y) {
00489         ColorType *rDst = (ColorType *)dstPos;
00490         const uint8 *src = srcPos;
00491 
00492         for (int x = 0; x < w; ++x) {
00493             if (*src == 255) {
00494                 *rDst = color;
00495             } else if (*src) {
00496                 const uint8 a = *src;
00497 
00498                 uint8 dR, dG, dB;
00499                 dstFormat.colorToRGB(*rDst, dR, dG, dB);
00500 
00501                 dR = ((255 - a) * dR + a * sR) / 255;
00502                 dG = ((255 - a) * dG + a * sG) / 255;
00503                 dB = ((255 - a) * dB + a * sB) / 255;
00504 
00505                 *rDst = dstFormat.RGBToColor(dR, dG, dB);
00506             }
00507 
00508             ++rDst;
00509             ++src;
00510         }
00511 
00512         dstPos += dstPitch;
00513         srcPos += srcPitch;
00514     }
00515 }
00516 
00517 } // End of anonymous namespace
00518 
00519 void TTFFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const {
00520     assureCached(chr);
00521     GlyphCache::const_iterator glyphEntry = _glyphs.find(chr);
00522     if (glyphEntry == _glyphs.end())
00523         return;
00524 
00525     const Glyph &glyph = glyphEntry->_value;
00526 
00527     x += glyph.xOffset;
00528     y += glyph.yOffset;
00529 
00530     if (x > dst->w)
00531         return;
00532     if (y > dst->h)
00533         return;
00534 
00535     int w = glyph.image.w;
00536     int h = glyph.image.h;
00537 
00538     const uint8 *srcPos = (const uint8 *)glyph.image.getPixels();
00539 
00540     // Make sure we are not drawing outside the screen bounds
00541     if (x < 0) {
00542         srcPos -= x;
00543         w += x;
00544         x = 0;
00545     }
00546 
00547     if (x + w > dst->w)
00548         w = dst->w - x;
00549 
00550     if (w <= 0)
00551         return;
00552 
00553     if (y < 0) {
00554         srcPos -= y * glyph.image.pitch;
00555         h += y;
00556         y = 0;
00557     }
00558 
00559     if (y + h > dst->h)
00560         h = dst->h - y;
00561 
00562     if (h <= 0)
00563         return;
00564 
00565     uint8 *dstPos = (uint8 *)dst->getBasePtr(x, y);
00566 
00567     if (dst->format.bytesPerPixel == 1) {
00568         for (int cy = 0; cy < h; ++cy) {
00569             uint8 *rDst = dstPos;
00570             const uint8 *src = srcPos;
00571 
00572             for (int cx = 0; cx < w; ++cx) {
00573                 // We assume a 1Bpp mode is a color indexed mode, thus we can
00574                 // not take advantage of anti-aliasing here.
00575                 if (*src >= 0x80)
00576                     *rDst = color;
00577 
00578                 ++rDst;
00579                 ++src;
00580             }
00581 
00582             dstPos += dst->pitch;
00583             srcPos += glyph.image.pitch;
00584         }
00585     } else if (dst->format.bytesPerPixel == 2) {
00586         renderGlyph<uint16>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format);
00587     } else if (dst->format.bytesPerPixel == 4) {
00588         renderGlyph<uint32>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format);
00589     }
00590 }
00591 
00592 bool TTFFont::cacheGlyph(Glyph &glyph, uint32 chr) const {
00593     FT_UInt slot = FT_Get_Char_Index(_face, chr);
00594     if (!slot)
00595         return false;
00596 
00597     glyph.slot = slot;
00598 
00599     // We use the light target and render mode to improve the looks of the
00600     // glyphs. It is most noticable in FreeSansBold.ttf, where otherwise the
00601     // 't' glyph looks like it is cut off on the right side.
00602     if (FT_Load_Glyph(_face, slot, _loadFlags))
00603         return false;
00604 
00605     if (FT_Render_Glyph(_face->glyph, _renderMode))
00606         return false;
00607 
00608     if (_face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
00609         return false;
00610 
00611     glyph.xOffset = _face->glyph->bitmap_left;
00612     glyph.yOffset = _ascent - _face->glyph->bitmap_top;
00613 
00614     glyph.advance = ftCeil26_6(_face->glyph->advance.x);
00615 
00616     const FT_Bitmap &bitmap = _face->glyph->bitmap;
00617     glyph.image.create(bitmap.width, bitmap.rows, PixelFormat::createFormatCLUT8());
00618 
00619     const uint8 *src = bitmap.buffer;
00620     int srcPitch = bitmap.pitch;
00621     if (srcPitch < 0) {
00622         src += (bitmap.rows - 1) * srcPitch;
00623         srcPitch = -srcPitch;
00624     }
00625 
00626     uint8 *dst = (uint8 *)glyph.image.getPixels();
00627     memset(dst, 0, glyph.image.h * glyph.image.pitch);
00628 
00629     switch (bitmap.pixel_mode) {
00630     case FT_PIXEL_MODE_MONO:
00631         for (int y = 0; y < (int)bitmap.rows; ++y) {
00632             const uint8 *curSrc = src;
00633             uint8 mask = 0;
00634 
00635             for (int x = 0; x < (int)bitmap.width; ++x) {
00636                 if ((x % 8) == 0)
00637                     mask = *curSrc++;
00638 
00639                 if (mask & 0x80)
00640                     *dst = 255;
00641 
00642                 mask <<= 1;
00643                 ++dst;
00644             }
00645 
00646             src += srcPitch;
00647         }
00648         break;
00649 
00650     case FT_PIXEL_MODE_GRAY:
00651         for (int y = 0; y < (int)bitmap.rows; ++y) {
00652             memcpy(dst, src, bitmap.width);
00653             dst += glyph.image.pitch;
00654             src += srcPitch;
00655         }
00656         break;
00657 
00658     default:
00659         warning("TTFFont::cacheGlyph: Unsupported pixel mode %d", bitmap.pixel_mode);
00660         glyph.image.free();
00661         return false;
00662     }
00663 
00664     return true;
00665 }
00666 
00667 void TTFFont::assureCached(uint32 chr) const {
00668     if (!chr || !_allowLateCaching || _glyphs.contains(chr)) {
00669         return;
00670     }
00671 
00672     Glyph newGlyph;
00673     if (cacheGlyph(newGlyph, chr)) {
00674         _glyphs[chr] = newGlyph;
00675     }
00676 }
00677 
00678 Font *loadTTFFont(Common::SeekableReadStream &stream, int size, TTFSizeMode sizeMode, uint dpi, TTFRenderMode renderMode, const uint32 *mapping, bool stemDarkening) {
00679     TTFFont *font = new TTFFont();
00680 
00681     if (!font->load(stream, size, sizeMode, dpi, renderMode, mapping, stemDarkening)) {
00682         delete font;
00683         return 0;
00684     }
00685 
00686     return font;
00687 }
00688 
00689 Font *loadTTFFontFromArchive(const Common::String &filename, int size, TTFSizeMode sizeMode, uint dpi, TTFRenderMode renderMode, const uint32 *mapping) {
00690     Common::SeekableReadStream *archiveStream = nullptr;
00691     if (ConfMan.hasKey("extrapath")) {
00692         Common::FSDirectory extrapath(ConfMan.get("extrapath"));
00693         archiveStream = extrapath.createReadStreamForMember("fonts.dat");
00694     }
00695 
00696     if (!archiveStream) {
00697         archiveStream = SearchMan.createReadStreamForMember("fonts.dat");
00698     }
00699 
00700     Common::Archive *archive = Common::makeZipArchive(archiveStream);
00701     if (!archive) {
00702         return nullptr;
00703     }
00704 
00705     Common::File f;
00706     if (!f.open(filename, *archive)) {
00707         return nullptr;
00708     }
00709 
00710     Font *font = loadTTFFont(f, size, sizeMode, dpi, renderMode, mapping);
00711 
00712     delete archive;
00713     return font;
00714 }
00715 
00716 } // End of namespace Graphics
00717 
00718 namespace Common {
00719 DECLARE_SINGLETON(Graphics::TTFLibrary);
00720 } // End of namespace Common
00721 
00722 #endif
00723 


Generated on Sat Aug 17 2019 05:00:43 for ResidualVM by doxygen 1.7.1
curved edge   curved edge