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


Generated on Sat May 25 2019 05:00:39 for ResidualVM by doxygen 1.7.1
curved edge   curved edge