~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/webkit/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 { 
 
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 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 !PLATFORM(CG)
 
74
// Fixed type is not defined on non-CG 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
 
 
165
EOTHeader::EOTHeader()
 
166
{
 
167
    m_buffer.resize(sizeof(EOTPrefix));
 
168
}
 
169
 
 
170
void EOTHeader::updateEOTSize(size_t fontDataSize)
 
171
{
 
172
    prefix()->eotSize = m_buffer.size() + fontDataSize;
 
173
}
 
174
 
 
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
 
 
188
void EOTHeader::appendPaddingShort()
 
189
{
 
190
    unsigned short padding = 0;
 
191
    m_buffer.append(reinterpret_cast<uint8_t*>(&padding), sizeof(padding));
 
192
}
 
193
 
 
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
 
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 PLATFORM(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
 
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
 
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
}