tor-browser

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

gfxFontUtils.h (50118B)


      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 #ifndef GFX_FONT_UTILS_H
      7 #define GFX_FONT_UTILS_H
      8 
      9 #include <string.h>
     10 #include <algorithm>
     11 #include <new>
     12 #include "gfxPlatform.h"
     13 #include "harfbuzz/hb.h"
     14 #include "mozilla/Assertions.h"
     15 #include "mozilla/Attributes.h"
     16 #include "mozilla/Casting.h"
     17 #include "mozilla/EndianUtils.h"
     18 #include "mozilla/ServoStyleConstsInlines.h"
     19 #include "mozilla/MemoryReporting.h"
     20 #include "nsStringFwd.h"
     21 #include "nsTArray.h"
     22 #include "nscore.h"
     23 #include "zlib.h"
     24 
     25 class PickleIterator;
     26 class gfxFontEntry;
     27 struct gfxFontVariationAxis;
     28 struct gfxFontVariationInstance;
     29 
     30 namespace mozilla {
     31 class Encoding;
     32 class ServoStyleSet;
     33 }  // namespace mozilla
     34 
     35 /* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
     36 #ifdef __MINGW32__
     37 #  undef min
     38 #  undef max
     39 #endif
     40 
     41 #undef ERROR /* defined by Windows.h, conflicts with some generated bindings \
     42                code when this gets indirectly included via shared font list \
     43              */
     44 
     45 typedef struct hb_blob_t hb_blob_t;
     46 
     47 class SharedBitSet;
     48 
     49 namespace IPC {
     50 template <typename T>
     51 struct ParamTraits;
     52 }
     53 
     54 class gfxSparseBitSet {
     55 private:
     56  friend class SharedBitSet;
     57 
     58  enum { BLOCK_SIZE = 32 };  // ==> 256 codepoints per block
     59  enum { BLOCK_SIZE_BITS = BLOCK_SIZE * 8 };
     60  enum { NO_BLOCK = 0xffff };  // index value indicating missing (empty) block
     61 
     62  // The BlockIndex type is just a uint16_t, except it will default-construct
     63  // with the value NO_BLOCK so that we can do AppendElements(size_t) to grow
     64  // the index.
     65  struct BlockIndex {
     66    BlockIndex() : mIndex(NO_BLOCK) {}
     67    explicit BlockIndex(uint16_t aIndex) : mIndex(aIndex) {}
     68 
     69    operator uint16_t() const { return mIndex; }
     70 
     71    uint16_t mIndex;
     72  };
     73 
     74  struct Block {
     75    Block() { memset(mBits, 0, BLOCK_SIZE); }
     76    explicit Block(unsigned char memsetValue) {
     77      memset(mBits, memsetValue, BLOCK_SIZE);
     78    }
     79    uint8_t mBits[BLOCK_SIZE];
     80  };
     81 
     82  friend struct IPC::ParamTraits<gfxSparseBitSet>;
     83  friend struct IPC::ParamTraits<BlockIndex>;
     84  friend struct IPC::ParamTraits<Block>;
     85 
     86 public:
     87  gfxSparseBitSet() = default;
     88  explicit gfxSparseBitSet(uint32_t aReserveCapacity)
     89      : mBlockIndex(aReserveCapacity), mBlocks(aReserveCapacity) {}
     90 
     91  bool Equals(const gfxSparseBitSet* aOther) const {
     92    if (mBlockIndex.Length() != aOther->mBlockIndex.Length()) {
     93      return false;
     94    }
     95    size_t n = mBlockIndex.Length();
     96    for (size_t i = 0; i < n; ++i) {
     97      uint16_t b1 = mBlockIndex[i];
     98      uint16_t b2 = aOther->mBlockIndex[i];
     99      if ((b1 == NO_BLOCK) != (b2 == NO_BLOCK)) {
    100        return false;
    101      }
    102      if (b1 == NO_BLOCK) {
    103        continue;
    104      }
    105      if (memcmp(&mBlocks[b1].mBits, &aOther->mBlocks[b2].mBits, BLOCK_SIZE) !=
    106          0) {
    107        return false;
    108      }
    109    }
    110    return true;
    111  }
    112 
    113  bool test(uint32_t aIndex) const {
    114    uint32_t i = aIndex / BLOCK_SIZE_BITS;
    115    if (i >= mBlockIndex.Length() || mBlockIndex[i] == NO_BLOCK) {
    116      return false;
    117    }
    118    const Block& block = mBlocks[mBlockIndex[i]];
    119    return ((block.mBits[(aIndex >> 3) & (BLOCK_SIZE - 1)]) &
    120            (1 << (aIndex & 0x7))) != 0;
    121  }
    122 
    123  // dump out contents of bitmap
    124  void Dump(const char* aPrefix, eGfxLog aWhichLog) const;
    125 
    126  bool TestRange(uint32_t aStart, uint32_t aEnd) {
    127    // start point is beyond the end of the block array? return false
    128    // immediately
    129    uint32_t startBlock = aStart / BLOCK_SIZE_BITS;
    130    uint32_t blockLen = mBlockIndex.Length();
    131    if (startBlock >= blockLen) {
    132      return false;
    133    }
    134 
    135    // check for blocks in range, if none, return false
    136    bool hasBlocksInRange = false;
    137    uint32_t endBlock = aEnd / BLOCK_SIZE_BITS;
    138    for (uint32_t bi = startBlock; bi <= endBlock; bi++) {
    139      if (bi < blockLen && mBlockIndex[bi] != NO_BLOCK) {
    140        hasBlocksInRange = true;
    141        break;
    142      }
    143    }
    144    if (!hasBlocksInRange) {
    145      return false;
    146    }
    147 
    148    // first block, check bits
    149    if (mBlockIndex[startBlock] != NO_BLOCK) {
    150      const Block& block = mBlocks[mBlockIndex[startBlock]];
    151      uint32_t start = aStart;
    152      uint32_t end = std::min(aEnd, ((startBlock + 1) * BLOCK_SIZE_BITS) - 1);
    153      for (uint32_t i = start; i <= end; i++) {
    154        if ((block.mBits[(i >> 3) & (BLOCK_SIZE - 1)]) & (1 << (i & 0x7))) {
    155          return true;
    156        }
    157      }
    158    }
    159    if (endBlock == startBlock) {
    160      return false;
    161    }
    162 
    163    // [2..n-1] blocks check bytes
    164    for (uint32_t i = startBlock + 1; i < endBlock; i++) {
    165      if (i >= blockLen || mBlockIndex[i] == NO_BLOCK) {
    166        continue;
    167      }
    168      const Block& block = mBlocks[mBlockIndex[i]];
    169      for (uint32_t index = 0; index < BLOCK_SIZE; index++) {
    170        if (block.mBits[index]) {
    171          return true;
    172        }
    173      }
    174    }
    175 
    176    // last block, check bits
    177    if (endBlock < blockLen && mBlockIndex[endBlock] != NO_BLOCK) {
    178      const Block& block = mBlocks[mBlockIndex[endBlock]];
    179      uint32_t start = endBlock * BLOCK_SIZE_BITS;
    180      uint32_t end = aEnd;
    181      for (uint32_t i = start; i <= end; i++) {
    182        if ((block.mBits[(i >> 3) & (BLOCK_SIZE - 1)]) & (1 << (i & 0x7))) {
    183          return true;
    184        }
    185      }
    186    }
    187 
    188    return false;
    189  }
    190 
    191  void set(uint32_t aIndex) {
    192    uint32_t i = aIndex / BLOCK_SIZE_BITS;
    193    if (i >= mBlockIndex.Length()) {
    194      mBlockIndex.AppendElements(i - mBlockIndex.Length() + 1);
    195    }
    196    if (mBlockIndex[i] == NO_BLOCK) {
    197      mBlocks.AppendElement();
    198      MOZ_ASSERT(mBlocks.Length() < 0xffff, "block index overflow!");
    199      mBlockIndex[i].mIndex = static_cast<uint16_t>(mBlocks.Length() - 1);
    200    }
    201    Block& block = mBlocks[mBlockIndex[i]];
    202    block.mBits[(aIndex >> 3) & (BLOCK_SIZE - 1)] |= 1 << (aIndex & 0x7);
    203  }
    204 
    205  void set(uint32_t aIndex, bool aValue) {
    206    if (aValue) {
    207      set(aIndex);
    208    } else {
    209      clear(aIndex);
    210    }
    211  }
    212 
    213  void SetRange(uint32_t aStart, uint32_t aEnd) {
    214    const uint32_t startIndex = aStart / BLOCK_SIZE_BITS;
    215    const uint32_t endIndex = aEnd / BLOCK_SIZE_BITS;
    216 
    217    if (endIndex >= mBlockIndex.Length()) {
    218      mBlockIndex.AppendElements(endIndex - mBlockIndex.Length() + 1);
    219    }
    220 
    221    for (uint32_t i = startIndex; i <= endIndex; ++i) {
    222      const uint32_t blockFirstBit = i * BLOCK_SIZE_BITS;
    223      const uint32_t blockLastBit = blockFirstBit + BLOCK_SIZE_BITS - 1;
    224 
    225      if (mBlockIndex[i] == NO_BLOCK) {
    226        bool fullBlock = (aStart <= blockFirstBit && aEnd >= blockLastBit);
    227        mBlocks.AppendElement(fullBlock ? Block(0xFF) : Block());
    228        MOZ_ASSERT(mBlocks.Length() < 0xffff, "block index overflow!");
    229        mBlockIndex[i].mIndex = static_cast<uint16_t>(mBlocks.Length() - 1);
    230        if (fullBlock) {
    231          continue;
    232        }
    233      }
    234 
    235      Block& block = mBlocks[mBlockIndex[i]];
    236      const uint32_t start =
    237          aStart > blockFirstBit ? aStart - blockFirstBit : 0;
    238      const uint32_t end =
    239          std::min<uint32_t>(aEnd - blockFirstBit, BLOCK_SIZE_BITS - 1);
    240 
    241      for (uint32_t bit = start; bit <= end; ++bit) {
    242        block.mBits[bit >> 3] |= 1 << (bit & 0x7);
    243      }
    244    }
    245  }
    246 
    247  void clear(uint32_t aIndex) {
    248    uint32_t i = aIndex / BLOCK_SIZE_BITS;
    249    if (i >= mBlockIndex.Length()) {
    250      return;
    251    }
    252    if (mBlockIndex[i] == NO_BLOCK) {
    253      return;
    254    }
    255    Block& block = mBlocks[mBlockIndex[i]];
    256    block.mBits[(aIndex >> 3) & (BLOCK_SIZE - 1)] &= ~(1 << (aIndex & 0x7));
    257  }
    258 
    259  void ClearRange(uint32_t aStart, uint32_t aEnd) {
    260    const uint32_t startIndex = aStart / BLOCK_SIZE_BITS;
    261    const uint32_t endIndex = aEnd / BLOCK_SIZE_BITS;
    262 
    263    for (uint32_t i = startIndex; i <= endIndex; ++i) {
    264      if (i >= mBlockIndex.Length()) {
    265        return;
    266      }
    267      if (mBlockIndex[i] == NO_BLOCK) {
    268        continue;
    269      }
    270 
    271      const uint32_t blockFirstBit = i * BLOCK_SIZE_BITS;
    272      Block& block = mBlocks[mBlockIndex[i]];
    273 
    274      const uint32_t start =
    275          aStart > blockFirstBit ? aStart - blockFirstBit : 0;
    276      const uint32_t end =
    277          std::min<uint32_t>(aEnd - blockFirstBit, BLOCK_SIZE_BITS - 1);
    278 
    279      for (uint32_t bit = start; bit <= end; ++bit) {
    280        block.mBits[bit >> 3] &= ~(1 << (bit & 0x7));
    281      }
    282    }
    283  }
    284 
    285  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
    286    return mBlocks.ShallowSizeOfExcludingThis(aMallocSizeOf) +
    287           mBlockIndex.ShallowSizeOfExcludingThis(aMallocSizeOf);
    288  }
    289 
    290  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
    291    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    292  }
    293 
    294  // clear out all blocks in the array
    295  void reset() {
    296    mBlocks.Clear();
    297    mBlockIndex.Clear();
    298  }
    299 
    300  // set this bitset to the union of its current contents and another
    301  void Union(const gfxSparseBitSet& aBitset) {
    302    // ensure mBlockIndex is large enough
    303    uint32_t blockCount = aBitset.mBlockIndex.Length();
    304    if (blockCount > mBlockIndex.Length()) {
    305      mBlockIndex.AppendElements(blockCount - mBlockIndex.Length());
    306    }
    307    // for each block that may be present in aBitset...
    308    for (uint32_t i = 0; i < blockCount; ++i) {
    309      // if it is missing (implicitly empty), just skip
    310      if (aBitset.mBlockIndex[i] == NO_BLOCK) {
    311        continue;
    312      }
    313      // if the block is missing in this set, just copy the other
    314      if (mBlockIndex[i] == NO_BLOCK) {
    315        mBlocks.AppendElement(aBitset.mBlocks[aBitset.mBlockIndex[i]]);
    316        MOZ_ASSERT(mBlocks.Length() < 0xffff, "block index overflow!");
    317        mBlockIndex[i].mIndex = static_cast<uint16_t>(mBlocks.Length() - 1);
    318        continue;
    319      }
    320      // else set existing block to the union of both
    321      uint32_t* dst =
    322          reinterpret_cast<uint32_t*>(&mBlocks[mBlockIndex[i]].mBits);
    323      const uint32_t* src = reinterpret_cast<const uint32_t*>(
    324          &aBitset.mBlocks[aBitset.mBlockIndex[i]].mBits);
    325      for (uint32_t j = 0; j < BLOCK_SIZE / 4; ++j) {
    326        dst[j] |= src[j];
    327      }
    328    }
    329  }
    330 
    331  inline void Union(const SharedBitSet& aBitset);
    332 
    333  void Compact() {
    334    // TODO: Discard any empty blocks, and adjust index accordingly.
    335    // (May not be worth doing, though, because we so rarely clear bits
    336    // that were previously set.)
    337    mBlocks.Compact();
    338    mBlockIndex.Compact();
    339  }
    340 
    341  uint32_t GetChecksum() const {
    342    uint32_t check =
    343        adler32(0, reinterpret_cast<const uint8_t*>(mBlockIndex.Elements()),
    344                mBlockIndex.Length() * sizeof(uint16_t));
    345    check = adler32(check, reinterpret_cast<const uint8_t*>(mBlocks.Elements()),
    346                    mBlocks.Length() * sizeof(Block));
    347    return check;
    348  }
    349 
    350 protected:
    351  CopyableTArray<BlockIndex> mBlockIndex;
    352  CopyableTArray<Block> mBlocks;
    353 };
    354 
    355 /**
    356 * SharedBitSet is a version of gfxSparseBitSet that is intended to be used
    357 * in a shared-memory block, and can be used regardless of the address at which
    358 * the block has been mapped. The SharedBitSet cannot be modified once it has
    359 * been created.
    360 *
    361 * Max size of a SharedBitSet = 4352 * 32  ; blocks
    362 *                              + 4352 * 2 ; index
    363 *                              + 4        ; counts
    364 *   = 147972 bytes
    365 *
    366 * Therefore, SharedFontList must be able to allocate a contiguous block of at
    367 * least this size.
    368 */
    369 class SharedBitSet {
    370 private:
    371  // We use the same Block type as gfxSparseBitSet.
    372  typedef gfxSparseBitSet::Block Block;
    373 
    374  enum { BLOCK_SIZE = gfxSparseBitSet::BLOCK_SIZE };
    375  enum { BLOCK_SIZE_BITS = gfxSparseBitSet::BLOCK_SIZE_BITS };
    376  enum { NO_BLOCK = gfxSparseBitSet::NO_BLOCK };
    377 
    378 public:
    379  static const size_t kMaxSize = 147972;  // see above
    380 
    381  // Returns the size needed for a SharedBitSet version of the given
    382  // gfxSparseBitSet.
    383  static size_t RequiredSize(const gfxSparseBitSet& aBitset) {
    384    size_t total = sizeof(SharedBitSet);
    385    size_t len = aBitset.mBlockIndex.Length();
    386    total += len * sizeof(uint16_t);  // add size for index array
    387    // add size for blocks, excluding any missing ones
    388    for (uint16_t i = 0; i < len; i++) {
    389      if (aBitset.mBlockIndex[i] != NO_BLOCK) {
    390        total += sizeof(Block);
    391      }
    392    }
    393    MOZ_ASSERT(total <= kMaxSize);
    394    return total;
    395  }
    396 
    397  // Create a SharedBitSet in the provided buffer, initializing it with the
    398  // contents of aBitset.
    399  static SharedBitSet* Create(void* aBuffer, size_t aBufSize,
    400                              const gfxSparseBitSet& aBitset) {
    401    MOZ_ASSERT(aBufSize >= RequiredSize(aBitset));
    402    return new (aBuffer) SharedBitSet(aBitset);
    403  }
    404 
    405  bool test(uint32_t aIndex) const {
    406    const auto i = static_cast<uint16_t>(aIndex / BLOCK_SIZE_BITS);
    407    if (i >= mBlockIndexCount) {
    408      return false;
    409    }
    410    const uint16_t* const blockIndex =
    411        reinterpret_cast<const uint16_t*>(this + 1);
    412    if (blockIndex[i] == NO_BLOCK) {
    413      return false;
    414    }
    415    const Block* const blocks =
    416        reinterpret_cast<const Block*>(blockIndex + mBlockIndexCount);
    417    const Block& block = blocks[blockIndex[i]];
    418    return ((block.mBits[(aIndex >> 3) & (BLOCK_SIZE - 1)]) &
    419            (1 << (aIndex & 0x7))) != 0;
    420  }
    421 
    422  bool Equals(const gfxSparseBitSet* aOther) const {
    423    if (mBlockIndexCount != aOther->mBlockIndex.Length()) {
    424      return false;
    425    }
    426    const uint16_t* const blockIndex =
    427        reinterpret_cast<const uint16_t*>(this + 1);
    428    const Block* const blocks =
    429        reinterpret_cast<const Block*>(blockIndex + mBlockIndexCount);
    430    for (uint16_t i = 0; i < mBlockIndexCount; ++i) {
    431      uint16_t index = blockIndex[i];
    432      uint16_t otherIndex = aOther->mBlockIndex[i];
    433      if ((index == NO_BLOCK) != (otherIndex == NO_BLOCK)) {
    434        return false;
    435      }
    436      if (index == NO_BLOCK) {
    437        continue;
    438      }
    439      const Block& b1 = blocks[index];
    440      const Block& b2 = aOther->mBlocks[otherIndex];
    441      if (memcmp(&b1.mBits, &b2.mBits, BLOCK_SIZE) != 0) {
    442        return false;
    443      }
    444    }
    445    return true;
    446  }
    447 
    448 private:
    449  friend class gfxSparseBitSet;
    450  SharedBitSet() = delete;
    451 
    452  explicit SharedBitSet(const gfxSparseBitSet& aBitset)
    453      : mBlockIndexCount(
    454            mozilla::AssertedCast<uint16_t>(aBitset.mBlockIndex.Length())),
    455        mBlockCount(0) {
    456    uint16_t* blockIndex = reinterpret_cast<uint16_t*>(this + 1);
    457    Block* blocks = reinterpret_cast<Block*>(blockIndex + mBlockIndexCount);
    458    for (uint16_t i = 0; i < mBlockIndexCount; i++) {
    459      if (aBitset.mBlockIndex[i] != NO_BLOCK) {
    460        const Block& srcBlock = aBitset.mBlocks[aBitset.mBlockIndex[i]];
    461        std::memcpy(&blocks[mBlockCount], &srcBlock, sizeof(Block));
    462        blockIndex[i] = mBlockCount;
    463        mBlockCount++;
    464      } else {
    465        blockIndex[i] = NO_BLOCK;
    466      }
    467    }
    468  }
    469 
    470  // We never manage SharedBitSet as a "normal" object, it's a view onto a
    471  // buffer of shared memory. So we should never be trying to call this.
    472  ~SharedBitSet() = delete;
    473 
    474  uint16_t mBlockIndexCount;
    475  uint16_t mBlockCount;
    476 
    477  // After the two "header" fields above, we have a block index array
    478  // of uint16_t[mBlockIndexCount], followed by mBlockCount Block records.
    479 };
    480 
    481 // Union the contents of a SharedBitSet with the target gfxSparseBitSet
    482 inline void gfxSparseBitSet::Union(const SharedBitSet& aBitset) {
    483  // ensure mBlockIndex is large enough
    484  while (mBlockIndex.Length() < aBitset.mBlockIndexCount) {
    485    mBlockIndex.AppendElement(NO_BLOCK);
    486  }
    487  auto blockIndex = reinterpret_cast<const uint16_t*>(&aBitset + 1);
    488  auto blocks =
    489      reinterpret_cast<const Block*>(blockIndex + aBitset.mBlockIndexCount);
    490  for (uint32_t i = 0; i < aBitset.mBlockIndexCount; ++i) {
    491    // if it is missing (implicitly empty) in source, just skip
    492    if (blockIndex[i] == NO_BLOCK) {
    493      continue;
    494    }
    495    // if the block is missing, just copy from source bitset
    496    if (mBlockIndex[i] == NO_BLOCK) {
    497      mBlocks.AppendElement(blocks[blockIndex[i]]);
    498      MOZ_ASSERT(mBlocks.Length() < 0xffff, "block index overflow");
    499      mBlockIndex[i].mIndex = uint16_t(mBlocks.Length() - 1);
    500      continue;
    501    }
    502    // Else set existing target block to the union of both.
    503    // Note that blocks in SharedBitSet may not be 4-byte aligned, so we don't
    504    // try to optimize by casting to uint32_t* here and processing 4 bytes at
    505    // once, as this could result in misaligned access.
    506    uint8_t* dst = reinterpret_cast<uint8_t*>(&mBlocks[mBlockIndex[i]].mBits);
    507    const uint8_t* src =
    508        reinterpret_cast<const uint8_t*>(&blocks[blockIndex[i]].mBits);
    509    for (uint32_t j = 0; j < BLOCK_SIZE; ++j) {
    510      dst[j] |= src[j];
    511    }
    512  }
    513 }
    514 
    515 #define TRUETYPE_TAG(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
    516 
    517 namespace mozilla {
    518 
    519 // Byte-swapping types and name table structure definitions moved from
    520 // gfxFontUtils.cpp to .h file so that gfxFont.cpp can also refer to them
    521 #pragma pack(1)
    522 
    523 struct AutoSwap_PRUint16 {
    524 #ifdef __SUNPRO_CC
    525  AutoSwap_PRUint16& operator=(const uint16_t aValue) {
    526    this->value = mozilla::NativeEndian::swapToBigEndian(aValue);
    527    return *this;
    528  }
    529 #else
    530  MOZ_IMPLICIT AutoSwap_PRUint16(uint16_t aValue) {
    531    value = mozilla::NativeEndian::swapToBigEndian(aValue);
    532  }
    533 #endif
    534  operator uint16_t() const {
    535    return mozilla::NativeEndian::swapFromBigEndian(value);
    536  }
    537 
    538  operator uint32_t() const {
    539    return mozilla::NativeEndian::swapFromBigEndian(value);
    540  }
    541 
    542  operator uint64_t() const {
    543    return mozilla::NativeEndian::swapFromBigEndian(value);
    544  }
    545 
    546 private:
    547  uint16_t value;
    548 };
    549 
    550 struct AutoSwap_PRInt16 {
    551 #ifdef __SUNPRO_CC
    552  AutoSwap_PRInt16& operator=(const int16_t aValue) {
    553    this->value = mozilla::NativeEndian::swapToBigEndian(aValue);
    554    return *this;
    555  }
    556 #else
    557  MOZ_IMPLICIT AutoSwap_PRInt16(int16_t aValue) {
    558    value = mozilla::NativeEndian::swapToBigEndian(aValue);
    559  }
    560 #endif
    561  operator int16_t() const {
    562    return mozilla::NativeEndian::swapFromBigEndian(value);
    563  }
    564 
    565  operator uint32_t() const {
    566    return mozilla::NativeEndian::swapFromBigEndian(value);
    567  }
    568 
    569 private:
    570  int16_t value;
    571 };
    572 
    573 struct AutoSwap_PRUint32 {
    574 #ifdef __SUNPRO_CC
    575  AutoSwap_PRUint32& operator=(const uint32_t aValue) {
    576    this->value = mozilla::NativeEndian::swapToBigEndian(aValue);
    577    return *this;
    578  }
    579 #else
    580  MOZ_IMPLICIT AutoSwap_PRUint32(uint32_t aValue) {
    581    value = mozilla::NativeEndian::swapToBigEndian(aValue);
    582  }
    583 #endif
    584  operator uint32_t() const {
    585    return mozilla::NativeEndian::swapFromBigEndian(value);
    586  }
    587 
    588 private:
    589  uint32_t value;
    590 };
    591 
    592 struct AutoSwap_PRInt32 {
    593 #ifdef __SUNPRO_CC
    594  AutoSwap_PRInt32& operator=(const int32_t aValue) {
    595    this->value = mozilla::NativeEndian::swapToBigEndian(aValue);
    596    return *this;
    597  }
    598 #else
    599  MOZ_IMPLICIT AutoSwap_PRInt32(int32_t aValue) {
    600    value = mozilla::NativeEndian::swapToBigEndian(aValue);
    601  }
    602 #endif
    603  operator int32_t() const {
    604    return mozilla::NativeEndian::swapFromBigEndian(value);
    605  }
    606 
    607 private:
    608  int32_t value;
    609 };
    610 
    611 struct AutoSwap_PRUint64 {
    612 #ifdef __SUNPRO_CC
    613  AutoSwap_PRUint64& operator=(const uint64_t aValue) {
    614    this->value = mozilla::NativeEndian::swapToBigEndian(aValue);
    615    return *this;
    616  }
    617 #else
    618  MOZ_IMPLICIT AutoSwap_PRUint64(uint64_t aValue) {
    619    value = mozilla::NativeEndian::swapToBigEndian(aValue);
    620  }
    621 #endif
    622  operator uint64_t() const {
    623    return mozilla::NativeEndian::swapFromBigEndian(value);
    624  }
    625 
    626 private:
    627  uint64_t value;
    628 };
    629 
    630 struct AutoSwap_PRUint24 {
    631  operator uint32_t() const {
    632    return value[0] << 16 | value[1] << 8 | value[2];
    633  }
    634 
    635 private:
    636  AutoSwap_PRUint24() = default;
    637  uint8_t value[3];
    638 };
    639 
    640 struct SFNTHeader {
    641  AutoSwap_PRUint32 sfntVersion;    // Fixed, 0x00010000 for version 1.0.
    642  AutoSwap_PRUint16 numTables;      // Number of tables.
    643  AutoSwap_PRUint16 searchRange;    // (Maximum power of 2 <= numTables) x 16.
    644  AutoSwap_PRUint16 entrySelector;  // Log2(maximum power of 2 <= numTables).
    645  AutoSwap_PRUint16 rangeShift;     // NumTables x 16-searchRange.
    646 };
    647 
    648 struct TTCHeader {
    649  AutoSwap_PRUint32 ttcTag;  // 4 -byte identifier 'ttcf'.
    650  AutoSwap_PRUint16 majorVersion;
    651  AutoSwap_PRUint16 minorVersion;
    652  AutoSwap_PRUint32 numFonts;
    653  // followed by:
    654  // AutoSwap_PRUint32 offsetTable[numFonts]
    655 };
    656 
    657 struct TableDirEntry {
    658  AutoSwap_PRUint32 tag;       // 4 -byte identifier.
    659  AutoSwap_PRUint32 checkSum;  // CheckSum for this table.
    660  AutoSwap_PRUint32 offset;    // Offset from beginning of TrueType font file.
    661  AutoSwap_PRUint32 length;    // Length of this table.
    662 };
    663 
    664 struct HeadTable {
    665  enum {
    666    HEAD_VERSION = 0x00010000,
    667    HEAD_MAGIC_NUMBER = 0x5F0F3CF5,
    668    HEAD_CHECKSUM_CALC_CONST = 0xB1B0AFBA
    669  };
    670 
    671  AutoSwap_PRUint32 tableVersionNumber;  // Fixed, 0x00010000 for version 1.0.
    672  AutoSwap_PRUint32 fontRevision;        // Set by font manufacturer.
    673  AutoSwap_PRUint32
    674      checkSumAdjustment;  // To compute: set it to 0, sum the entire font as
    675                           // ULONG, then store 0xB1B0AFBA - sum.
    676  AutoSwap_PRUint32 magicNumber;  // Set to 0x5F0F3CF5.
    677  AutoSwap_PRUint16 flags;
    678  AutoSwap_PRUint16
    679      unitsPerEm;  // Valid range is from 16 to 16384. This value should be a
    680                   // power of 2 for fonts that have TrueType outlines.
    681  AutoSwap_PRUint64 created;  // Number of seconds since 12:00 midnight, January
    682                              // 1, 1904. 64-bit integer
    683  AutoSwap_PRUint64 modified;       // Number of seconds since 12:00 midnight,
    684                                    // January 1, 1904. 64-bit integer
    685  AutoSwap_PRInt16 xMin;            // For all glyph bounding boxes.
    686  AutoSwap_PRInt16 yMin;            // For all glyph bounding boxes.
    687  AutoSwap_PRInt16 xMax;            // For all glyph bounding boxes.
    688  AutoSwap_PRInt16 yMax;            // For all glyph bounding boxes.
    689  AutoSwap_PRUint16 macStyle;       // Bit 0: Bold (if set to 1);
    690  AutoSwap_PRUint16 lowestRecPPEM;  // Smallest readable size in pixels.
    691  AutoSwap_PRInt16 fontDirectionHint;
    692  AutoSwap_PRInt16 indexToLocFormat;
    693  AutoSwap_PRInt16 glyphDataFormat;
    694 };
    695 
    696 struct OS2Table {
    697  AutoSwap_PRUint16 version;  // 0004 = OpenType 1.5
    698  AutoSwap_PRInt16 xAvgCharWidth;
    699  AutoSwap_PRUint16 usWeightClass;
    700  AutoSwap_PRUint16 usWidthClass;
    701  AutoSwap_PRUint16 fsType;
    702  AutoSwap_PRInt16 ySubscriptXSize;
    703  AutoSwap_PRInt16 ySubscriptYSize;
    704  AutoSwap_PRInt16 ySubscriptXOffset;
    705  AutoSwap_PRInt16 ySubscriptYOffset;
    706  AutoSwap_PRInt16 ySuperscriptXSize;
    707  AutoSwap_PRInt16 ySuperscriptYSize;
    708  AutoSwap_PRInt16 ySuperscriptXOffset;
    709  AutoSwap_PRInt16 ySuperscriptYOffset;
    710  AutoSwap_PRInt16 yStrikeoutSize;
    711  AutoSwap_PRInt16 yStrikeoutPosition;
    712  AutoSwap_PRInt16 sFamilyClass;
    713  uint8_t panose[10];
    714  AutoSwap_PRUint32 unicodeRange1;
    715  AutoSwap_PRUint32 unicodeRange2;
    716  AutoSwap_PRUint32 unicodeRange3;
    717  AutoSwap_PRUint32 unicodeRange4;
    718  uint8_t achVendID[4];
    719  AutoSwap_PRUint16 fsSelection;
    720  AutoSwap_PRUint16 usFirstCharIndex;
    721  AutoSwap_PRUint16 usLastCharIndex;
    722  AutoSwap_PRInt16 sTypoAscender;
    723  AutoSwap_PRInt16 sTypoDescender;
    724  AutoSwap_PRInt16 sTypoLineGap;
    725  AutoSwap_PRUint16 usWinAscent;
    726  AutoSwap_PRUint16 usWinDescent;
    727  AutoSwap_PRUint32 codePageRange1;
    728  AutoSwap_PRUint32 codePageRange2;
    729  AutoSwap_PRInt16 sxHeight;
    730  AutoSwap_PRInt16 sCapHeight;
    731  AutoSwap_PRUint16 usDefaultChar;
    732  AutoSwap_PRUint16 usBreakChar;
    733  AutoSwap_PRUint16 usMaxContext;
    734 };
    735 
    736 struct PostTable {
    737  AutoSwap_PRUint32 version;
    738  AutoSwap_PRInt32 italicAngle;
    739  AutoSwap_PRInt16 underlinePosition;
    740  AutoSwap_PRUint16 underlineThickness;
    741  AutoSwap_PRUint32 isFixedPitch;
    742  AutoSwap_PRUint32 minMemType42;
    743  AutoSwap_PRUint32 maxMemType42;
    744  AutoSwap_PRUint32 minMemType1;
    745  AutoSwap_PRUint32 maxMemType1;
    746 };
    747 
    748 // This structure is used for both 'hhea' and 'vhea' tables.
    749 // The field names here are those of the horizontal version; the
    750 // vertical table just exchanges vertical and horizontal coordinates.
    751 struct MetricsHeader {
    752  AutoSwap_PRUint32 version;
    753  AutoSwap_PRInt16 ascender;
    754  AutoSwap_PRInt16 descender;
    755  AutoSwap_PRInt16 lineGap;
    756  AutoSwap_PRUint16 advanceWidthMax;
    757  AutoSwap_PRInt16 minLeftSideBearing;
    758  AutoSwap_PRInt16 minRightSideBearing;
    759  AutoSwap_PRInt16 xMaxExtent;
    760  AutoSwap_PRInt16 caretSlopeRise;
    761  AutoSwap_PRInt16 caretSlopeRun;
    762  AutoSwap_PRInt16 caretOffset;
    763  AutoSwap_PRInt16 reserved1;
    764  AutoSwap_PRInt16 reserved2;
    765  AutoSwap_PRInt16 reserved3;
    766  AutoSwap_PRInt16 reserved4;
    767  AutoSwap_PRInt16 metricDataFormat;
    768  AutoSwap_PRUint16 numOfLongMetrics;
    769 };
    770 
    771 struct MaxpTableHeader {
    772  AutoSwap_PRUint32 version;  // CFF: 0x00005000; TrueType: 0x00010000
    773  AutoSwap_PRUint16 numGlyphs;
    774  // truetype version has additional fields that we don't currently use
    775 };
    776 
    777 // old 'kern' table, supported on Windows
    778 // see http://www.microsoft.com/typography/otspec/kern.htm
    779 struct KernTableVersion0 {
    780  AutoSwap_PRUint16 version;  // 0x0000
    781  AutoSwap_PRUint16 nTables;
    782 };
    783 
    784 struct KernTableSubtableHeaderVersion0 {
    785  AutoSwap_PRUint16 version;
    786  AutoSwap_PRUint16 length;
    787  AutoSwap_PRUint16 coverage;
    788 };
    789 
    790 // newer Mac-only 'kern' table, ignored by Windows
    791 // see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6kern.html
    792 struct KernTableVersion1 {
    793  AutoSwap_PRUint32 version;  // 0x00010000
    794  AutoSwap_PRUint32 nTables;
    795 };
    796 
    797 struct KernTableSubtableHeaderVersion1 {
    798  AutoSwap_PRUint32 length;
    799  AutoSwap_PRUint16 coverage;
    800  AutoSwap_PRUint16 tupleIndex;
    801 };
    802 
    803 #pragma pack()
    804 
    805 // Return just the highest bit of the given value, i.e., the highest
    806 // power of 2 that is <= value, or zero if the input value is zero.
    807 inline uint32_t FindHighestBit(uint32_t value) {
    808  // propagate highest bit into all lower bits of the value
    809  value |= (value >> 1);
    810  value |= (value >> 2);
    811  value |= (value >> 4);
    812  value |= (value >> 8);
    813  value |= (value >> 16);
    814  // isolate the leftmost bit
    815  return (value & ~(value >> 1));
    816 }
    817 
    818 }  // namespace mozilla
    819 
    820 // used for overlaying name changes without touching original font data
    821 struct FontDataOverlay {
    822  // overlaySrc != 0 ==> use overlay
    823  uint32_t overlaySrc;     // src offset from start of font data
    824  uint32_t overlaySrcLen;  // src length
    825  uint32_t overlayDest;    // dest offset from start of font data
    826 };
    827 
    828 enum gfxUserFontType {
    829  GFX_USERFONT_UNKNOWN = 0,
    830  GFX_USERFONT_OPENTYPE = 1,
    831  GFX_USERFONT_SVG = 2,
    832  GFX_USERFONT_WOFF = 3,
    833  GFX_USERFONT_WOFF2 = 4
    834 };
    835 
    836 extern const uint8_t sCJKCompatSVSTable[];
    837 
    838 class gfxFontUtils {
    839 public:
    840  // these are public because gfxFont.cpp also looks into the name table
    841  enum {
    842    NAME_ID_FAMILY = 1,
    843    NAME_ID_STYLE = 2,
    844    NAME_ID_UNIQUE = 3,
    845    NAME_ID_FULL = 4,
    846    NAME_ID_VERSION = 5,
    847    NAME_ID_POSTSCRIPT = 6,
    848    NAME_ID_PREFERRED_FAMILY = 16,
    849    NAME_ID_PREFERRED_STYLE = 17,
    850 
    851    PLATFORM_ALL = -1,
    852    PLATFORM_ID_UNICODE = 0,  // Mac OS uses this typically
    853    PLATFORM_ID_MAC = 1,
    854    PLATFORM_ID_ISO = 2,
    855    PLATFORM_ID_MICROSOFT = 3,
    856 
    857    ENCODING_ID_MAC_ROMAN = 0,  // traditional Mac OS script manager encodings
    858    ENCODING_ID_MAC_JAPANESE =
    859        1,  // (there are others defined, but some were never
    860    ENCODING_ID_MAC_TRAD_CHINESE =
    861        2,  // implemented by Apple, and I have never seen them
    862    ENCODING_ID_MAC_KOREAN = 3,  // used in font names)
    863    ENCODING_ID_MAC_ARABIC = 4,
    864    ENCODING_ID_MAC_HEBREW = 5,
    865    ENCODING_ID_MAC_GREEK = 6,
    866    ENCODING_ID_MAC_CYRILLIC = 7,
    867    ENCODING_ID_MAC_DEVANAGARI = 9,
    868    ENCODING_ID_MAC_GURMUKHI = 10,
    869    ENCODING_ID_MAC_GUJARATI = 11,
    870    ENCODING_ID_MAC_SIMP_CHINESE = 25,
    871 
    872    ENCODING_ID_MICROSOFT_SYMBOL = 0,  // Microsoft platform encoding IDs
    873    ENCODING_ID_MICROSOFT_UNICODEBMP = 1,
    874    ENCODING_ID_MICROSOFT_SHIFTJIS = 2,
    875    ENCODING_ID_MICROSOFT_PRC = 3,
    876    ENCODING_ID_MICROSOFT_BIG5 = 4,
    877    ENCODING_ID_MICROSOFT_WANSUNG = 5,
    878    ENCODING_ID_MICROSOFT_JOHAB = 6,
    879    ENCODING_ID_MICROSOFT_UNICODEFULL = 10,
    880 
    881    LANG_ALL = -1,
    882    LANG_ID_MAC_ENGLISH = 0,  // many others are defined, but most don't affect
    883    LANG_ID_MAC_HEBREW =
    884        10,  // the charset; should check all the central/eastern
    885    LANG_ID_MAC_JAPANESE = 11,  // european codes, though
    886    LANG_ID_MAC_ARABIC = 12,
    887    LANG_ID_MAC_ICELANDIC = 15,
    888    LANG_ID_MAC_TURKISH = 17,
    889    LANG_ID_MAC_TRAD_CHINESE = 19,
    890    LANG_ID_MAC_URDU = 20,
    891    LANG_ID_MAC_KOREAN = 23,
    892    LANG_ID_MAC_POLISH = 25,
    893    LANG_ID_MAC_FARSI = 31,
    894    LANG_ID_MAC_SIMP_CHINESE = 33,
    895    LANG_ID_MAC_ROMANIAN = 37,
    896    LANG_ID_MAC_CZECH = 38,
    897    LANG_ID_MAC_SLOVAK = 39,
    898 
    899    LANG_ID_MICROSOFT_EN_US =
    900        0x0409,  // with Microsoft platformID, EN US lang code
    901 
    902    CMAP_MAX_CODEPOINT = 0x10ffff  // maximum possible Unicode codepoint
    903                                   // contained in a cmap
    904  };
    905 
    906  // name table has a header, followed by name records, followed by string data
    907  struct NameHeader {
    908    mozilla::AutoSwap_PRUint16 format;        // Format selector (=0).
    909    mozilla::AutoSwap_PRUint16 count;         // Number of name records.
    910    mozilla::AutoSwap_PRUint16 stringOffset;  // Offset to start of string
    911                                              // storage (from start of table)
    912  };
    913 
    914  struct NameRecord {
    915    mozilla::AutoSwap_PRUint16 platformID;  // Platform ID
    916    mozilla::AutoSwap_PRUint16 encodingID;  // Platform-specific encoding ID
    917    mozilla::AutoSwap_PRUint16 languageID;  // Language ID
    918    mozilla::AutoSwap_PRUint16 nameID;      // Name ID.
    919    mozilla::AutoSwap_PRUint16 length;      // String length (in bytes).
    920    mozilla::AutoSwap_PRUint16 offset;  // String offset from start of storage
    921                                        // (in bytes).
    922  };
    923 
    924  // Helper to ensure we free a font table when we return.
    925  class AutoHBBlob {
    926   public:
    927    explicit AutoHBBlob(hb_blob_t* aBlob) : mBlob(aBlob) {}
    928 
    929    ~AutoHBBlob() { hb_blob_destroy(mBlob); }
    930 
    931    operator hb_blob_t*() { return mBlob; }
    932 
    933   private:
    934    hb_blob_t* const mBlob;
    935  };
    936 
    937  // for reading big-endian font data on either big or little-endian platforms
    938 
    939  static inline uint16_t ReadShortAt(const uint8_t* aBuf, uint32_t aIndex) {
    940    return static_cast<uint16_t>(aBuf[aIndex] << 8) | aBuf[aIndex + 1];
    941  }
    942 
    943  static inline uint16_t ReadShortAt16(const uint16_t* aBuf, uint32_t aIndex) {
    944    const uint8_t* buf = reinterpret_cast<const uint8_t*>(aBuf);
    945    uint32_t index = aIndex << 1;
    946    return static_cast<uint16_t>(buf[index] << 8) | buf[index + 1];
    947  }
    948 
    949  static inline uint32_t ReadUint24At(const uint8_t* aBuf, uint32_t aIndex) {
    950    return ((aBuf[aIndex] << 16) | (aBuf[aIndex + 1] << 8) |
    951            (aBuf[aIndex + 2]));
    952  }
    953 
    954  static inline uint32_t ReadLongAt(const uint8_t* aBuf, uint32_t aIndex) {
    955    return ((aBuf[aIndex] << 24) | (aBuf[aIndex + 1] << 16) |
    956            (aBuf[aIndex + 2] << 8) | (aBuf[aIndex + 3]));
    957  }
    958 
    959  static nsresult ReadCMAPTableFormat10(const uint8_t* aBuf, uint32_t aLength,
    960                                        gfxSparseBitSet& aCharacterMap);
    961 
    962  static nsresult ReadCMAPTableFormat12or13(const uint8_t* aBuf,
    963                                            uint32_t aLength,
    964                                            gfxSparseBitSet& aCharacterMap);
    965 
    966  static nsresult ReadCMAPTableFormat4(const uint8_t* aBuf, uint32_t aLength,
    967                                       gfxSparseBitSet& aCharacterMap,
    968                                       bool aIsSymbolFont);
    969 
    970  static nsresult ReadCMAPTableFormat14(const uint8_t* aBuf, uint32_t aLength,
    971                                        const uint8_t*& aTable);
    972 
    973  static uint32_t FindPreferredSubtable(const uint8_t* aBuf,
    974                                        uint32_t aBufLength,
    975                                        uint32_t* aTableOffset,
    976                                        uint32_t* aUVSTableOffset,
    977                                        bool* aIsSymbolFont);
    978 
    979  static nsresult ReadCMAP(const uint8_t* aBuf, uint32_t aBufLength,
    980                           gfxSparseBitSet& aCharacterMap,
    981                           uint32_t& aUVSOffset);
    982 
    983  static uint32_t MapCharToGlyphFormat4(const uint8_t* aBuf, uint32_t aLength,
    984                                        char16_t aCh);
    985 
    986  static uint32_t MapCharToGlyphFormat10(const uint8_t* aBuf, uint32_t aCh);
    987 
    988  static uint32_t MapCharToGlyphFormat12or13(const uint8_t* aBuf, uint32_t aCh);
    989 
    990  static uint16_t MapUVSToGlyphFormat14(const uint8_t* aBuf, uint32_t aCh,
    991                                        uint32_t aVS);
    992 
    993  // Return whether <aCh, aVS> is supported as the default variation for aCh.
    994  static bool IsDefaultUVSSequence(const uint8_t* aBuf, uint32_t aCh,
    995                                   uint32_t aVS);
    996 
    997  // sCJKCompatSVSTable is a 'cmap' format 14 subtable that maps
    998  // <char + var-selector> pairs to the corresponding Unicode
    999  // compatibility ideograph codepoints.
   1000  static MOZ_ALWAYS_INLINE uint32_t GetUVSFallback(uint32_t aCh, uint32_t aVS) {
   1001    aCh = MapUVSToGlyphFormat14(sCJKCompatSVSTable, aCh, aVS);
   1002    return aCh >= 0xFB00 ? aCh + (0x2F800 - 0xFB00) : aCh;
   1003  }
   1004 
   1005  static uint32_t MapCharToGlyph(const uint8_t* aCmapBuf, uint32_t aBufLength,
   1006                                 uint32_t aUnicode, uint32_t aVarSelector = 0);
   1007 
   1008  // For legacy MS Symbol fonts, we try mapping 8-bit character codes to the
   1009  // Private Use range at U+F0xx used by the cmaps in these fonts.
   1010  static MOZ_ALWAYS_INLINE uint32_t MapLegacySymbolFontCharToPUA(uint32_t aCh) {
   1011    return aCh >= 0x20 && aCh <= 0xff ? 0xf000 + aCh : 0;
   1012  }
   1013 
   1014 #ifdef XP_WIN
   1015  // determine whether a font (which has already been sanitized, so is known
   1016  // to be a valid sfnt) is CFF format rather than TrueType
   1017  static bool IsCffFont(const uint8_t* aFontData);
   1018 #endif
   1019 
   1020  // determine the format of font data
   1021  static gfxUserFontType DetermineFontDataType(const uint8_t* aFontData,
   1022                                               uint32_t aFontDataLength);
   1023 
   1024  // Read the fullname from the sfnt data (used to save the original name
   1025  // prior to renaming the font for installation).
   1026  // This is called with sfnt data that has already been validated,
   1027  // so it should always succeed in finding the name table.
   1028  static nsresult GetFullNameFromSFNT(const uint8_t* aFontData,
   1029                                      uint32_t aLength, nsACString& aFullName);
   1030 
   1031  // helper to get fullname from name table, constructing from family+style
   1032  // if no explicit fullname is present
   1033  static nsresult GetFullNameFromTable(hb_blob_t* aNameTable,
   1034                                       nsACString& aFullName);
   1035 
   1036  // helper to get family name from name table
   1037  static nsresult GetFamilyNameFromTable(hb_blob_t* aNameTable,
   1038                                         nsACString& aFamilyName);
   1039 
   1040  // Find the table directory entry for a given table tag, in a (validated)
   1041  // buffer of 'sfnt' data. Returns null if the tag is not present.
   1042  static mozilla::TableDirEntry* FindTableDirEntry(const void* aFontData,
   1043                                                   uint32_t aTableTag);
   1044 
   1045  // Return a blob that wraps a table found within a buffer of font data.
   1046  // The blob does NOT own its data; caller guarantees that the buffer
   1047  // will remain valid at least as long as the blob.
   1048  // Returns null if the specified table is not found.
   1049  // This method assumes aFontData is valid 'sfnt' data; before using this,
   1050  // caller is responsible to do any sanitization/validation necessary.
   1051  static hb_blob_t* GetTableFromFontData(const void* aFontData,
   1052                                         uint32_t aTableTag);
   1053 
   1054  // create a new name table and build a new font with that name table
   1055  // appended on the end, returns true on success
   1056  static nsresult RenameFont(const nsAString& aName, const uint8_t* aFontData,
   1057                             uint32_t aFontDataLength,
   1058                             FallibleTArray<uint8_t>* aNewFont);
   1059 
   1060  // read all names matching aNameID, returning in aNames array
   1061  static nsresult ReadNames(const char* aNameData, uint32_t aDataLen,
   1062                            uint32_t aNameID, int32_t aPlatformID,
   1063                            nsTArray<nsCString>& aNames);
   1064 
   1065  // reads English or first name matching aNameID, returning in aName
   1066  // platform based on OS
   1067  static nsresult ReadCanonicalName(hb_blob_t* aNameTable, uint32_t aNameID,
   1068                                    nsCString& aName);
   1069 
   1070  static nsresult ReadCanonicalName(const char* aNameData, uint32_t aDataLen,
   1071                                    uint32_t aNameID, nsCString& aName);
   1072 
   1073  // convert a name from the raw name table data into an nsString,
   1074  // provided we know how; return true if successful, or false
   1075  // if we can't handle the encoding
   1076  static bool DecodeFontName(const char* aBuf, int32_t aLength,
   1077                             uint32_t aPlatformCode, uint32_t aScriptCode,
   1078                             uint32_t aLangCode, nsACString& dest);
   1079 
   1080  static inline bool IsJoinCauser(uint32_t ch) { return (ch == 0x200D); }
   1081 
   1082  // We treat Combining Grapheme Joiner (U+034F) together with the join
   1083  // controls (ZWJ, ZWNJ) here, because (like them) it is an invisible
   1084  // char that will be handled by the shaper even if not explicitly
   1085  // supported by the font. (See bug 1408366.)
   1086  static inline bool IsJoinControl(uint32_t ch) {
   1087    return (ch == 0x200C || ch == 0x200D || ch == 0x034f);
   1088  }
   1089 
   1090  enum {
   1091    kUnicodeVS1 = 0xFE00,
   1092    kUnicodeVS16 = 0xFE0F,
   1093    kUnicodeVS17 = 0xE0100,
   1094    kUnicodeVS256 = 0xE01EF
   1095  };
   1096 
   1097  static inline bool IsVarSelector(uint32_t ch) {
   1098    return (ch >= kUnicodeVS1 && ch <= kUnicodeVS16) ||
   1099           (ch >= kUnicodeVS17 && ch <= kUnicodeVS256);
   1100  }
   1101 
   1102  enum {
   1103    kUnicodeRegionalIndicatorA = 0x1F1E6,
   1104    kUnicodeRegionalIndicatorZ = 0x1F1FF
   1105  };
   1106 
   1107  static inline bool IsRegionalIndicator(uint32_t aCh) {
   1108    return aCh >= kUnicodeRegionalIndicatorA &&
   1109           aCh <= kUnicodeRegionalIndicatorZ;
   1110  }
   1111 
   1112  static inline bool IsEmojiFlagAndTag(uint32_t aCh, uint32_t aNext) {
   1113    constexpr uint32_t kBlackFlag = 0x1F3F4;
   1114    constexpr uint32_t kTagLetterA = 0xE0061;
   1115    constexpr uint32_t kTagLetterZ = 0xE007A;
   1116 
   1117    return aCh == kBlackFlag && aNext >= kTagLetterA && aNext <= kTagLetterZ;
   1118  }
   1119 
   1120  // parse a simple list of font family names into
   1121  // an array of strings
   1122  static void ParseFontList(const nsACString& aFamilyList,
   1123                            nsTArray<nsCString>& aFontList);
   1124 
   1125  // for a given pref name, initialize a list of font names
   1126  static void GetPrefsFontList(const char* aPrefName,
   1127                               nsTArray<nsCString>& aFontList);
   1128 
   1129  // generate a unique font name
   1130  static nsresult MakeUniqueUserFontName(nsAString& aName);
   1131 
   1132  // Helper used to implement gfxFontEntry::GetVariation{Axes,Instances} for
   1133  // platforms where the native font APIs don't provide the info we want
   1134  // in a convenient form, or when native APIs are too expensive.
   1135  // (Not used on platforms -- currently, freetype -- where the font APIs
   1136  // expose variation instance details directly.)
   1137  static void GetVariationData(gfxFontEntry* aFontEntry,
   1138                               nsTArray<gfxFontVariationAxis>* aAxes,
   1139                               nsTArray<gfxFontVariationInstance>* aInstances);
   1140 
   1141  // Helper method for reading localized family names from the name table
   1142  // of a single face.
   1143  static void ReadOtherFamilyNamesForFace(
   1144      const nsACString& aFamilyName, const char* aNameData,
   1145      uint32_t aDataLength, nsTArray<nsCString>& aOtherFamilyNames,
   1146      bool useFullName);
   1147 
   1148  // Main, DOM worker or servo thread safe method to check if we are performing
   1149  // Servo traversal.
   1150  static bool IsInServoTraversal();
   1151 
   1152  // Main, DOM worker or servo thread safe method to get the current
   1153  // ServoTypeSet. Always returns nullptr for DOM worker threads.
   1154  static mozilla::ServoStyleSet* CurrentServoStyleSet();
   1155 
   1156  static void AssertSafeThreadOrServoFontMetricsLocked()
   1157 #ifdef DEBUG
   1158      ;
   1159 #else
   1160  {
   1161  }
   1162 #endif
   1163 
   1164 protected:
   1165  friend struct MacCharsetMappingComparator;
   1166 
   1167  static nsresult ReadNames(const char* aNameData, uint32_t aDataLen,
   1168                            uint32_t aNameID, int32_t aLangID,
   1169                            int32_t aPlatformID, nsTArray<nsCString>& aNames);
   1170 
   1171  // convert opentype name-table platform/encoding/language values to an
   1172  // Encoding object we can use to convert the name data to unicode
   1173  static const mozilla::Encoding* GetCharsetForFontName(uint16_t aPlatform,
   1174                                                        uint16_t aScript,
   1175                                                        uint16_t aLanguage);
   1176 
   1177  struct MacFontNameCharsetMapping {
   1178    uint16_t mScript;
   1179    uint16_t mLanguage;
   1180    const mozilla::Encoding* mEncoding;
   1181 
   1182    bool operator<(const MacFontNameCharsetMapping& rhs) const {
   1183      return (mScript < rhs.mScript) ||
   1184             ((mScript == rhs.mScript) && (mLanguage < rhs.mLanguage));
   1185    }
   1186  };
   1187  static const MacFontNameCharsetMapping gMacFontNameCharsets[];
   1188  static const mozilla::Encoding* gISOFontNameCharsets[];
   1189  static const mozilla::Encoding* gMSFontNameCharsets[];
   1190 };
   1191 
   1192 // Factors used to weight the distances between the available and target font
   1193 // properties during font-matching. These ensure that we respect the CSS-fonts
   1194 // requirement that font-stretch >> font-style >> font-weight; and in addition,
   1195 // a mismatch between the desired and actual glyph presentation (emoji vs text)
   1196 // will take precedence over any of the style attributes.
   1197 constexpr double kPresentationMismatch = 1.0e12;
   1198 constexpr double kStretchFactor = 1.0e8;
   1199 constexpr double kStyleFactor = 1.0e4;
   1200 constexpr double kWeightFactor = 1.0e0;
   1201 
   1202 // If the output range of this function is extended, check assertions &
   1203 // usage at the callsites!
   1204 // style distance ==> [0,900]
   1205 static inline double StyleDistance(const mozilla::SlantStyleRange& aRange,
   1206                                   mozilla::FontSlantStyle aTargetStyle,
   1207                                   bool aItalicToObliqueFallback) {
   1208  const mozilla::FontSlantStyle minStyle = aRange.Min();
   1209  const mozilla::FontSlantStyle maxStyle = aRange.Max();
   1210  if (aTargetStyle == minStyle || aTargetStyle == maxStyle) {
   1211    return 0.0;  // styles match exactly ==> 0
   1212  }
   1213 
   1214  // bias added to angle difference when searching in the non-preferred
   1215  // direction from a target angle
   1216  const double kReverse = 100.0;
   1217 
   1218  // bias added when we've crossed from positive to negative angles or
   1219  // vice versa
   1220  const double kNegate = 200.0;
   1221 
   1222  // bias added for oblique faces when italic is requested, and only-oblique
   1223  // font-synthesis-style is in effect
   1224  const double kBadFallback = 400.0;
   1225 
   1226  if (aTargetStyle.IsNormal()) {
   1227    if (minStyle.IsItalic() || maxStyle.IsItalic()) {
   1228      // italic is the worst match (prefer any oblique; 0deg was requested)
   1229      return kBadFallback + kNegate + kReverse;
   1230    }
   1231    const double minAngle = minStyle.ObliqueAngle();
   1232    if (minAngle >= 0.0) {
   1233      return minAngle;
   1234    }
   1235    const double maxAngle = maxStyle.ObliqueAngle();
   1236    if (maxAngle >= 0.0) {
   1237      // [min,max] range includes 0.0, so it's a perfect match
   1238      return 0.0;
   1239    }
   1240    return kNegate - maxAngle;
   1241  }
   1242 
   1243  const double kDefaultAngle = mozilla::FontSlantStyle::DEFAULT_OBLIQUE_DEGREES;
   1244 
   1245  if (aTargetStyle.IsItalic()) {
   1246    MOZ_ASSERT(!minStyle.IsItalic());  // we checked for equality above
   1247    double targetAngle = kDefaultAngle;
   1248    double fallbackBias = 0.0;
   1249    if (!aItalicToObliqueFallback) {
   1250      // If 'font-style-synthesis: oblique-only' is applied, we should not use
   1251      // oblique as a fallback for italic, so we add a large "fallback bias" to
   1252      // all results here, and prefer an angle as close to zero as possible.
   1253      targetAngle = 0.0;
   1254      fallbackBias = kBadFallback;
   1255    }
   1256    const double minAngle = minStyle.ObliqueAngle();
   1257    if (minAngle >= targetAngle) {
   1258      // Add 1.0 to ensure italic vs non-italic never returns 0.0, even if the
   1259      // angle matches.
   1260      return fallbackBias + minAngle - targetAngle + 1.0;
   1261    }
   1262    const double maxAngle = maxStyle.ObliqueAngle();
   1263    if (maxAngle >= targetAngle) {
   1264      return fallbackBias + 1.0;
   1265    }
   1266    if (maxAngle > 0.0) {
   1267      // wrong direction but still > 0, add bias of 100
   1268      return fallbackBias + kReverse + (targetAngle - maxAngle);
   1269    }
   1270    // negative oblique angle, add bias of 300
   1271    return fallbackBias + kReverse + kNegate + (targetAngle - maxAngle);
   1272  }
   1273 
   1274  // target is oblique <angle>: four different cases depending on
   1275  // the value of the <angle>, which determines the preferred direction
   1276  // of search
   1277  const double targetAngle = aTargetStyle.ObliqueAngle();
   1278 
   1279  // italic is a bad fallback if it was not requested
   1280  if (minStyle.IsItalic() || maxStyle.IsItalic()) {
   1281    return kBadFallback + kNegate + kReverse;
   1282  }
   1283 
   1284  if (targetAngle >= kDefaultAngle) {
   1285    const double minAngle = minStyle.ObliqueAngle();
   1286    if (minAngle >= targetAngle) {
   1287      return minAngle - targetAngle;
   1288    }
   1289    const double maxAngle = maxStyle.ObliqueAngle();
   1290    if (maxAngle >= targetAngle) {
   1291      return 0.0;
   1292    }
   1293    if (maxAngle > 0.0) {
   1294      return kReverse + (targetAngle - maxAngle);
   1295    }
   1296    return kReverse + kNegate + (targetAngle - maxAngle);
   1297  }
   1298 
   1299  if (targetAngle <= -kDefaultAngle) {
   1300    const double maxAngle = maxStyle.ObliqueAngle();
   1301    if (maxAngle <= targetAngle) {
   1302      return targetAngle - maxAngle;
   1303    }
   1304    const double minAngle = minStyle.ObliqueAngle();
   1305    if (minAngle <= targetAngle) {
   1306      return 0.0;
   1307    }
   1308    if (minAngle < 0.0) {
   1309      return kReverse + (minAngle - targetAngle);
   1310    }
   1311    return kReverse + kNegate + (minAngle - targetAngle);
   1312  }
   1313 
   1314  if (targetAngle >= 0.0) {
   1315    const double minAngle = minStyle.ObliqueAngle();
   1316    if (minAngle > targetAngle) {
   1317      return kReverse + (minAngle - targetAngle);
   1318    }
   1319    const double maxAngle = maxStyle.ObliqueAngle();
   1320    if (maxAngle >= targetAngle) {
   1321      return 0.0;
   1322    }
   1323    if (maxAngle > 0.0) {
   1324      return targetAngle - maxAngle;
   1325    }
   1326    return kReverse + kNegate + (targetAngle - maxAngle);
   1327  }
   1328 
   1329  // last case: (targetAngle < 0.0 && targetAngle > kDefaultAngle)
   1330  const double maxAngle = maxStyle.ObliqueAngle();
   1331  if (maxAngle < targetAngle) {
   1332    return kReverse + (targetAngle - maxAngle);
   1333  }
   1334  const double minAngle = minStyle.ObliqueAngle();
   1335  if (minAngle <= targetAngle) {
   1336    return 0.0;
   1337  }
   1338  if (minAngle < 0.0) {
   1339    return minAngle - targetAngle;
   1340  }
   1341  return kReverse + kNegate + (minAngle - targetAngle);
   1342 }
   1343 
   1344 // If the output range of this function is extended, check assertions &
   1345 // usage at the callsites!
   1346 // stretch distance ==> [0,2000]
   1347 static inline double StretchDistance(const mozilla::StretchRange& aRange,
   1348                                     mozilla::FontStretch aTargetStretch) {
   1349  const double kReverseDistance = 1000.0;
   1350 
   1351  mozilla::FontStretch minStretch = aRange.Min();
   1352  mozilla::FontStretch maxStretch = aRange.Max();
   1353 
   1354  // The stretch value is a (non-negative) percentage; currently we support
   1355  // values in the range 0 .. 1000. (If the upper limit is ever increased,
   1356  // the kReverseDistance value used here may need to be adjusted.)
   1357  // If aTargetStretch is >100, we prefer larger values if available;
   1358  // if <=100, we prefer smaller values if available.
   1359  if (aTargetStretch < minStretch) {
   1360    if (aTargetStretch > mozilla::FontStretch::NORMAL) {
   1361      return minStretch.ToFloat() - aTargetStretch.ToFloat();
   1362    }
   1363    return (minStretch.ToFloat() - aTargetStretch.ToFloat()) + kReverseDistance;
   1364  }
   1365  if (aTargetStretch > maxStretch) {
   1366    if (aTargetStretch <= mozilla::FontStretch::NORMAL) {
   1367      return aTargetStretch.ToFloat() - maxStretch.ToFloat();
   1368    }
   1369    return (aTargetStretch.ToFloat() - maxStretch.ToFloat()) + kReverseDistance;
   1370  }
   1371  return 0.0;
   1372 }
   1373 
   1374 // Calculate weight distance with values in the range (0..1000). In general,
   1375 // heavier weights match towards even heavier weights while lighter weights
   1376 // match towards even lighter weights. Target weight values in the range
   1377 // [400..500] are special, since they will first match up to 500, then down
   1378 // towards 0, then up again towards 999.
   1379 //
   1380 // Example: with target 600 and font weight 800, distance will be 200. With
   1381 // target 300 and font weight 600, distance will be 900, since heavier
   1382 // weights are farther away than lighter weights. If the target is 5 and the
   1383 // font weight 995, the distance would be 1590 for the same reason.
   1384 
   1385 // If the output range of this function is extended, check assertions &
   1386 // usage at the callsites!
   1387 // weight distance ==> [0,1600]
   1388 static inline double WeightDistance(const mozilla::WeightRange& aRange,
   1389                                    mozilla::FontWeight aTargetWeight) {
   1390  const double kNotWithinCentralRange = 100.0;
   1391  const double kReverseDistance = 600.0;
   1392 
   1393  mozilla::FontWeight minWeight = aRange.Min();
   1394  mozilla::FontWeight maxWeight = aRange.Max();
   1395 
   1396  if (aTargetWeight >= minWeight && aTargetWeight <= maxWeight) {
   1397    // Target is within the face's range, so it's a perfect match
   1398    return 0.0;
   1399  }
   1400 
   1401  if (aTargetWeight < mozilla::FontWeight::NORMAL) {
   1402    // Requested a lighter-than-400 weight
   1403    if (maxWeight < aTargetWeight) {
   1404      return aTargetWeight.ToFloat() - maxWeight.ToFloat();
   1405    }
   1406    // Add reverse-search penalty for bolder faces
   1407    return (minWeight.ToFloat() - aTargetWeight.ToFloat()) + kReverseDistance;
   1408  }
   1409 
   1410  if (aTargetWeight > mozilla::FontWeight::FromInt(500)) {
   1411    // Requested a bolder-than-500 weight
   1412    if (minWeight > aTargetWeight) {
   1413      return minWeight.ToFloat() - aTargetWeight.ToFloat();
   1414    }
   1415    // Add reverse-search penalty for lighter faces
   1416    return (aTargetWeight.ToFloat() - maxWeight.ToFloat()) + kReverseDistance;
   1417  }
   1418 
   1419  // Special case for requested weight in the [400..500] range
   1420  if (minWeight > aTargetWeight) {
   1421    if (minWeight <= mozilla::FontWeight::FromInt(500)) {
   1422      // Bolder weight up to 500 is first choice
   1423      return minWeight.ToFloat() - aTargetWeight.ToFloat();
   1424    }
   1425    // Other bolder weights get a reverse-search penalty
   1426    return (minWeight.ToFloat() - aTargetWeight.ToFloat()) + kReverseDistance;
   1427  }
   1428  // Lighter weights are not as good as bolder ones within [400..500]
   1429  return (aTargetWeight.ToFloat() - maxWeight.ToFloat()) +
   1430         kNotWithinCentralRange;
   1431 }
   1432 
   1433 #endif /* GFX_FONT_UTILS_H */