Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/thebes/gfxFontUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "mozilla/ArrayUtils.h"
7
#include "mozilla/BinarySearch.h"
8
9
#include "gfxFontUtils.h"
10
#include "gfxFontEntry.h"
11
#include "gfxFontVariations.h"
12
13
#include "nsServiceManagerUtils.h"
14
15
#include "mozilla/Preferences.h"
16
#include "mozilla/Services.h"
17
#include "mozilla/BinarySearch.h"
18
#include "mozilla/Sprintf.h"
19
#include "mozilla/Unused.h"
20
21
#include "nsCOMPtr.h"
22
#include "nsIUUIDGenerator.h"
23
#include "mozilla/Encoding.h"
24
25
#include "harfbuzz/hb.h"
26
27
#include "plbase64.h"
28
#include "mozilla/Logging.h"
29
30
#ifdef XP_MACOSX
31
#include <CoreFoundation/CoreFoundation.h>
32
#endif
33
34
0
#define LOG(log, args) MOZ_LOG(gfxPlatform::GetLog(log), \
35
0
                               LogLevel::Debug, args)
36
37
0
#define UNICODE_BMP_LIMIT 0x10000
38
39
using namespace mozilla;
40
41
#pragma pack(1)
42
43
typedef struct {
44
    AutoSwap_PRUint16 format;
45
    AutoSwap_PRUint16 reserved;
46
    AutoSwap_PRUint32 length;
47
    AutoSwap_PRUint32 language;
48
    AutoSwap_PRUint32 startCharCode;
49
    AutoSwap_PRUint32 numChars;
50
} Format10CmapHeader;
51
52
typedef struct {
53
    AutoSwap_PRUint16 format;
54
    AutoSwap_PRUint16 reserved;
55
    AutoSwap_PRUint32 length;
56
    AutoSwap_PRUint32 language;
57
    AutoSwap_PRUint32 numGroups;
58
} Format12CmapHeader;
59
60
typedef struct {
61
    AutoSwap_PRUint32 startCharCode;
62
    AutoSwap_PRUint32 endCharCode;
63
    AutoSwap_PRUint32 startGlyphId;
64
} Format12Group;
65
66
#pragma pack()
67
68
void
69
gfxSparseBitSet::Dump(const char* aPrefix, eGfxLog aWhichLog) const
70
0
{
71
0
    uint32_t numBlocks = mBlockIndex.Length();
72
0
73
0
    for (uint32_t b = 0; b < numBlocks; b++) {
74
0
        if (mBlockIndex[b] == NO_BLOCK) {
75
0
            continue;
76
0
        }
77
0
        const Block* block = &mBlocks[mBlockIndex[b]];
78
0
        const int BUFSIZE = 256;
79
0
        char outStr[BUFSIZE];
80
0
        int index = 0;
81
0
        index += snprintf(&outStr[index], BUFSIZE - index, "%s u+%6.6x [",
82
0
                          aPrefix, (b * BLOCK_SIZE_BITS));
83
0
        for (int i = 0; i < 32; i += 4) {
84
0
            for (int j = i; j < i + 4; j++) {
85
0
                uint8_t bits = block->mBits[j];
86
0
                uint8_t flip1 = ((bits & 0xaa) >> 1) | ((bits & 0x55) << 1);
87
0
                uint8_t flip2 = ((flip1 & 0xcc) >> 2) | ((flip1 & 0x33) << 2);
88
0
                uint8_t flipped = ((flip2 & 0xf0) >> 4) | ((flip2 & 0x0f) << 4);
89
0
90
0
                index += snprintf(&outStr[index], BUFSIZE - index, "%2.2x", flipped);
91
0
            }
92
0
            if (i + 4 != 32) index += snprintf(&outStr[index], BUFSIZE - index, " ");
93
0
        }
94
0
        Unused << snprintf(&outStr[index], BUFSIZE - index, "]");
95
0
        LOG(aWhichLog, ("%s", outStr));
96
0
    }
97
0
}
98
99
nsresult
100
gfxFontUtils::ReadCMAPTableFormat10(const uint8_t *aBuf, uint32_t aLength,
101
                                    gfxSparseBitSet& aCharacterMap)
102
0
{
103
0
    // Ensure table is large enough that we can safely read the header
104
0
    NS_ENSURE_TRUE(aLength >= sizeof(Format10CmapHeader),
105
0
                    NS_ERROR_GFX_CMAP_MALFORMED);
106
0
107
0
    // Sanity-check header fields
108
0
    const Format10CmapHeader *cmap10 =
109
0
        reinterpret_cast<const Format10CmapHeader*>(aBuf);
110
0
    NS_ENSURE_TRUE(uint16_t(cmap10->format) == 10,
111
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
112
0
    NS_ENSURE_TRUE(uint16_t(cmap10->reserved) == 0,
113
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
114
0
115
0
    uint32_t tablelen = cmap10->length;
116
0
    NS_ENSURE_TRUE(tablelen >= sizeof(Format10CmapHeader) &&
117
0
                   tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
118
0
119
0
    NS_ENSURE_TRUE(cmap10->language == 0, NS_ERROR_GFX_CMAP_MALFORMED);
120
0
121
0
    uint32_t numChars = cmap10->numChars;
122
0
    NS_ENSURE_TRUE(tablelen == sizeof(Format10CmapHeader) +
123
0
                   numChars * sizeof(uint16_t), NS_ERROR_GFX_CMAP_MALFORMED);
124
0
125
0
    uint32_t charCode = cmap10->startCharCode;
126
0
    NS_ENSURE_TRUE(charCode <= CMAP_MAX_CODEPOINT &&
127
0
                   charCode + numChars <= CMAP_MAX_CODEPOINT,
128
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
129
0
130
0
    // glyphs[] array immediately follows the subtable header
131
0
    const AutoSwap_PRUint16 *glyphs =
132
0
        reinterpret_cast<const AutoSwap_PRUint16 *>(cmap10 + 1);
133
0
134
0
    for (uint32_t i = 0; i < numChars; ++i) {
135
0
        if (uint16_t(*glyphs) != 0) {
136
0
            aCharacterMap.set(charCode);
137
0
        }
138
0
        ++charCode;
139
0
        ++glyphs;
140
0
    }
141
0
142
0
    aCharacterMap.Compact();
143
0
144
0
    return NS_OK;
145
0
}
146
147
nsresult
148
gfxFontUtils::ReadCMAPTableFormat12or13(const uint8_t *aBuf, uint32_t aLength,
149
                                        gfxSparseBitSet& aCharacterMap)
150
0
{
151
0
    // Format 13 has the same structure as format 12, the only difference is
152
0
    // the interpretation of the glyphID field. So we can share the code here
153
0
    // that reads the table and just records character coverage.
154
0
155
0
    // Ensure table is large enough that we can safely read the header
156
0
    NS_ENSURE_TRUE(aLength >= sizeof(Format12CmapHeader),
157
0
                    NS_ERROR_GFX_CMAP_MALFORMED);
158
0
159
0
    // Sanity-check header fields
160
0
    const Format12CmapHeader *cmap12 =
161
0
        reinterpret_cast<const Format12CmapHeader*>(aBuf);
162
0
    NS_ENSURE_TRUE(uint16_t(cmap12->format) == 12 ||
163
0
                   uint16_t(cmap12->format) == 13,
164
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
165
0
    NS_ENSURE_TRUE(uint16_t(cmap12->reserved) == 0,
166
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
167
0
168
0
    uint32_t tablelen = cmap12->length;
169
0
    NS_ENSURE_TRUE(tablelen >= sizeof(Format12CmapHeader) &&
170
0
                   tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
171
0
172
0
    NS_ENSURE_TRUE(cmap12->language == 0, NS_ERROR_GFX_CMAP_MALFORMED);
173
0
174
0
    // Check that the table is large enough for the group array
175
0
    const uint32_t numGroups = cmap12->numGroups;
176
0
    NS_ENSURE_TRUE((tablelen - sizeof(Format12CmapHeader)) /
177
0
                       sizeof(Format12Group) >= numGroups,
178
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
179
0
180
0
    // The array of groups immediately follows the subtable header.
181
0
    const Format12Group *group =
182
0
        reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
183
0
184
0
    // Check that groups are in correct order and do not overlap,
185
0
    // and record character coverage in aCharacterMap.
186
0
    uint32_t prevEndCharCode = 0;
187
0
    for (uint32_t i = 0; i < numGroups; i++, group++) {
188
0
        uint32_t startCharCode = group->startCharCode;
189
0
        const uint32_t endCharCode = group->endCharCode;
190
0
        NS_ENSURE_TRUE((prevEndCharCode < startCharCode || i == 0) &&
191
0
                       startCharCode <= endCharCode &&
192
0
                       endCharCode <= CMAP_MAX_CODEPOINT,
193
0
                       NS_ERROR_GFX_CMAP_MALFORMED);
194
0
        // don't include a character that maps to glyph ID 0 (.notdef)
195
0
        if (group->startGlyphId == 0) {
196
0
            startCharCode++;
197
0
        }
198
0
        if (startCharCode <= endCharCode) {
199
0
            aCharacterMap.SetRange(startCharCode, endCharCode);
200
0
        }
201
0
        prevEndCharCode = endCharCode;
202
0
    }
203
0
204
0
    aCharacterMap.Compact();
205
0
206
0
    return NS_OK;
207
0
}
208
209
nsresult
210
gfxFontUtils::ReadCMAPTableFormat4(const uint8_t *aBuf, uint32_t aLength,
211
                                   gfxSparseBitSet& aCharacterMap)
212
0
{
213
0
    enum {
214
0
        OffsetFormat = 0,
215
0
        OffsetLength = 2,
216
0
        OffsetLanguage = 4,
217
0
        OffsetSegCountX2 = 6
218
0
    };
219
0
220
0
    NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 4,
221
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
222
0
    uint16_t tablelen = ReadShortAt(aBuf, OffsetLength);
223
0
    NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
224
0
    NS_ENSURE_TRUE(tablelen > 16, NS_ERROR_GFX_CMAP_MALFORMED);
225
0
226
0
    // This field should normally (except for Mac platform subtables) be zero according to
227
0
    // the OT spec, but some buggy fonts have lang = 1 (which would be English for MacOS).
228
0
    // E.g. Arial Narrow Bold, v. 1.1 (Tiger), Arial Unicode MS (see bug 530614).
229
0
    // So accept either zero or one here; the error should be harmless.
230
0
    NS_ENSURE_TRUE((ReadShortAt(aBuf, OffsetLanguage) & 0xfffe) == 0,
231
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
232
0
233
0
    uint16_t segCountX2 = ReadShortAt(aBuf, OffsetSegCountX2);
234
0
    NS_ENSURE_TRUE(tablelen >= 16 + (segCountX2 * 4),
235
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
236
0
237
0
    const uint16_t segCount = segCountX2 / 2;
238
0
239
0
    const uint16_t *endCounts = reinterpret_cast<const uint16_t*>(aBuf + 14);
240
0
    const uint16_t *startCounts = endCounts + 1 /* skip one uint16_t for reservedPad */ + segCount;
241
0
    const uint16_t *idDeltas = startCounts + segCount;
242
0
    const uint16_t *idRangeOffsets = idDeltas + segCount;
243
0
    uint16_t prevEndCount = 0;
244
0
    for (uint16_t i = 0; i < segCount; i++) {
245
0
        const uint16_t endCount = ReadShortAt16(endCounts, i);
246
0
        const uint16_t startCount = ReadShortAt16(startCounts, i);
247
0
        const uint16_t idRangeOffset = ReadShortAt16(idRangeOffsets, i);
248
0
249
0
        // sanity-check range
250
0
        // This permits ranges to overlap by 1 character, which is strictly
251
0
        // incorrect but occurs in Baskerville on OS X 10.7 (see bug 689087),
252
0
        // and appears to be harmless in practice
253
0
        NS_ENSURE_TRUE(startCount >= prevEndCount && startCount <= endCount,
254
0
                       NS_ERROR_GFX_CMAP_MALFORMED);
255
0
        prevEndCount = endCount;
256
0
257
0
        if (idRangeOffset == 0) {
258
0
            // figure out if there's a code in the range that would map to
259
0
            // glyph ID 0 (.notdef); if so, we need to skip setting that
260
0
            // character code in the map
261
0
            const uint16_t skipCode = 65536 - ReadShortAt16(idDeltas, i);
262
0
            if (startCount < skipCode) {
263
0
                aCharacterMap.SetRange(startCount,
264
0
                                       std::min<uint16_t>(skipCode - 1,
265
0
                                                          endCount));
266
0
            }
267
0
            if (skipCode < endCount) {
268
0
                aCharacterMap.SetRange(std::max<uint16_t>(startCount,
269
0
                                                          skipCode + 1),
270
0
                                       endCount);
271
0
            }
272
0
        } else {
273
0
            // const uint16_t idDelta = ReadShortAt16(idDeltas, i); // Unused: self-documenting.
274
0
            for (uint32_t c = startCount; c <= endCount; ++c) {
275
0
                if (c == 0xFFFF)
276
0
                    break;
277
0
278
0
                const uint16_t *gdata = (idRangeOffset/2
279
0
                                         + (c - startCount)
280
0
                                         + &idRangeOffsets[i]);
281
0
282
0
                NS_ENSURE_TRUE((uint8_t*)gdata > aBuf &&
283
0
                               (uint8_t*)gdata < aBuf + aLength,
284
0
                               NS_ERROR_GFX_CMAP_MALFORMED);
285
0
286
0
                // make sure we have a glyph
287
0
                if (*gdata != 0) {
288
0
                    // The glyph index at this point is:
289
0
                    uint16_t glyph = ReadShortAt16(idDeltas, i) + *gdata;
290
0
                    if (glyph) {
291
0
                        aCharacterMap.set(c);
292
0
                    }
293
0
                }
294
0
            }
295
0
        }
296
0
    }
297
0
298
0
    aCharacterMap.Compact();
299
0
300
0
    return NS_OK;
301
0
}
302
303
nsresult
304
gfxFontUtils::ReadCMAPTableFormat14(const uint8_t *aBuf, uint32_t aLength,
305
                                    UniquePtr<uint8_t[]>& aTable)
306
0
{
307
0
    enum {
308
0
        OffsetFormat = 0,
309
0
        OffsetTableLength = 2,
310
0
        OffsetNumVarSelectorRecords = 6,
311
0
        OffsetVarSelectorRecords = 10,
312
0
313
0
        SizeOfVarSelectorRecord = 11,
314
0
        VSRecOffsetVarSelector = 0,
315
0
        VSRecOffsetDefUVSOffset = 3,
316
0
        VSRecOffsetNonDefUVSOffset = 7,
317
0
318
0
        SizeOfDefUVSTable = 4,
319
0
        DefUVSOffsetStartUnicodeValue = 0,
320
0
        DefUVSOffsetAdditionalCount = 3,
321
0
322
0
        SizeOfNonDefUVSTable = 5,
323
0
        NonDefUVSOffsetUnicodeValue = 0,
324
0
        NonDefUVSOffsetGlyphID = 3
325
0
    };
326
0
    NS_ENSURE_TRUE(aLength >= OffsetVarSelectorRecords,
327
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
328
0
329
0
    NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 14,
330
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
331
0
332
0
    uint32_t tablelen = ReadLongAt(aBuf, OffsetTableLength);
333
0
    NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
334
0
    NS_ENSURE_TRUE(tablelen >= OffsetVarSelectorRecords,
335
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
336
0
337
0
    const uint32_t numVarSelectorRecords = ReadLongAt(aBuf, OffsetNumVarSelectorRecords);
338
0
    NS_ENSURE_TRUE((tablelen - OffsetVarSelectorRecords) /
339
0
                   SizeOfVarSelectorRecord >= numVarSelectorRecords,
340
0
                   NS_ERROR_GFX_CMAP_MALFORMED);
341
0
342
0
    const uint8_t *records = aBuf + OffsetVarSelectorRecords;
343
0
    for (uint32_t i = 0; i < numVarSelectorRecords;
344
0
         i++, records += SizeOfVarSelectorRecord) {
345
0
        const uint32_t varSelector = ReadUint24At(records, VSRecOffsetVarSelector);
346
0
        const uint32_t defUVSOffset = ReadLongAt(records, VSRecOffsetDefUVSOffset);
347
0
        const uint32_t nonDefUVSOffset = ReadLongAt(records, VSRecOffsetNonDefUVSOffset);
348
0
        NS_ENSURE_TRUE(varSelector <= CMAP_MAX_CODEPOINT &&
349
0
                       defUVSOffset <= tablelen - 4 &&
350
0
                       nonDefUVSOffset <= tablelen - 4,
351
0
                       NS_ERROR_GFX_CMAP_MALFORMED);
352
0
353
0
        if (defUVSOffset) {
354
0
            const uint32_t numUnicodeValueRanges = ReadLongAt(aBuf, defUVSOffset);
355
0
            NS_ENSURE_TRUE((tablelen - defUVSOffset) /
356
0
                           SizeOfDefUVSTable >= numUnicodeValueRanges,
357
0
                           NS_ERROR_GFX_CMAP_MALFORMED);
358
0
            const uint8_t *tables = aBuf + defUVSOffset + 4;
359
0
            uint32_t prevEndUnicode = 0;
360
0
            for (uint32_t j = 0; j < numUnicodeValueRanges; j++, tables += SizeOfDefUVSTable) {
361
0
                const uint32_t startUnicode = ReadUint24At(tables, DefUVSOffsetStartUnicodeValue);
362
0
                const uint32_t endUnicode = startUnicode + tables[DefUVSOffsetAdditionalCount];
363
0
                NS_ENSURE_TRUE((prevEndUnicode < startUnicode || j == 0) &&
364
0
                               endUnicode <= CMAP_MAX_CODEPOINT,
365
0
                               NS_ERROR_GFX_CMAP_MALFORMED);
366
0
                prevEndUnicode = endUnicode;
367
0
            }
368
0
        }
369
0
370
0
        if (nonDefUVSOffset) {
371
0
            const uint32_t numUVSMappings = ReadLongAt(aBuf, nonDefUVSOffset);
372
0
            NS_ENSURE_TRUE((tablelen - nonDefUVSOffset) /
373
0
                           SizeOfNonDefUVSTable >= numUVSMappings,
374
0
                           NS_ERROR_GFX_CMAP_MALFORMED);
375
0
            const uint8_t *tables = aBuf + nonDefUVSOffset + 4;
376
0
            uint32_t prevUnicode = 0;
377
0
            for (uint32_t j = 0; j < numUVSMappings; j++, tables += SizeOfNonDefUVSTable) {
378
0
                const uint32_t unicodeValue = ReadUint24At(tables, NonDefUVSOffsetUnicodeValue);
379
0
                NS_ENSURE_TRUE((prevUnicode < unicodeValue || j == 0) &&
380
0
                               unicodeValue <= CMAP_MAX_CODEPOINT,
381
0
                               NS_ERROR_GFX_CMAP_MALFORMED);
382
0
                prevUnicode = unicodeValue;
383
0
            }
384
0
        }
385
0
    }
386
0
387
0
    aTable = MakeUnique<uint8_t[]>(tablelen);
388
0
    memcpy(aTable.get(), aBuf, tablelen);
389
0
390
0
    return NS_OK;
391
0
}
392
393
// For fonts with two format-4 tables, the first one (Unicode platform) is preferred on the Mac;
394
// on other platforms we allow the Microsoft-platform subtable to replace it.
395
396
#if defined(XP_MACOSX)
397
    #define acceptableFormat4(p,e,k) (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft && !(k)) || \
398
                                      ((p) == PLATFORM_ID_UNICODE))
399
400
    #define acceptableUCS4Encoding(p, e, k) \
401
        (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform) && (k) != 12 || \
402
         ((p) == PLATFORM_ID_UNICODE   && \
403
          ((e) != EncodingIDUVSForUnicodePlatform)))
404
#else
405
0
    #define acceptableFormat4(p,e,k) (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft) || \
406
0
                                      ((p) == PLATFORM_ID_UNICODE))
407
408
    #define acceptableUCS4Encoding(p, e, k) \
409
0
        ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform)
410
#endif
411
412
0
#define acceptablePlatform(p) ((p) == PLATFORM_ID_UNICODE || (p) == PLATFORM_ID_MICROSOFT)
413
0
#define isSymbol(p,e)         ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDSymbol)
414
0
#define isUVSEncoding(p, e)   ((p) == PLATFORM_ID_UNICODE && (e) == EncodingIDUVSForUnicodePlatform)
415
416
uint32_t
417
gfxFontUtils::FindPreferredSubtable(const uint8_t *aBuf, uint32_t aBufLength,
418
                                    uint32_t *aTableOffset,
419
                                    uint32_t *aUVSTableOffset)
420
0
{
421
0
    enum {
422
0
        OffsetVersion = 0,
423
0
        OffsetNumTables = 2,
424
0
        SizeOfHeader = 4,
425
0
426
0
        TableOffsetPlatformID = 0,
427
0
        TableOffsetEncodingID = 2,
428
0
        TableOffsetOffset = 4,
429
0
        SizeOfTable = 8,
430
0
431
0
        SubtableOffsetFormat = 0
432
0
    };
433
0
    enum {
434
0
        EncodingIDSymbol = 0,
435
0
        EncodingIDMicrosoft = 1,
436
0
        EncodingIDDefaultForUnicodePlatform = 0,
437
0
        EncodingIDUCS4ForUnicodePlatform = 3,
438
0
        EncodingIDUVSForUnicodePlatform = 5,
439
0
        EncodingIDUCS4ForMicrosoftPlatform = 10
440
0
    };
441
0
442
0
    if (aUVSTableOffset) {
443
0
        *aUVSTableOffset = 0;
444
0
    }
445
0
446
0
    if (!aBuf || aBufLength < SizeOfHeader) {
447
0
        // cmap table is missing, or too small to contain header fields!
448
0
        return 0;
449
0
    }
450
0
451
0
    // uint16_t version = ReadShortAt(aBuf, OffsetVersion); // Unused: self-documenting.
452
0
    uint16_t numTables = ReadShortAt(aBuf, OffsetNumTables);
453
0
    if (aBufLength < uint32_t(SizeOfHeader + numTables * SizeOfTable)) {
454
0
        return 0;
455
0
    }
456
0
457
0
    // save the format we want here
458
0
    uint32_t keepFormat = 0;
459
0
460
0
    const uint8_t *table = aBuf + SizeOfHeader;
461
0
    for (uint16_t i = 0; i < numTables; ++i, table += SizeOfTable) {
462
0
        const uint16_t platformID = ReadShortAt(table, TableOffsetPlatformID);
463
0
        if (!acceptablePlatform(platformID))
464
0
            continue;
465
0
466
0
        const uint16_t encodingID = ReadShortAt(table, TableOffsetEncodingID);
467
0
        const uint32_t offset = ReadLongAt(table, TableOffsetOffset);
468
0
        if (aBufLength - 2 < offset) {
469
0
            // this subtable is not valid - beyond end of buffer
470
0
            return 0;
471
0
        }
472
0
473
0
        const uint8_t *subtable = aBuf + offset;
474
0
        const uint16_t format = ReadShortAt(subtable, SubtableOffsetFormat);
475
0
476
0
        if (isSymbol(platformID, encodingID)) {
477
0
            keepFormat = format;
478
0
            *aTableOffset = offset;
479
0
            break;
480
0
        } else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) {
481
0
            keepFormat = format;
482
0
            *aTableOffset = offset;
483
0
        } else if ((format == 10 || format == 12 || format == 13) &&
484
0
                   acceptableUCS4Encoding(platformID, encodingID, keepFormat)) {
485
0
            keepFormat = format;
486
0
            *aTableOffset = offset;
487
0
            if (platformID > PLATFORM_ID_UNICODE || !aUVSTableOffset || *aUVSTableOffset) {
488
0
                break; // we don't want to try anything else when this format is available.
489
0
            }
490
0
        } else if (format == 14 && isUVSEncoding(platformID, encodingID) && aUVSTableOffset) {
491
0
            *aUVSTableOffset = offset;
492
0
            if (keepFormat == 10 || keepFormat == 12) {
493
0
                break;
494
0
            }
495
0
        }
496
0
    }
497
0
498
0
    return keepFormat;
499
0
}
500
501
nsresult
502
gfxFontUtils::ReadCMAP(const uint8_t *aBuf, uint32_t aBufLength,
503
                       gfxSparseBitSet& aCharacterMap,
504
                       uint32_t& aUVSOffset)
505
0
{
506
0
    uint32_t offset;
507
0
    uint32_t format = FindPreferredSubtable(aBuf, aBufLength,
508
0
                                            &offset, &aUVSOffset);
509
0
510
0
    switch (format) {
511
0
    case 4:
512
0
        return ReadCMAPTableFormat4(aBuf + offset, aBufLength - offset,
513
0
                                    aCharacterMap);
514
0
515
0
    case 10:
516
0
        return ReadCMAPTableFormat10(aBuf + offset, aBufLength - offset,
517
0
                                     aCharacterMap);
518
0
519
0
    case 12:
520
0
    case 13:
521
0
        return ReadCMAPTableFormat12or13(aBuf + offset, aBufLength - offset,
522
0
                                         aCharacterMap);
523
0
524
0
    default:
525
0
        break;
526
0
    }
527
0
528
0
    return NS_ERROR_FAILURE;
529
0
}
530
531
#pragma pack(1)
532
533
typedef struct {
534
    AutoSwap_PRUint16 format;
535
    AutoSwap_PRUint16 length;
536
    AutoSwap_PRUint16 language;
537
    AutoSwap_PRUint16 segCountX2;
538
    AutoSwap_PRUint16 searchRange;
539
    AutoSwap_PRUint16 entrySelector;
540
    AutoSwap_PRUint16 rangeShift;
541
542
    AutoSwap_PRUint16 arrays[1];
543
} Format4Cmap;
544
545
typedef struct {
546
    AutoSwap_PRUint16 format;
547
    AutoSwap_PRUint32 length;
548
    AutoSwap_PRUint32 numVarSelectorRecords;
549
550
    typedef struct {
551
        AutoSwap_PRUint24 varSelector;
552
        AutoSwap_PRUint32 defaultUVSOffset;
553
        AutoSwap_PRUint32 nonDefaultUVSOffset;
554
    } VarSelectorRecord;
555
556
    VarSelectorRecord varSelectorRecords[1];
557
} Format14Cmap;
558
559
typedef struct {
560
    AutoSwap_PRUint32 numUVSMappings;
561
562
    typedef struct {
563
        AutoSwap_PRUint24 unicodeValue;
564
        AutoSwap_PRUint16 glyphID;
565
    } UVSMapping;
566
567
    UVSMapping uvsMappings[1];
568
} NonDefUVSTable;
569
570
#pragma pack()
571
572
uint32_t
573
gfxFontUtils::MapCharToGlyphFormat4(const uint8_t* aBuf, uint32_t aLength,
574
                                    char16_t aCh)
575
0
{
576
0
    const Format4Cmap *cmap4 = reinterpret_cast<const Format4Cmap*>(aBuf);
577
0
578
0
    uint16_t segCount = (uint16_t)(cmap4->segCountX2) / 2;
579
0
580
0
    const AutoSwap_PRUint16* endCodes = &cmap4->arrays[0];
581
0
    const AutoSwap_PRUint16* startCodes = &cmap4->arrays[segCount + 1];
582
0
    const AutoSwap_PRUint16* idDelta = &startCodes[segCount];
583
0
    const AutoSwap_PRUint16* idRangeOffset = &idDelta[segCount];
584
0
585
0
    // Sanity-check that the fixed-size arrays don't exceed the buffer.
586
0
    const uint8_t* const limit = aBuf + aLength;
587
0
    if ((const uint8_t*)(&idRangeOffset[segCount]) > limit) {
588
0
        return 0; // broken font, just bail out safely
589
0
    }
590
0
591
0
    // For most efficient binary search, we want to work on a range of segment
592
0
    // indexes that is a power of 2 so that we can always halve it by shifting.
593
0
    // So we find the largest power of 2 that is <= segCount.
594
0
    // We will offset this range by segOffset so as to reach the end
595
0
    // of the table, provided that doesn't put us beyond the target
596
0
    // value from the outset.
597
0
    uint32_t powerOf2 = mozilla::FindHighestBit(segCount);
598
0
    uint32_t segOffset = segCount - powerOf2;
599
0
    uint32_t idx = 0;
600
0
601
0
    if (uint16_t(startCodes[segOffset]) <= aCh) {
602
0
        idx = segOffset;
603
0
    }
604
0
605
0
    // Repeatedly halve the size of the range until we find the target group
606
0
    while (powerOf2 > 1) {
607
0
        powerOf2 >>= 1;
608
0
        if (uint16_t(startCodes[idx + powerOf2]) <= aCh) {
609
0
            idx += powerOf2;
610
0
        }
611
0
    }
612
0
613
0
    if (aCh >= uint16_t(startCodes[idx]) && aCh <= uint16_t(endCodes[idx])) {
614
0
        uint16_t result;
615
0
        if (uint16_t(idRangeOffset[idx]) == 0) {
616
0
            result = aCh;
617
0
        } else {
618
0
            uint16_t offset = aCh - uint16_t(startCodes[idx]);
619
0
            const AutoSwap_PRUint16* glyphIndexTable =
620
0
                (const AutoSwap_PRUint16*)((const char*)&idRangeOffset[idx] +
621
0
                                           uint16_t(idRangeOffset[idx]));
622
0
            if ((const uint8_t*)(glyphIndexTable + offset + 1) > limit) {
623
0
                return 0; // broken font, just bail out safely
624
0
            }
625
0
            result = glyphIndexTable[offset];
626
0
        }
627
0
628
0
        // Note that this is unsigned 16-bit arithmetic, and may wrap around
629
0
        // (which is required behavior per spec)
630
0
        result += uint16_t(idDelta[idx]);
631
0
        return result;
632
0
    }
633
0
634
0
    return 0;
635
0
}
636
637
uint32_t
638
gfxFontUtils::MapCharToGlyphFormat10(const uint8_t *aBuf, uint32_t aCh)
639
0
{
640
0
    const Format10CmapHeader *cmap10 =
641
0
        reinterpret_cast<const Format10CmapHeader*>(aBuf);
642
0
643
0
    uint32_t startChar = cmap10->startCharCode;
644
0
    uint32_t numChars = cmap10->numChars;
645
0
646
0
    if (aCh < startChar || aCh >= startChar + numChars) {
647
0
        return 0;
648
0
    }
649
0
650
0
    const AutoSwap_PRUint16 *glyphs =
651
0
        reinterpret_cast<const AutoSwap_PRUint16 *>(cmap10 + 1);
652
0
653
0
    uint16_t glyph = glyphs[aCh - startChar];
654
0
    return glyph;
655
0
}
656
657
uint32_t
658
gfxFontUtils::MapCharToGlyphFormat12or13(const uint8_t *aBuf, uint32_t aCh)
659
0
{
660
0
    // The only difference between formats 12 and 13 is the interpretation of
661
0
    // the glyphId field. So the code here uses the same "Format12" structures,
662
0
    // etc., to handle both subtable formats.
663
0
664
0
    const Format12CmapHeader *cmap12 =
665
0
        reinterpret_cast<const Format12CmapHeader*>(aBuf);
666
0
667
0
    // We know that numGroups is within range for the subtable size
668
0
    // because it was checked by ReadCMAPTableFormat12or13.
669
0
    uint32_t numGroups = cmap12->numGroups;
670
0
671
0
    // The array of groups immediately follows the subtable header.
672
0
    const Format12Group *groups =
673
0
        reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
674
0
675
0
    // For most efficient binary search, we want to work on a range that
676
0
    // is a power of 2 so that we can always halve it by shifting.
677
0
    // So we find the largest power of 2 that is <= numGroups.
678
0
    // We will offset this range by rangeOffset so as to reach the end
679
0
    // of the table, provided that doesn't put us beyond the target
680
0
    // value from the outset.
681
0
    uint32_t powerOf2 = mozilla::FindHighestBit(numGroups);
682
0
    uint32_t rangeOffset = numGroups - powerOf2;
683
0
    uint32_t range = 0;
684
0
    uint32_t startCharCode;
685
0
686
0
    if (groups[rangeOffset].startCharCode <= aCh) {
687
0
        range = rangeOffset;
688
0
    }
689
0
690
0
    // Repeatedly halve the size of the range until we find the target group
691
0
    while (powerOf2 > 1) {
692
0
        powerOf2 >>= 1;
693
0
        if (groups[range + powerOf2].startCharCode <= aCh) {
694
0
            range += powerOf2;
695
0
        }
696
0
    }
697
0
698
0
    // Check if the character is actually present in the range and return
699
0
    // the corresponding glyph ID. Here is where formats 12 and 13 interpret
700
0
    // the startGlyphId (12) or glyphId (13) field differently
701
0
    startCharCode = groups[range].startCharCode;
702
0
    if (startCharCode <= aCh && groups[range].endCharCode >= aCh) {
703
0
        return uint16_t(cmap12->format) == 12
704
0
               ? uint16_t(groups[range].startGlyphId) + aCh - startCharCode
705
0
               : uint16_t(groups[range].startGlyphId);
706
0
    }
707
0
708
0
    // Else it's not present, so return the .notdef glyph
709
0
    return 0;
710
0
}
711
712
namespace {
713
714
struct Format14CmapWrapper
715
{
716
    const Format14Cmap& mCmap14;
717
0
    explicit Format14CmapWrapper(const Format14Cmap& cmap14) : mCmap14(cmap14) {}
718
0
    uint32_t operator[](size_t index) const {
719
0
        return mCmap14.varSelectorRecords[index].varSelector;
720
0
    }
721
};
722
723
struct NonDefUVSTableWrapper
724
{
725
    const NonDefUVSTable& mTable;
726
0
    explicit NonDefUVSTableWrapper(const NonDefUVSTable& table) : mTable(table) {}
727
0
    uint32_t operator[](size_t index) const {
728
0
        return mTable.uvsMappings[index].unicodeValue;
729
0
    }
730
};
731
732
} // namespace
733
734
uint16_t
735
gfxFontUtils::MapUVSToGlyphFormat14(const uint8_t *aBuf, uint32_t aCh, uint32_t aVS)
736
0
{
737
0
    using mozilla::BinarySearch;
738
0
    const Format14Cmap *cmap14 = reinterpret_cast<const Format14Cmap*>(aBuf);
739
0
740
0
    size_t index;
741
0
    if (!BinarySearch(Format14CmapWrapper(*cmap14),
742
0
                      0, cmap14->numVarSelectorRecords, aVS, &index)) {
743
0
        return 0;
744
0
    }
745
0
746
0
    const uint32_t nonDefUVSOffset = cmap14->varSelectorRecords[index].nonDefaultUVSOffset;
747
0
    if (!nonDefUVSOffset) {
748
0
        return 0;
749
0
    }
750
0
751
0
    const NonDefUVSTable *table = reinterpret_cast<const NonDefUVSTable*>
752
0
                                      (aBuf + nonDefUVSOffset);
753
0
754
0
    if (BinarySearch(NonDefUVSTableWrapper(*table), 0, table->numUVSMappings,
755
0
                     aCh, &index)) {
756
0
        return table->uvsMappings[index].glyphID;
757
0
    }
758
0
759
0
    return 0;
760
0
}
761
762
uint32_t
763
gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
764
                             uint32_t aUnicode, uint32_t aVarSelector)
765
0
{
766
0
    uint32_t offset, uvsOffset;
767
0
    uint32_t format = FindPreferredSubtable(aCmapBuf, aBufLength, &offset,
768
0
                                            &uvsOffset);
769
0
770
0
    uint32_t gid;
771
0
    switch (format) {
772
0
    case 4:
773
0
        gid = aUnicode < UNICODE_BMP_LIMIT ?
774
0
            MapCharToGlyphFormat4(aCmapBuf + offset, aBufLength - offset,
775
0
                                  char16_t(aUnicode)) : 0;
776
0
        break;
777
0
    case 10:
778
0
        gid = MapCharToGlyphFormat10(aCmapBuf + offset, aUnicode);
779
0
        break;
780
0
    case 12:
781
0
    case 13:
782
0
        gid = MapCharToGlyphFormat12or13(aCmapBuf + offset, aUnicode);
783
0
        break;
784
0
    default:
785
0
        NS_WARNING("unsupported cmap format, glyphs will be missing");
786
0
        gid = 0;
787
0
    }
788
0
789
0
    if (aVarSelector && uvsOffset && gid) {
790
0
        uint32_t varGID =
791
0
            gfxFontUtils::MapUVSToGlyphFormat14(aCmapBuf + uvsOffset,
792
0
                                                aUnicode, aVarSelector);
793
0
        if (!varGID) {
794
0
            aUnicode = gfxFontUtils::GetUVSFallback(aUnicode, aVarSelector);
795
0
            if (aUnicode) {
796
0
                switch (format) {
797
0
                case 4:
798
0
                    if (aUnicode < UNICODE_BMP_LIMIT) {
799
0
                        varGID = MapCharToGlyphFormat4(aCmapBuf + offset,
800
0
                                                       aBufLength - offset,
801
0
                                                       char16_t(aUnicode));
802
0
                    }
803
0
                    break;
804
0
                case 10:
805
0
                    varGID = MapCharToGlyphFormat10(aCmapBuf + offset,
806
0
                                                    aUnicode);
807
0
                    break;
808
0
                case 12:
809
0
                case 13:
810
0
                    varGID = MapCharToGlyphFormat12or13(aCmapBuf + offset,
811
0
                                                        aUnicode);
812
0
                    break;
813
0
                }
814
0
            }
815
0
        }
816
0
        if (varGID) {
817
0
            gid = varGID;
818
0
        }
819
0
820
0
        // else the variation sequence was not supported, use default mapping
821
0
        // of the character code alone
822
0
    }
823
0
824
0
    return gid;
825
0
}
826
827
void gfxFontUtils::ParseFontList(const nsACString& aFamilyList,
828
                                 nsTArray<nsCString>& aFontList)
829
0
{
830
0
    const char kComma = ',';
831
0
832
0
    // append each font name to the list
833
0
    nsAutoCString fontname;
834
0
    const char *p, *p_end;
835
0
    aFamilyList.BeginReading(p);
836
0
    aFamilyList.EndReading(p_end);
837
0
838
0
     while (p < p_end) {
839
0
        const char *nameStart = p;
840
0
        while (++p != p_end && *p != kComma)
841
0
        /* nothing */ ;
842
0
843
0
        // pull out a single name and clean out leading/trailing whitespace
844
0
        fontname = Substring(nameStart, p);
845
0
        fontname.CompressWhitespace(true, true);
846
0
847
0
        // append it to the list if it's not empty
848
0
        if (!fontname.IsEmpty()) {
849
0
            aFontList.AppendElement(fontname);
850
0
        }
851
0
        ++p;
852
0
    }
853
0
}
854
855
void gfxFontUtils::AppendPrefsFontList(const char *aPrefName,
856
                                       nsTArray<nsCString>& aFontList)
857
0
{
858
0
    // get the list of single-face font families
859
0
    nsAutoCString fontlistValue;
860
0
    nsresult rv = Preferences::GetCString(aPrefName, fontlistValue);
861
0
    if (NS_FAILED(rv)) {
862
0
        return;
863
0
    }
864
0
865
0
    ParseFontList(fontlistValue, aFontList);
866
0
}
867
868
void gfxFontUtils::GetPrefsFontList(const char *aPrefName,
869
                                    nsTArray<nsCString>& aFontList)
870
0
{
871
0
    aFontList.Clear();
872
0
    AppendPrefsFontList(aPrefName, aFontList);
873
0
}
874
875
// produce a unique font name that is (1) a valid Postscript name and (2) less
876
// than 31 characters in length.  Using AddFontMemResourceEx on Windows fails
877
// for names longer than 30 characters in length.
878
879
#define MAX_B64_LEN 32
880
881
nsresult gfxFontUtils::MakeUniqueUserFontName(nsAString& aName)
882
0
{
883
0
    nsCOMPtr<nsIUUIDGenerator> uuidgen =
884
0
      do_GetService("@mozilla.org/uuid-generator;1");
885
0
    NS_ENSURE_TRUE(uuidgen, NS_ERROR_OUT_OF_MEMORY);
886
0
887
0
    nsID guid;
888
0
889
0
    NS_ASSERTION(sizeof(guid) * 2 <= MAX_B64_LEN, "size of nsID has changed!");
890
0
891
0
    nsresult rv = uuidgen->GenerateUUIDInPlace(&guid);
892
0
    NS_ENSURE_SUCCESS(rv, rv);
893
0
894
0
    char guidB64[MAX_B64_LEN] = {0};
895
0
896
0
    if (!PL_Base64Encode(reinterpret_cast<char*>(&guid), sizeof(guid), guidB64))
897
0
        return NS_ERROR_FAILURE;
898
0
899
0
    // all b64 characters except for '/' are allowed in Postscript names, so convert / ==> -
900
0
    char *p;
901
0
    for (p = guidB64; *p; p++) {
902
0
        if (*p == '/')
903
0
            *p = '-';
904
0
    }
905
0
906
0
    aName.AssignLiteral(u"uf");
907
0
    aName.AppendASCII(guidB64);
908
0
    return NS_OK;
909
0
}
910
911
912
// TrueType/OpenType table handling code
913
914
// need byte aligned structs
915
#pragma pack(1)
916
917
// name table stores set of name record structures, followed by
918
// large block containing all the strings.  name record offset and length
919
// indicates the offset and length within that block.
920
// http://www.microsoft.com/typography/otspec/name.htm
921
struct NameRecordData {
922
    uint32_t  offset;
923
    uint32_t  length;
924
};
925
926
#pragma pack()
927
928
static bool
929
IsValidSFNTVersion(uint32_t version)
930
0
{
931
0
    // normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 'true'
932
0
    // 'typ1' is also possible for old Type 1 fonts in a SFNT container but not supported
933
0
    return version == 0x10000 ||
934
0
           version == TRUETYPE_TAG('O','T','T','O') ||
935
0
           version == TRUETYPE_TAG('t','r','u','e');
936
0
}
937
938
gfxUserFontType
939
gfxFontUtils::DetermineFontDataType(const uint8_t *aFontData, uint32_t aFontDataLength)
940
0
{
941
0
    // test for OpenType font data
942
0
    // problem: EOT-Lite with 0x10000 length will look like TrueType!
943
0
    if (aFontDataLength >= sizeof(SFNTHeader)) {
944
0
        const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
945
0
        uint32_t sfntVersion = sfntHeader->sfntVersion;
946
0
        if (IsValidSFNTVersion(sfntVersion)) {
947
0
            return GFX_USERFONT_OPENTYPE;
948
0
        }
949
0
    }
950
0
951
0
    // test for WOFF
952
0
    if (aFontDataLength >= sizeof(AutoSwap_PRUint32)) {
953
0
        const AutoSwap_PRUint32 *version =
954
0
            reinterpret_cast<const AutoSwap_PRUint32*>(aFontData);
955
0
        if (uint32_t(*version) == TRUETYPE_TAG('w','O','F','F')) {
956
0
            return GFX_USERFONT_WOFF;
957
0
        }
958
0
        if (Preferences::GetBool(GFX_PREF_WOFF2_ENABLED) &&
959
0
            uint32_t(*version) == TRUETYPE_TAG('w','O','F','2')) {
960
0
            return GFX_USERFONT_WOFF2;
961
0
        }
962
0
    }
963
0
964
0
    // tests for other formats here
965
0
966
0
    return GFX_USERFONT_UNKNOWN;
967
0
}
968
969
static int
970
DirEntryCmp(const void* aKey, const void* aItem)
971
0
{
972
0
    int32_t tag = *static_cast<const int32_t*>(aKey);
973
0
    const TableDirEntry* entry = static_cast<const TableDirEntry*>(aItem);
974
0
    return tag - int32_t(entry->tag);
975
0
}
976
977
/* static */
978
TableDirEntry*
979
gfxFontUtils::FindTableDirEntry(const void* aFontData, uint32_t aTableTag)
980
0
{
981
0
    const SFNTHeader* header =
982
0
        reinterpret_cast<const SFNTHeader*>(aFontData);
983
0
    const TableDirEntry* dir =
984
0
        reinterpret_cast<const TableDirEntry*>(header + 1);
985
0
    return static_cast<TableDirEntry*>
986
0
        (bsearch(&aTableTag, dir, uint16_t(header->numTables),
987
0
                 sizeof(TableDirEntry), DirEntryCmp));
988
0
}
989
990
/* static */
991
hb_blob_t*
992
gfxFontUtils::GetTableFromFontData(const void* aFontData, uint32_t aTableTag)
993
0
{
994
0
    const TableDirEntry* dir = FindTableDirEntry(aFontData, aTableTag);
995
0
    if (dir) {
996
0
        return hb_blob_create(reinterpret_cast<const char*>(aFontData) +
997
0
                                  dir->offset, dir->length,
998
0
                              HB_MEMORY_MODE_READONLY, nullptr, nullptr);
999
0
1000
0
    }
1001
0
    return nullptr;
1002
0
}
1003
1004
nsresult
1005
gfxFontUtils::RenameFont(const nsAString& aName, const uint8_t *aFontData,
1006
                         uint32_t aFontDataLength, FallibleTArray<uint8_t> *aNewFont)
1007
0
{
1008
0
    NS_ASSERTION(aNewFont, "null font data array");
1009
0
1010
0
    uint64_t dataLength(aFontDataLength);
1011
0
1012
0
    // new name table
1013
0
    static const uint32_t neededNameIDs[] = {NAME_ID_FAMILY,
1014
0
                                             NAME_ID_STYLE,
1015
0
                                             NAME_ID_UNIQUE,
1016
0
                                             NAME_ID_FULL,
1017
0
                                             NAME_ID_POSTSCRIPT};
1018
0
1019
0
    // calculate new name table size
1020
0
    uint16_t nameCount = ArrayLength(neededNameIDs);
1021
0
1022
0
    // leave room for null-terminator
1023
0
    uint32_t nameStrLength = (aName.Length() + 1) * sizeof(char16_t);
1024
0
    if (nameStrLength > 65535) {
1025
0
        // The name length _in bytes_ must fit in an unsigned short field;
1026
0
        // therefore, a name longer than this cannot be used.
1027
0
        return NS_ERROR_FAILURE;
1028
0
    }
1029
0
1030
0
    // round name table size up to 4-byte multiple
1031
0
    uint32_t nameTableSize = (sizeof(NameHeader) +
1032
0
                              sizeof(NameRecord) * nameCount +
1033
0
                              nameStrLength +
1034
0
                              3) & ~3;
1035
0
1036
0
    if (dataLength + nameTableSize > UINT32_MAX)
1037
0
        return NS_ERROR_FAILURE;
1038
0
1039
0
    // bug 505386 - need to handle unpadded font length
1040
0
    uint32_t paddedFontDataSize = (aFontDataLength + 3) & ~3;
1041
0
    uint32_t adjFontDataSize = paddedFontDataSize + nameTableSize;
1042
0
1043
0
    // create new buffer: old font data plus new name table
1044
0
    if (!aNewFont->AppendElements(adjFontDataSize, fallible))
1045
0
        return NS_ERROR_OUT_OF_MEMORY;
1046
0
1047
0
    // copy the old font data
1048
0
    uint8_t *newFontData = reinterpret_cast<uint8_t*>(aNewFont->Elements());
1049
0
1050
0
    // null the last four bytes in case the font length is not a multiple of 4
1051
0
    memset(newFontData + aFontDataLength, 0, paddedFontDataSize - aFontDataLength);
1052
0
1053
0
    // copy font data
1054
0
    memcpy(newFontData, aFontData, aFontDataLength);
1055
0
1056
0
    // null out the last 4 bytes for checksum calculations
1057
0
    memset(newFontData + adjFontDataSize - 4, 0, 4);
1058
0
1059
0
    NameHeader *nameHeader = reinterpret_cast<NameHeader*>(newFontData +
1060
0
                                                            paddedFontDataSize);
1061
0
1062
0
    // -- name header
1063
0
    nameHeader->format = 0;
1064
0
    nameHeader->count = nameCount;
1065
0
    nameHeader->stringOffset = sizeof(NameHeader) + nameCount * sizeof(NameRecord);
1066
0
1067
0
    // -- name records
1068
0
    uint32_t i;
1069
0
    NameRecord *nameRecord = reinterpret_cast<NameRecord*>(nameHeader + 1);
1070
0
1071
0
    for (i = 0; i < nameCount; i++, nameRecord++) {
1072
0
        nameRecord->platformID = PLATFORM_ID_MICROSOFT;
1073
0
        nameRecord->encodingID = ENCODING_ID_MICROSOFT_UNICODEBMP;
1074
0
        nameRecord->languageID = LANG_ID_MICROSOFT_EN_US;
1075
0
        nameRecord->nameID = neededNameIDs[i];
1076
0
        nameRecord->offset = 0;
1077
0
        nameRecord->length = nameStrLength;
1078
0
    }
1079
0
1080
0
    // -- string data, located after the name records, stored in big-endian form
1081
0
    char16_t *strData = reinterpret_cast<char16_t*>(nameRecord);
1082
0
1083
0
    mozilla::NativeEndian::copyAndSwapToBigEndian(strData,
1084
0
                                                  aName.BeginReading(),
1085
0
                                                  aName.Length());
1086
0
    strData[aName.Length()] = 0; // add null termination
1087
0
1088
0
    // adjust name table header to point to the new name table
1089
0
    SFNTHeader *sfntHeader = reinterpret_cast<SFNTHeader*>(newFontData);
1090
0
1091
0
    // table directory entries begin immediately following SFNT header
1092
0
    TableDirEntry *dirEntry =
1093
0
        FindTableDirEntry(newFontData, TRUETYPE_TAG('n','a','m','e'));
1094
0
    // function only called if font validates, so this should always be true
1095
0
    MOZ_ASSERT(dirEntry, "attempt to rename font with no name table");
1096
0
1097
0
    uint32_t numTables = sfntHeader->numTables;
1098
0
1099
0
    // note: dirEntry now points to 'name' table record
1100
0
1101
0
    // recalculate name table checksum
1102
0
    uint32_t checkSum = 0;
1103
0
    AutoSwap_PRUint32 *nameData = reinterpret_cast<AutoSwap_PRUint32*> (nameHeader);
1104
0
    AutoSwap_PRUint32 *nameDataEnd = nameData + (nameTableSize >> 2);
1105
0
1106
0
    while (nameData < nameDataEnd)
1107
0
        checkSum = checkSum + *nameData++;
1108
0
1109
0
    // adjust name table entry to point to new name table
1110
0
    dirEntry->offset = paddedFontDataSize;
1111
0
    dirEntry->length = nameTableSize;
1112
0
    dirEntry->checkSum = checkSum;
1113
0
1114
0
    // fix up checksums
1115
0
    uint32_t checksum = 0;
1116
0
1117
0
    // checksum for font = (checksum of header) + (checksum of tables)
1118
0
    uint32_t headerLen = sizeof(SFNTHeader) + sizeof(TableDirEntry) * numTables;
1119
0
    const AutoSwap_PRUint32 *headerData =
1120
0
        reinterpret_cast<const AutoSwap_PRUint32*>(newFontData);
1121
0
1122
0
    // header length is in bytes, checksum calculated in longwords
1123
0
    for (i = 0; i < (headerLen >> 2); i++, headerData++) {
1124
0
        checksum += *headerData;
1125
0
    }
1126
0
1127
0
    uint32_t headOffset = 0;
1128
0
    dirEntry = reinterpret_cast<TableDirEntry*>(newFontData + sizeof(SFNTHeader));
1129
0
1130
0
    for (i = 0; i < numTables; i++, dirEntry++) {
1131
0
        if (dirEntry->tag == TRUETYPE_TAG('h','e','a','d')) {
1132
0
            headOffset = dirEntry->offset;
1133
0
        }
1134
0
        checksum += dirEntry->checkSum;
1135
0
    }
1136
0
1137
0
    NS_ASSERTION(headOffset != 0, "no head table for font");
1138
0
1139
0
    HeadTable *headData = reinterpret_cast<HeadTable*>(newFontData + headOffset);
1140
0
1141
0
    headData->checkSumAdjustment = HeadTable::HEAD_CHECKSUM_CALC_CONST - checksum;
1142
0
1143
0
    return NS_OK;
1144
0
}
1145
1146
// This is only called after the basic validity of the downloaded sfnt
1147
// data has been checked, so it should never fail to find the name table
1148
// (though it might fail to read it, if memory isn't available);
1149
// other checks here are just for extra paranoia.
1150
nsresult
1151
gfxFontUtils::GetFullNameFromSFNT(const uint8_t* aFontData, uint32_t aLength,
1152
                                  nsACString& aFullName)
1153
0
{
1154
0
    aFullName = "(MISSING NAME)"; // should always get replaced
1155
0
1156
0
    const TableDirEntry *dirEntry =
1157
0
        FindTableDirEntry(aFontData, TRUETYPE_TAG('n','a','m','e'));
1158
0
1159
0
    // should never fail, as we're only called after font validation succeeded
1160
0
    NS_ENSURE_TRUE(dirEntry, NS_ERROR_NOT_AVAILABLE);
1161
0
1162
0
    uint32_t len = dirEntry->length;
1163
0
    NS_ENSURE_TRUE(aLength > len && aLength - len >= dirEntry->offset,
1164
0
                   NS_ERROR_UNEXPECTED);
1165
0
1166
0
    hb_blob_t *nameBlob =
1167
0
        hb_blob_create((const char*)aFontData + dirEntry->offset, len,
1168
0
                       HB_MEMORY_MODE_READONLY, nullptr, nullptr);
1169
0
    nsresult rv = GetFullNameFromTable(nameBlob, aFullName);
1170
0
    hb_blob_destroy(nameBlob);
1171
0
1172
0
    return rv;
1173
0
}
1174
1175
nsresult
1176
gfxFontUtils::GetFullNameFromTable(hb_blob_t *aNameTable,
1177
                                   nsACString& aFullName)
1178
0
{
1179
0
    nsAutoCString name;
1180
0
    nsresult rv =
1181
0
        gfxFontUtils::ReadCanonicalName(aNameTable,
1182
0
                                        gfxFontUtils::NAME_ID_FULL,
1183
0
                                        name);
1184
0
    if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
1185
0
        aFullName = name;
1186
0
        return NS_OK;
1187
0
    }
1188
0
    rv = gfxFontUtils::ReadCanonicalName(aNameTable,
1189
0
                                         gfxFontUtils::NAME_ID_FAMILY,
1190
0
                                         name);
1191
0
    if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
1192
0
        nsAutoCString styleName;
1193
0
        rv = gfxFontUtils::ReadCanonicalName(aNameTable,
1194
0
                                             gfxFontUtils::NAME_ID_STYLE,
1195
0
                                             styleName);
1196
0
        if (NS_SUCCEEDED(rv) && !styleName.IsEmpty()) {
1197
0
            name.Append(' ');
1198
0
            name.Append(styleName);
1199
0
            aFullName = name;
1200
0
        }
1201
0
        return NS_OK;
1202
0
    }
1203
0
1204
0
    return NS_ERROR_NOT_AVAILABLE;
1205
0
}
1206
1207
nsresult
1208
gfxFontUtils::GetFamilyNameFromTable(hb_blob_t *aNameTable,
1209
                                     nsACString& aFamilyName)
1210
0
{
1211
0
    nsAutoCString name;
1212
0
    nsresult rv =
1213
0
        gfxFontUtils::ReadCanonicalName(aNameTable,
1214
0
                                        gfxFontUtils::NAME_ID_FAMILY,
1215
0
                                        name);
1216
0
    if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
1217
0
        aFamilyName = name;
1218
0
        return NS_OK;
1219
0
    }
1220
0
    return NS_ERROR_NOT_AVAILABLE;
1221
0
}
1222
1223
enum {
1224
#if defined(XP_MACOSX)
1225
    CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MAC_ENGLISH,
1226
    PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MAC
1227
#else
1228
    CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MICROSOFT_EN_US,
1229
    PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MICROSOFT
1230
#endif
1231
};
1232
1233
nsresult
1234
gfxFontUtils::ReadNames(const char *aNameData, uint32_t aDataLen,
1235
                        uint32_t aNameID, int32_t aPlatformID,
1236
                        nsTArray<nsCString>& aNames)
1237
0
{
1238
0
    return ReadNames(aNameData, aDataLen, aNameID, LANG_ALL,
1239
0
                     aPlatformID, aNames);
1240
0
}
1241
1242
nsresult
1243
gfxFontUtils::ReadCanonicalName(hb_blob_t *aNameTable, uint32_t aNameID,
1244
                                nsCString& aName)
1245
0
{
1246
0
    uint32_t nameTableLen;
1247
0
    const char *nameTable = hb_blob_get_data(aNameTable, &nameTableLen);
1248
0
    return ReadCanonicalName(nameTable, nameTableLen, aNameID, aName);
1249
0
}
1250
1251
nsresult
1252
gfxFontUtils::ReadCanonicalName(const char *aNameData, uint32_t aDataLen,
1253
                                uint32_t aNameID, nsCString& aName)
1254
0
{
1255
0
    nsresult rv;
1256
0
1257
0
    nsTArray<nsCString> names;
1258
0
1259
0
    // first, look for the English name (this will succeed 99% of the time)
1260
0
    rv = ReadNames(aNameData, aDataLen, aNameID, CANONICAL_LANG_ID,
1261
0
                   PLATFORM_ID, names);
1262
0
    NS_ENSURE_SUCCESS(rv, rv);
1263
0
1264
0
    // otherwise, grab names for all languages
1265
0
    if (names.Length() == 0) {
1266
0
        rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ALL,
1267
0
                       PLATFORM_ID, names);
1268
0
        NS_ENSURE_SUCCESS(rv, rv);
1269
0
    }
1270
0
1271
#if defined(XP_MACOSX)
1272
    // may be dealing with font that only has Microsoft name entries
1273
    if (names.Length() == 0) {
1274
        rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ID_MICROSOFT_EN_US,
1275
                       PLATFORM_ID_MICROSOFT, names);
1276
        NS_ENSURE_SUCCESS(rv, rv);
1277
1278
        // getting really desperate now, take anything!
1279
        if (names.Length() == 0) {
1280
            rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ALL,
1281
                           PLATFORM_ID_MICROSOFT, names);
1282
            NS_ENSURE_SUCCESS(rv, rv);
1283
        }
1284
    }
1285
#endif
1286
1287
0
    // return the first name (99.9% of the time names will
1288
0
    // contain a single English name)
1289
0
    if (names.Length()) {
1290
0
        aName.Assign(names[0]);
1291
0
        return NS_OK;
1292
0
    }
1293
0
1294
0
    return NS_ERROR_FAILURE;
1295
0
}
1296
1297
// Charsets to use for decoding Mac platform font names.
1298
// This table is sorted by {encoding, language}, with the wildcard "ANY" being
1299
// greater than any defined values for each field; we use a binary search on both
1300
// fields, and fall back to matching only encoding if necessary
1301
1302
// Some "redundant" entries for specific combinations are included such as
1303
// encoding=roman, lang=english, in order that common entries will be found
1304
// on the first search.
1305
1306
const uint16_t ANY = 0xffff;
1307
const gfxFontUtils::MacFontNameCharsetMapping gfxFontUtils::gMacFontNameCharsets[] =
1308
{
1309
    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ENGLISH,      MACINTOSH_ENCODING },
1310
    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ICELANDIC,    X_USER_DEFINED_ENCODING },
1311
    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_TURKISH,      X_USER_DEFINED_ENCODING },
1312
    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_POLISH,       X_USER_DEFINED_ENCODING },
1313
    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ROMANIAN,     X_USER_DEFINED_ENCODING },
1314
    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_CZECH,        X_USER_DEFINED_ENCODING },
1315
    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_SLOVAK,       X_USER_DEFINED_ENCODING },
1316
    { ENCODING_ID_MAC_ROMAN,        ANY,                      MACINTOSH_ENCODING },
1317
    { ENCODING_ID_MAC_JAPANESE,     LANG_ID_MAC_JAPANESE,     SHIFT_JIS_ENCODING },
1318
    { ENCODING_ID_MAC_JAPANESE,     ANY,                      SHIFT_JIS_ENCODING },
1319
    { ENCODING_ID_MAC_TRAD_CHINESE, LANG_ID_MAC_TRAD_CHINESE, BIG5_ENCODING },
1320
    { ENCODING_ID_MAC_TRAD_CHINESE, ANY,                      BIG5_ENCODING },
1321
    { ENCODING_ID_MAC_KOREAN,       LANG_ID_MAC_KOREAN,       EUC_KR_ENCODING },
1322
    { ENCODING_ID_MAC_KOREAN,       ANY,                      EUC_KR_ENCODING },
1323
    { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_ARABIC,       X_USER_DEFINED_ENCODING },
1324
    { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_URDU,         X_USER_DEFINED_ENCODING },
1325
    { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_FARSI,        X_USER_DEFINED_ENCODING },
1326
    { ENCODING_ID_MAC_ARABIC,       ANY,                      X_USER_DEFINED_ENCODING },
1327
    { ENCODING_ID_MAC_HEBREW,       LANG_ID_MAC_HEBREW,       X_USER_DEFINED_ENCODING },
1328
    { ENCODING_ID_MAC_HEBREW,       ANY,                      X_USER_DEFINED_ENCODING },
1329
    { ENCODING_ID_MAC_GREEK,        ANY,                      X_USER_DEFINED_ENCODING },
1330
    { ENCODING_ID_MAC_CYRILLIC,     ANY,                      X_MAC_CYRILLIC_ENCODING },
1331
    { ENCODING_ID_MAC_DEVANAGARI,   ANY,                      X_USER_DEFINED_ENCODING },
1332
    { ENCODING_ID_MAC_GURMUKHI,     ANY,                      X_USER_DEFINED_ENCODING },
1333
    { ENCODING_ID_MAC_GUJARATI,     ANY,                      X_USER_DEFINED_ENCODING },
1334
    { ENCODING_ID_MAC_SIMP_CHINESE, LANG_ID_MAC_SIMP_CHINESE, GB18030_ENCODING },
1335
    { ENCODING_ID_MAC_SIMP_CHINESE, ANY,                      GB18030_ENCODING }
1336
};
1337
1338
const Encoding* gfxFontUtils::gISOFontNameCharsets[] =
1339
{
1340
    /* 0 */ WINDOWS_1252_ENCODING, /* US-ASCII */
1341
    /* 1 */ nullptr       , /* spec says "ISO 10646" but does not specify encoding form! */
1342
    /* 2 */ WINDOWS_1252_ENCODING  /* ISO-8859-1 */
1343
};
1344
1345
const Encoding* gfxFontUtils::gMSFontNameCharsets[] =
1346
{
1347
    /* [0] ENCODING_ID_MICROSOFT_SYMBOL */      UTF_16BE_ENCODING,
1348
    /* [1] ENCODING_ID_MICROSOFT_UNICODEBMP */  UTF_16BE_ENCODING,
1349
    /* [2] ENCODING_ID_MICROSOFT_SHIFTJIS */    SHIFT_JIS_ENCODING,
1350
    /* [3] ENCODING_ID_MICROSOFT_PRC */         nullptr      ,
1351
    /* [4] ENCODING_ID_MICROSOFT_BIG5 */        BIG5_ENCODING,
1352
    /* [5] ENCODING_ID_MICROSOFT_WANSUNG */     nullptr      ,
1353
    /* [6] ENCODING_ID_MICROSOFT_JOHAB */       nullptr      ,
1354
    /* [7] reserved */                          nullptr      ,
1355
    /* [8] reserved */                          nullptr      ,
1356
    /* [9] reserved */                          nullptr      ,
1357
    /*[10] ENCODING_ID_MICROSOFT_UNICODEFULL */ UTF_16BE_ENCODING
1358
};
1359
1360
struct MacCharsetMappingComparator
1361
{
1362
    typedef gfxFontUtils::MacFontNameCharsetMapping MacFontNameCharsetMapping;
1363
    const MacFontNameCharsetMapping& mSearchValue;
1364
    explicit MacCharsetMappingComparator(const MacFontNameCharsetMapping& aSearchValue)
1365
0
      : mSearchValue(aSearchValue) {}
1366
0
    int operator()(const MacFontNameCharsetMapping& aEntry) const {
1367
0
        if (mSearchValue < aEntry) {
1368
0
            return -1;
1369
0
        }
1370
0
        if (aEntry < mSearchValue) {
1371
0
            return 1;
1372
0
        }
1373
0
        return 0;
1374
0
    }
1375
};
1376
1377
// Return the Encoding object we should use to decode a font name
1378
// given the name table attributes.
1379
// Special return values:
1380
//    X_USER_DEFINED_ENCODING  One of Mac legacy encodings that is not a part
1381
//                             of Encoding Standard
1382
//    nullptr                  unknown charset, do not attempt conversion
1383
const Encoding*
1384
gfxFontUtils::GetCharsetForFontName(uint16_t aPlatform, uint16_t aScript, uint16_t aLanguage)
1385
0
{
1386
0
    switch (aPlatform)
1387
0
    {
1388
0
    case PLATFORM_ID_UNICODE:
1389
0
        return UTF_16BE_ENCODING;
1390
0
1391
0
    case PLATFORM_ID_MAC:
1392
0
        {
1393
0
            MacFontNameCharsetMapping searchValue = { aScript, aLanguage, nullptr };
1394
0
            for (uint32_t i = 0; i < 2; ++i) {
1395
0
                size_t idx;
1396
0
                if (BinarySearchIf(gMacFontNameCharsets, 0, ArrayLength(gMacFontNameCharsets),
1397
0
                                            MacCharsetMappingComparator(searchValue), &idx)) {
1398
0
                    return gMacFontNameCharsets[idx].mEncoding;
1399
0
                }
1400
0
1401
0
                // no match, so try again finding one in any language
1402
0
                searchValue.mLanguage = ANY;
1403
0
            }
1404
0
        }
1405
0
        break;
1406
0
1407
0
    case PLATFORM_ID_ISO:
1408
0
        if (aScript < ArrayLength(gISOFontNameCharsets)) {
1409
0
            return gISOFontNameCharsets[aScript];
1410
0
        }
1411
0
        break;
1412
0
1413
0
    case PLATFORM_ID_MICROSOFT:
1414
0
        if (aScript < ArrayLength(gMSFontNameCharsets)) {
1415
0
            return gMSFontNameCharsets[aScript];
1416
0
        }
1417
0
        break;
1418
0
    }
1419
0
1420
0
    return nullptr;
1421
0
}
1422
1423
template<int N>
1424
static bool
1425
StartsWith(const nsACString& string, const char (&prefix)[N])
1426
{
1427
  if (N - 1 > string.Length()) {
1428
    return false;
1429
  }
1430
  return memcmp(string.Data(), prefix, N - 1) == 0;
1431
}
1432
1433
// convert a raw name from the name table to an nsString, if possible;
1434
// return value indicates whether conversion succeeded
1435
bool
1436
gfxFontUtils::DecodeFontName(const char *aNameData, int32_t aByteLen,
1437
                             uint32_t aPlatformCode, uint32_t aScriptCode,
1438
                             uint32_t aLangCode, nsACString& aName)
1439
0
{
1440
0
    if (aByteLen <= 0) {
1441
0
        NS_WARNING("empty font name");
1442
0
        aName.SetLength(0);
1443
0
        return true;
1444
0
    }
1445
0
1446
0
    auto encoding = GetCharsetForFontName(aPlatformCode, aScriptCode, aLangCode);
1447
0
1448
0
    if (!encoding) {
1449
0
        // nullptr -> unknown charset
1450
#ifdef DEBUG
1451
        char warnBuf[128];
1452
        if (aByteLen > 64)
1453
            aByteLen = 64;
1454
        SprintfLiteral(warnBuf, "skipping font name, unknown charset %d:%d:%d for <%.*s>",
1455
                       aPlatformCode, aScriptCode, aLangCode, aByteLen, aNameData);
1456
        NS_WARNING(warnBuf);
1457
#endif
1458
        return false;
1459
0
    }
1460
0
1461
0
    if (encoding == X_USER_DEFINED_ENCODING) {
1462
#ifdef XP_MACOSX
1463
        // Special case for macOS only: support legacy Mac encodings
1464
        // that aren't part of the Encoding Standard.
1465
        if (aPlatformCode == PLATFORM_ID_MAC) {
1466
            CFStringRef str =
1467
                CFStringCreateWithBytes(kCFAllocatorDefault,
1468
                                        (const UInt8*)aNameData, aByteLen,
1469
                                        aScriptCode, false);
1470
            if (str) {
1471
                CFIndex length = CFStringGetLength(str);
1472
                nsAutoString name16;
1473
                name16.SetLength(length);
1474
                CFStringGetCharacters(str, CFRangeMake(0, length),
1475
                                      (UniChar*)name16.BeginWriting());
1476
                CFRelease(str);
1477
                CopyUTF16toUTF8(name16, aName);
1478
                return true;
1479
            }
1480
        }
1481
#endif
1482
0
        NS_WARNING("failed to get the decoder for a font name string");
1483
0
        return false;
1484
0
    }
1485
0
1486
0
    auto rv = encoding->DecodeWithoutBOMHandling(
1487
0
        nsDependentCSubstring(aNameData, aByteLen), aName);
1488
0
    return NS_SUCCEEDED(rv);
1489
0
}
1490
1491
nsresult
1492
gfxFontUtils::ReadNames(const char *aNameData, uint32_t aDataLen,
1493
                        uint32_t aNameID,
1494
                        int32_t aLangID, int32_t aPlatformID,
1495
                        nsTArray<nsCString>& aNames)
1496
0
{
1497
0
    NS_ASSERTION(aDataLen != 0, "null name table");
1498
0
1499
0
    if (!aDataLen) {
1500
0
        return NS_ERROR_FAILURE;
1501
0
    }
1502
0
1503
0
    // -- name table data
1504
0
    const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(aNameData);
1505
0
1506
0
    uint32_t nameCount = nameHeader->count;
1507
0
1508
0
    // -- sanity check the number of name records
1509
0
    if (uint64_t(nameCount) * sizeof(NameRecord) > aDataLen) {
1510
0
        NS_WARNING("invalid font (name table data)");
1511
0
        return NS_ERROR_FAILURE;
1512
0
    }
1513
0
1514
0
    // -- iterate through name records
1515
0
    const NameRecord *nameRecord
1516
0
        = reinterpret_cast<const NameRecord*>(aNameData + sizeof(NameHeader));
1517
0
    uint64_t nameStringsBase = uint64_t(nameHeader->stringOffset);
1518
0
1519
0
    uint32_t i;
1520
0
    for (i = 0; i < nameCount; i++, nameRecord++) {
1521
0
        uint32_t platformID;
1522
0
1523
0
        // skip over unwanted nameID's
1524
0
        if (uint32_t(nameRecord->nameID) != aNameID) {
1525
0
            continue;
1526
0
        }
1527
0
1528
0
        // skip over unwanted platform data
1529
0
        platformID = nameRecord->platformID;
1530
0
        if (aPlatformID != PLATFORM_ALL &&
1531
0
            platformID != uint32_t(aPlatformID)) {
1532
0
            continue;
1533
0
        }
1534
0
1535
0
        // skip over unwanted languages
1536
0
        if (aLangID != LANG_ALL &&
1537
0
            uint32_t(nameRecord->languageID) != uint32_t(aLangID)) {
1538
0
            continue;
1539
0
        }
1540
0
1541
0
        // add name to names array
1542
0
1543
0
        // -- calculate string location
1544
0
        uint32_t namelen = nameRecord->length;
1545
0
        uint32_t nameoff = nameRecord->offset;  // offset from base of string storage
1546
0
1547
0
        if (nameStringsBase + uint64_t(nameoff) + uint64_t(namelen)
1548
0
                > aDataLen) {
1549
0
            NS_WARNING("invalid font (name table strings)");
1550
0
            return NS_ERROR_FAILURE;
1551
0
        }
1552
0
1553
0
        // -- decode if necessary and make nsString
1554
0
        nsAutoCString name;
1555
0
1556
0
        DecodeFontName(aNameData + nameStringsBase + nameoff, namelen,
1557
0
                       platformID, uint32_t(nameRecord->encodingID),
1558
0
                       uint32_t(nameRecord->languageID), name);
1559
0
1560
0
        uint32_t k, numNames;
1561
0
        bool foundName = false;
1562
0
1563
0
        numNames = aNames.Length();
1564
0
        for (k = 0; k < numNames; k++) {
1565
0
            if (name.Equals(aNames[k])) {
1566
0
                foundName = true;
1567
0
                break;
1568
0
            }
1569
0
        }
1570
0
1571
0
        if (!foundName)
1572
0
            aNames.AppendElement(name);
1573
0
1574
0
    }
1575
0
1576
0
    return NS_OK;
1577
0
}
1578
1579
#pragma pack(1)
1580
1581
struct COLRBaseGlyphRecord {
1582
    AutoSwap_PRUint16    glyphId;
1583
    AutoSwap_PRUint16    firstLayerIndex;
1584
    AutoSwap_PRUint16    numLayers;
1585
};
1586
1587
struct COLRLayerRecord {
1588
    AutoSwap_PRUint16    glyphId;
1589
    AutoSwap_PRUint16    paletteEntryIndex;
1590
};
1591
1592
struct CPALColorRecord {
1593
    uint8_t              blue;
1594
    uint8_t              green;
1595
    uint8_t              red;
1596
    uint8_t              alpha;
1597
};
1598
1599
#pragma pack()
1600
1601
bool
1602
gfxFontUtils::ValidateColorGlyphs(hb_blob_t* aCOLR, hb_blob_t* aCPAL)
1603
0
{
1604
0
    unsigned int colrLength;
1605
0
    const COLRHeader* colr =
1606
0
        reinterpret_cast<const COLRHeader*>(hb_blob_get_data(aCOLR, &colrLength));
1607
0
    unsigned int cpalLength;
1608
0
    const CPALHeaderVersion0* cpal =
1609
0
        reinterpret_cast<const CPALHeaderVersion0*>(hb_blob_get_data(aCPAL, &cpalLength));
1610
0
1611
0
    if (!colr || !cpal || !colrLength || !cpalLength) {
1612
0
        return false;
1613
0
    }
1614
0
1615
0
    if (uint16_t(colr->version) != 0 || uint16_t(cpal->version) != 0) {
1616
0
        // We only support version 0 headers.
1617
0
        return false;
1618
0
    }
1619
0
1620
0
    const uint32_t offsetBaseGlyphRecord = colr->offsetBaseGlyphRecord;
1621
0
    const uint16_t numBaseGlyphRecord = colr->numBaseGlyphRecord;
1622
0
    const uint32_t offsetLayerRecord = colr->offsetLayerRecord;
1623
0
    const uint16_t numLayerRecords = colr->numLayerRecords;
1624
0
1625
0
    const uint32_t offsetFirstColorRecord = cpal->offsetFirstColorRecord;
1626
0
    const uint16_t numColorRecords = cpal->numColorRecords;
1627
0
    const uint32_t numPaletteEntries = cpal->numPaletteEntries;
1628
0
1629
0
    if (offsetBaseGlyphRecord >= colrLength) {
1630
0
        return false;
1631
0
    }
1632
0
1633
0
    if (offsetLayerRecord >= colrLength) {
1634
0
        return false;
1635
0
    }
1636
0
1637
0
    if (offsetFirstColorRecord >= cpalLength) {
1638
0
        return false;
1639
0
    }
1640
0
1641
0
    if (!numPaletteEntries) {
1642
0
        return false;
1643
0
    }
1644
0
1645
0
    if (sizeof(COLRBaseGlyphRecord) * numBaseGlyphRecord >
1646
0
            colrLength - offsetBaseGlyphRecord) {
1647
0
        // COLR base glyph record will be overflow
1648
0
        return false;
1649
0
    }
1650
0
1651
0
    if (sizeof(COLRLayerRecord) * numLayerRecords >
1652
0
            colrLength - offsetLayerRecord) {
1653
0
        // COLR layer record will be overflow
1654
0
        return false;
1655
0
    }
1656
0
1657
0
    if (sizeof(CPALColorRecord) * numColorRecords >
1658
0
            cpalLength - offsetFirstColorRecord) {
1659
0
        // CPAL color record will be overflow
1660
0
        return false;
1661
0
    }
1662
0
1663
0
    if (numPaletteEntries * uint16_t(cpal->numPalettes) != numColorRecords ) {
1664
0
        // palette of CPAL color record will be overflow.
1665
0
        return false;
1666
0
    }
1667
0
1668
0
    uint16_t lastGlyphId = 0;
1669
0
    const COLRBaseGlyphRecord* baseGlyph =
1670
0
        reinterpret_cast<const COLRBaseGlyphRecord*>(
1671
0
            reinterpret_cast<const uint8_t*>(colr) + offsetBaseGlyphRecord);
1672
0
1673
0
    for (uint16_t i = 0; i < numBaseGlyphRecord; i++, baseGlyph++) {
1674
0
        const uint32_t firstLayerIndex = baseGlyph->firstLayerIndex;
1675
0
        const uint16_t numLayers = baseGlyph->numLayers;
1676
0
        const uint16_t glyphId = baseGlyph->glyphId;
1677
0
1678
0
        if (lastGlyphId && lastGlyphId >= glyphId) {
1679
0
            // glyphId must be sorted
1680
0
            return false;
1681
0
        }
1682
0
        lastGlyphId = glyphId;
1683
0
1684
0
        if (!numLayers) {
1685
0
            // no layer
1686
0
            return false;
1687
0
        }
1688
0
        if (firstLayerIndex + numLayers > numLayerRecords) {
1689
0
            // layer length of target glyph is overflow
1690
0
            return false;
1691
0
        }
1692
0
    }
1693
0
1694
0
    const COLRLayerRecord* layer =
1695
0
        reinterpret_cast<const COLRLayerRecord*>(
1696
0
            reinterpret_cast<const uint8_t*>(colr) + offsetLayerRecord);
1697
0
1698
0
    for (uint16_t i = 0; i < numLayerRecords; i++, layer++) {
1699
0
        if (uint16_t(layer->paletteEntryIndex) >= numPaletteEntries &&
1700
0
            uint16_t(layer->paletteEntryIndex) != 0xFFFF) {
1701
0
            // CPAL palette entry record is overflow
1702
0
            return false;
1703
0
        }
1704
0
    }
1705
0
1706
0
    return true;
1707
0
}
1708
1709
static int
1710
CompareBaseGlyph(const void* key, const void* data)
1711
0
{
1712
0
    uint32_t glyphId = (uint32_t)(uintptr_t)key;
1713
0
    const COLRBaseGlyphRecord* baseGlyph =
1714
0
        reinterpret_cast<const COLRBaseGlyphRecord*>(data);
1715
0
    uint32_t baseGlyphId = uint16_t(baseGlyph->glyphId);
1716
0
1717
0
    if (baseGlyphId == glyphId) {
1718
0
        return 0;
1719
0
    }
1720
0
1721
0
    return baseGlyphId > glyphId ? -1 : 1;
1722
0
}
1723
1724
static
1725
COLRBaseGlyphRecord*
1726
LookForBaseGlyphRecord(const COLRHeader* aCOLR, uint32_t aGlyphId)
1727
0
{
1728
0
    const uint8_t* baseGlyphRecords =
1729
0
        reinterpret_cast<const uint8_t*>(aCOLR) +
1730
0
        uint32_t(aCOLR->offsetBaseGlyphRecord);
1731
0
    // BaseGlyphRecord is sorted by glyphId
1732
0
    return reinterpret_cast<COLRBaseGlyphRecord*>(
1733
0
               bsearch((void*)(uintptr_t)aGlyphId,
1734
0
                       baseGlyphRecords,
1735
0
                       uint16_t(aCOLR->numBaseGlyphRecord),
1736
0
                       sizeof(COLRBaseGlyphRecord),
1737
0
                       CompareBaseGlyph));
1738
0
}
1739
1740
bool
1741
gfxFontUtils::GetColorGlyphLayers(hb_blob_t* aCOLR,
1742
                                  hb_blob_t* aCPAL,
1743
                                  uint32_t aGlyphId,
1744
                                  const mozilla::gfx::Color& aDefaultColor,
1745
                                  nsTArray<uint16_t>& aGlyphs,
1746
                                  nsTArray<mozilla::gfx::Color>& aColors)
1747
0
{
1748
0
    unsigned int blobLength;
1749
0
    const COLRHeader* colr =
1750
0
        reinterpret_cast<const COLRHeader*>(hb_blob_get_data(aCOLR,
1751
0
                                                             &blobLength));
1752
0
    MOZ_ASSERT(colr, "Cannot get COLR raw data");
1753
0
    MOZ_ASSERT(blobLength, "Found COLR data, but length is 0");
1754
0
1755
0
    COLRBaseGlyphRecord* baseGlyph = LookForBaseGlyphRecord(colr, aGlyphId);
1756
0
    if (!baseGlyph) {
1757
0
        return false;
1758
0
    }
1759
0
1760
0
    const CPALHeaderVersion0* cpal =
1761
0
        reinterpret_cast<const CPALHeaderVersion0*>(
1762
0
            hb_blob_get_data(aCPAL, &blobLength));
1763
0
    MOZ_ASSERT(cpal, "Cannot get CPAL raw data");
1764
0
    MOZ_ASSERT(blobLength, "Found CPAL data, but length is 0");
1765
0
1766
0
    const COLRLayerRecord* layer =
1767
0
        reinterpret_cast<const COLRLayerRecord*>(
1768
0
            reinterpret_cast<const uint8_t*>(colr) +
1769
0
            uint32_t(colr->offsetLayerRecord) +
1770
0
            sizeof(COLRLayerRecord) * uint16_t(baseGlyph->firstLayerIndex));
1771
0
    const uint16_t numLayers = baseGlyph->numLayers;
1772
0
    const uint32_t offsetFirstColorRecord = cpal->offsetFirstColorRecord;
1773
0
1774
0
    for (uint16_t layerIndex = 0; layerIndex < numLayers; layerIndex++) {
1775
0
        aGlyphs.AppendElement(uint16_t(layer->glyphId));
1776
0
        if (uint16_t(layer->paletteEntryIndex) == 0xFFFF) {
1777
0
            aColors.AppendElement(aDefaultColor);
1778
0
        } else {
1779
0
            const CPALColorRecord* color =
1780
0
                reinterpret_cast<const CPALColorRecord*>(
1781
0
                    reinterpret_cast<const uint8_t*>(cpal) +
1782
0
                    offsetFirstColorRecord +
1783
0
                    sizeof(CPALColorRecord) * uint16_t(layer->paletteEntryIndex));
1784
0
            aColors.AppendElement(mozilla::gfx::Color(color->red / 255.0,
1785
0
                                                      color->green / 255.0,
1786
0
                                                      color->blue / 255.0,
1787
0
                                                      color->alpha / 255.0));
1788
0
        }
1789
0
        layer++;
1790
0
    }
1791
0
    return true;
1792
0
}
1793
1794
void
1795
gfxFontUtils::GetVariationInstances(gfxFontEntry* aFontEntry,
1796
                                    nsTArray<gfxFontVariationInstance>& aInstances)
1797
0
{
1798
0
    MOZ_ASSERT(aInstances.IsEmpty());
1799
0
1800
0
    if (!aFontEntry->HasVariations()) {
1801
0
        return;
1802
0
    }
1803
0
1804
0
    // Some platforms don't offer a simple API to return the list of instances,
1805
0
    // so we have to interpret the 'fvar' table ourselves.
1806
0
1807
0
    // https://www.microsoft.com/typography/otspec/fvar.htm#fvarHeader
1808
0
    struct FvarHeader {
1809
0
        AutoSwap_PRUint16 majorVersion;
1810
0
        AutoSwap_PRUint16 minorVersion;
1811
0
        AutoSwap_PRUint16 axesArrayOffset;
1812
0
        AutoSwap_PRUint16 reserved;
1813
0
        AutoSwap_PRUint16 axisCount;
1814
0
        AutoSwap_PRUint16 axisSize;
1815
0
        AutoSwap_PRUint16 instanceCount;
1816
0
        AutoSwap_PRUint16 instanceSize;
1817
0
    };
1818
0
1819
0
    // https://www.microsoft.com/typography/otspec/fvar.htm#variationAxisRecord
1820
0
    struct AxisRecord {
1821
0
        AutoSwap_PRUint32 axisTag;
1822
0
        AutoSwap_PRInt32  minValue;
1823
0
        AutoSwap_PRInt32  defaultValue;
1824
0
        AutoSwap_PRInt32  maxValue;
1825
0
        AutoSwap_PRUint16 flags;
1826
0
        AutoSwap_PRUint16 axisNameID;
1827
0
    };
1828
0
1829
0
    // https://www.microsoft.com/typography/otspec/fvar.htm#instanceRecord
1830
0
    struct InstanceRecord {
1831
0
        AutoSwap_PRUint16 subfamilyNameID;
1832
0
        AutoSwap_PRUint16 flags;
1833
0
        AutoSwap_PRInt32  coordinates[1]; // variable-size array [axisCount]
1834
0
        // The variable-length 'coordinates' array may be followed by an
1835
0
        // optional extra field 'postScriptNameID'. We can't directly
1836
0
        // represent this in the struct, because its offset varies depending
1837
0
        // on the number of axes present.
1838
0
        // (Not currently used by our code here anyhow.)
1839
0
    //  AutoSwap_PRUint16 postScriptNameID;
1840
0
    };
1841
0
1842
0
    // Helper to ensure we free a font table when we return.
1843
0
    class AutoHBBlob {
1844
0
    public:
1845
0
        explicit AutoHBBlob(hb_blob_t* aBlob) : mBlob(aBlob)
1846
0
        { }
1847
0
1848
0
        ~AutoHBBlob() {
1849
0
            if (mBlob) {
1850
0
                hb_blob_destroy(mBlob);
1851
0
            }
1852
0
        }
1853
0
1854
0
        operator hb_blob_t* () { return mBlob; }
1855
0
1856
0
    private:
1857
0
        hb_blob_t* const mBlob;
1858
0
    };
1859
0
1860
0
    // Load the two font tables we need as harfbuzz blobs; if either is absent,
1861
0
    // just bail out.
1862
0
    AutoHBBlob fvarTable(aFontEntry->GetFontTable(TRUETYPE_TAG('f','v','a','r')));
1863
0
    AutoHBBlob nameTable(aFontEntry->GetFontTable(TRUETYPE_TAG('n','a','m','e')));
1864
0
    if (!fvarTable || !nameTable) {
1865
0
        return;
1866
0
    }
1867
0
    unsigned int len;
1868
0
    const char* data = hb_blob_get_data(fvarTable, &len);
1869
0
    if (len < sizeof(FvarHeader)) {
1870
0
        return;
1871
0
    }
1872
0
    // Read the fields of the table header; bail out if it looks broken.
1873
0
    auto fvar = reinterpret_cast<const FvarHeader*>(data);
1874
0
    if (uint16_t(fvar->majorVersion) != 1 ||
1875
0
        uint16_t(fvar->minorVersion) != 0 ||
1876
0
        uint16_t(fvar->reserved) != 2) {
1877
0
        return;
1878
0
    }
1879
0
    uint16_t axisCount = fvar->axisCount;
1880
0
    uint16_t axisSize = fvar->axisSize;
1881
0
    uint16_t instanceCount = fvar->instanceCount;
1882
0
    uint16_t instanceSize = fvar->instanceSize;
1883
0
    if (axisCount == 0 || // no axes?
1884
0
        // https://www.microsoft.com/typography/otspec/fvar.htm#axisSize
1885
0
        axisSize != 20 || // required value for current table version
1886
0
        instanceCount == 0 || // no instances?
1887
0
        // https://www.microsoft.com/typography/otspec/fvar.htm#instanceSize
1888
0
        (instanceSize != axisCount * sizeof(int32_t) + 4 &&
1889
0
         instanceSize != axisCount * sizeof(int32_t) + 6)) {
1890
0
        return;
1891
0
    }
1892
0
    // Check that axis array will not exceed table size
1893
0
    uint16_t axesOffset = fvar->axesArrayOffset;
1894
0
    if (axesOffset + uint32_t(axisCount) * axisSize > len) {
1895
0
        return;
1896
0
    }
1897
0
    // Get pointer to the array of axis records
1898
0
    auto axes = reinterpret_cast<const AxisRecord*>(data + axesOffset);
1899
0
    // Get address of instance array, and check it doesn't overflow table size.
1900
0
    // https://www.microsoft.com/typography/otspec/fvar.htm#axisAndInstanceArrays
1901
0
    auto instData = data + axesOffset + axisCount * axisSize;
1902
0
    if (instData + uint32_t(instanceCount) * instanceSize > data + len) {
1903
0
        return;
1904
0
    }
1905
0
    aInstances.SetCapacity(instanceCount);
1906
0
    for (unsigned i = 0; i < instanceCount; ++i, instData += instanceSize) {
1907
0
        // Typed pointer to the current instance record, to read its fields.
1908
0
        auto inst = reinterpret_cast<const InstanceRecord*>(instData);
1909
0
        // Pointer to the coordinates array within the instance record.
1910
0
        // This array has axisCount elements, and is included in instanceSize
1911
0
        // (which depends on axisCount, and was validated above) so we know
1912
0
        // access to coords[j] below will not be outside the table bounds.
1913
0
        auto coords = &inst->coordinates[0];
1914
0
        gfxFontVariationInstance instance;
1915
0
        uint16_t nameID = inst->subfamilyNameID;
1916
0
        nsresult rv =
1917
0
            ReadCanonicalName(nameTable, nameID, instance.mName);
1918
0
        if (NS_FAILED(rv)) {
1919
0
            // If no name was available for the instance, ignore it.
1920
0
            continue;
1921
0
        }
1922
0
        instance.mValues.SetCapacity(axisCount);
1923
0
        for (unsigned j = 0; j < axisCount; ++j) {
1924
0
            gfxFontVariationValue value;
1925
0
            value.mAxis = axes[j].axisTag;
1926
0
            value.mValue = int32_t(coords[j]) / 65536.0;
1927
0
            instance.mValues.AppendElement(value);
1928
0
        }
1929
0
        aInstances.AppendElement(instance);
1930
0
    }
1931
0
}
1932
1933
#ifdef XP_WIN
1934
1935
/* static */
1936
bool
1937
gfxFontUtils::IsCffFont(const uint8_t* aFontData)
1938
{
1939
    // this is only called after aFontData has passed basic validation,
1940
    // so we know there is enough data present to allow us to read the version!
1941
    const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
1942
    return (sfntHeader->sfntVersion == TRUETYPE_TAG('O','T','T','O'));
1943
}
1944
1945
#endif
1946
1947
#undef acceptablePlatform
1948
#undef isSymbol
1949
#undef isUVSEncoding
1950
#undef LOG
1951
#undef LOG_ENABLED