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             byte *dst = bitmap = new byte[box.height * bytesPerRow];
00256 
00257             for (int y = 0; y < box.height; ++y) {
00258                 line = stream.readLine();
00259                 if (stream.err() || stream.eos()) {
00260                     warning("BdfFont::loadCharacter: Premature end of file");
00261                     delete[] bitmap;
00262                     return 0;
00263                 }
00264 
00265                 if (line.size() != 2 * bytesPerRow) {
00266                     warning("BdfFont::loadCharacter: Pixel line has wrong size");
00267                     delete[] bitmap;
00268                     return 0;
00269                 }
00270 
00271                 for (uint x = 0; x < bytesPerRow; ++x) {
00272                     char nibble1 = line[x * 2 + 0];
00273                     char nibble2 = line[x * 2 + 1];
00274                     *dst++ = (hexToInt(nibble1) << 4) | hexToInt(nibble2);
00275                 }
00276             }
00277         } else if (line == "ENDCHAR") {
00278             return bitmap;
00279         }
00280     }
00281 }
00282 
00283 void freeBitmaps(byte **bitmaps, int size) {
00284     for (int i = 0; i < size; ++i)
00285         delete[] bitmaps[i];
00286 }
00287 
00288 } // End of anonymous namespace
00289 
00290 BdfFont *BdfFont::loadFont(Common::SeekableReadStream &stream) {
00291     BdfFontData font;
00292     memset(&font, 0, sizeof(font));
00293     font.ascent = -1;
00294     font.defaultCharacter = -1;
00295 
00296     // We only load the first 256 characters
00297     font.numCharacters = 256;
00298     byte **bitmaps = new byte *[font.numCharacters];
00299     memset(bitmaps, 0, sizeof(byte *) * font.numCharacters);
00300     byte *advances = new byte[font.numCharacters];
00301     BdfBoundingBox *boxes = new BdfBoundingBox[font.numCharacters];
00302     char *familyName = nullptr;
00303     char *slant = nullptr;
00304 
00305     int descent = -1;
00306 
00307     Common::String line;
00308     while (true) {
00309         line = stream.readLine();
00310         if (stream.err() || stream.eos()) {
00311             warning("BdfFont::loadFont: Premature end of file");
00312             freeBitmaps(bitmaps, font.numCharacters);
00313             delete[] bitmaps;
00314             delete[] advances;
00315             delete[] boxes;
00316             delete[] familyName;
00317             delete[] slant;
00318             return 0;
00319         }
00320 
00321         // Only parse and handle declarations we actually need
00322         if (line.hasPrefix("FONTBOUNDINGBOX ")) {
00323             int width, height, xOffset, yOffset;
00324             if (sscanf(line.c_str(), "FONTBOUNDINGBOX %d %d %d %d",
00325                        &width, &height, &xOffset, &yOffset) != 4) {
00326                 warning("BdfFont::loadFont: Invalid FONTBOUNDINGBOX");
00327                 freeBitmaps(bitmaps, font.numCharacters);
00328                 delete[] bitmaps;
00329                 delete[] advances;
00330                 delete[] boxes;
00331                 delete[] familyName;
00332                 delete[] slant;
00333                 return 0;
00334             }
00335 
00336             font.defaultBox.width = width;
00337             font.defaultBox.height = height;
00338             font.defaultBox.xOffset = xOffset;
00339             font.defaultBox.yOffset = yOffset;
00340         } else if (line.hasPrefix("PIXEL_SIZE ")) {
00341             if (sscanf(line.c_str(), "PIXEL_SIZE %d", &font.size) != 1) {
00342                 warning("BdfFont::loadFont: Invalid PIXEL_SIZE");
00343                 freeBitmaps(bitmaps, font.numCharacters);
00344                 delete[] bitmaps;
00345                 delete[] advances;
00346                 delete[] boxes;
00347                 delete[] familyName;
00348                 delete[] slant;
00349                 return 0;
00350             }
00351         } else if (line.hasPrefix("FONT_ASCENT ")) {
00352             if (sscanf(line.c_str(), "FONT_ASCENT %d", &font.ascent) != 1) {
00353                 warning("BdfFont::loadFont: Invalid FONT_ASCENT");
00354                 freeBitmaps(bitmaps, font.numCharacters);
00355                 delete[] bitmaps;
00356                 delete[] advances;
00357                 delete[] boxes;
00358                 delete[] familyName;
00359                 delete[] slant;
00360                 return 0;
00361             }
00362         } else if (line.hasPrefix("FONT_DESCENT ")) {
00363             if (sscanf(line.c_str(), "FONT_DESCENT %d", &descent) != 1) {
00364                 warning("BdfFont::loadFont: Invalid FONT_DESCENT");
00365                 freeBitmaps(bitmaps, font.numCharacters);
00366                 delete[] bitmaps;
00367                 delete[] advances;
00368                 delete[] boxes;
00369                 delete[] familyName;
00370                 delete[] slant;
00371                 return 0;
00372             }
00373         } else if (line.hasPrefix("DEFAULT_CHAR ")) {
00374             if (sscanf(line.c_str(), "DEFAULT_CHAR %d", &font.defaultCharacter) != 1) {
00375                 warning("BdfFont::loadFont: Invalid DEFAULT_CHAR");
00376                 freeBitmaps(bitmaps, font.numCharacters);
00377                 delete[] bitmaps;
00378                 delete[] advances;
00379                 delete[] boxes;
00380                 delete[] familyName;
00381                 delete[] slant;
00382                 return 0;
00383             }
00384         } else if (line.hasPrefix("STARTCHAR ")) {
00385             BdfBoundingBox box = font.defaultBox;
00386             int encoding = -1;
00387             int advance = -1;
00388             byte *bitmap = loadCharacter(stream, encoding, advance, box);
00389 
00390             // Ignore all characters above 255.
00391             if (encoding < -1 || encoding >= font.numCharacters) {
00392                 delete[] bitmap;
00393                 encoding = -1;
00394             }
00395 
00396             // Calculate the max advance
00397             if (encoding != -1 && advance > font.maxAdvance)
00398                 font.maxAdvance = advance;
00399 
00400             if (!bitmap && encoding != -1) {
00401                 warning("BdfFont::loadFont: Character %d invalid", encoding);
00402                 freeBitmaps(bitmaps, font.numCharacters);
00403                 delete[] bitmaps;
00404                 delete[] advances;
00405                 delete[] boxes;
00406                 delete[] familyName;
00407                 delete[] slant;
00408                 return 0;
00409             }
00410 
00411             if (encoding != -1) {
00412                 bitmaps[encoding] = bitmap;
00413                 advances[encoding] = advance;
00414                 boxes[encoding] = box;
00415             }
00416         } else if (line.hasPrefix("FAMILY_NAME \"")) {
00417             familyName = new char[line.size()];
00418             Common::strlcpy(familyName, line.c_str() + 13, line.size() - 12);   // strlcpy() copies at most size-1 characters and then add a '\0'
00419             char *p = &familyName[strlen(familyName)];
00420             while (p != familyName && *p != '"')
00421                 p--;
00422             if (p == familyName) {
00423                 warning("BdfFont::loadFont: Invalid FAMILY_NAME");
00424                 freeBitmaps(bitmaps, font.numCharacters);
00425                 delete[] bitmaps;
00426                 delete[] advances;
00427                 delete[] boxes;
00428                 delete[] familyName;
00429                 delete[] slant;
00430                 return 0;
00431             }
00432             *p = '\0'; // Remove last quote
00433         } else if (line.hasPrefix("SLANT \"")) {
00434             slant = new char[line.size()];
00435             Common::strlcpy(slant, line.c_str() + 7, line.size() - 6);  // strlcpy() copies at most size-1 characters and then add a '\0'
00436             char *p = &slant[strlen(slant)];
00437             while (p != slant && *p != '"')
00438                 p--;
00439             if (p == slant) {
00440                 warning("BdfFont::loadFont: Invalid SLANT");
00441                 freeBitmaps(bitmaps, font.numCharacters);
00442                 delete[] bitmaps;
00443                 delete[] advances;
00444                 delete[] boxes;
00445                 delete[] familyName;
00446                 delete[] slant;
00447                 return 0;
00448             }
00449             *p = '\0'; // Remove last quote
00450         } else if (line == "ENDFONT") {
00451             break;
00452         }
00453     }
00454 
00455     if (font.ascent < 0 || descent < 0) {
00456         warning("BdfFont::loadFont: Invalid ascent or descent");
00457         freeBitmaps(bitmaps, font.numCharacters);
00458         delete[] bitmaps;
00459         delete[] advances;
00460         delete[] boxes;
00461         delete[] familyName;
00462         delete[] slant;
00463         return 0;
00464     }
00465 
00466     font.height = font.ascent + descent;
00467 
00468     font.bitmaps = bitmaps;
00469     font.advances = advances;
00470     font.boxes = boxes;
00471     font.familyName = familyName;
00472     font.slant = slant;
00473 
00474     int firstCharacter = font.numCharacters;
00475     int lastCharacter = -1;
00476     bool hasFixedBBox = true;
00477     bool hasFixedAdvance = true;
00478 
00479     for (int i = 0; i < font.numCharacters; ++i) {
00480         if (!font.bitmaps[i])
00481             continue;
00482 
00483         if (i < firstCharacter)
00484             firstCharacter = i;
00485 
00486         if (i > lastCharacter)
00487             lastCharacter = i;
00488 
00489         if (font.advances[i] != font.maxAdvance)
00490             hasFixedAdvance = false;
00491 
00492         const BdfBoundingBox &bbox = font.boxes[i];
00493         if (bbox.width != font.defaultBox.width
00494             || bbox.height != font.defaultBox.height
00495             || bbox.xOffset != font.defaultBox.xOffset
00496             || bbox.yOffset != font.defaultBox.yOffset)
00497             hasFixedBBox = false;
00498     }
00499 
00500     if (lastCharacter == -1) {
00501         warning("BdfFont::loadFont: No glyphs found");
00502         delete[] font.bitmaps;
00503         delete[] font.advances;
00504         delete[] font.boxes;
00505         delete[] familyName;
00506         delete[] slant;
00507         return 0;
00508     }
00509 
00510     // Free the advance table, in case all glyphs use the same advance
00511     if (hasFixedAdvance) {
00512         delete[] font.advances;
00513         font.advances = 0;
00514     }
00515 
00516     // Free the box table, in case all glyphs use the same box
00517     if (hasFixedBBox) {
00518         delete[] font.boxes;
00519         font.boxes = 0;
00520     }
00521 
00522     // Adapt for the fact that we never use encoding 0.
00523     if (font.defaultCharacter < firstCharacter
00524         || font.defaultCharacter > lastCharacter)
00525         font.defaultCharacter = -1;
00526 
00527     font.firstCharacter = firstCharacter;
00528 
00529     const int charsAvailable = lastCharacter - firstCharacter + 1;
00530     // Try to compact the tables
00531     if (charsAvailable < font.numCharacters) {
00532         byte **newBitmaps = new byte *[charsAvailable];
00533         boxes = 0;
00534         advances = 0;
00535         if (!hasFixedBBox)
00536             boxes = new BdfBoundingBox[charsAvailable];
00537         if (!hasFixedAdvance)
00538             advances = new byte[charsAvailable];
00539 
00540         for (int i = 0; i < charsAvailable; ++i) {
00541             const int encoding = i + firstCharacter;
00542             if (font.bitmaps[encoding]) {
00543                 newBitmaps[i] = bitmaps[encoding];
00544 
00545                 if (!hasFixedBBox)
00546                     boxes[i] = font.boxes[encoding];
00547                 if (!hasFixedAdvance)
00548                     advances[i] = font.advances[encoding];
00549             } else {
00550                 newBitmaps[i] = 0;
00551             }
00552         }
00553 
00554         delete[] font.bitmaps;
00555         font.bitmaps = newBitmaps;
00556         delete[] font.advances;
00557         font.advances = advances;
00558         delete[] font.boxes;
00559         font.boxes = boxes;
00560 
00561         font.numCharacters = charsAvailable;
00562     }
00563 
00564     return new BdfFont(font, DisposeAfterUse::YES);
00565 }
00566 
00567 #define BDF_FONTCACHE_TAG MKTAG('S', 'V', 'F', 'C')
00568 #define BDF_FONTCACHE_VERSION 1
00569 
00570 bool BdfFont::cacheFontData(const BdfFont &font, const Common::String &filename) {
00571     Common::DumpFile cacheFile;
00572     if (!cacheFile.open(filename)) {
00573         warning("BdfFont::cacheFontData: Couldn't open file '%s' for writing", filename.c_str());
00574         return false;
00575     }
00576 
00577     const BdfFontData &data = font._data;
00578 
00579     cacheFile.writeUint32BE(BDF_FONTCACHE_TAG);
00580     cacheFile.writeUint32BE(BDF_FONTCACHE_VERSION);
00581     cacheFile.writeUint16BE(data.maxAdvance);
00582     cacheFile.writeByte(data.height);
00583     cacheFile.writeByte(data.defaultBox.width);
00584     cacheFile.writeByte(data.defaultBox.height);
00585     cacheFile.writeSByte(data.defaultBox.xOffset);
00586     cacheFile.writeSByte(data.defaultBox.yOffset);
00587     cacheFile.writeByte(data.ascent);
00588     cacheFile.writeUint16BE(data.firstCharacter);
00589     cacheFile.writeSint16BE(data.defaultCharacter);
00590     cacheFile.writeUint16BE(data.numCharacters);
00591 
00592     for (int i = 0; i < data.numCharacters; ++i) {
00593         const BdfBoundingBox &box = data.boxes ? data.boxes[i] : data.defaultBox;
00594         if (data.bitmaps[i]) {
00595             const int bytes = ((box.width + 7) / 8) * box.height;
00596             cacheFile.writeUint32BE(bytes);
00597             cacheFile.write(data.bitmaps[i], bytes);
00598         } else {
00599             cacheFile.writeUint32BE(0);
00600         }
00601     }
00602 
00603     if (data.advances) {
00604         cacheFile.writeByte(0xFF);
00605         cacheFile.write(data.advances, data.numCharacters);
00606     } else {
00607         cacheFile.writeByte(0x00);
00608     }
00609 
00610     if (data.boxes) {
00611         cacheFile.writeByte(0xFF);
00612 
00613         for (int i = 0; i < data.numCharacters; ++i) {
00614             const BdfBoundingBox &box = data.boxes[i];
00615             cacheFile.writeByte(box.width);
00616             cacheFile.writeByte(box.height);
00617             cacheFile.writeSByte(box.xOffset);
00618             cacheFile.writeSByte(box.yOffset);
00619         }
00620     } else {
00621         cacheFile.writeByte(0x00);
00622     }
00623 
00624     return !cacheFile.err();
00625 }
00626 
00627 BdfFont *BdfFont::loadFromCache(Common::SeekableReadStream &stream) {
00628     const uint32 magic = stream.readUint32BE();
00629     if (magic != BDF_FONTCACHE_TAG)
00630         return 0;
00631 
00632     const uint32 version = stream.readUint32BE();
00633     if (version != BDF_FONTCACHE_VERSION)
00634         return 0;
00635 
00636     BdfFontData data;
00637 
00638     data.maxAdvance = stream.readUint16BE();
00639     data.height = stream.readByte();
00640     data.defaultBox.width = stream.readByte();
00641     data.defaultBox.height = stream.readByte();
00642     data.defaultBox.xOffset = stream.readSByte();
00643     data.defaultBox.yOffset = stream.readSByte();
00644     data.ascent = stream.readByte();
00645     data.firstCharacter = stream.readUint16BE();
00646     data.defaultCharacter = stream.readSint16BE();
00647     data.numCharacters = stream.readUint16BE();
00648 
00649     if (stream.err() || stream.eos())
00650         return 0;
00651 
00652     byte **bitmaps = new byte *[data.numCharacters];
00653     byte *advances = 0;
00654     BdfBoundingBox *boxes = 0;
00655     for (int i = 0; i < data.numCharacters; ++i) {
00656         uint32 size = stream.readUint32BE();
00657 
00658         if (stream.err() || stream.eos()) {
00659             for (int j = 0; j < i; ++j)
00660                 delete[] bitmaps[i];
00661             delete[] bitmaps;
00662             return 0;
00663         }
00664 
00665         if (size) {
00666             bitmaps[i] = new byte[size];
00667             stream.read(bitmaps[i], size);
00668         } else {
00669             bitmaps[i] = 0;
00670         }
00671     }
00672 
00673 
00674     if (stream.readByte() == 0xFF) {
00675         advances = new byte[data.numCharacters];
00676         stream.read(advances, data.numCharacters);
00677     }
00678 
00679     if (stream.readByte() == 0xFF) {
00680         boxes = new BdfBoundingBox[data.numCharacters];
00681         for (int i = 0; i < data.numCharacters; ++i) {
00682             boxes[i].width = stream.readByte();
00683             boxes[i].height = stream.readByte();
00684             boxes[i].xOffset = stream.readSByte();
00685             boxes[i].yOffset = stream.readSByte();
00686         }
00687     }
00688 
00689     if (stream.eos() || stream.err()) {
00690         for (int i = 0; i < data.numCharacters; ++i)
00691             delete[] bitmaps[i];
00692         delete[] bitmaps;
00693         delete[] advances;
00694         delete[] boxes;
00695         return 0;
00696     }
00697 
00698     data.bitmaps = bitmaps;
00699     data.advances = advances;
00700     data.boxes = boxes;
00701     data.familyName = nullptr;
00702     data.slant = nullptr;
00703     return new BdfFont(data, DisposeAfterUse::YES);
00704 }
00705 
00706 BdfFont *BdfFont::scaleFont(BdfFont *src, int newSize) {
00707     if (!src) {
00708         warning("Empty font reference in scale font");
00709         return NULL;
00710     }
00711 
00712     if (src->getFontSize() == 0) {
00713         warning("Requested to scale 0 size font");
00714         return NULL;
00715     }
00716 
00717     float scale = (float)newSize / (float)src->getFontSize();
00718 
00719     BdfFontData data;
00720 
00721     data.maxAdvance = (int)((float)src->_data.maxAdvance * scale);
00722     data.height = (int)((float)src->_data.height * scale);
00723     data.defaultBox.width = (int)((float)src->_data.defaultBox.width * scale);
00724     data.defaultBox.height = (int)((float)src->_data.defaultBox.height * scale);
00725     data.defaultBox.xOffset = (int)((float)src->_data.defaultBox.xOffset * scale);
00726     data.defaultBox.yOffset = (int)((float)src->_data.defaultBox.yOffset * scale);
00727     data.ascent = (int)((float)src->_data.ascent * scale);
00728     data.firstCharacter = src->_data.firstCharacter;
00729     data.defaultCharacter = src->_data.defaultCharacter;
00730     data.numCharacters = src->_data.numCharacters;
00731     data.familyName = scumm_strdup(src->_data.familyName);
00732     data.slant = scumm_strdup(src->_data.slant);
00733 
00734     BdfBoundingBox *boxes = new BdfBoundingBox[data.numCharacters];
00735     for (int i = 0; i < data.numCharacters; ++i) {
00736         boxes[i].width = (int)((float)src->_data.boxes[i].width * scale);
00737         boxes[i].height = (int)((float)src->_data.boxes[i].height * scale);
00738         boxes[i].xOffset = (int)((float)src->_data.boxes[i].xOffset * scale);
00739         boxes[i].yOffset = (int)((float)src->_data.boxes[i].yOffset * scale);
00740     }
00741     data.boxes = boxes;
00742 
00743     byte *advances = new byte[data.numCharacters];
00744     for (int i = 0; i < data.numCharacters; ++i) {
00745         advances[i] = (int)((float)src->_data.advances[i] * scale);
00746     }
00747     data.advances = advances;
00748 
00749     byte **bitmaps = new byte *[data.numCharacters];
00750 
00751     for (int i = 0; i < data.numCharacters; i++) {
00752         const BdfBoundingBox &box = data.boxes ? data.boxes[i] : data.defaultBox;
00753         const BdfBoundingBox &srcBox = data.boxes ? src->_data.boxes[i] : src->_data.defaultBox;
00754 
00755         if (src->_data.bitmaps[i]) {
00756             const int bytes = ((box.width + 7) / 8) * box.height; // Dimensions have been already corrected
00757             bitmaps[i] = new byte[bytes];
00758 
00759             int srcPitch = (srcBox.width + 7) / 8;
00760             int dstPitch = (box.width + 7) / 8;
00761 
00762             byte *ptr = bitmaps[i];
00763 
00764             for (int y = 0; y < box.height; y++) {
00765                 const byte *srcd = (const byte *)&src->_data.bitmaps[i][((int)((float)y / scale)) * srcPitch];
00766                 byte *dst = ptr;
00767                 byte b = 0;
00768 
00769                 for (int x = 0; x < box.width; x++) {
00770                     int sx = (int)((float)x / scale);
00771 
00772                     if (srcd[sx / 8] & (0x80 >> (sx % 8)))
00773                         b |= 1;
00774 
00775                     if (!(x % 8) && x) {
00776                         *dst++ = b;
00777                         b = 0;
00778                     }
00779 
00780                     b <<= 1;
00781                 }
00782 
00783                 if (((box.width - 1) % 8)) {
00784                     b <<= 7 - ((box.width - 1) % 8);
00785                     *dst = b;
00786                 }
00787 
00788                 ptr += dstPitch;
00789             }
00790 
00791         } else {
00792             bitmaps[i] = 0;
00793         }
00794     }
00795 
00796     data.bitmaps = bitmaps;
00797 
00798     return new BdfFont(data, DisposeAfterUse::YES);
00799 }
00800 
00801 } // End of namespace Graphics


Generated on Sat Oct 12 2019 05:01:05 for ResidualVM by doxygen 1.7.1
curved edge   curved edge