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

bdf.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 #include "graphics/fonts/bdf.h"
00024 
00025 #include "common/file.h"
00026 #include "common/endian.h"
00027 #include "common/textconsole.h"
00028 
00029 #include "graphics/surface.h"
00030 
00031 namespace Graphics {
00032 
00033 BdfFont::BdfFont(const BdfFontData &data, DisposeAfterUse::Flag dispose)
00034     : _data(data), _dispose(dispose) {
00035 }
00036 
00037 BdfFont::~BdfFont() {
00038     if (_dispose == DisposeAfterUse::YES) {
00039         for (int i = 0; i < _data.numCharacters; ++i)
00040             delete[] _data.bitmaps[i];
00041         delete[] _data.bitmaps;
00042         delete[] _data.advances;
00043         delete[] _data.boxes;
00044         delete[] _data.familyName;
00045         delete[] _data.slant;
00046     }
00047 }
00048 
00049 const char *BdfFont::getFamilyName() const {
00050     return _data.familyName;
00051 }
00052 
00053 const char *BdfFont::getFontSlant() const {
00054     return _data.slant;
00055 }
00056 
00057 int BdfFont::getFontHeight() const {
00058     return _data.height;
00059 }
00060 
00061 int BdfFont::getFontSize() const {
00062     return _data.size;
00063 }
00064 
00065 int BdfFont::getMaxCharWidth() const {
00066     return _data.maxAdvance;
00067 }
00068 
00069 int BdfFont::getCharWidth(uint32 chr) const {
00070     // In case all font have the same advance value, we use the maximum.
00071     if (!_data.advances)
00072         return _data.maxAdvance;
00073 
00074     const int ch = mapToIndex(chr);
00075     // In case no mapping exists, we use the maximum advance.
00076     if (ch < 0)
00077         return _data.maxAdvance;
00078     else
00079         return _data.advances[ch];
00080 }
00081 
00082 
00083 template<typename PixelType>
00084 void drawCharIntern(byte *ptr, uint pitch, const byte *src, int h, int width, int minX, int maxX, const PixelType color) {
00085     byte data = 0;
00086     while (h--) {
00087         PixelType *dst = (PixelType *)ptr;
00088 
00089         for (int x = 0; x < width; ++x) {
00090             if (!(x % 8))
00091                 data = *src++;
00092 
00093             if (x >= minX && x <= maxX && (data & 0x80))
00094                 dst[x] = color;
00095 
00096             data <<= 1;
00097         }
00098 
00099         ptr += pitch;
00100     }
00101 }
00102 
00103 int BdfFont::mapToIndex(uint32 ch) const {
00104     // Check whether the character is included
00105     if (_data.firstCharacter <= (int)ch && (int)ch <= _data.firstCharacter + _data.numCharacters) {
00106         if (_data.bitmaps[ch - _data.firstCharacter])
00107             return ch - _data.firstCharacter;
00108     }
00109 
00110     return _data.defaultCharacter - _data.firstCharacter;
00111 }
00112 
00113 void BdfFont::drawChar(Surface *dst, uint32 chr, const int tx, const int ty, const uint32 color) const {
00114     assert(dst != 0);
00115 
00116     // TODO: Where is the relation between the max advance being smaller or
00117     // equal to 50 and the decision of the theme designer?
00118     // asserting _data.maxAdvance <= 50: let the theme designer decide what looks best
00119     //assert(_data.maxAdvance <= 50);
00120     assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4);
00121 
00122     const int idx = mapToIndex(chr);
00123     if (idx < 0)
00124         return;
00125 
00126     int width, height, xOffset, yOffset;
00127 
00128     // Get the bounding box of the character
00129     if (!_data.boxes) {
00130         width = _data.defaultBox.width;
00131         height = _data.defaultBox.height;
00132         xOffset = _data.defaultBox.xOffset;
00133         yOffset = _data.defaultBox.yOffset;
00134     } else {
00135         width = _data.boxes[idx].width;
00136         height = _data.boxes[idx].height;
00137         xOffset = _data.boxes[idx].xOffset;
00138         yOffset = _data.boxes[idx].yOffset;
00139     }
00140 
00141     int y = ty + _data.ascent - yOffset - height;
00142     int x = tx + xOffset;
00143 
00144     const byte *src = _data.bitmaps[idx];
00145 
00146     const int bytesPerRow = (width + 7) / 8;
00147     const int originalWidth = width;
00148 
00149     // Make sure we do not draw outside the surface
00150     if (y < 0) {
00151         src -= y * bytesPerRow;
00152         height += y;
00153         y = 0;
00154     }
00155 
00156     if (y + height > dst->h)
00157         height = dst->h - y;
00158 
00159     if (height <= 0)
00160         return;
00161 
00162     int xStart = 0;
00163     if (x < 0) {
00164         xStart = -x;
00165         width += x;
00166         x = 0;
00167     }
00168 
00169     if (x + width > dst->w)
00170         width = dst->w - x;
00171 
00172     if (width <= 0)
00173         return;
00174 
00175     const int xEnd = xStart + width - 1;
00176 
00177     byte *ptr = (byte *)dst->getBasePtr(x, y);
00178 
00179     if (dst->format.bytesPerPixel == 1)
00180         drawCharIntern<byte>(ptr, dst->pitch, src, height, originalWidth, xStart, xEnd, color);
00181     else if (dst->format.bytesPerPixel == 2)
00182         drawCharIntern<uint16>(ptr, dst->pitch, src, height, originalWidth, xStart, xEnd, color);
00183     else if (dst->format.bytesPerPixel == 4)
00184         drawCharIntern<uint32>(ptr, dst->pitch, src, height, originalWidth, xStart, xEnd, color);
00185 }
00186 
00187 namespace {
00188 
00189 inline byte hexToInt(char c) {
00190     if (c >= '0' && c <= '9')
00191         return c - '0';
00192     else if (c >= 'A' && c <= 'F')
00193         return c - 'A' + 10;
00194     else if (c >= 'a' && c <= 'f')
00195         return c - 'a' + 10;
00196     else
00197         return 0;
00198 }
00199 
00200 byte *loadCharacter(Common::SeekableReadStream &stream, int &encoding, int &advance, BdfBoundingBox &box) {
00201     Common::String line;
00202     byte *bitmap = 0;
00203 
00204     while (true) {
00205         line = stream.readLine();
00206         line.trim();    // BDF files created from unifont tools (make hex)
00207                         // have a rogue space character after the "BITMAP" label
00208 
00209         if (stream.err() || stream.eos()) {
00210             warning("BdfFont::loadCharacter: Premature end of file");
00211             delete[] bitmap;
00212             return 0;
00213         }
00214 
00215         if (line.hasPrefix("ENCODING ")) {
00216             if (sscanf(line.c_str(), "ENCODING %d", &encoding) != 1) {
00217                 warning("BdfFont::loadCharacter: Invalid ENCODING");
00218                 delete[] bitmap;
00219                 return 0;
00220             }
00221         } else if (line.hasPrefix("DWIDTH ")) {
00222             int yAdvance;
00223             if (sscanf(line.c_str(), "DWIDTH %d %d", &advance, &yAdvance) != 2) {
00224                 warning("BdfFont::loadCharacter: Invalid DWIDTH");
00225                 delete[] bitmap;
00226                 return 0;
00227             }
00228 
00229             if (yAdvance != 0) {
00230                 warning("BdfFont::loadCharacter: Character %d has an y advance of %d", encoding, yAdvance);
00231                 delete[] bitmap;
00232                 return 0;
00233             }
00234 
00235             if (advance < 0) {
00236                 warning("BdfFont::loadCharacter: Character %d has an x advance of %d", encoding, advance);
00237                 delete[] bitmap;
00238                 return 0;
00239             }
00240         } else if (line.hasPrefix("BBX ")) {
00241             int width, height, xOffset, yOffset;
00242             if (sscanf(line.c_str(), "BBX %d %d %d %d",
00243                        &width, &height, &xOffset, &yOffset) != 4) {
00244                 warning("BdfFont::loadCharacter: Invalid BBX");
00245                 delete[] bitmap;
00246                 return 0;
00247             }
00248 
00249             box.width = width;
00250             box.height = height;
00251             box.xOffset = xOffset;
00252             box.yOffset = yOffset;
00253         } else if (line == "BITMAP") {
00254             const uint bytesPerRow = (box.width + 7) / 8;
00255 
00256             if (bitmap) {
00257                 warning("Bdf::loadCharacter(): Double BITMAP definitions");
00258                 delete[] bitmap;
00259             }
00260 
00261             byte *dst = bitmap = new byte[box.height * bytesPerRow];
00262 
00263             for (int y = 0; y < box.height; ++y) {
00264                 line = stream.readLine();
00265                 if (stream.err() || stream.eos()) {
00266                     warning("BdfFont::loadCharacter: Premature end of file");
00267                     delete[] bitmap;
00268                     return 0;
00269                 }
00270 
00271                 if (line.size() != 2 * bytesPerRow) {
00272                     warning("BdfFont::loadCharacter: Pixel line has wrong size");
00273                     delete[] bitmap;
00274                     return 0;
00275                 }
00276 
00277                 for (uint x = 0; x < bytesPerRow; ++x) {
00278                     char nibble1 = line[x * 2 + 0];
00279                     char nibble2 = line[x * 2 + 1];
00280                     *dst++ = (hexToInt(nibble1) << 4) | hexToInt(nibble2);
00281                 }
00282             }
00283         } else if (line == "ENDCHAR") {
00284             return bitmap;
00285         }
00286     }
00287 }
00288 
00289 void freeBitmaps(byte **bitmaps, int size) {
00290     for (int i = 0; i < size; ++i)
00291         delete[] bitmaps[i];
00292 }
00293 
00294 } // End of anonymous namespace
00295 
00296 BdfFont *BdfFont::loadFont(Common::SeekableReadStream &stream) {
00297     BdfFontData font;
00298     memset(&font, 0, sizeof(font));
00299     font.ascent = -1;
00300     font.defaultCharacter = -1;
00301 
00302     // We only load the first 256 characters
00303     font.numCharacters = 256;
00304     byte **bitmaps = new byte *[font.numCharacters];
00305     memset(bitmaps, 0, sizeof(byte *) * font.numCharacters);
00306     byte *advances = new byte[font.numCharacters];
00307     BdfBoundingBox *boxes = new BdfBoundingBox[font.numCharacters];
00308     char *familyName = nullptr;
00309     char *slant = nullptr;
00310 
00311     int descent = -1;
00312 
00313     Common::String line;
00314     while (true) {
00315         line = stream.readLine();
00316         if (stream.err() || stream.eos()) {
00317             warning("BdfFont::loadFont: Premature end of file");
00318             freeBitmaps(bitmaps, font.numCharacters);
00319             delete[] bitmaps;
00320             delete[] advances;
00321             delete[] boxes;
00322             delete[] familyName;
00323             delete[] slant;
00324             return 0;
00325         }
00326 
00327         // Only parse and handle declarations we actually need
00328         if (line.hasPrefix("FONTBOUNDINGBOX ")) {
00329             int width, height, xOffset, yOffset;
00330             if (sscanf(line.c_str(), "FONTBOUNDINGBOX %d %d %d %d",
00331                        &width, &height, &xOffset, &yOffset) != 4) {
00332                 warning("BdfFont::loadFont: Invalid FONTBOUNDINGBOX");
00333                 freeBitmaps(bitmaps, font.numCharacters);
00334                 delete[] bitmaps;
00335                 delete[] advances;
00336                 delete[] boxes;
00337                 delete[] familyName;
00338                 delete[] slant;
00339                 return 0;
00340             }
00341 
00342             font.defaultBox.width = width;
00343             font.defaultBox.height = height;
00344             font.defaultBox.xOffset = xOffset;
00345             font.defaultBox.yOffset = yOffset;
00346         } else if (line.hasPrefix("PIXEL_SIZE ")) {
00347             if (sscanf(line.c_str(), "PIXEL_SIZE %d", &font.size) != 1) {
00348                 warning("BdfFont::loadFont: Invalid PIXEL_SIZE");
00349                 freeBitmaps(bitmaps, font.numCharacters);
00350                 delete[] bitmaps;
00351                 delete[] advances;
00352                 delete[] boxes;
00353                 delete[] familyName;
00354                 delete[] slant;
00355                 return 0;
00356             }
00357         } else if (line.hasPrefix("FONT_ASCENT ")) {
00358             if (sscanf(line.c_str(), "FONT_ASCENT %d", &font.ascent) != 1) {
00359                 warning("BdfFont::loadFont: Invalid FONT_ASCENT");
00360                 freeBitmaps(bitmaps, font.numCharacters);
00361                 delete[] bitmaps;
00362                 delete[] advances;
00363                 delete[] boxes;
00364                 delete[] familyName;
00365                 delete[] slant;
00366                 return 0;
00367             }
00368         } else if (line.hasPrefix("FONT_DESCENT ")) {
00369             if (sscanf(line.c_str(), "FONT_DESCENT %d", &descent) != 1) {
00370                 warning("BdfFont::loadFont: Invalid FONT_DESCENT");
00371                 freeBitmaps(bitmaps, font.numCharacters);
00372                 delete[] bitmaps;
00373                 delete[] advances;
00374                 delete[] boxes;
00375                 delete[] familyName;
00376                 delete[] slant;
00377                 return 0;
00378             }
00379         } else if (line.hasPrefix("DEFAULT_CHAR ")) {
00380             if (sscanf(line.c_str(), "DEFAULT_CHAR %d", &font.defaultCharacter) != 1) {
00381                 warning("BdfFont::loadFont: Invalid DEFAULT_CHAR");
00382                 freeBitmaps(bitmaps, font.numCharacters);
00383                 delete[] bitmaps;
00384                 delete[] advances;
00385                 delete[] boxes;
00386                 delete[] familyName;
00387                 delete[] slant;
00388                 return 0;
00389             }
00390         } else if (line.hasPrefix("STARTCHAR ")) {
00391             BdfBoundingBox box = font.defaultBox;
00392             int encoding = -1;
00393             int advance = -1;
00394             byte *bitmap = loadCharacter(stream, encoding, advance, box);
00395 
00396             // Ignore all characters above 255.
00397             if (encoding < -1 || encoding >= font.numCharacters) {
00398                 delete[] bitmap;
00399                 encoding = -1;
00400             }
00401 
00402             // Calculate the max advance
00403             if (encoding != -1 && advance > font.maxAdvance)
00404                 font.maxAdvance = advance;
00405 
00406             if (!bitmap && encoding != -1) {
00407                 warning("BdfFont::loadFont: Character %d invalid", encoding);
00408                 freeBitmaps(bitmaps, font.numCharacters);
00409                 delete[] bitmaps;
00410                 delete[] advances;
00411                 delete[] boxes;
00412                 delete[] familyName;
00413                 delete[] slant;
00414                 return 0;
00415             }
00416 
00417             if (encoding != -1) {
00418                 bitmaps[encoding] = bitmap;
00419                 advances[encoding] = advance;
00420                 boxes[encoding] = box;
00421             }
00422         } else if (line.hasPrefix("FAMILY_NAME \"")) {
00423             if (familyName != nullptr) {
00424                 warning("BdfFont::loadFont: Duplicated FAMILY_NAME");
00425                 delete[] familyName;
00426             }
00427             familyName = new char[line.size()];
00428             Common::strlcpy(familyName, line.c_str() + 13, line.size() - 12);   // strlcpy() copies at most size-1 characters and then add a '\0'
00429             char *p = &familyName[strlen(familyName)];
00430             while (p != familyName && *p != '"')
00431                 p--;
00432             if (p == familyName) {
00433                 warning("BdfFont::loadFont: Invalid FAMILY_NAME");
00434                 freeBitmaps(bitmaps, font.numCharacters);
00435                 delete[] bitmaps;
00436                 delete[] advances;
00437                 delete[] boxes;
00438                 delete[] familyName;
00439                 delete[] slant;
00440                 return 0;
00441             }
00442             *p = '\0'; // Remove last quote
00443         } else if (line.hasPrefix("SLANT \"")) {
00444             if (slant != nullptr) {
00445                 warning("BdfFont::loadFont: Duplicated SLANT");
00446                 delete[] slant;
00447             }
00448             slant = new char[line.size()];
00449             Common::strlcpy(slant, line.c_str() + 7, line.size() - 6);  // strlcpy() copies at most size-1 characters and then add a '\0'
00450             char *p = &slant[strlen(slant)];
00451             while (p != slant && *p != '"')
00452                 p--;
00453             if (p == slant) {
00454                 warning("BdfFont::loadFont: Invalid SLANT");
00455                 freeBitmaps(bitmaps, font.numCharacters);
00456                 delete[] bitmaps;
00457                 delete[] advances;
00458                 delete[] boxes;
00459                 delete[] familyName;
00460                 delete[] slant;
00461                 return 0;
00462             }
00463             *p = '\0'; // Remove last quote
00464         } else if (line == "ENDFONT") {
00465             break;
00466         }
00467     }
00468 
00469     if (font.ascent < 0 || descent < 0) {
00470         warning("BdfFont::loadFont: Invalid ascent or descent");
00471         freeBitmaps(bitmaps, font.numCharacters);
00472         delete[] bitmaps;
00473         delete[] advances;
00474         delete[] boxes;
00475         delete[] familyName;
00476         delete[] slant;
00477         return 0;
00478     }
00479 
00480     font.height = font.ascent + descent;
00481 
00482     font.bitmaps = bitmaps;
00483     font.advances = advances;
00484     font.boxes = boxes;
00485     font.familyName = familyName;
00486     font.slant = slant;
00487 
00488     int firstCharacter = font.numCharacters;
00489     int lastCharacter = -1;
00490     bool hasFixedBBox = true;
00491     bool hasFixedAdvance = true;
00492 
00493     for (int i = 0; i < font.numCharacters; ++i) {
00494         if (!font.bitmaps[i])
00495             continue;
00496 
00497         if (i < firstCharacter)
00498             firstCharacter = i;
00499 
00500         if (i > lastCharacter)
00501             lastCharacter = i;
00502 
00503         if (font.advances[i] != font.maxAdvance)
00504             hasFixedAdvance = false;
00505 
00506         const BdfBoundingBox &bbox = font.boxes[i];
00507         if (bbox.width != font.defaultBox.width
00508             || bbox.height != font.defaultBox.height
00509             || bbox.xOffset != font.defaultBox.xOffset
00510             || bbox.yOffset != font.defaultBox.yOffset)
00511             hasFixedBBox = false;
00512     }
00513 
00514     if (lastCharacter == -1) {
00515         warning("BdfFont::loadFont: No glyphs found");
00516         delete[] font.bitmaps;
00517         delete[] font.advances;
00518         delete[] font.boxes;
00519         delete[] familyName;
00520         delete[] slant;
00521         return 0;
00522     }
00523 
00524     // Free the advance table, in case all glyphs use the same advance
00525     if (hasFixedAdvance) {
00526         delete[] font.advances;
00527         font.advances = 0;
00528     }
00529 
00530     // Free the box table, in case all glyphs use the same box
00531     if (hasFixedBBox) {
00532         delete[] font.boxes;
00533         font.boxes = 0;
00534     }
00535 
00536     // Adapt for the fact that we never use encoding 0.
00537     if (font.defaultCharacter < firstCharacter
00538         || font.defaultCharacter > lastCharacter)
00539         font.defaultCharacter = -1;
00540 
00541     font.firstCharacter = firstCharacter;
00542 
00543     const int charsAvailable = lastCharacter - firstCharacter + 1;
00544     // Try to compact the tables
00545     if (charsAvailable < font.numCharacters) {
00546         byte **newBitmaps = new byte *[charsAvailable];
00547         boxes = 0;
00548         advances = 0;
00549         if (!hasFixedBBox)
00550             boxes = new BdfBoundingBox[charsAvailable];
00551         if (!hasFixedAdvance)
00552             advances = new byte[charsAvailable];
00553 
00554         for (int i = 0; i < charsAvailable; ++i) {
00555             const int encoding = i + firstCharacter;
00556             if (font.bitmaps[encoding]) {
00557                 newBitmaps[i] = bitmaps[encoding];
00558 
00559                 if (!hasFixedBBox)
00560                     boxes[i] = font.boxes[encoding];
00561                 if (!hasFixedAdvance)
00562                     advances[i] = font.advances[encoding];
00563             } else {
00564                 newBitmaps[i] = 0;
00565             }
00566         }
00567 
00568         delete[] font.bitmaps;
00569         font.bitmaps = newBitmaps;
00570         delete[] font.advances;
00571         font.advances = advances;
00572         delete[] font.boxes;
00573         font.boxes = boxes;
00574 
00575         font.numCharacters = charsAvailable;
00576     }
00577 
00578     return new BdfFont(font, DisposeAfterUse::YES);
00579 }
00580 
00581 #define BDF_FONTCACHE_TAG MKTAG('S', 'V', 'F', 'C')
00582 #define BDF_FONTCACHE_VERSION 1
00583 
00584 bool BdfFont::cacheFontData(const BdfFont &font, const Common::String &filename) {
00585     Common::DumpFile cacheFile;
00586     if (!cacheFile.open(filename)) {
00587         warning("BdfFont::cacheFontData: Couldn't open file '%s' for writing", filename.c_str());
00588         return false;
00589     }
00590 
00591     const BdfFontData &data = font._data;
00592 
00593     cacheFile.writeUint32BE(BDF_FONTCACHE_TAG);
00594     cacheFile.writeUint32BE(BDF_FONTCACHE_VERSION);
00595     cacheFile.writeUint16BE(data.maxAdvance);
00596     cacheFile.writeByte(data.height);
00597     cacheFile.writeByte(data.defaultBox.width);
00598     cacheFile.writeByte(data.defaultBox.height);
00599     cacheFile.writeSByte(data.defaultBox.xOffset);
00600     cacheFile.writeSByte(data.defaultBox.yOffset);
00601     cacheFile.writeByte(data.ascent);
00602     cacheFile.writeUint16BE(data.firstCharacter);
00603     cacheFile.writeSint16BE(data.defaultCharacter);
00604     cacheFile.writeUint16BE(data.numCharacters);
00605 
00606     for (int i = 0; i < data.numCharacters; ++i) {
00607         const BdfBoundingBox &box = data.boxes ? data.boxes[i] : data.defaultBox;
00608         if (data.bitmaps[i]) {
00609             const int bytes = ((box.width + 7) / 8) * box.height;
00610             cacheFile.writeUint32BE(bytes);
00611             cacheFile.write(data.bitmaps[i], bytes);
00612         } else {
00613             cacheFile.writeUint32BE(0);
00614         }
00615     }
00616 
00617     if (data.advances) {
00618         cacheFile.writeByte(0xFF);
00619         cacheFile.write(data.advances, data.numCharacters);
00620     } else {
00621         cacheFile.writeByte(0x00);
00622     }
00623 
00624     if (data.boxes) {
00625         cacheFile.writeByte(0xFF);
00626 
00627         for (int i = 0; i < data.numCharacters; ++i) {
00628             const BdfBoundingBox &box = data.boxes[i];
00629             cacheFile.writeByte(box.width);
00630             cacheFile.writeByte(box.height);
00631             cacheFile.writeSByte(box.xOffset);
00632             cacheFile.writeSByte(box.yOffset);
00633         }
00634     } else {
00635         cacheFile.writeByte(0x00);
00636     }
00637 
00638     return !cacheFile.err();
00639 }
00640 
00641 BdfFont *BdfFont::loadFromCache(Common::SeekableReadStream &stream) {
00642     const uint32 magic = stream.readUint32BE();
00643     if (magic != BDF_FONTCACHE_TAG)
00644         return nullptr;
00645 
00646     const uint32 version = stream.readUint32BE();
00647     if (version != BDF_FONTCACHE_VERSION)
00648         return nullptr;
00649 
00650     BdfFontData data;
00651 
00652     data.maxAdvance = stream.readUint16BE();
00653     data.height = stream.readByte();
00654     data.defaultBox.width = stream.readByte();
00655     data.defaultBox.height = stream.readByte();
00656     data.defaultBox.xOffset = stream.readSByte();
00657     data.defaultBox.yOffset = stream.readSByte();
00658     data.ascent = stream.readByte();
00659     data.firstCharacter = stream.readUint16BE();
00660     data.defaultCharacter = stream.readSint16BE();
00661     data.numCharacters = stream.readUint16BE();
00662 
00663     if (stream.err() || stream.eos())
00664         return nullptr;
00665 
00666     if (data.numCharacters == 0) {
00667         warning("BdfFont::loadFromCache(): Requested to load 0 characters font");
00668         return nullptr;
00669     }
00670 
00671     byte **bitmaps = new byte *[data.numCharacters];
00672     byte *advances = 0;
00673     BdfBoundingBox *boxes = 0;
00674     for (int i = 0; i < data.numCharacters; ++i) {
00675         uint32 size = stream.readUint32BE();
00676 
00677         if (stream.err() || stream.eos()) {
00678             for (int j = 0; j < i; ++j)
00679                 delete[] bitmaps[i];
00680             delete[] bitmaps;
00681             return nullptr;
00682         }
00683 
00684         if (size) {
00685             bitmaps[i] = new byte[size];
00686             stream.read(bitmaps[i], size);
00687         } else {
00688             bitmaps[i] = 0;
00689         }
00690     }
00691 
00692 
00693     if (stream.readByte() == 0xFF) {
00694         advances = new byte[data.numCharacters];
00695         stream.read(advances, data.numCharacters);
00696     }
00697 
00698     if (stream.readByte() == 0xFF) {
00699         boxes = new BdfBoundingBox[data.numCharacters];
00700         for (int i = 0; i < data.numCharacters; ++i) {
00701             boxes[i].width = stream.readByte();
00702             boxes[i].height = stream.readByte();
00703             boxes[i].xOffset = stream.readSByte();
00704             boxes[i].yOffset = stream.readSByte();
00705         }
00706     }
00707 
00708     if (stream.eos() || stream.err()) {
00709         for (int i = 0; i < data.numCharacters; ++i)
00710             delete[] bitmaps[i];
00711         delete[] bitmaps;
00712         delete[] advances;
00713         delete[] boxes;
00714         return nullptr;
00715     }
00716 
00717     data.bitmaps = bitmaps;
00718     data.advances = advances;
00719     data.boxes = boxes;
00720     data.familyName = nullptr;
00721     data.slant = nullptr;
00722     data.size = data.height;
00723     return new BdfFont(data, DisposeAfterUse::YES);
00724 }
00725 
00726 BdfFont *BdfFont::scaleFont(BdfFont *src, int newSize) {
00727     if (!src) {
00728         warning("BdfFont::scaleFont(): Empty font reference in scale font");
00729         return nullptr;
00730     }
00731 
00732     if (src->getFontSize() == 0) {
00733         warning("BdfFont::scaleFont(): Requested to scale 0 size font");
00734         return nullptr;
00735     }
00736 
00737     if (src->_data.numCharacters == 0) {
00738         warning("BdfFont::scaleFont(): Requested to scale 0 characters font");
00739         return nullptr;
00740     }
00741 
00742     float scale = (float)newSize / (float)src->getFontSize();
00743 
00744     BdfFontData data;
00745 
00746     data.maxAdvance = (int)((float)src->_data.maxAdvance * scale);
00747     data.height = (int)((float)src->_data.height * scale);
00748     data.size = (int)((float)src->_data.size * scale);
00749     data.defaultBox.width = (int)((float)src->_data.defaultBox.width * scale);
00750     data.defaultBox.height = (int)((float)src->_data.defaultBox.height * scale);
00751     data.defaultBox.xOffset = (int)((float)src->_data.defaultBox.xOffset * scale);
00752     data.defaultBox.yOffset = (int)((float)src->_data.defaultBox.yOffset * scale);
00753     data.ascent = (int)((float)src->_data.ascent * scale);
00754     data.firstCharacter = src->_data.firstCharacter;
00755     data.defaultCharacter = src->_data.defaultCharacter;
00756     data.numCharacters = src->_data.numCharacters;
00757     char *familyName = new char[1 + strlen(src->_data.familyName)];
00758     strcpy(familyName, src->_data.familyName);
00759     data.familyName = familyName;
00760     char *slant = new char[1 + strlen(src->_data.slant)];
00761     strcpy(slant, src->_data.slant);
00762     data.slant = slant;
00763 
00764     BdfBoundingBox *boxes = new BdfBoundingBox[data.numCharacters];
00765     for (int i = 0; i < data.numCharacters; ++i) {
00766         boxes[i].width = (int)((float)src->_data.boxes[i].width * scale);
00767         boxes[i].height = (int)((float)src->_data.boxes[i].height * scale);
00768         boxes[i].xOffset = (int)((float)src->_data.boxes[i].xOffset * scale);
00769         boxes[i].yOffset = (int)((float)src->_data.boxes[i].yOffset * scale);
00770     }
00771     data.boxes = boxes;
00772 
00773     byte *advances = new byte[data.numCharacters];
00774     for (int i = 0; i < data.numCharacters; ++i) {
00775         advances[i] = (int)((float)src->_data.advances[i] * scale);
00776     }
00777     data.advances = advances;
00778 
00779     byte **bitmaps = new byte *[data.numCharacters];
00780 
00781     for (int i = 0; i < data.numCharacters; i++) {
00782         const BdfBoundingBox &box = data.boxes ? data.boxes[i] : data.defaultBox;
00783         const BdfBoundingBox &srcBox = data.boxes ? src->_data.boxes[i] : src->_data.defaultBox;
00784 
00785         if (src->_data.bitmaps[i]) {
00786             const int bytes = ((box.width + 7) / 8) * box.height; // Dimensions have been already corrected
00787             bitmaps[i] = new byte[bytes];
00788 
00789             int srcPitch = (srcBox.width + 7) / 8;
00790             int dstPitch = (box.width + 7) / 8;
00791 
00792             byte *ptr = bitmaps[i];
00793 
00794             for (int y = 0; y < box.height; y++) {
00795                 const byte *srcd = (const byte *)&src->_data.bitmaps[i][((int)((float)y / scale)) * srcPitch];
00796                 byte *dst = ptr;
00797                 byte b = 0;
00798 
00799                 for (int x = 0; x < box.width; x++) {
00800                     b <<= 1;
00801 
00802                     int sx = (int)((float)x / scale);
00803 
00804                     if (srcd[sx / 8] & (0x80 >> (sx % 8)))
00805                         b |= 1;
00806 
00807                     if (x % 8 == 7) {
00808                         *dst++ = b;
00809                         b = 0;
00810                     }
00811                 }
00812 
00813                 if (((box.width - 1) % 8)) {
00814                     b <<= 7 - ((box.width - 1) % 8);
00815                     *dst = b;
00816                 }
00817 
00818                 ptr += dstPitch;
00819             }
00820 
00821         } else {
00822             bitmaps[i] = 0;
00823         }
00824     }
00825 
00826     data.bitmaps = bitmaps;
00827 
00828     return new BdfFont(data, DisposeAfterUse::YES);
00829 }
00830 
00831 } // End of namespace Graphics


Generated on Sat May 30 2020 05:01:01 for ResidualVM by doxygen 1.7.1
curved edge   curved edge