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