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/. */
6 #ifndef GFX_FONT_UTILS_H
7 #define GFX_FONT_UTILS_H
13 #include "gfxPlatform.h"
14 #include "harfbuzz/hb.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/Attributes.h"
17 #include "mozilla/Casting.h"
18 #include "mozilla/EndianUtils.h"
19 #include "mozilla/ServoStyleConstsInlines.h"
20 #include "mozilla/MemoryReporting.h"
21 #include "mozilla/UniquePtr.h"
22 #include "nsStringFwd.h"
29 struct gfxFontVariationAxis
;
30 struct gfxFontVariationInstance
;
35 } // namespace mozilla
37 /* Bug 341128 - w32api defines min/max which causes problems with <bitset> */
43 #undef ERROR /* defined by Windows.h, conflicts with some generated bindings \
44 code when this gets indirectly included via shared font list \
47 typedef struct hb_blob_t hb_blob_t
;
56 class gfxSparseBitSet
{
58 friend class SharedBitSet
;
60 enum { BLOCK_SIZE
= 32 }; // ==> 256 codepoints per block
61 enum { BLOCK_SIZE_BITS
= BLOCK_SIZE
* 8 };
62 enum { NO_BLOCK
= 0xffff }; // index value indicating missing (empty) block
65 explicit Block(unsigned char memsetValue
= 0) {
66 memset(mBits
, memsetValue
, BLOCK_SIZE
);
68 uint8_t mBits
[BLOCK_SIZE
];
71 friend struct IPC::ParamTraits
<gfxSparseBitSet
>;
72 friend struct IPC::ParamTraits
<Block
>;
75 gfxSparseBitSet() = default;
77 bool Equals(const gfxSparseBitSet
* aOther
) const {
78 if (mBlockIndex
.Length() != aOther
->mBlockIndex
.Length()) {
81 size_t n
= mBlockIndex
.Length();
82 for (size_t i
= 0; i
< n
; ++i
) {
83 uint32_t b1
= mBlockIndex
[i
];
84 uint32_t b2
= aOther
->mBlockIndex
[i
];
85 if ((b1
== NO_BLOCK
) != (b2
== NO_BLOCK
)) {
91 if (memcmp(&mBlocks
[b1
].mBits
, &aOther
->mBlocks
[b2
].mBits
, BLOCK_SIZE
) !=
99 bool test(uint32_t aIndex
) const {
100 uint32_t i
= aIndex
/ BLOCK_SIZE_BITS
;
101 if (i
>= mBlockIndex
.Length() || mBlockIndex
[i
] == NO_BLOCK
) {
104 const Block
& block
= mBlocks
[mBlockIndex
[i
]];
105 return ((block
.mBits
[(aIndex
>> 3) & (BLOCK_SIZE
- 1)]) &
106 (1 << (aIndex
& 0x7))) != 0;
109 // dump out contents of bitmap
110 void Dump(const char* aPrefix
, eGfxLog aWhichLog
) const;
112 bool TestRange(uint32_t aStart
, uint32_t aEnd
) {
113 // start point is beyond the end of the block array? return false
115 uint32_t startBlock
= aStart
/ BLOCK_SIZE_BITS
;
116 uint32_t blockLen
= mBlockIndex
.Length();
117 if (startBlock
>= blockLen
) {
121 // check for blocks in range, if none, return false
122 bool hasBlocksInRange
= false;
123 uint32_t endBlock
= aEnd
/ BLOCK_SIZE_BITS
;
124 for (uint32_t bi
= startBlock
; bi
<= endBlock
; bi
++) {
125 if (bi
< blockLen
&& mBlockIndex
[bi
] != NO_BLOCK
) {
126 hasBlocksInRange
= true;
130 if (!hasBlocksInRange
) {
134 // first block, check bits
135 if (mBlockIndex
[startBlock
] != NO_BLOCK
) {
136 const Block
& block
= mBlocks
[mBlockIndex
[startBlock
]];
137 uint32_t start
= aStart
;
138 uint32_t end
= std::min(aEnd
, ((startBlock
+ 1) * BLOCK_SIZE_BITS
) - 1);
139 for (uint32_t i
= start
; i
<= end
; i
++) {
140 if ((block
.mBits
[(i
>> 3) & (BLOCK_SIZE
- 1)]) & (1 << (i
& 0x7))) {
145 if (endBlock
== startBlock
) {
149 // [2..n-1] blocks check bytes
150 for (uint32_t i
= startBlock
+ 1; i
< endBlock
; i
++) {
151 if (i
>= blockLen
|| mBlockIndex
[i
] == NO_BLOCK
) {
154 const Block
& block
= mBlocks
[mBlockIndex
[i
]];
155 for (uint32_t index
= 0; index
< BLOCK_SIZE
; index
++) {
156 if (block
.mBits
[index
]) {
162 // last block, check bits
163 if (endBlock
< blockLen
&& mBlockIndex
[endBlock
] != NO_BLOCK
) {
164 const Block
& block
= mBlocks
[mBlockIndex
[endBlock
]];
165 uint32_t start
= endBlock
* BLOCK_SIZE_BITS
;
167 for (uint32_t i
= start
; i
<= end
; i
++) {
168 if ((block
.mBits
[(i
>> 3) & (BLOCK_SIZE
- 1)]) & (1 << (i
& 0x7))) {
177 void set(uint32_t aIndex
) {
178 uint32_t i
= aIndex
/ BLOCK_SIZE_BITS
;
179 while (i
>= mBlockIndex
.Length()) {
180 mBlockIndex
.AppendElement(NO_BLOCK
);
182 if (mBlockIndex
[i
] == NO_BLOCK
) {
183 mBlocks
.AppendElement();
184 MOZ_ASSERT(mBlocks
.Length() < 0xffff, "block index overflow!");
185 mBlockIndex
[i
] = static_cast<uint16_t>(mBlocks
.Length() - 1);
187 Block
& block
= mBlocks
[mBlockIndex
[i
]];
188 block
.mBits
[(aIndex
>> 3) & (BLOCK_SIZE
- 1)] |= 1 << (aIndex
& 0x7);
191 void set(uint32_t aIndex
, bool aValue
) {
199 void SetRange(uint32_t aStart
, uint32_t aEnd
) {
200 const uint32_t startIndex
= aStart
/ BLOCK_SIZE_BITS
;
201 const uint32_t endIndex
= aEnd
/ BLOCK_SIZE_BITS
;
203 while (endIndex
>= mBlockIndex
.Length()) {
204 mBlockIndex
.AppendElement(NO_BLOCK
);
207 for (uint32_t i
= startIndex
; i
<= endIndex
; ++i
) {
208 const uint32_t blockFirstBit
= i
* BLOCK_SIZE_BITS
;
209 const uint32_t blockLastBit
= blockFirstBit
+ BLOCK_SIZE_BITS
- 1;
211 if (mBlockIndex
[i
] == NO_BLOCK
) {
212 bool fullBlock
= (aStart
<= blockFirstBit
&& aEnd
>= blockLastBit
);
213 mBlocks
.AppendElement(Block(fullBlock
? 0xFF : 0));
214 MOZ_ASSERT(mBlocks
.Length() < 0xffff, "block index overflow!");
215 mBlockIndex
[i
] = static_cast<uint16_t>(mBlocks
.Length() - 1);
221 Block
& block
= mBlocks
[mBlockIndex
[i
]];
222 const uint32_t start
=
223 aStart
> blockFirstBit
? aStart
- blockFirstBit
: 0;
225 std::min
<uint32_t>(aEnd
- blockFirstBit
, BLOCK_SIZE_BITS
- 1);
227 for (uint32_t bit
= start
; bit
<= end
; ++bit
) {
228 block
.mBits
[bit
>> 3] |= 1 << (bit
& 0x7);
233 void clear(uint32_t aIndex
) {
234 uint32_t i
= aIndex
/ BLOCK_SIZE_BITS
;
235 if (i
>= mBlockIndex
.Length()) {
238 if (mBlockIndex
[i
] == NO_BLOCK
) {
239 mBlocks
.AppendElement();
240 MOZ_ASSERT(mBlocks
.Length() < 0xffff, "block index overflow!");
241 mBlockIndex
[i
] = static_cast<uint16_t>(mBlocks
.Length() - 1);
243 Block
& block
= mBlocks
[mBlockIndex
[i
]];
244 block
.mBits
[(aIndex
>> 3) & (BLOCK_SIZE
- 1)] &= ~(1 << (aIndex
& 0x7));
247 void ClearRange(uint32_t aStart
, uint32_t aEnd
) {
248 const uint32_t startIndex
= aStart
/ BLOCK_SIZE_BITS
;
249 const uint32_t endIndex
= aEnd
/ BLOCK_SIZE_BITS
;
251 for (uint32_t i
= startIndex
; i
<= endIndex
; ++i
) {
252 if (i
>= mBlockIndex
.Length()) {
255 if (mBlockIndex
[i
] == NO_BLOCK
) {
259 const uint32_t blockFirstBit
= i
* BLOCK_SIZE_BITS
;
260 Block
& block
= mBlocks
[mBlockIndex
[i
]];
262 const uint32_t start
=
263 aStart
> blockFirstBit
? aStart
- blockFirstBit
: 0;
265 std::min
<uint32_t>(aEnd
- blockFirstBit
, BLOCK_SIZE_BITS
- 1);
267 for (uint32_t bit
= start
; bit
<= end
; ++bit
) {
268 block
.mBits
[bit
>> 3] &= ~(1 << (bit
& 0x7));
273 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const {
274 return mBlocks
.ShallowSizeOfExcludingThis(aMallocSizeOf
) +
275 mBlockIndex
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
278 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const {
279 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
282 // clear out all blocks in the array
288 // set this bitset to the union of its current contents and another
289 void Union(const gfxSparseBitSet
& aBitset
) {
290 // ensure mBlocks is large enough
291 uint32_t blockCount
= aBitset
.mBlockIndex
.Length();
292 while (blockCount
> mBlockIndex
.Length()) {
293 mBlockIndex
.AppendElement(NO_BLOCK
);
295 // for each block that may be present in aBitset...
296 for (uint32_t i
= 0; i
< blockCount
; ++i
) {
297 // if it is missing (implicitly empty), just skip
298 if (aBitset
.mBlockIndex
[i
] == NO_BLOCK
) {
301 // if the block is missing in this set, just copy the other
302 if (mBlockIndex
[i
] == NO_BLOCK
) {
303 mBlocks
.AppendElement(aBitset
.mBlocks
[aBitset
.mBlockIndex
[i
]]);
304 MOZ_ASSERT(mBlocks
.Length() < 0xffff, "block index overflow!");
305 mBlockIndex
[i
] = static_cast<uint16_t>(mBlocks
.Length() - 1);
308 // else set existing block to the union of both
310 reinterpret_cast<uint32_t*>(&mBlocks
[mBlockIndex
[i
]].mBits
);
311 const uint32_t* src
= reinterpret_cast<const uint32_t*>(
312 &aBitset
.mBlocks
[aBitset
.mBlockIndex
[i
]].mBits
);
313 for (uint32_t j
= 0; j
< BLOCK_SIZE
/ 4; ++j
) {
319 inline void Union(const SharedBitSet
& aBitset
);
322 // TODO: Discard any empty blocks, and adjust index accordingly.
323 // (May not be worth doing, though, because we so rarely clear bits
324 // that were previously set.)
326 mBlockIndex
.Compact();
329 uint32_t GetChecksum() const {
331 adler32(0, reinterpret_cast<const uint8_t*>(mBlockIndex
.Elements()),
332 mBlockIndex
.Length() * sizeof(uint16_t));
333 check
= adler32(check
, reinterpret_cast<const uint8_t*>(mBlocks
.Elements()),
334 mBlocks
.Length() * sizeof(Block
));
339 CopyableTArray
<uint16_t> mBlockIndex
;
340 CopyableTArray
<Block
> mBlocks
;
344 * SharedBitSet is a version of gfxSparseBitSet that is intended to be used
345 * in a shared-memory block, and can be used regardless of the address at which
346 * the block has been mapped. The SharedBitSet cannot be modified once it has
349 * Max size of a SharedBitSet = 4352 * 32 ; blocks
354 * Therefore, SharedFontList must be able to allocate a contiguous block of at
359 // We use the same Block type as gfxSparseBitSet.
360 typedef gfxSparseBitSet::Block Block
;
362 enum { BLOCK_SIZE
= gfxSparseBitSet::BLOCK_SIZE
};
363 enum { BLOCK_SIZE_BITS
= gfxSparseBitSet::BLOCK_SIZE_BITS
};
364 enum { NO_BLOCK
= gfxSparseBitSet::NO_BLOCK
};
367 static const size_t kMaxSize
= 147972; // see above
369 // Returns the size needed for a SharedBitSet version of the given
371 static size_t RequiredSize(const gfxSparseBitSet
& aBitset
) {
372 size_t total
= sizeof(SharedBitSet
);
373 size_t len
= aBitset
.mBlockIndex
.Length();
374 total
+= len
* sizeof(uint16_t); // add size for index array
375 // add size for blocks, excluding any missing ones
376 for (uint16_t i
= 0; i
< len
; i
++) {
377 if (aBitset
.mBlockIndex
[i
] != NO_BLOCK
) {
378 total
+= sizeof(Block
);
381 MOZ_ASSERT(total
<= kMaxSize
);
385 // Create a SharedBitSet in the provided buffer, initializing it with the
386 // contents of aBitset.
387 static SharedBitSet
* Create(void* aBuffer
, size_t aBufSize
,
388 const gfxSparseBitSet
& aBitset
) {
389 MOZ_ASSERT(aBufSize
>= RequiredSize(aBitset
));
390 return new (aBuffer
) SharedBitSet(aBitset
);
393 bool test(uint32_t aIndex
) const {
394 const auto i
= static_cast<uint16_t>(aIndex
/ BLOCK_SIZE_BITS
);
395 if (i
>= mBlockIndexCount
) {
398 const uint16_t* const blockIndex
=
399 reinterpret_cast<const uint16_t*>(this + 1);
400 if (blockIndex
[i
] == NO_BLOCK
) {
403 const Block
* const blocks
=
404 reinterpret_cast<const Block
*>(blockIndex
+ mBlockIndexCount
);
405 const Block
& block
= blocks
[blockIndex
[i
]];
406 return ((block
.mBits
[(aIndex
>> 3) & (BLOCK_SIZE
- 1)]) &
407 (1 << (aIndex
& 0x7))) != 0;
410 bool Equals(const gfxSparseBitSet
* aOther
) const {
411 if (mBlockIndexCount
!= aOther
->mBlockIndex
.Length()) {
414 const uint16_t* const blockIndex
=
415 reinterpret_cast<const uint16_t*>(this + 1);
416 const Block
* const blocks
=
417 reinterpret_cast<const Block
*>(blockIndex
+ mBlockIndexCount
);
418 for (uint16_t i
= 0; i
< mBlockIndexCount
; ++i
) {
419 uint16_t index
= blockIndex
[i
];
420 uint16_t otherIndex
= aOther
->mBlockIndex
[i
];
421 if ((index
== NO_BLOCK
) != (otherIndex
== NO_BLOCK
)) {
424 if (index
== NO_BLOCK
) {
427 const Block
& b1
= blocks
[index
];
428 const Block
& b2
= aOther
->mBlocks
[otherIndex
];
429 if (memcmp(&b1
.mBits
, &b2
.mBits
, BLOCK_SIZE
) != 0) {
437 friend class gfxSparseBitSet
;
438 SharedBitSet() = delete;
440 explicit SharedBitSet(const gfxSparseBitSet
& aBitset
)
442 mozilla::AssertedCast
<uint16_t>(aBitset
.mBlockIndex
.Length())),
444 uint16_t* blockIndex
= reinterpret_cast<uint16_t*>(this + 1);
445 Block
* blocks
= reinterpret_cast<Block
*>(blockIndex
+ mBlockIndexCount
);
446 for (uint16_t i
= 0; i
< mBlockIndexCount
; i
++) {
447 if (aBitset
.mBlockIndex
[i
] != NO_BLOCK
) {
448 const Block
& srcBlock
= aBitset
.mBlocks
[aBitset
.mBlockIndex
[i
]];
449 std::memcpy(&blocks
[mBlockCount
], &srcBlock
, sizeof(Block
));
450 blockIndex
[i
] = mBlockCount
;
453 blockIndex
[i
] = NO_BLOCK
;
458 // We never manage SharedBitSet as a "normal" object, it's a view onto a
459 // buffer of shared memory. So we should never be trying to call this.
460 ~SharedBitSet() = delete;
462 uint16_t mBlockIndexCount
;
463 uint16_t mBlockCount
;
465 // After the two "header" fields above, we have a block index array
466 // of uint16_t[mBlockIndexCount], followed by mBlockCount Block records.
469 // Union the contents of a SharedBitSet with the target gfxSparseBitSet
470 inline void gfxSparseBitSet::Union(const SharedBitSet
& aBitset
) {
471 // ensure mBlockIndex is large enough
472 while (mBlockIndex
.Length() < aBitset
.mBlockIndexCount
) {
473 mBlockIndex
.AppendElement(NO_BLOCK
);
475 auto blockIndex
= reinterpret_cast<const uint16_t*>(&aBitset
+ 1);
477 reinterpret_cast<const Block
*>(blockIndex
+ aBitset
.mBlockIndexCount
);
478 for (uint32_t i
= 0; i
< aBitset
.mBlockIndexCount
; ++i
) {
479 // if it is missing (implicitly empty) in source, just skip
480 if (blockIndex
[i
] == NO_BLOCK
) {
483 // if the block is missing, just copy from source bitset
484 if (mBlockIndex
[i
] == NO_BLOCK
) {
485 mBlocks
.AppendElement(blocks
[blockIndex
[i
]]);
486 MOZ_ASSERT(mBlocks
.Length() < 0xffff, "block index overflow");
487 mBlockIndex
[i
] = uint16_t(mBlocks
.Length() - 1);
490 // Else set existing target block to the union of both.
491 // Note that blocks in SharedBitSet may not be 4-byte aligned, so we don't
492 // try to optimize by casting to uint32_t* here and processing 4 bytes at
493 // once, as this could result in misaligned access.
494 uint8_t* dst
= reinterpret_cast<uint8_t*>(&mBlocks
[mBlockIndex
[i
]].mBits
);
496 reinterpret_cast<const uint8_t*>(&blocks
[blockIndex
[i
]].mBits
);
497 for (uint32_t j
= 0; j
< BLOCK_SIZE
; ++j
) {
503 #define TRUETYPE_TAG(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
507 // Byte-swapping types and name table structure definitions moved from
508 // gfxFontUtils.cpp to .h file so that gfxFont.cpp can also refer to them
511 struct AutoSwap_PRUint16
{
513 AutoSwap_PRUint16
& operator=(const uint16_t aValue
) {
514 this->value
= mozilla::NativeEndian::swapToBigEndian(aValue
);
518 MOZ_IMPLICIT
AutoSwap_PRUint16(uint16_t aValue
) {
519 value
= mozilla::NativeEndian::swapToBigEndian(aValue
);
522 operator uint16_t() const {
523 return mozilla::NativeEndian::swapFromBigEndian(value
);
526 operator uint32_t() const {
527 return mozilla::NativeEndian::swapFromBigEndian(value
);
530 operator uint64_t() const {
531 return mozilla::NativeEndian::swapFromBigEndian(value
);
538 struct AutoSwap_PRInt16
{
540 AutoSwap_PRInt16
& operator=(const int16_t aValue
) {
541 this->value
= mozilla::NativeEndian::swapToBigEndian(aValue
);
545 MOZ_IMPLICIT
AutoSwap_PRInt16(int16_t aValue
) {
546 value
= mozilla::NativeEndian::swapToBigEndian(aValue
);
549 operator int16_t() const {
550 return mozilla::NativeEndian::swapFromBigEndian(value
);
553 operator uint32_t() const {
554 return mozilla::NativeEndian::swapFromBigEndian(value
);
561 struct AutoSwap_PRUint32
{
563 AutoSwap_PRUint32
& operator=(const uint32_t aValue
) {
564 this->value
= mozilla::NativeEndian::swapToBigEndian(aValue
);
568 MOZ_IMPLICIT
AutoSwap_PRUint32(uint32_t aValue
) {
569 value
= mozilla::NativeEndian::swapToBigEndian(aValue
);
572 operator uint32_t() const {
573 return mozilla::NativeEndian::swapFromBigEndian(value
);
580 struct AutoSwap_PRInt32
{
582 AutoSwap_PRInt32
& operator=(const int32_t aValue
) {
583 this->value
= mozilla::NativeEndian::swapToBigEndian(aValue
);
587 MOZ_IMPLICIT
AutoSwap_PRInt32(int32_t aValue
) {
588 value
= mozilla::NativeEndian::swapToBigEndian(aValue
);
591 operator int32_t() const {
592 return mozilla::NativeEndian::swapFromBigEndian(value
);
599 struct AutoSwap_PRUint64
{
601 AutoSwap_PRUint64
& operator=(const uint64_t aValue
) {
602 this->value
= mozilla::NativeEndian::swapToBigEndian(aValue
);
606 MOZ_IMPLICIT
AutoSwap_PRUint64(uint64_t aValue
) {
607 value
= mozilla::NativeEndian::swapToBigEndian(aValue
);
610 operator uint64_t() const {
611 return mozilla::NativeEndian::swapFromBigEndian(value
);
618 struct AutoSwap_PRUint24
{
619 operator uint32_t() const {
620 return value
[0] << 16 | value
[1] << 8 | value
[2];
624 AutoSwap_PRUint24() = default;
629 AutoSwap_PRUint32 sfntVersion
; // Fixed, 0x00010000 for version 1.0.
630 AutoSwap_PRUint16 numTables
; // Number of tables.
631 AutoSwap_PRUint16 searchRange
; // (Maximum power of 2 <= numTables) x 16.
632 AutoSwap_PRUint16 entrySelector
; // Log2(maximum power of 2 <= numTables).
633 AutoSwap_PRUint16 rangeShift
; // NumTables x 16-searchRange.
637 AutoSwap_PRUint32 ttcTag
; // 4 -byte identifier 'ttcf'.
638 AutoSwap_PRUint16 majorVersion
;
639 AutoSwap_PRUint16 minorVersion
;
640 AutoSwap_PRUint32 numFonts
;
642 // AutoSwap_PRUint32 offsetTable[numFonts]
645 struct TableDirEntry
{
646 AutoSwap_PRUint32 tag
; // 4 -byte identifier.
647 AutoSwap_PRUint32 checkSum
; // CheckSum for this table.
648 AutoSwap_PRUint32 offset
; // Offset from beginning of TrueType font file.
649 AutoSwap_PRUint32 length
; // Length of this table.
654 HEAD_VERSION
= 0x00010000,
655 HEAD_MAGIC_NUMBER
= 0x5F0F3CF5,
656 HEAD_CHECKSUM_CALC_CONST
= 0xB1B0AFBA
659 AutoSwap_PRUint32 tableVersionNumber
; // Fixed, 0x00010000 for version 1.0.
660 AutoSwap_PRUint32 fontRevision
; // Set by font manufacturer.
662 checkSumAdjustment
; // To compute: set it to 0, sum the entire font as
663 // ULONG, then store 0xB1B0AFBA - sum.
664 AutoSwap_PRUint32 magicNumber
; // Set to 0x5F0F3CF5.
665 AutoSwap_PRUint16 flags
;
667 unitsPerEm
; // Valid range is from 16 to 16384. This value should be a
668 // power of 2 for fonts that have TrueType outlines.
669 AutoSwap_PRUint64 created
; // Number of seconds since 12:00 midnight, January
670 // 1, 1904. 64-bit integer
671 AutoSwap_PRUint64 modified
; // Number of seconds since 12:00 midnight,
672 // January 1, 1904. 64-bit integer
673 AutoSwap_PRInt16 xMin
; // For all glyph bounding boxes.
674 AutoSwap_PRInt16 yMin
; // For all glyph bounding boxes.
675 AutoSwap_PRInt16 xMax
; // For all glyph bounding boxes.
676 AutoSwap_PRInt16 yMax
; // For all glyph bounding boxes.
677 AutoSwap_PRUint16 macStyle
; // Bit 0: Bold (if set to 1);
678 AutoSwap_PRUint16 lowestRecPPEM
; // Smallest readable size in pixels.
679 AutoSwap_PRInt16 fontDirectionHint
;
680 AutoSwap_PRInt16 indexToLocFormat
;
681 AutoSwap_PRInt16 glyphDataFormat
;
685 AutoSwap_PRUint16 version
; // 0004 = OpenType 1.5
686 AutoSwap_PRInt16 xAvgCharWidth
;
687 AutoSwap_PRUint16 usWeightClass
;
688 AutoSwap_PRUint16 usWidthClass
;
689 AutoSwap_PRUint16 fsType
;
690 AutoSwap_PRInt16 ySubscriptXSize
;
691 AutoSwap_PRInt16 ySubscriptYSize
;
692 AutoSwap_PRInt16 ySubscriptXOffset
;
693 AutoSwap_PRInt16 ySubscriptYOffset
;
694 AutoSwap_PRInt16 ySuperscriptXSize
;
695 AutoSwap_PRInt16 ySuperscriptYSize
;
696 AutoSwap_PRInt16 ySuperscriptXOffset
;
697 AutoSwap_PRInt16 ySuperscriptYOffset
;
698 AutoSwap_PRInt16 yStrikeoutSize
;
699 AutoSwap_PRInt16 yStrikeoutPosition
;
700 AutoSwap_PRInt16 sFamilyClass
;
702 AutoSwap_PRUint32 unicodeRange1
;
703 AutoSwap_PRUint32 unicodeRange2
;
704 AutoSwap_PRUint32 unicodeRange3
;
705 AutoSwap_PRUint32 unicodeRange4
;
706 uint8_t achVendID
[4];
707 AutoSwap_PRUint16 fsSelection
;
708 AutoSwap_PRUint16 usFirstCharIndex
;
709 AutoSwap_PRUint16 usLastCharIndex
;
710 AutoSwap_PRInt16 sTypoAscender
;
711 AutoSwap_PRInt16 sTypoDescender
;
712 AutoSwap_PRInt16 sTypoLineGap
;
713 AutoSwap_PRUint16 usWinAscent
;
714 AutoSwap_PRUint16 usWinDescent
;
715 AutoSwap_PRUint32 codePageRange1
;
716 AutoSwap_PRUint32 codePageRange2
;
717 AutoSwap_PRInt16 sxHeight
;
718 AutoSwap_PRInt16 sCapHeight
;
719 AutoSwap_PRUint16 usDefaultChar
;
720 AutoSwap_PRUint16 usBreakChar
;
721 AutoSwap_PRUint16 usMaxContext
;
725 AutoSwap_PRUint32 version
;
726 AutoSwap_PRInt32 italicAngle
;
727 AutoSwap_PRInt16 underlinePosition
;
728 AutoSwap_PRUint16 underlineThickness
;
729 AutoSwap_PRUint32 isFixedPitch
;
730 AutoSwap_PRUint32 minMemType42
;
731 AutoSwap_PRUint32 maxMemType42
;
732 AutoSwap_PRUint32 minMemType1
;
733 AutoSwap_PRUint32 maxMemType1
;
736 // This structure is used for both 'hhea' and 'vhea' tables.
737 // The field names here are those of the horizontal version; the
738 // vertical table just exchanges vertical and horizontal coordinates.
739 struct MetricsHeader
{
740 AutoSwap_PRUint32 version
;
741 AutoSwap_PRInt16 ascender
;
742 AutoSwap_PRInt16 descender
;
743 AutoSwap_PRInt16 lineGap
;
744 AutoSwap_PRUint16 advanceWidthMax
;
745 AutoSwap_PRInt16 minLeftSideBearing
;
746 AutoSwap_PRInt16 minRightSideBearing
;
747 AutoSwap_PRInt16 xMaxExtent
;
748 AutoSwap_PRInt16 caretSlopeRise
;
749 AutoSwap_PRInt16 caretSlopeRun
;
750 AutoSwap_PRInt16 caretOffset
;
751 AutoSwap_PRInt16 reserved1
;
752 AutoSwap_PRInt16 reserved2
;
753 AutoSwap_PRInt16 reserved3
;
754 AutoSwap_PRInt16 reserved4
;
755 AutoSwap_PRInt16 metricDataFormat
;
756 AutoSwap_PRUint16 numOfLongMetrics
;
759 struct MaxpTableHeader
{
760 AutoSwap_PRUint32 version
; // CFF: 0x00005000; TrueType: 0x00010000
761 AutoSwap_PRUint16 numGlyphs
;
762 // truetype version has additional fields that we don't currently use
765 // old 'kern' table, supported on Windows
766 // see http://www.microsoft.com/typography/otspec/kern.htm
767 struct KernTableVersion0
{
768 AutoSwap_PRUint16 version
; // 0x0000
769 AutoSwap_PRUint16 nTables
;
772 struct KernTableSubtableHeaderVersion0
{
773 AutoSwap_PRUint16 version
;
774 AutoSwap_PRUint16 length
;
775 AutoSwap_PRUint16 coverage
;
778 // newer Mac-only 'kern' table, ignored by Windows
779 // see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6kern.html
780 struct KernTableVersion1
{
781 AutoSwap_PRUint32 version
; // 0x00010000
782 AutoSwap_PRUint32 nTables
;
785 struct KernTableSubtableHeaderVersion1
{
786 AutoSwap_PRUint32 length
;
787 AutoSwap_PRUint16 coverage
;
788 AutoSwap_PRUint16 tupleIndex
;
793 // Return just the highest bit of the given value, i.e., the highest
794 // power of 2 that is <= value, or zero if the input value is zero.
795 inline uint32_t FindHighestBit(uint32_t value
) {
796 // propagate highest bit into all lower bits of the value
797 value
|= (value
>> 1);
798 value
|= (value
>> 2);
799 value
|= (value
>> 4);
800 value
|= (value
>> 8);
801 value
|= (value
>> 16);
802 // isolate the leftmost bit
803 return (value
& ~(value
>> 1));
806 } // namespace mozilla
808 // used for overlaying name changes without touching original font data
809 struct FontDataOverlay
{
810 // overlaySrc != 0 ==> use overlay
811 uint32_t overlaySrc
; // src offset from start of font data
812 uint32_t overlaySrcLen
; // src length
813 uint32_t overlayDest
; // dest offset from start of font data
816 enum gfxUserFontType
{
817 GFX_USERFONT_UNKNOWN
= 0,
818 GFX_USERFONT_OPENTYPE
= 1,
819 GFX_USERFONT_SVG
= 2,
820 GFX_USERFONT_WOFF
= 3,
821 GFX_USERFONT_WOFF2
= 4
824 extern const uint8_t sCJKCompatSVSTable
[];
828 // these are public because gfxFont.cpp also looks into the name table
835 NAME_ID_POSTSCRIPT
= 6,
836 NAME_ID_PREFERRED_FAMILY
= 16,
837 NAME_ID_PREFERRED_STYLE
= 17,
840 PLATFORM_ID_UNICODE
= 0, // Mac OS uses this typically
843 PLATFORM_ID_MICROSOFT
= 3,
845 ENCODING_ID_MAC_ROMAN
= 0, // traditional Mac OS script manager encodings
846 ENCODING_ID_MAC_JAPANESE
=
847 1, // (there are others defined, but some were never
848 ENCODING_ID_MAC_TRAD_CHINESE
=
849 2, // implemented by Apple, and I have never seen them
850 ENCODING_ID_MAC_KOREAN
= 3, // used in font names)
851 ENCODING_ID_MAC_ARABIC
= 4,
852 ENCODING_ID_MAC_HEBREW
= 5,
853 ENCODING_ID_MAC_GREEK
= 6,
854 ENCODING_ID_MAC_CYRILLIC
= 7,
855 ENCODING_ID_MAC_DEVANAGARI
= 9,
856 ENCODING_ID_MAC_GURMUKHI
= 10,
857 ENCODING_ID_MAC_GUJARATI
= 11,
858 ENCODING_ID_MAC_SIMP_CHINESE
= 25,
860 ENCODING_ID_MICROSOFT_SYMBOL
= 0, // Microsoft platform encoding IDs
861 ENCODING_ID_MICROSOFT_UNICODEBMP
= 1,
862 ENCODING_ID_MICROSOFT_SHIFTJIS
= 2,
863 ENCODING_ID_MICROSOFT_PRC
= 3,
864 ENCODING_ID_MICROSOFT_BIG5
= 4,
865 ENCODING_ID_MICROSOFT_WANSUNG
= 5,
866 ENCODING_ID_MICROSOFT_JOHAB
= 6,
867 ENCODING_ID_MICROSOFT_UNICODEFULL
= 10,
870 LANG_ID_MAC_ENGLISH
= 0, // many others are defined, but most don't affect
872 10, // the charset; should check all the central/eastern
873 LANG_ID_MAC_JAPANESE
= 11, // european codes, though
874 LANG_ID_MAC_ARABIC
= 12,
875 LANG_ID_MAC_ICELANDIC
= 15,
876 LANG_ID_MAC_TURKISH
= 17,
877 LANG_ID_MAC_TRAD_CHINESE
= 19,
878 LANG_ID_MAC_URDU
= 20,
879 LANG_ID_MAC_KOREAN
= 23,
880 LANG_ID_MAC_POLISH
= 25,
881 LANG_ID_MAC_FARSI
= 31,
882 LANG_ID_MAC_SIMP_CHINESE
= 33,
883 LANG_ID_MAC_ROMANIAN
= 37,
884 LANG_ID_MAC_CZECH
= 38,
885 LANG_ID_MAC_SLOVAK
= 39,
887 LANG_ID_MICROSOFT_EN_US
=
888 0x0409, // with Microsoft platformID, EN US lang code
890 CMAP_MAX_CODEPOINT
= 0x10ffff // maximum possible Unicode codepoint
891 // contained in a cmap
894 // name table has a header, followed by name records, followed by string data
896 mozilla::AutoSwap_PRUint16 format
; // Format selector (=0).
897 mozilla::AutoSwap_PRUint16 count
; // Number of name records.
898 mozilla::AutoSwap_PRUint16 stringOffset
; // Offset to start of string
899 // storage (from start of table)
903 mozilla::AutoSwap_PRUint16 platformID
; // Platform ID
904 mozilla::AutoSwap_PRUint16 encodingID
; // Platform-specific encoding ID
905 mozilla::AutoSwap_PRUint16 languageID
; // Language ID
906 mozilla::AutoSwap_PRUint16 nameID
; // Name ID.
907 mozilla::AutoSwap_PRUint16 length
; // String length (in bytes).
908 mozilla::AutoSwap_PRUint16 offset
; // String offset from start of storage
912 // Helper to ensure we free a font table when we return.
915 explicit AutoHBBlob(hb_blob_t
* aBlob
) : mBlob(aBlob
) {}
917 ~AutoHBBlob() { hb_blob_destroy(mBlob
); }
919 operator hb_blob_t
*() { return mBlob
; }
922 hb_blob_t
* const mBlob
;
925 // for reading big-endian font data on either big or little-endian platforms
927 static inline uint16_t ReadShortAt(const uint8_t* aBuf
, uint32_t aIndex
) {
928 return static_cast<uint16_t>(aBuf
[aIndex
] << 8) | aBuf
[aIndex
+ 1];
931 static inline uint16_t ReadShortAt16(const uint16_t* aBuf
, uint32_t aIndex
) {
932 const uint8_t* buf
= reinterpret_cast<const uint8_t*>(aBuf
);
933 uint32_t index
= aIndex
<< 1;
934 return static_cast<uint16_t>(buf
[index
] << 8) | buf
[index
+ 1];
937 static inline uint32_t ReadUint24At(const uint8_t* aBuf
, uint32_t aIndex
) {
938 return ((aBuf
[aIndex
] << 16) | (aBuf
[aIndex
+ 1] << 8) |
942 static inline uint32_t ReadLongAt(const uint8_t* aBuf
, uint32_t aIndex
) {
943 return ((aBuf
[aIndex
] << 24) | (aBuf
[aIndex
+ 1] << 16) |
944 (aBuf
[aIndex
+ 2] << 8) | (aBuf
[aIndex
+ 3]));
947 static nsresult
ReadCMAPTableFormat10(const uint8_t* aBuf
, uint32_t aLength
,
948 gfxSparseBitSet
& aCharacterMap
);
950 static nsresult
ReadCMAPTableFormat12or13(const uint8_t* aBuf
,
952 gfxSparseBitSet
& aCharacterMap
);
954 static nsresult
ReadCMAPTableFormat4(const uint8_t* aBuf
, uint32_t aLength
,
955 gfxSparseBitSet
& aCharacterMap
,
958 static nsresult
ReadCMAPTableFormat14(const uint8_t* aBuf
, uint32_t aLength
,
959 const uint8_t*& aTable
);
961 static uint32_t FindPreferredSubtable(const uint8_t* aBuf
,
963 uint32_t* aTableOffset
,
964 uint32_t* aUVSTableOffset
,
965 bool* aIsSymbolFont
);
967 static nsresult
ReadCMAP(const uint8_t* aBuf
, uint32_t aBufLength
,
968 gfxSparseBitSet
& aCharacterMap
,
969 uint32_t& aUVSOffset
);
971 static uint32_t MapCharToGlyphFormat4(const uint8_t* aBuf
, uint32_t aLength
,
974 static uint32_t MapCharToGlyphFormat10(const uint8_t* aBuf
, uint32_t aCh
);
976 static uint32_t MapCharToGlyphFormat12or13(const uint8_t* aBuf
, uint32_t aCh
);
978 static uint16_t MapUVSToGlyphFormat14(const uint8_t* aBuf
, uint32_t aCh
,
981 // sCJKCompatSVSTable is a 'cmap' format 14 subtable that maps
982 // <char + var-selector> pairs to the corresponding Unicode
983 // compatibility ideograph codepoints.
984 static MOZ_ALWAYS_INLINE
uint32_t GetUVSFallback(uint32_t aCh
, uint32_t aVS
) {
985 aCh
= MapUVSToGlyphFormat14(sCJKCompatSVSTable
, aCh
, aVS
);
986 return aCh
>= 0xFB00 ? aCh
+ (0x2F800 - 0xFB00) : aCh
;
989 static uint32_t MapCharToGlyph(const uint8_t* aCmapBuf
, uint32_t aBufLength
,
990 uint32_t aUnicode
, uint32_t aVarSelector
= 0);
992 // For legacy MS Symbol fonts, we try mapping 8-bit character codes to the
993 // Private Use range at U+F0xx used by the cmaps in these fonts.
994 static MOZ_ALWAYS_INLINE
uint32_t MapLegacySymbolFontCharToPUA(uint32_t aCh
) {
995 return aCh
>= 0x20 && aCh
<= 0xff ? 0xf000 + aCh
: 0;
999 // determine whether a font (which has already been sanitized, so is known
1000 // to be a valid sfnt) is CFF format rather than TrueType
1001 static bool IsCffFont(const uint8_t* aFontData
);
1004 // determine the format of font data
1005 static gfxUserFontType
DetermineFontDataType(const uint8_t* aFontData
,
1006 uint32_t aFontDataLength
);
1008 // Read the fullname from the sfnt data (used to save the original name
1009 // prior to renaming the font for installation).
1010 // This is called with sfnt data that has already been validated,
1011 // so it should always succeed in finding the name table.
1012 static nsresult
GetFullNameFromSFNT(const uint8_t* aFontData
,
1013 uint32_t aLength
, nsACString
& aFullName
);
1015 // helper to get fullname from name table, constructing from family+style
1016 // if no explicit fullname is present
1017 static nsresult
GetFullNameFromTable(hb_blob_t
* aNameTable
,
1018 nsACString
& aFullName
);
1020 // helper to get family name from name table
1021 static nsresult
GetFamilyNameFromTable(hb_blob_t
* aNameTable
,
1022 nsACString
& aFamilyName
);
1024 // Find the table directory entry for a given table tag, in a (validated)
1025 // buffer of 'sfnt' data. Returns null if the tag is not present.
1026 static mozilla::TableDirEntry
* FindTableDirEntry(const void* aFontData
,
1027 uint32_t aTableTag
);
1029 // Return a blob that wraps a table found within a buffer of font data.
1030 // The blob does NOT own its data; caller guarantees that the buffer
1031 // will remain valid at least as long as the blob.
1032 // Returns null if the specified table is not found.
1033 // This method assumes aFontData is valid 'sfnt' data; before using this,
1034 // caller is responsible to do any sanitization/validation necessary.
1035 static hb_blob_t
* GetTableFromFontData(const void* aFontData
,
1036 uint32_t aTableTag
);
1038 // create a new name table and build a new font with that name table
1039 // appended on the end, returns true on success
1040 static nsresult
RenameFont(const nsAString
& aName
, const uint8_t* aFontData
,
1041 uint32_t aFontDataLength
,
1042 FallibleTArray
<uint8_t>* aNewFont
);
1044 // read all names matching aNameID, returning in aNames array
1045 static nsresult
ReadNames(const char* aNameData
, uint32_t aDataLen
,
1046 uint32_t aNameID
, int32_t aPlatformID
,
1047 nsTArray
<nsCString
>& aNames
);
1049 // reads English or first name matching aNameID, returning in aName
1050 // platform based on OS
1051 static nsresult
ReadCanonicalName(hb_blob_t
* aNameTable
, uint32_t aNameID
,
1054 static nsresult
ReadCanonicalName(const char* aNameData
, uint32_t aDataLen
,
1055 uint32_t aNameID
, nsCString
& aName
);
1057 // convert a name from the raw name table data into an nsString,
1058 // provided we know how; return true if successful, or false
1059 // if we can't handle the encoding
1060 static bool DecodeFontName(const char* aBuf
, int32_t aLength
,
1061 uint32_t aPlatformCode
, uint32_t aScriptCode
,
1062 uint32_t aLangCode
, nsACString
& dest
);
1064 static inline bool IsJoinCauser(uint32_t ch
) { return (ch
== 0x200D); }
1066 // We treat Combining Grapheme Joiner (U+034F) together with the join
1067 // controls (ZWJ, ZWNJ) here, because (like them) it is an invisible
1068 // char that will be handled by the shaper even if not explicitly
1069 // supported by the font. (See bug 1408366.)
1070 static inline bool IsJoinControl(uint32_t ch
) {
1071 return (ch
== 0x200C || ch
== 0x200D || ch
== 0x034f);
1075 kUnicodeVS1
= 0xFE00,
1076 kUnicodeVS16
= 0xFE0F,
1077 kUnicodeVS17
= 0xE0100,
1078 kUnicodeVS256
= 0xE01EF
1081 static inline bool IsVarSelector(uint32_t ch
) {
1082 return (ch
>= kUnicodeVS1
&& ch
<= kUnicodeVS16
) ||
1083 (ch
>= kUnicodeVS17
&& ch
<= kUnicodeVS256
);
1087 kUnicodeRegionalIndicatorA
= 0x1F1E6,
1088 kUnicodeRegionalIndicatorZ
= 0x1F1FF
1091 static inline bool IsRegionalIndicator(uint32_t aCh
) {
1092 return aCh
>= kUnicodeRegionalIndicatorA
&&
1093 aCh
<= kUnicodeRegionalIndicatorZ
;
1096 static inline bool IsEmojiFlagAndTag(uint32_t aCh
, uint32_t aNext
) {
1097 constexpr uint32_t kBlackFlag
= 0x1F3F4;
1098 constexpr uint32_t kTagLetterA
= 0xE0061;
1099 constexpr uint32_t kTagLetterZ
= 0xE007A;
1101 return aCh
== kBlackFlag
&& aNext
>= kTagLetterA
&& aNext
<= kTagLetterZ
;
1104 static inline bool IsInvalid(uint32_t ch
) { return (ch
== 0xFFFD); }
1106 // Font code may want to know if there is the potential for bidi behavior
1107 // to be triggered by any of the characters in a text run; this can be
1108 // used to test that possibility.
1110 kUnicodeBidiScriptsStart
= 0x0590,
1111 kUnicodeBidiScriptsEnd
= 0x08FF,
1112 kUnicodeBidiPresentationStart
= 0xFB1D,
1113 kUnicodeBidiPresentationEnd
= 0xFEFC,
1114 kUnicodeFirstHighSurrogateBlock
= 0xD800,
1115 kUnicodeRLM
= 0x200F,
1116 kUnicodeRLE
= 0x202B,
1117 kUnicodeRLO
= 0x202E
1120 static inline bool PotentialRTLChar(char16_t aCh
) {
1121 if (aCh
>= kUnicodeBidiScriptsStart
&& aCh
<= kUnicodeBidiScriptsEnd
)
1122 // bidi scripts Hebrew, Arabic, Syriac, Thaana, N'Ko are all encoded
1126 if (aCh
== kUnicodeRLM
|| aCh
== kUnicodeRLE
|| aCh
== kUnicodeRLO
)
1127 // directional controls that trigger bidi layout
1130 if (aCh
>= kUnicodeBidiPresentationStart
&&
1131 aCh
<= kUnicodeBidiPresentationEnd
)
1132 // presentation forms of Arabic and Hebrew letters
1135 if ((aCh
& 0xFF00) == kUnicodeFirstHighSurrogateBlock
)
1136 // surrogate that could be part of a bidi supplementary char
1137 // (Cypriot, Aramaic, Phoenecian, etc)
1140 // otherwise we know this char cannot trigger bidi reordering
1144 // parse a simple list of font family names into
1145 // an array of strings
1146 static void ParseFontList(const nsACString
& aFamilyList
,
1147 nsTArray
<nsCString
>& aFontList
);
1149 // for a given pref name, initialize a list of font names
1150 static void GetPrefsFontList(const char* aPrefName
,
1151 nsTArray
<nsCString
>& aFontList
,
1152 bool aLocalized
= false);
1154 // generate a unique font name
1155 static nsresult
MakeUniqueUserFontName(nsAString
& aName
);
1157 // Helper used to implement gfxFontEntry::GetVariation{Axes,Instances} for
1158 // platforms where the native font APIs don't provide the info we want
1159 // in a convenient form, or when native APIs are too expensive.
1160 // (Not used on platforms -- currently, freetype -- where the font APIs
1161 // expose variation instance details directly.)
1162 static void GetVariationData(gfxFontEntry
* aFontEntry
,
1163 nsTArray
<gfxFontVariationAxis
>* aAxes
,
1164 nsTArray
<gfxFontVariationInstance
>* aInstances
);
1166 // Helper method for reading localized family names from the name table
1167 // of a single face.
1168 static void ReadOtherFamilyNamesForFace(
1169 const nsACString
& aFamilyName
, const char* aNameData
,
1170 uint32_t aDataLength
, nsTArray
<nsCString
>& aOtherFamilyNames
,
1173 // Main, DOM worker or servo thread safe method to check if we are performing
1175 static bool IsInServoTraversal();
1177 // Main, DOM worker or servo thread safe method to get the current
1178 // ServoTypeSet. Always returns nullptr for DOM worker threads.
1179 static mozilla::ServoStyleSet
* CurrentServoStyleSet();
1181 static void AssertSafeThreadOrServoFontMetricsLocked()
1190 friend struct MacCharsetMappingComparator
;
1192 static nsresult
ReadNames(const char* aNameData
, uint32_t aDataLen
,
1193 uint32_t aNameID
, int32_t aLangID
,
1194 int32_t aPlatformID
, nsTArray
<nsCString
>& aNames
);
1196 // convert opentype name-table platform/encoding/language values to an
1197 // Encoding object we can use to convert the name data to unicode
1198 static const mozilla::Encoding
* GetCharsetForFontName(uint16_t aPlatform
,
1200 uint16_t aLanguage
);
1202 struct MacFontNameCharsetMapping
{
1205 const mozilla::Encoding
* mEncoding
;
1207 bool operator<(const MacFontNameCharsetMapping
& rhs
) const {
1208 return (mScript
< rhs
.mScript
) ||
1209 ((mScript
== rhs
.mScript
) && (mLanguage
< rhs
.mLanguage
));
1212 static const MacFontNameCharsetMapping gMacFontNameCharsets
[];
1213 static const mozilla::Encoding
* gISOFontNameCharsets
[];
1214 static const mozilla::Encoding
* gMSFontNameCharsets
[];
1217 // Factors used to weight the distances between the available and target font
1218 // properties during font-matching. These ensure that we respect the CSS-fonts
1219 // requirement that font-stretch >> font-style >> font-weight; and in addition,
1220 // a mismatch between the desired and actual glyph presentation (emoji vs text)
1221 // will take precedence over any of the style attributes.
1222 constexpr double kPresentationMismatch
= 1.0e12
;
1223 constexpr double kStretchFactor
= 1.0e8
;
1224 constexpr double kStyleFactor
= 1.0e4
;
1225 constexpr double kWeightFactor
= 1.0e0
;
1227 // style distance ==> [0,500]
1228 static inline double StyleDistance(const mozilla::SlantStyleRange
& aRange
,
1229 mozilla::FontSlantStyle aTargetStyle
) {
1230 const mozilla::FontSlantStyle minStyle
= aRange
.Min();
1231 if (aTargetStyle
== minStyle
) {
1232 return 0.0; // styles match exactly ==> 0
1235 // bias added to angle difference when searching in the non-preferred
1236 // direction from a target angle
1237 const double kReverse
= 100.0;
1239 // bias added when we've crossed from positive to negative angles or
1241 const double kNegate
= 200.0;
1243 if (aTargetStyle
.IsNormal()) {
1244 if (minStyle
.IsOblique()) {
1245 // to distinguish oblique 0deg from normal, we add 1.0 to the angle
1246 const double minAngle
= minStyle
.ObliqueAngle();
1247 if (minAngle
>= 0.0) {
1248 return 1.0 + minAngle
;
1250 const mozilla::FontSlantStyle maxStyle
= aRange
.Max();
1251 const double maxAngle
= maxStyle
.ObliqueAngle();
1252 if (maxAngle
>= 0.0) {
1253 // [min,max] range includes 0.0, so just return our minimum
1256 // negative oblique is even worse than italic
1257 return kNegate
- maxAngle
;
1259 // must be italic, which is worse than any non-negative oblique;
1260 // treat as a match in the wrong search direction
1261 MOZ_ASSERT(minStyle
.IsItalic());
1265 const double kDefaultAngle
= mozilla::FontSlantStyle::DEFAULT_OBLIQUE_DEGREES
;
1267 if (aTargetStyle
.IsItalic()) {
1268 if (minStyle
.IsOblique()) {
1269 const double minAngle
= minStyle
.ObliqueAngle();
1270 if (minAngle
>= kDefaultAngle
) {
1271 return 1.0 + (minAngle
- kDefaultAngle
);
1273 const mozilla::FontSlantStyle maxStyle
= aRange
.Max();
1274 const double maxAngle
= maxStyle
.ObliqueAngle();
1275 if (maxAngle
>= kDefaultAngle
) {
1278 if (maxAngle
> 0.0) {
1279 // wrong direction but still > 0, add bias of 100
1280 return kReverse
+ (kDefaultAngle
- maxAngle
);
1282 // negative oblique angle, add bias of 300
1283 return kReverse
+ kNegate
+ (kDefaultAngle
- maxAngle
);
1285 // normal is worse than oblique > 0, but better than oblique <= 0
1286 MOZ_ASSERT(minStyle
.IsNormal());
1290 // target is oblique <angle>: four different cases depending on
1291 // the value of the <angle>, which determines the preferred direction
1293 const double targetAngle
= aTargetStyle
.ObliqueAngle();
1294 if (targetAngle
>= kDefaultAngle
) {
1295 if (minStyle
.IsOblique()) {
1296 const double minAngle
= minStyle
.ObliqueAngle();
1297 if (minAngle
>= targetAngle
) {
1298 return minAngle
- targetAngle
;
1300 const mozilla::FontSlantStyle maxStyle
= aRange
.Max();
1301 const double maxAngle
= maxStyle
.ObliqueAngle();
1302 if (maxAngle
>= targetAngle
) {
1305 if (maxAngle
> 0.0) {
1306 return kReverse
+ (targetAngle
- maxAngle
);
1308 return kReverse
+ kNegate
+ (targetAngle
- maxAngle
);
1310 if (minStyle
.IsItalic()) {
1311 return kReverse
+ kNegate
;
1313 return kReverse
+ kNegate
+ 1.0;
1316 if (targetAngle
<= -kDefaultAngle
) {
1317 if (minStyle
.IsOblique()) {
1318 const mozilla::FontSlantStyle maxStyle
= aRange
.Max();
1319 const double maxAngle
= maxStyle
.ObliqueAngle();
1320 if (maxAngle
<= targetAngle
) {
1321 return targetAngle
- maxAngle
;
1323 const double minAngle
= minStyle
.ObliqueAngle();
1324 if (minAngle
<= targetAngle
) {
1327 if (minAngle
< 0.0) {
1328 return kReverse
+ (minAngle
- targetAngle
);
1330 return kReverse
+ kNegate
+ (minAngle
- targetAngle
);
1332 if (minStyle
.IsItalic()) {
1333 return kReverse
+ kNegate
;
1335 return kReverse
+ kNegate
+ 1.0;
1338 if (targetAngle
>= 0.0) {
1339 if (minStyle
.IsOblique()) {
1340 const double minAngle
= minStyle
.ObliqueAngle();
1341 if (minAngle
> targetAngle
) {
1342 return kReverse
+ (minAngle
- targetAngle
);
1344 const mozilla::FontSlantStyle maxStyle
= aRange
.Max();
1345 const double maxAngle
= maxStyle
.ObliqueAngle();
1346 if (maxAngle
>= targetAngle
) {
1349 if (maxAngle
> 0.0) {
1350 return targetAngle
- maxAngle
;
1352 return kReverse
+ kNegate
+ (targetAngle
- maxAngle
);
1354 if (minStyle
.IsItalic()) {
1355 return kReverse
+ kNegate
- 2.0;
1357 return kReverse
+ kNegate
- 1.0;
1360 // last case: (targetAngle < 0.0 && targetAngle > kDefaultAngle)
1361 if (minStyle
.IsOblique()) {
1362 const mozilla::FontSlantStyle maxStyle
= aRange
.Max();
1363 const double maxAngle
= maxStyle
.ObliqueAngle();
1364 if (maxAngle
< targetAngle
) {
1365 return kReverse
+ (targetAngle
- maxAngle
);
1367 const double minAngle
= minStyle
.ObliqueAngle();
1368 if (minAngle
<= targetAngle
) {
1371 if (minAngle
< 0.0) {
1372 return minAngle
- targetAngle
;
1374 return kReverse
+ kNegate
+ (minAngle
- targetAngle
);
1376 if (minStyle
.IsItalic()) {
1377 return kReverse
+ kNegate
- 2.0;
1379 return kReverse
+ kNegate
- 1.0;
1382 // stretch distance ==> [0,2000]
1383 static inline double StretchDistance(const mozilla::StretchRange
& aRange
,
1384 mozilla::FontStretch aTargetStretch
) {
1385 const double kReverseDistance
= 1000.0;
1387 mozilla::FontStretch minStretch
= aRange
.Min();
1388 mozilla::FontStretch maxStretch
= aRange
.Max();
1390 // The stretch value is a (non-negative) percentage; currently we support
1391 // values in the range 0 .. 1000. (If the upper limit is ever increased,
1392 // the kReverseDistance value used here may need to be adjusted.)
1393 // If aTargetStretch is >100, we prefer larger values if available;
1394 // if <=100, we prefer smaller values if available.
1395 if (aTargetStretch
< minStretch
) {
1396 if (aTargetStretch
> mozilla::FontStretch::NORMAL
) {
1397 return minStretch
.ToFloat() - aTargetStretch
.ToFloat();
1399 return (minStretch
.ToFloat() - aTargetStretch
.ToFloat()) + kReverseDistance
;
1401 if (aTargetStretch
> maxStretch
) {
1402 if (aTargetStretch
<= mozilla::FontStretch::NORMAL
) {
1403 return aTargetStretch
.ToFloat() - maxStretch
.ToFloat();
1405 return (aTargetStretch
.ToFloat() - maxStretch
.ToFloat()) + kReverseDistance
;
1410 // Calculate weight distance with values in the range (0..1000). In general,
1411 // heavier weights match towards even heavier weights while lighter weights
1412 // match towards even lighter weights. Target weight values in the range
1413 // [400..500] are special, since they will first match up to 500, then down
1414 // towards 0, then up again towards 999.
1416 // Example: with target 600 and font weight 800, distance will be 200. With
1417 // target 300 and font weight 600, distance will be 900, since heavier
1418 // weights are farther away than lighter weights. If the target is 5 and the
1419 // font weight 995, the distance would be 1590 for the same reason.
1421 // weight distance ==> [0,1600]
1422 static inline double WeightDistance(const mozilla::WeightRange
& aRange
,
1423 mozilla::FontWeight aTargetWeight
) {
1424 const double kNotWithinCentralRange
= 100.0;
1425 const double kReverseDistance
= 600.0;
1427 mozilla::FontWeight minWeight
= aRange
.Min();
1428 mozilla::FontWeight maxWeight
= aRange
.Max();
1430 if (aTargetWeight
>= minWeight
&& aTargetWeight
<= maxWeight
) {
1431 // Target is within the face's range, so it's a perfect match
1435 if (aTargetWeight
< mozilla::FontWeight::NORMAL
) {
1436 // Requested a lighter-than-400 weight
1437 if (maxWeight
< aTargetWeight
) {
1438 return aTargetWeight
.ToFloat() - maxWeight
.ToFloat();
1440 // Add reverse-search penalty for bolder faces
1441 return (minWeight
.ToFloat() - aTargetWeight
.ToFloat()) + kReverseDistance
;
1444 if (aTargetWeight
> mozilla::FontWeight::FromInt(500)) {
1445 // Requested a bolder-than-500 weight
1446 if (minWeight
> aTargetWeight
) {
1447 return minWeight
.ToFloat() - aTargetWeight
.ToFloat();
1449 // Add reverse-search penalty for lighter faces
1450 return (aTargetWeight
.ToFloat() - maxWeight
.ToFloat()) + kReverseDistance
;
1453 // Special case for requested weight in the [400..500] range
1454 if (minWeight
> aTargetWeight
) {
1455 if (minWeight
<= mozilla::FontWeight::FromInt(500)) {
1456 // Bolder weight up to 500 is first choice
1457 return minWeight
.ToFloat() - aTargetWeight
.ToFloat();
1459 // Other bolder weights get a reverse-search penalty
1460 return (minWeight
.ToFloat() - aTargetWeight
.ToFloat()) + kReverseDistance
;
1462 // Lighter weights are not as good as bolder ones within [400..500]
1463 return (aTargetWeight
.ToFloat() - maxWeight
.ToFloat()) +
1464 kNotWithinCentralRange
;
1467 #endif /* GFX_FONT_UTILS_H */