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