| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2008 Apple Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions | |
| 6 * are met: | |
| 7 * 1. Redistributions of source code must retain the above copyright | |
| 8 * notice, this list of conditions and the following disclaimer. | |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | |
| 10 * notice, this list of conditions and the following disclaimer in the | |
| 11 * documentation and/or other materials provided with the distribution. | |
| 12 * | |
| 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | |
| 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
| 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 24 */ | |
| 25 | |
| 26 #include "config.h" | |
| 27 #include "OpenTypeUtilities.h" | |
| 28 | |
| 29 #include "SharedBuffer.h" | |
| 30 | |
| 31 namespace WebCore { | |
| 32 | |
| 33 struct BigEndianUShort { | |
| 34 operator unsigned short() const { return (v & 0x00ff) << 8 | v >> 8; } | |
| 35 BigEndianUShort(unsigned short u) : v((u & 0x00ff) << 8 | u >> 8) { } | |
| 36 unsigned short v; | |
| 37 }; | |
| 38 | |
| 39 struct BigEndianULong { | |
| 40 operator unsigned() const { return (v & 0xff) << 24 | (v & 0xff00) << 8 | (v
& 0xff0000) >> 8 | v >> 24; } | |
| 41 BigEndianULong(unsigned u) : v((u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0
xff0000) >> 8 | u >> 24) { } | |
| 42 unsigned v; | |
| 43 }; | |
| 44 | |
| 45 #pragma pack(1) | |
| 46 | |
| 47 struct EOTPrefix { | |
| 48 unsigned eotSize; | |
| 49 unsigned fontDataSize; | |
| 50 unsigned version; | |
| 51 unsigned flags; | |
| 52 UInt8 fontPANOSE[10]; | |
| 53 UInt8 charset; | |
| 54 UInt8 italic; | |
| 55 unsigned weight; | |
| 56 unsigned short fsType; | |
| 57 unsigned short magicNumber; | |
| 58 unsigned unicodeRange[4]; | |
| 59 unsigned codePageRange[2]; | |
| 60 unsigned checkSumAdjustment; | |
| 61 unsigned reserved[4]; | |
| 62 unsigned short padding1; | |
| 63 }; | |
| 64 | |
| 65 struct TableDirectoryEntry { | |
| 66 BigEndianULong tag; | |
| 67 BigEndianULong checkSum; | |
| 68 BigEndianULong offset; | |
| 69 BigEndianULong length; | |
| 70 }; | |
| 71 | |
| 72 struct sfntHeader { | |
| 73 Fixed version; | |
| 74 BigEndianUShort numTables; | |
| 75 BigEndianUShort searchRange; | |
| 76 BigEndianUShort entrySelector; | |
| 77 BigEndianUShort rangeShift; | |
| 78 TableDirectoryEntry tables[1]; | |
| 79 }; | |
| 80 | |
| 81 struct OS2Table { | |
| 82 BigEndianUShort version; | |
| 83 BigEndianUShort avgCharWidth; | |
| 84 BigEndianUShort weightClass; | |
| 85 BigEndianUShort widthClass; | |
| 86 BigEndianUShort fsType; | |
| 87 BigEndianUShort subscriptXSize; | |
| 88 BigEndianUShort subscriptYSize; | |
| 89 BigEndianUShort subscriptXOffset; | |
| 90 BigEndianUShort subscriptYOffset; | |
| 91 BigEndianUShort superscriptXSize; | |
| 92 BigEndianUShort superscriptYSize; | |
| 93 BigEndianUShort superscriptXOffset; | |
| 94 BigEndianUShort superscriptYOffset; | |
| 95 BigEndianUShort strikeoutSize; | |
| 96 BigEndianUShort strikeoutPosition; | |
| 97 BigEndianUShort familyClass; | |
| 98 UInt8 panose[10]; | |
| 99 BigEndianULong unicodeRange[4]; | |
| 100 UInt8 vendID[4]; | |
| 101 BigEndianUShort fsSelection; | |
| 102 BigEndianUShort firstCharIndex; | |
| 103 BigEndianUShort lastCharIndex; | |
| 104 BigEndianUShort typoAscender; | |
| 105 BigEndianUShort typoDescender; | |
| 106 BigEndianUShort typoLineGap; | |
| 107 BigEndianUShort winAscent; | |
| 108 BigEndianUShort winDescent; | |
| 109 BigEndianULong codePageRange[2]; | |
| 110 BigEndianUShort xHeight; | |
| 111 BigEndianUShort capHeight; | |
| 112 BigEndianUShort defaultChar; | |
| 113 BigEndianUShort breakChar; | |
| 114 BigEndianUShort maxContext; | |
| 115 }; | |
| 116 | |
| 117 struct headTable { | |
| 118 Fixed version; | |
| 119 Fixed fontRevision; | |
| 120 BigEndianULong checkSumAdjustment; | |
| 121 BigEndianULong magicNumber; | |
| 122 BigEndianUShort flags; | |
| 123 BigEndianUShort unitsPerEm; | |
| 124 long long created; | |
| 125 long long modified; | |
| 126 BigEndianUShort xMin; | |
| 127 BigEndianUShort xMax; | |
| 128 BigEndianUShort yMin; | |
| 129 BigEndianUShort yMax; | |
| 130 BigEndianUShort macStyle; | |
| 131 BigEndianUShort lowestRectPPEM; | |
| 132 BigEndianUShort fontDirectionHint; | |
| 133 BigEndianUShort indexToLocFormat; | |
| 134 BigEndianUShort glyphDataFormat; | |
| 135 }; | |
| 136 | |
| 137 struct nameRecord { | |
| 138 BigEndianUShort platformID; | |
| 139 BigEndianUShort encodingID; | |
| 140 BigEndianUShort languageID; | |
| 141 BigEndianUShort nameID; | |
| 142 BigEndianUShort length; | |
| 143 BigEndianUShort offset; | |
| 144 }; | |
| 145 | |
| 146 struct nameTable { | |
| 147 BigEndianUShort format; | |
| 148 BigEndianUShort count; | |
| 149 BigEndianUShort stringOffset; | |
| 150 nameRecord nameRecords[1]; | |
| 151 }; | |
| 152 | |
| 153 #pragma pack() | |
| 154 | |
| 155 static void appendBigEndianStringToEOTHeader(Vector<UInt8, 512>& eotHeader, cons
t BigEndianUShort* string, unsigned short length) | |
| 156 { | |
| 157 size_t size = eotHeader.size(); | |
| 158 eotHeader.resize(size + length + 2 * sizeof(unsigned short)); | |
| 159 UChar* dst = reinterpret_cast<UChar*>(eotHeader.data() + size); | |
| 160 unsigned i = 0; | |
| 161 dst[i++] = length; | |
| 162 unsigned numCharacters = length / 2; | |
| 163 for (unsigned j = 0; j < numCharacters; j++) | |
| 164 dst[i++] = string[j]; | |
| 165 dst[i] = 0; | |
| 166 } | |
| 167 | |
| 168 bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t&
overlayDst, size_t& overlaySrc, size_t& overlayLength) | |
| 169 { | |
| 170 overlayDst = 0; | |
| 171 overlaySrc = 0; | |
| 172 overlayLength = 0; | |
| 173 | |
| 174 size_t dataLength = fontData->size(); | |
| 175 const char* data = fontData->data(); | |
| 176 | |
| 177 eotHeader.resize(sizeof(EOTPrefix)); | |
| 178 EOTPrefix* prefix = reinterpret_cast<EOTPrefix*>(eotHeader.data()); | |
| 179 | |
| 180 prefix->fontDataSize = dataLength; | |
| 181 prefix->version = 0x00020001; | |
| 182 prefix->flags = 0; | |
| 183 | |
| 184 if (dataLength < offsetof(sfntHeader, tables)) | |
| 185 return false; | |
| 186 | |
| 187 const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(data); | |
| 188 | |
| 189 if (dataLength < offsetof(sfntHeader, tables) + sfnt->numTables * sizeof(Tab
leDirectoryEntry)) | |
| 190 return false; | |
| 191 | |
| 192 bool haveOS2 = false; | |
| 193 bool haveHead = false; | |
| 194 bool haveName = false; | |
| 195 | |
| 196 const BigEndianUShort* familyName = 0; | |
| 197 unsigned short familyNameLength = 0; | |
| 198 const BigEndianUShort* subfamilyName = 0; | |
| 199 unsigned short subfamilyNameLength = 0; | |
| 200 const BigEndianUShort* fullName = 0; | |
| 201 unsigned short fullNameLength = 0; | |
| 202 const BigEndianUShort* versionString = 0; | |
| 203 unsigned short versionStringLength = 0; | |
| 204 | |
| 205 for (unsigned i = 0; i < sfnt->numTables; i++) { | |
| 206 unsigned tableOffset = sfnt->tables[i].offset; | |
| 207 unsigned tableLength = sfnt->tables[i].length; | |
| 208 | |
| 209 if (dataLength < tableOffset || dataLength < tableLength || dataLength <
tableOffset + tableLength) | |
| 210 return false; | |
| 211 | |
| 212 unsigned tableTag = sfnt->tables[i].tag; | |
| 213 switch (tableTag) { | |
| 214 case 'OS/2': | |
| 215 { | |
| 216 if (dataLength < tableOffset + sizeof(OS2Table)) | |
| 217 return false; | |
| 218 | |
| 219 haveOS2 = true; | |
| 220 const OS2Table* OS2 = reinterpret_cast<const OS2Table*>(data
+ tableOffset); | |
| 221 for (unsigned j = 0; j < 10; j++) | |
| 222 prefix->fontPANOSE[j] = OS2->panose[j]; | |
| 223 prefix->italic = OS2->fsSelection & 0x01; | |
| 224 prefix->weight = OS2->weightClass; | |
| 225 // FIXME: Should use OS2->fsType, but some TrueType fonts se
t it to an over-restrictive value. | |
| 226 // Since ATS does not enforce this on Mac OS X, we do not en
force it either. | |
| 227 prefix->fsType = 0; | |
| 228 for (unsigned j = 0; j < 4; j++) | |
| 229 prefix->unicodeRange[j] = OS2->unicodeRange[j]; | |
| 230 for (unsigned j = 0; j < 2; j++) | |
| 231 prefix->codePageRange[j] = OS2->codePageRange[j]; | |
| 232 break; | |
| 233 } | |
| 234 case 'head': | |
| 235 { | |
| 236 if (dataLength < tableOffset + sizeof(headTable)) | |
| 237 return false; | |
| 238 | |
| 239 haveHead = true; | |
| 240 const headTable* head = reinterpret_cast<const headTable*>(d
ata + tableOffset); | |
| 241 prefix->checkSumAdjustment = head->checkSumAdjustment; | |
| 242 break; | |
| 243 } | |
| 244 case 'name': | |
| 245 { | |
| 246 if (dataLength < tableOffset + offsetof(nameTable, nameRecor
ds)) | |
| 247 return false; | |
| 248 | |
| 249 haveName = true; | |
| 250 const nameTable* name = reinterpret_cast<const nameTable*>(d
ata + tableOffset); | |
| 251 for (int j = 0; j < name->count; j++) { | |
| 252 if (dataLength < tableOffset + offsetof(nameTable, nameR
ecords) + (j + 1) * sizeof(nameRecord)) | |
| 253 return false; | |
| 254 if (name->nameRecords[j].platformID == 3 && name->nameRe
cords[j].encodingID == 1 && name->nameRecords[j].languageID == 0x0409) { | |
| 255 if (dataLength < tableOffset + name->stringOffset +
name->nameRecords[j].offset + name->nameRecords[j].length) | |
| 256 return false; | |
| 257 | |
| 258 unsigned short nameLength = name->nameRecords[j].len
gth; | |
| 259 const BigEndianUShort* nameString = reinterpret_cast
<const BigEndianUShort*>(data + tableOffset + name->stringOffset + name->nameRec
ords[j].offset); | |
| 260 | |
| 261 switch (name->nameRecords[j].nameID) { | |
| 262 case 1: | |
| 263 familyNameLength = nameLength; | |
| 264 familyName = nameString; | |
| 265 break; | |
| 266 case 2: | |
| 267 subfamilyNameLength = nameLength; | |
| 268 subfamilyName = nameString; | |
| 269 break; | |
| 270 case 4: | |
| 271 fullNameLength = nameLength; | |
| 272 fullName = nameString; | |
| 273 break; | |
| 274 case 5: | |
| 275 versionStringLength = nameLength; | |
| 276 versionString = nameString; | |
| 277 break; | |
| 278 default: | |
| 279 break; | |
| 280 } | |
| 281 } | |
| 282 } | |
| 283 break; | |
| 284 } | |
| 285 default: | |
| 286 break; | |
| 287 } | |
| 288 if (haveOS2 && haveHead && haveName) | |
| 289 break; | |
| 290 } | |
| 291 | |
| 292 prefix->charset = DEFAULT_CHARSET; | |
| 293 prefix->magicNumber = 0x504c; | |
| 294 prefix->reserved[0] = 0; | |
| 295 prefix->reserved[1] = 0; | |
| 296 prefix->reserved[2] = 0; | |
| 297 prefix->reserved[3] = 0; | |
| 298 prefix->padding1 = 0; | |
| 299 | |
| 300 appendBigEndianStringToEOTHeader(eotHeader, familyName, familyNameLength); | |
| 301 appendBigEndianStringToEOTHeader(eotHeader, subfamilyName, subfamilyNameLeng
th); | |
| 302 appendBigEndianStringToEOTHeader(eotHeader, versionString, versionStringLeng
th); | |
| 303 | |
| 304 // If possible, ensure that the family name is a prefix of the full name. | |
| 305 if (fullNameLength >= familyNameLength && memcmp(familyName, fullName, famil
yNameLength)) { | |
| 306 overlaySrc = reinterpret_cast<const char*>(fullName) - data; | |
| 307 overlayDst = reinterpret_cast<const char*>(familyName) - data; | |
| 308 overlayLength = familyNameLength; | |
| 309 } | |
| 310 | |
| 311 appendBigEndianStringToEOTHeader(eotHeader, fullName, fullNameLength); | |
| 312 | |
| 313 unsigned short padding = 0; | |
| 314 eotHeader.append(reinterpret_cast<UInt8*>(&padding), sizeof(padding)); | |
| 315 | |
| 316 prefix->eotSize = eotHeader.size() + fontData->size(); | |
| 317 | |
| 318 return true; | |
| 319 } | |
| 320 | |
| 321 HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) | |
| 322 { | |
| 323 size_t originalDataSize = fontData->size(); | |
| 324 const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(fontData->data(
)); | |
| 325 | |
| 326 unsigned t; | |
| 327 for (t = 0; t < sfnt->numTables; ++t) { | |
| 328 if (sfnt->tables[t].tag == 'name') | |
| 329 break; | |
| 330 } | |
| 331 if (t == sfnt->numTables) | |
| 332 return 0; | |
| 333 | |
| 334 const int nameRecordCount = 5; | |
| 335 | |
| 336 // Rounded up to a multiple of 4 to simplify the checksum calculation. | |
| 337 size_t nameTableSize = ((offsetof(nameTable, nameRecords) + nameRecordCount
* sizeof(nameRecord) + fontName.length() * sizeof(UChar)) & ~3) + 4; | |
| 338 | |
| 339 Vector<char> rewrittenFontData(fontData->size() + nameTableSize); | |
| 340 char* data = rewrittenFontData.data(); | |
| 341 memcpy(data, fontData->data(), originalDataSize); | |
| 342 | |
| 343 // Make the table directory entry point to the new 'name' table. | |
| 344 sfntHeader* rewrittenSfnt = reinterpret_cast<sfntHeader*>(data); | |
| 345 rewrittenSfnt->tables[t].length = nameTableSize; | |
| 346 rewrittenSfnt->tables[t].offset = originalDataSize; | |
| 347 | |
| 348 // Write the new 'name' table after the original font data. | |
| 349 nameTable* name = reinterpret_cast<nameTable*>(data + originalDataSize); | |
| 350 name->format = 0; | |
| 351 name->count = nameRecordCount; | |
| 352 name->stringOffset = offsetof(nameTable, nameRecords) + nameRecordCount * si
zeof(nameRecord); | |
| 353 for (unsigned i = 0; i < nameRecordCount; ++i) { | |
| 354 name->nameRecords[i].platformID = 3; | |
| 355 name->nameRecords[i].encodingID = 1; | |
| 356 name->nameRecords[i].languageID = 0x0409; | |
| 357 name->nameRecords[i].offset = 0; | |
| 358 name->nameRecords[i].length = fontName.length() * sizeof(UChar); | |
| 359 } | |
| 360 | |
| 361 // The required 'name' record types: Family, Style, Unique, Full and PostScr
ipt. | |
| 362 name->nameRecords[0].nameID = 1; | |
| 363 name->nameRecords[1].nameID = 2; | |
| 364 name->nameRecords[2].nameID = 3; | |
| 365 name->nameRecords[3].nameID = 4; | |
| 366 name->nameRecords[4].nameID = 6; | |
| 367 | |
| 368 for (unsigned i = 0; i < fontName.length(); ++i) | |
| 369 reinterpret_cast<BigEndianUShort*>(data + originalDataSize + name->strin
gOffset)[i] = fontName[i]; | |
| 370 | |
| 371 // Update the table checksum in the directory entry. | |
| 372 rewrittenSfnt->tables[t].checkSum = 0; | |
| 373 for (unsigned i = 0; i * sizeof(BigEndianULong) < nameTableSize; ++i) | |
| 374 rewrittenSfnt->tables[t].checkSum = rewrittenSfnt->tables[t].checkSum +
reinterpret_cast<BigEndianULong*>(name)[i]; | |
| 375 | |
| 376 DWORD numFonts = 0; | |
| 377 HANDLE fontHandle = AddFontMemResourceEx(data, originalDataSize + nameTableS
ize, 0, &numFonts); | |
| 378 | |
| 379 if (fontHandle && numFonts != 1) { | |
| 380 RemoveFontMemResourceEx(fontHandle); | |
| 381 return 0; | |
| 382 } | |
| 383 | |
| 384 return fontHandle; | |
| 385 } | |
| 386 | |
| 387 } | |
| OLD | NEW |