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