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 "OpenTypeUtilities.h"
29
30 #include "SharedBuffer.h"
31
32 namespace WebCore {
33
34 struct BigEndianUShort {
operator unsigned shortWebCore::BigEndianUShort35 operator unsigned short() const { return (v & 0x00ff) << 8 | v >> 8; }
BigEndianUShortWebCore::BigEndianUShort36 BigEndianUShort(unsigned short u) : v((u & 0x00ff) << 8 | u >> 8) { }
37 unsigned short v;
38 };
39
40 struct BigEndianULong {
operator unsignedWebCore::BigEndianULong41 operator unsigned() const { return (v & 0xff) << 24 | (v & 0xff00) << 8 | (v & 0xff0000) >> 8 | v >> 24; }
BigEndianULongWebCore::BigEndianULong42 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 EOTPrefix {
49 unsigned eotSize;
50 unsigned fontDataSize;
51 unsigned version;
52 unsigned flags;
53 uint8_t fontPANOSE[10];
54 uint8_t charset;
55 uint8_t italic;
56 unsigned weight;
57 unsigned short fsType;
58 unsigned short magicNumber;
59 unsigned unicodeRange[4];
60 unsigned codePageRange[2];
61 unsigned checkSumAdjustment;
62 unsigned reserved[4];
63 unsigned short padding1;
64 };
65
66 struct TableDirectoryEntry {
67 BigEndianULong tag;
68 BigEndianULong checkSum;
69 BigEndianULong offset;
70 BigEndianULong length;
71 };
72
73 #if !USE(CG) || !defined(COREGRAPHICS_INCLUDES_CORESERVICES_HEADER)
74 // Fixed type is not defined on non-CG and Windows platforms. |version| in sfntHeader
75 // and headTable and |fontRevision| in headTable are of Fixed, but they're
76 // not actually refered to anywhere. Therefore, we just have to match
77 // the size (4 bytes). For the definition of Fixed type, see
78 // http://developer.apple.com/documentation/mac/Legacy/GXEnvironment/GXEnvironment-356.html#HEADING356-6.
79 typedef int32_t Fixed;
80 #endif
81
82 struct sfntHeader {
83 Fixed version;
84 BigEndianUShort numTables;
85 BigEndianUShort searchRange;
86 BigEndianUShort entrySelector;
87 BigEndianUShort rangeShift;
88 TableDirectoryEntry tables[1];
89 };
90
91 struct OS2Table {
92 BigEndianUShort version;
93 BigEndianUShort avgCharWidth;
94 BigEndianUShort weightClass;
95 BigEndianUShort widthClass;
96 BigEndianUShort fsType;
97 BigEndianUShort subscriptXSize;
98 BigEndianUShort subscriptYSize;
99 BigEndianUShort subscriptXOffset;
100 BigEndianUShort subscriptYOffset;
101 BigEndianUShort superscriptXSize;
102 BigEndianUShort superscriptYSize;
103 BigEndianUShort superscriptXOffset;
104 BigEndianUShort superscriptYOffset;
105 BigEndianUShort strikeoutSize;
106 BigEndianUShort strikeoutPosition;
107 BigEndianUShort familyClass;
108 uint8_t panose[10];
109 BigEndianULong unicodeRange[4];
110 uint8_t vendID[4];
111 BigEndianUShort fsSelection;
112 BigEndianUShort firstCharIndex;
113 BigEndianUShort lastCharIndex;
114 BigEndianUShort typoAscender;
115 BigEndianUShort typoDescender;
116 BigEndianUShort typoLineGap;
117 BigEndianUShort winAscent;
118 BigEndianUShort winDescent;
119 BigEndianULong codePageRange[2];
120 BigEndianUShort xHeight;
121 BigEndianUShort capHeight;
122 BigEndianUShort defaultChar;
123 BigEndianUShort breakChar;
124 BigEndianUShort maxContext;
125 };
126
127 struct headTable {
128 Fixed version;
129 Fixed fontRevision;
130 BigEndianULong checkSumAdjustment;
131 BigEndianULong magicNumber;
132 BigEndianUShort flags;
133 BigEndianUShort unitsPerEm;
134 long long created;
135 long long modified;
136 BigEndianUShort xMin;
137 BigEndianUShort xMax;
138 BigEndianUShort yMin;
139 BigEndianUShort yMax;
140 BigEndianUShort macStyle;
141 BigEndianUShort lowestRectPPEM;
142 BigEndianUShort fontDirectionHint;
143 BigEndianUShort indexToLocFormat;
144 BigEndianUShort glyphDataFormat;
145 };
146
147 struct nameRecord {
148 BigEndianUShort platformID;
149 BigEndianUShort encodingID;
150 BigEndianUShort languageID;
151 BigEndianUShort nameID;
152 BigEndianUShort length;
153 BigEndianUShort offset;
154 };
155
156 struct nameTable {
157 BigEndianUShort format;
158 BigEndianUShort count;
159 BigEndianUShort stringOffset;
160 nameRecord nameRecords[1];
161 };
162
163 #pragma pack()
164
EOTHeader()165 EOTHeader::EOTHeader()
166 {
167 m_buffer.resize(sizeof(EOTPrefix));
168 }
169
updateEOTSize(size_t fontDataSize)170 void EOTHeader::updateEOTSize(size_t fontDataSize)
171 {
172 prefix()->eotSize = m_buffer.size() + fontDataSize;
173 }
174
appendBigEndianString(const BigEndianUShort * string,unsigned short length)175 void EOTHeader::appendBigEndianString(const BigEndianUShort* string, unsigned short length)
176 {
177 size_t oldSize = m_buffer.size();
178 m_buffer.resize(oldSize + length + 2 * sizeof(unsigned short));
179 UChar* dst = reinterpret_cast<UChar*>(m_buffer.data() + oldSize);
180 unsigned i = 0;
181 dst[i++] = length;
182 unsigned numCharacters = length / 2;
183 for (unsigned j = 0; j < numCharacters; j++)
184 dst[i++] = string[j];
185 dst[i] = 0;
186 }
187
appendPaddingShort()188 void EOTHeader::appendPaddingShort()
189 {
190 unsigned short padding = 0;
191 m_buffer.append(reinterpret_cast<uint8_t*>(&padding), sizeof(padding));
192 }
193
getEOTHeader(SharedBuffer * fontData,EOTHeader & eotHeader,size_t & overlayDst,size_t & overlaySrc,size_t & overlayLength)194 bool getEOTHeader(SharedBuffer* fontData, EOTHeader& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
195 {
196 overlayDst = 0;
197 overlaySrc = 0;
198 overlayLength = 0;
199
200 size_t dataLength = fontData->size();
201 const char* data = fontData->data();
202
203 EOTPrefix* prefix = eotHeader.prefix();
204
205 prefix->fontDataSize = dataLength;
206 prefix->version = 0x00020001;
207 prefix->flags = 0;
208
209 if (dataLength < offsetof(sfntHeader, tables))
210 return false;
211
212 const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(data);
213
214 if (dataLength < offsetof(sfntHeader, tables) + sfnt->numTables * sizeof(TableDirectoryEntry))
215 return false;
216
217 bool haveOS2 = false;
218 bool haveHead = false;
219 bool haveName = false;
220
221 const BigEndianUShort* familyName = 0;
222 unsigned short familyNameLength = 0;
223 const BigEndianUShort* subfamilyName = 0;
224 unsigned short subfamilyNameLength = 0;
225 const BigEndianUShort* fullName = 0;
226 unsigned short fullNameLength = 0;
227 const BigEndianUShort* versionString = 0;
228 unsigned short versionStringLength = 0;
229
230 for (unsigned i = 0; i < sfnt->numTables; i++) {
231 unsigned tableOffset = sfnt->tables[i].offset;
232 unsigned tableLength = sfnt->tables[i].length;
233
234 if (dataLength < tableOffset || dataLength < tableLength || dataLength < tableOffset + tableLength)
235 return false;
236
237 unsigned tableTag = sfnt->tables[i].tag;
238 switch (tableTag) {
239 case 'OS/2':
240 {
241 if (dataLength < tableOffset + sizeof(OS2Table))
242 return false;
243
244 haveOS2 = true;
245 const OS2Table* OS2 = reinterpret_cast<const OS2Table*>(data + tableOffset);
246 for (unsigned j = 0; j < 10; j++)
247 prefix->fontPANOSE[j] = OS2->panose[j];
248 prefix->italic = OS2->fsSelection & 0x01;
249 prefix->weight = OS2->weightClass;
250 // FIXME: Should use OS2->fsType, but some TrueType fonts set it to an over-restrictive value.
251 // Since ATS does not enforce this on Mac OS X, we do not enforce it either.
252 prefix->fsType = 0;
253 for (unsigned j = 0; j < 4; j++)
254 prefix->unicodeRange[j] = OS2->unicodeRange[j];
255 for (unsigned j = 0; j < 2; j++)
256 prefix->codePageRange[j] = OS2->codePageRange[j];
257 break;
258 }
259 case 'head':
260 {
261 if (dataLength < tableOffset + sizeof(headTable))
262 return false;
263
264 haveHead = true;
265 const headTable* head = reinterpret_cast<const headTable*>(data + tableOffset);
266 prefix->checkSumAdjustment = head->checkSumAdjustment;
267 break;
268 }
269 case 'name':
270 {
271 if (dataLength < tableOffset + offsetof(nameTable, nameRecords))
272 return false;
273
274 haveName = true;
275 const nameTable* name = reinterpret_cast<const nameTable*>(data + tableOffset);
276 for (int j = 0; j < name->count; j++) {
277 if (dataLength < tableOffset + offsetof(nameTable, nameRecords) + (j + 1) * sizeof(nameRecord))
278 return false;
279 if (name->nameRecords[j].platformID == 3 && name->nameRecords[j].encodingID == 1 && name->nameRecords[j].languageID == 0x0409) {
280 if (dataLength < tableOffset + name->stringOffset + name->nameRecords[j].offset + name->nameRecords[j].length)
281 return false;
282
283 unsigned short nameLength = name->nameRecords[j].length;
284 const BigEndianUShort* nameString = reinterpret_cast<const BigEndianUShort*>(data + tableOffset + name->stringOffset + name->nameRecords[j].offset);
285
286 switch (name->nameRecords[j].nameID) {
287 case 1:
288 familyNameLength = nameLength;
289 familyName = nameString;
290 break;
291 case 2:
292 subfamilyNameLength = nameLength;
293 subfamilyName = nameString;
294 break;
295 case 4:
296 fullNameLength = nameLength;
297 fullName = nameString;
298 break;
299 case 5:
300 versionStringLength = nameLength;
301 versionString = nameString;
302 break;
303 default:
304 break;
305 }
306 }
307 }
308 break;
309 }
310 default:
311 break;
312 }
313 if (haveOS2 && haveHead && haveName)
314 break;
315 }
316
317 prefix->charset = DEFAULT_CHARSET;
318 prefix->magicNumber = 0x504c;
319 prefix->reserved[0] = 0;
320 prefix->reserved[1] = 0;
321 prefix->reserved[2] = 0;
322 prefix->reserved[3] = 0;
323 prefix->padding1 = 0;
324
325 eotHeader.appendBigEndianString(familyName, familyNameLength);
326 eotHeader.appendBigEndianString(subfamilyName, subfamilyNameLength);
327 eotHeader.appendBigEndianString(versionString, versionStringLength);
328
329 // If possible, ensure that the family name is a prefix of the full name.
330 if (fullNameLength >= familyNameLength && memcmp(familyName, fullName, familyNameLength)) {
331 overlaySrc = reinterpret_cast<const char*>(fullName) - data;
332 overlayDst = reinterpret_cast<const char*>(familyName) - data;
333 overlayLength = familyNameLength;
334 }
335 eotHeader.appendBigEndianString(fullName, fullNameLength);
336
337 eotHeader.appendPaddingShort();
338 eotHeader.updateEOTSize(fontData->size());
339
340 return true;
341 }
342
343 // code shared by renameFont and renameAndActivateFont
344 // adds fontName to the font table in fontData, and writes the new font table to rewrittenFontTable
345 // returns the size of the name table (which is used by renameAndActivateFont), or 0 on early abort
renameFontInternal(SharedBuffer * fontData,const String & fontName,Vector<char> & rewrittenFontData)346 static size_t renameFontInternal(SharedBuffer* fontData, const String& fontName, Vector<char> &rewrittenFontData)
347 {
348 size_t originalDataSize = fontData->size();
349 const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(fontData->data());
350
351 unsigned t;
352 for (t = 0; t < sfnt->numTables; ++t) {
353 if (sfnt->tables[t].tag == 'name')
354 break;
355 }
356 if (t == sfnt->numTables)
357 return 0;
358
359 const int nameRecordCount = 5;
360
361 // Rounded up to a multiple of 4 to simplify the checksum calculation.
362 size_t nameTableSize = ((offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord) + fontName.length() * sizeof(UChar)) & ~3) + 4;
363
364 rewrittenFontData.resize(fontData->size() + nameTableSize);
365 char* data = rewrittenFontData.data();
366 memcpy(data, fontData->data(), originalDataSize);
367
368 // Make the table directory entry point to the new 'name' table.
369 sfntHeader* rewrittenSfnt = reinterpret_cast<sfntHeader*>(data);
370 rewrittenSfnt->tables[t].length = nameTableSize;
371 rewrittenSfnt->tables[t].offset = originalDataSize;
372
373 // Write the new 'name' table after the original font data.
374 nameTable* name = reinterpret_cast<nameTable*>(data + originalDataSize);
375 name->format = 0;
376 name->count = nameRecordCount;
377 name->stringOffset = offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord);
378 for (unsigned i = 0; i < nameRecordCount; ++i) {
379 name->nameRecords[i].platformID = 3;
380 name->nameRecords[i].encodingID = 1;
381 name->nameRecords[i].languageID = 0x0409;
382 name->nameRecords[i].offset = 0;
383 name->nameRecords[i].length = fontName.length() * sizeof(UChar);
384 }
385
386 // The required 'name' record types: Family, Style, Unique, Full and PostScript.
387 name->nameRecords[0].nameID = 1;
388 name->nameRecords[1].nameID = 2;
389 name->nameRecords[2].nameID = 3;
390 name->nameRecords[3].nameID = 4;
391 name->nameRecords[4].nameID = 6;
392
393 for (unsigned i = 0; i < fontName.length(); ++i)
394 reinterpret_cast<BigEndianUShort*>(data + originalDataSize + name->stringOffset)[i] = fontName[i];
395
396 // Update the table checksum in the directory entry.
397 rewrittenSfnt->tables[t].checkSum = 0;
398 for (unsigned i = 0; i * sizeof(BigEndianULong) < nameTableSize; ++i)
399 rewrittenSfnt->tables[t].checkSum = rewrittenSfnt->tables[t].checkSum + reinterpret_cast<BigEndianULong*>(name)[i];
400
401 return nameTableSize;
402 }
403
404 #if OS(WINCE)
405 // AddFontMemResourceEx does not exist on WinCE, so we must handle the font data manually
406 // This function just renames the font and overwrites the old font data with the new
renameFont(SharedBuffer * fontData,const String & fontName)407 bool renameFont(SharedBuffer* fontData, const String& fontName)
408 {
409 // abort if the data is too small to be a font header with a "tables" entry
410 if (fontData->size() < offsetof(sfntHeader, tables))
411 return false;
412
413 // abort if the data is too small to hold all the tables specified in the header
414 const sfntHeader* header = reinterpret_cast<const sfntHeader*>(fontData->data());
415 if (fontData->size() < offsetof(sfntHeader, tables) + header->numTables * sizeof(TableDirectoryEntry))
416 return false;
417
418 Vector<char> rewrittenFontData;
419 if (!renameFontInternal(fontData, fontName, rewrittenFontData))
420 return false;
421
422 fontData->clear();
423 fontData->append(rewrittenFontData.data(), rewrittenFontData.size());
424 return true;
425 }
426 #else
427 // Rename the font and install the new font data into the system
renameAndActivateFont(SharedBuffer * fontData,const String & fontName)428 HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName)
429 {
430 Vector<char> rewrittenFontData;
431 size_t nameTableSize = renameFontInternal(fontData, fontName, rewrittenFontData);
432 if (!nameTableSize)
433 return 0;
434
435 DWORD numFonts = 0;
436 HANDLE fontHandle = AddFontMemResourceEx(rewrittenFontData.data(), fontData->size() + nameTableSize, 0, &numFonts);
437
438 if (fontHandle && numFonts < 1) {
439 RemoveFontMemResourceEx(fontHandle);
440 return 0;
441 }
442
443 return fontHandle;
444 }
445 #endif
446
447 }
448