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