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