tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gfxFontUtils.cpp (64317B)


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