Home | History | Annotate | Download | only in opentype
      1 /*
      2  * Copyright (C) 2008, 2009 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2009 Torch Mobile, Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "platform/fonts/opentype/OpenTypeUtilities.h"
     29 
     30 #include "platform/SharedBuffer.h"
     31 
     32 namespace WebCore {
     33 
     34 struct BigEndianUShort {
     35     operator unsigned short() const { return (v & 0x00ff) << 8 | v >> 8; }
     36     BigEndianUShort(unsigned short u) : v((u & 0x00ff) << 8 | u >> 8) { }
     37     unsigned short v;
     38 };
     39 
     40 struct BigEndianULong {
     41     operator unsigned() const { return (v & 0xff) << 24 | (v & 0xff00) << 8 | (v & 0xff0000) >> 8 | v >> 24; }
     42     BigEndianULong(unsigned u) : v((u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | u >> 24) { }
     43     unsigned v;
     44 };
     45 
     46 #pragma pack(1)
     47 
     48 struct TableDirectoryEntry {
     49     BigEndianULong tag;
     50     BigEndianULong checkSum;
     51     BigEndianULong offset;
     52     BigEndianULong length;
     53 };
     54 
     55 // Fixed type is not defined on non-CG and Windows platforms. |version| in sfntHeader
     56 // and headTable and |fontRevision| in headTable are of Fixed, but they're
     57 // not actually refered to anywhere. Therefore, we just have to match
     58 // the size (4 bytes). For the definition of Fixed type, see
     59 // http://developer.apple.com/documentation/mac/Legacy/GXEnvironment/GXEnvironment-356.html#HEADING356-6.
     60 typedef int32_t Fixed;
     61 
     62 struct sfntHeader {
     63     Fixed version;
     64     BigEndianUShort numTables;
     65     BigEndianUShort searchRange;
     66     BigEndianUShort entrySelector;
     67     BigEndianUShort rangeShift;
     68     TableDirectoryEntry tables[1];
     69 };
     70 
     71 struct OS2Table {
     72     BigEndianUShort version;
     73     BigEndianUShort avgCharWidth;
     74     BigEndianUShort weightClass;
     75     BigEndianUShort widthClass;
     76     BigEndianUShort fsType;
     77     BigEndianUShort subscriptXSize;
     78     BigEndianUShort subscriptYSize;
     79     BigEndianUShort subscriptXOffset;
     80     BigEndianUShort subscriptYOffset;
     81     BigEndianUShort superscriptXSize;
     82     BigEndianUShort superscriptYSize;
     83     BigEndianUShort superscriptXOffset;
     84     BigEndianUShort superscriptYOffset;
     85     BigEndianUShort strikeoutSize;
     86     BigEndianUShort strikeoutPosition;
     87     BigEndianUShort familyClass;
     88     uint8_t panose[10];
     89     BigEndianULong unicodeRange[4];
     90     uint8_t vendID[4];
     91     BigEndianUShort fsSelection;
     92     BigEndianUShort firstCharIndex;
     93     BigEndianUShort lastCharIndex;
     94     BigEndianUShort typoAscender;
     95     BigEndianUShort typoDescender;
     96     BigEndianUShort typoLineGap;
     97     BigEndianUShort winAscent;
     98     BigEndianUShort winDescent;
     99     BigEndianULong codePageRange[2];
    100     BigEndianUShort xHeight;
    101     BigEndianUShort capHeight;
    102     BigEndianUShort defaultChar;
    103     BigEndianUShort breakChar;
    104     BigEndianUShort maxContext;
    105 };
    106 
    107 struct headTable {
    108     Fixed version;
    109     Fixed fontRevision;
    110     BigEndianULong checkSumAdjustment;
    111     BigEndianULong magicNumber;
    112     BigEndianUShort flags;
    113     BigEndianUShort unitsPerEm;
    114     long long created;
    115     long long modified;
    116     BigEndianUShort xMin;
    117     BigEndianUShort xMax;
    118     BigEndianUShort yMin;
    119     BigEndianUShort yMax;
    120     BigEndianUShort macStyle;
    121     BigEndianUShort lowestRectPPEM;
    122     BigEndianUShort fontDirectionHint;
    123     BigEndianUShort indexToLocFormat;
    124     BigEndianUShort glyphDataFormat;
    125 };
    126 
    127 struct nameRecord {
    128     BigEndianUShort platformID;
    129     BigEndianUShort encodingID;
    130     BigEndianUShort languageID;
    131     BigEndianUShort nameID;
    132     BigEndianUShort length;
    133     BigEndianUShort offset;
    134 };
    135 
    136 struct nameTable {
    137     BigEndianUShort format;
    138     BigEndianUShort count;
    139     BigEndianUShort stringOffset;
    140     nameRecord nameRecords[1];
    141 };
    142 
    143 #pragma pack()
    144 
    145 // adds fontName to the font table in fontData, and writes the new font table to rewrittenFontTable
    146 // returns the size of the name table (which is used by renameAndActivateFont), or 0 on early abort
    147 static size_t renameFont(SharedBuffer* fontData, const String& fontName, Vector<char> &rewrittenFontData)
    148 {
    149     size_t originalDataSize = fontData->size();
    150     const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(fontData->data());
    151 
    152     unsigned t;
    153     for (t = 0; t < sfnt->numTables; ++t) {
    154         if (sfnt->tables[t].tag == 'name')
    155             break;
    156     }
    157     if (t == sfnt->numTables)
    158         return 0;
    159 
    160     const int nameRecordCount = 5;
    161 
    162     // Rounded up to a multiple of 4 to simplify the checksum calculation.
    163     size_t nameTableSize = ((offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord) + fontName.length() * sizeof(UChar)) & ~3) + 4;
    164 
    165     rewrittenFontData.resize(fontData->size() + nameTableSize);
    166     char* data = rewrittenFontData.data();
    167     memcpy(data, fontData->data(), originalDataSize);
    168 
    169     // Make the table directory entry point to the new 'name' table.
    170     sfntHeader* rewrittenSfnt = reinterpret_cast<sfntHeader*>(data);
    171     rewrittenSfnt->tables[t].length = nameTableSize;
    172     rewrittenSfnt->tables[t].offset = originalDataSize;
    173 
    174     // Write the new 'name' table after the original font data.
    175     nameTable* name = reinterpret_cast<nameTable*>(data + originalDataSize);
    176     name->format = 0;
    177     name->count = nameRecordCount;
    178     name->stringOffset = offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord);
    179     for (unsigned i = 0; i < nameRecordCount; ++i) {
    180         name->nameRecords[i].platformID = 3;
    181         name->nameRecords[i].encodingID = 1;
    182         name->nameRecords[i].languageID = 0x0409;
    183         name->nameRecords[i].offset = 0;
    184         name->nameRecords[i].length = fontName.length() * sizeof(UChar);
    185     }
    186 
    187     // The required 'name' record types: Family, Style, Unique, Full and PostScript.
    188     name->nameRecords[0].nameID = 1;
    189     name->nameRecords[1].nameID = 2;
    190     name->nameRecords[2].nameID = 3;
    191     name->nameRecords[3].nameID = 4;
    192     name->nameRecords[4].nameID = 6;
    193 
    194     for (unsigned i = 0; i < fontName.length(); ++i)
    195         reinterpret_cast<BigEndianUShort*>(data + originalDataSize + name->stringOffset)[i] = fontName[i];
    196 
    197     // Update the table checksum in the directory entry.
    198     rewrittenSfnt->tables[t].checkSum = 0;
    199     for (unsigned i = 0; i * sizeof(BigEndianULong) < nameTableSize; ++i)
    200         rewrittenSfnt->tables[t].checkSum = rewrittenSfnt->tables[t].checkSum + reinterpret_cast<BigEndianULong*>(name)[i];
    201 
    202     return nameTableSize;
    203 }
    204 
    205 // Rename the font and install the new font data into the system
    206 HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName)
    207 {
    208     Vector<char> rewrittenFontData;
    209     size_t nameTableSize = renameFont(fontData, fontName, rewrittenFontData);
    210     if (!nameTableSize)
    211         return 0;
    212 
    213     DWORD numFonts = 0;
    214     HANDLE fontHandle = AddFontMemResourceEx(rewrittenFontData.data(), fontData->size() + nameTableSize, 0, &numFonts);
    215 
    216     if (fontHandle && numFonts < 1) {
    217         RemoveFontMemResourceEx(fontHandle);
    218         return 0;
    219     }
    220 
    221     return fontHandle;
    222 }
    223 
    224 }
    225