gfxFontUtils.cpp (64317B)
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 #include "gfxFontUtils.h" 7 #include "gfxFontEntry.h" 8 #include "gfxFontVariations.h" 9 #include "gfxUtils.h" 10 11 #include "nsServiceManagerUtils.h" 12 13 #include "mozilla/Preferences.h" 14 #include "mozilla/BinarySearch.h" 15 #include "mozilla/Sprintf.h" 16 17 #include "nsCOMPtr.h" 18 #include "nsIUUIDGenerator.h" 19 #include "mozilla/Encoding.h" 20 21 #include "mozilla/ServoStyleSet.h" 22 #include "mozilla/dom/WorkerCommon.h" 23 24 #include "mozilla/Logging.h" 25 #include "mozilla/Base64.h" 26 27 #ifdef XP_DARWIN 28 # include <CoreFoundation/CoreFoundation.h> 29 #endif 30 31 #define LOG(log, args) MOZ_LOG(gfxPlatform::GetLog(log), LogLevel::Debug, args) 32 33 #define UNICODE_BMP_LIMIT 0x10000 34 35 using namespace mozilla; 36 37 #pragma pack(1) 38 39 typedef struct { 40 AutoSwap_PRUint16 format; 41 AutoSwap_PRUint16 reserved; 42 AutoSwap_PRUint32 length; 43 AutoSwap_PRUint32 language; 44 AutoSwap_PRUint32 startCharCode; 45 AutoSwap_PRUint32 numChars; 46 } Format10CmapHeader; 47 48 typedef struct { 49 AutoSwap_PRUint16 format; 50 AutoSwap_PRUint16 reserved; 51 AutoSwap_PRUint32 length; 52 AutoSwap_PRUint32 language; 53 AutoSwap_PRUint32 numGroups; 54 } Format12CmapHeader; 55 56 typedef struct { 57 AutoSwap_PRUint32 startCharCode; 58 AutoSwap_PRUint32 endCharCode; 59 AutoSwap_PRUint32 startGlyphId; 60 } Format12Group; 61 62 #pragma pack() 63 64 void gfxSparseBitSet::Dump(const char* aPrefix, eGfxLog aWhichLog) const { 65 uint32_t numBlocks = mBlockIndex.Length(); 66 67 for (uint32_t b = 0; b < numBlocks; b++) { 68 if (mBlockIndex[b] == NO_BLOCK) { 69 continue; 70 } 71 const Block* block = &mBlocks[mBlockIndex[b]]; 72 const int BUFSIZE = 256; 73 char outStr[BUFSIZE]; 74 int index = 0; 75 index += snprintf(&outStr[index], BUFSIZE - index, "%s u+%6.6x [", aPrefix, 76 (b * BLOCK_SIZE_BITS)); 77 for (int i = 0; i < 32; i += 4) { 78 for (int j = i; j < i + 4; j++) { 79 uint8_t bits = block->mBits[j]; 80 uint8_t flip1 = ((bits & 0xaa) >> 1) | ((bits & 0x55) << 1); 81 uint8_t flip2 = ((flip1 & 0xcc) >> 2) | ((flip1 & 0x33) << 2); 82 uint8_t flipped = ((flip2 & 0xf0) >> 4) | ((flip2 & 0x0f) << 4); 83 84 index += snprintf(&outStr[index], BUFSIZE - index, "%2.2x", flipped); 85 } 86 if (i + 4 != 32) index += snprintf(&outStr[index], BUFSIZE - index, " "); 87 } 88 (void)snprintf(&outStr[index], BUFSIZE - index, "]"); 89 LOG(aWhichLog, ("%s", outStr)); 90 } 91 } 92 93 nsresult gfxFontUtils::ReadCMAPTableFormat10(const uint8_t* aBuf, 94 uint32_t aLength, 95 gfxSparseBitSet& aCharacterMap) { 96 // Ensure table is large enough that we can safely read the header 97 NS_ENSURE_TRUE(aLength >= sizeof(Format10CmapHeader), 98 NS_ERROR_GFX_CMAP_MALFORMED); 99 100 // Sanity-check header fields 101 const Format10CmapHeader* cmap10 = 102 reinterpret_cast<const Format10CmapHeader*>(aBuf); 103 NS_ENSURE_TRUE(uint16_t(cmap10->format) == 10, NS_ERROR_GFX_CMAP_MALFORMED); 104 NS_ENSURE_TRUE(uint16_t(cmap10->reserved) == 0, NS_ERROR_GFX_CMAP_MALFORMED); 105 106 uint32_t tablelen = cmap10->length; 107 NS_ENSURE_TRUE(tablelen >= sizeof(Format10CmapHeader) && tablelen <= aLength, 108 NS_ERROR_GFX_CMAP_MALFORMED); 109 110 NS_ENSURE_TRUE(cmap10->language == 0, NS_ERROR_GFX_CMAP_MALFORMED); 111 112 uint32_t numChars = cmap10->numChars; 113 NS_ENSURE_TRUE( 114 tablelen == sizeof(Format10CmapHeader) + numChars * sizeof(uint16_t), 115 NS_ERROR_GFX_CMAP_MALFORMED); 116 117 uint32_t charCode = cmap10->startCharCode; 118 NS_ENSURE_TRUE(charCode <= CMAP_MAX_CODEPOINT && 119 charCode + numChars <= CMAP_MAX_CODEPOINT, 120 NS_ERROR_GFX_CMAP_MALFORMED); 121 122 // glyphs[] array immediately follows the subtable header 123 const AutoSwap_PRUint16* glyphs = 124 reinterpret_cast<const AutoSwap_PRUint16*>(cmap10 + 1); 125 126 for (uint32_t i = 0; i < numChars; ++i) { 127 if (uint16_t(*glyphs) != 0) { 128 aCharacterMap.set(charCode); 129 } 130 ++charCode; 131 ++glyphs; 132 } 133 134 aCharacterMap.Compact(); 135 136 return NS_OK; 137 } 138 139 nsresult gfxFontUtils::ReadCMAPTableFormat12or13( 140 const uint8_t* aBuf, uint32_t aLength, gfxSparseBitSet& aCharacterMap) { 141 // Format 13 has the same structure as format 12, the only difference is 142 // the interpretation of the glyphID field. So we can share the code here 143 // that reads the table and just records character coverage. 144 145 // Ensure table is large enough that we can safely read the header 146 NS_ENSURE_TRUE(aLength >= sizeof(Format12CmapHeader), 147 NS_ERROR_GFX_CMAP_MALFORMED); 148 149 // Sanity-check header fields 150 const Format12CmapHeader* cmap12 = 151 reinterpret_cast<const Format12CmapHeader*>(aBuf); 152 NS_ENSURE_TRUE( 153 uint16_t(cmap12->format) == 12 || uint16_t(cmap12->format) == 13, 154 NS_ERROR_GFX_CMAP_MALFORMED); 155 NS_ENSURE_TRUE(uint16_t(cmap12->reserved) == 0, NS_ERROR_GFX_CMAP_MALFORMED); 156 157 uint32_t tablelen = cmap12->length; 158 NS_ENSURE_TRUE(tablelen >= sizeof(Format12CmapHeader) && tablelen <= aLength, 159 NS_ERROR_GFX_CMAP_MALFORMED); 160 161 NS_ENSURE_TRUE(cmap12->language == 0, NS_ERROR_GFX_CMAP_MALFORMED); 162 163 // Check that the table is large enough for the group array 164 const uint32_t numGroups = cmap12->numGroups; 165 NS_ENSURE_TRUE( 166 (tablelen - sizeof(Format12CmapHeader)) / sizeof(Format12Group) >= 167 numGroups, 168 NS_ERROR_GFX_CMAP_MALFORMED); 169 170 // The array of groups immediately follows the subtable header. 171 const Format12Group* group = 172 reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader)); 173 174 // Check that groups are in correct order and do not overlap, 175 // and record character coverage in aCharacterMap. 176 uint32_t prevEndCharCode = 0; 177 for (uint32_t i = 0; i < numGroups; i++, group++) { 178 uint32_t startCharCode = group->startCharCode; 179 const uint32_t endCharCode = group->endCharCode; 180 NS_ENSURE_TRUE((prevEndCharCode < startCharCode || i == 0) && 181 startCharCode <= endCharCode && 182 endCharCode <= CMAP_MAX_CODEPOINT, 183 NS_ERROR_GFX_CMAP_MALFORMED); 184 // don't include a character that maps to glyph ID 0 (.notdef) 185 if (group->startGlyphId == 0) { 186 startCharCode++; 187 } 188 if (startCharCode <= endCharCode) { 189 aCharacterMap.SetRange(startCharCode, endCharCode); 190 } 191 prevEndCharCode = endCharCode; 192 } 193 194 aCharacterMap.Compact(); 195 196 return NS_OK; 197 } 198 199 nsresult gfxFontUtils::ReadCMAPTableFormat4(const uint8_t* aBuf, 200 uint32_t aLength, 201 gfxSparseBitSet& aCharacterMap, 202 bool aIsSymbolFont) { 203 enum { 204 OffsetFormat = 0, 205 OffsetLength = 2, 206 OffsetLanguage = 4, 207 OffsetSegCountX2 = 6 208 }; 209 210 NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 4, 211 NS_ERROR_GFX_CMAP_MALFORMED); 212 uint16_t tablelen = ReadShortAt(aBuf, OffsetLength); 213 NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED); 214 NS_ENSURE_TRUE(tablelen > 16, NS_ERROR_GFX_CMAP_MALFORMED); 215 216 // This field should normally (except for Mac platform subtables) be zero 217 // according to the OT spec, but some buggy fonts have lang = 1 (which would 218 // be English for MacOS). E.g. Arial Narrow Bold, v. 1.1 (Tiger), Arial 219 // Unicode MS (see bug 530614). So accept either zero or one here; the error 220 // should be harmless. 221 NS_ENSURE_TRUE((ReadShortAt(aBuf, OffsetLanguage) & 0xfffe) == 0, 222 NS_ERROR_GFX_CMAP_MALFORMED); 223 224 uint16_t segCountX2 = ReadShortAt(aBuf, OffsetSegCountX2); 225 NS_ENSURE_TRUE(tablelen >= 16 + (segCountX2 * 4), 226 NS_ERROR_GFX_CMAP_MALFORMED); 227 228 const uint16_t segCount = segCountX2 / 2; 229 230 const uint16_t* endCounts = reinterpret_cast<const uint16_t*>(aBuf + 14); 231 const uint16_t* startCounts = 232 endCounts + 1 /* skip one uint16_t for reservedPad */ + segCount; 233 const uint16_t* idDeltas = startCounts + segCount; 234 const uint16_t* idRangeOffsets = idDeltas + segCount; 235 uint16_t prevEndCount = 0; 236 for (uint16_t i = 0; i < segCount; i++) { 237 const uint16_t endCount = ReadShortAt16(endCounts, i); 238 const uint16_t startCount = ReadShortAt16(startCounts, i); 239 const uint16_t idRangeOffset = ReadShortAt16(idRangeOffsets, i); 240 241 // sanity-check range 242 // This permits ranges to overlap by 1 character, which is strictly 243 // incorrect but occurs in Baskerville on OS X 10.7 (see bug 689087), 244 // and appears to be harmless in practice 245 NS_ENSURE_TRUE(startCount >= prevEndCount && startCount <= endCount, 246 NS_ERROR_GFX_CMAP_MALFORMED); 247 prevEndCount = endCount; 248 249 if (idRangeOffset == 0) { 250 // figure out if there's a code in the range that would map to 251 // glyph ID 0 (.notdef); if so, we need to skip setting that 252 // character code in the map 253 const uint16_t skipCode = 65536 - ReadShortAt16(idDeltas, i); 254 if (startCount < skipCode) { 255 aCharacterMap.SetRange(startCount, 256 std::min<uint16_t>(skipCode - 1, endCount)); 257 } 258 if (skipCode < endCount) { 259 aCharacterMap.SetRange(std::max<uint16_t>(startCount, skipCode + 1), 260 endCount); 261 } 262 } else { 263 // Unused: self-documenting. 264 // const uint16_t idDelta = ReadShortAt16(idDeltas, i); 265 for (uint32_t c = startCount; c <= endCount; ++c) { 266 if (c == 0xFFFF) break; 267 268 const uint16_t* gdata = 269 (idRangeOffset / 2 + (c - startCount) + &idRangeOffsets[i]); 270 271 NS_ENSURE_TRUE( 272 (uint8_t*)gdata > aBuf && (uint8_t*)gdata < aBuf + aLength, 273 NS_ERROR_GFX_CMAP_MALFORMED); 274 275 // make sure we have a glyph 276 if (*gdata != 0) { 277 // The glyph index at this point is: 278 uint16_t glyph = ReadShortAt16(idDeltas, i) + *gdata; 279 if (glyph) { 280 aCharacterMap.set(c); 281 } 282 } 283 } 284 } 285 } 286 287 if (aIsSymbolFont) { 288 // For fonts with "MS Symbol" encoding, we duplicate character mappings in 289 // the U+F0xx range down to U+00xx codepoints, so as to support fonts such 290 // as Wingdings. 291 // Note that if the font actually has cmap coverage for the U+00xx range 292 // (either duplicating the PUA codepoints or mapping to separate glyphs), 293 // this will not affect it. 294 for (uint32_t c = 0x0020; c <= 0x00ff; ++c) { 295 if (aCharacterMap.test(0xf000 + c)) { 296 aCharacterMap.set(c); 297 } 298 } 299 } 300 301 aCharacterMap.Compact(); 302 303 return NS_OK; 304 } 305 306 nsresult gfxFontUtils::ReadCMAPTableFormat14(const uint8_t* aBuf, 307 uint32_t aLength, 308 const uint8_t*& aTable) { 309 enum { 310 OffsetFormat = 0, 311 OffsetTableLength = 2, 312 OffsetNumVarSelectorRecords = 6, 313 OffsetVarSelectorRecords = 10, 314 315 SizeOfVarSelectorRecord = 11, 316 VSRecOffsetVarSelector = 0, 317 VSRecOffsetDefUVSOffset = 3, 318 VSRecOffsetNonDefUVSOffset = 7, 319 320 SizeOfDefUVSTable = 4, 321 DefUVSOffsetStartUnicodeValue = 0, 322 DefUVSOffsetAdditionalCount = 3, 323 324 SizeOfNonDefUVSTable = 5, 325 NonDefUVSOffsetUnicodeValue = 0, 326 NonDefUVSOffsetGlyphID = 3 327 }; 328 NS_ENSURE_TRUE(aLength >= OffsetVarSelectorRecords, 329 NS_ERROR_GFX_CMAP_MALFORMED); 330 331 NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 14, 332 NS_ERROR_GFX_CMAP_MALFORMED); 333 334 uint32_t tablelen = ReadLongAt(aBuf, OffsetTableLength); 335 NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED); 336 NS_ENSURE_TRUE(tablelen >= OffsetVarSelectorRecords, 337 NS_ERROR_GFX_CMAP_MALFORMED); 338 339 const uint32_t numVarSelectorRecords = 340 ReadLongAt(aBuf, OffsetNumVarSelectorRecords); 341 NS_ENSURE_TRUE( 342 (tablelen - OffsetVarSelectorRecords) / SizeOfVarSelectorRecord >= 343 numVarSelectorRecords, 344 NS_ERROR_GFX_CMAP_MALFORMED); 345 346 const uint8_t* records = aBuf + OffsetVarSelectorRecords; 347 for (uint32_t i = 0; i < numVarSelectorRecords; 348 i++, records += SizeOfVarSelectorRecord) { 349 const uint32_t varSelector = ReadUint24At(records, VSRecOffsetVarSelector); 350 const uint32_t defUVSOffset = ReadLongAt(records, VSRecOffsetDefUVSOffset); 351 const uint32_t nonDefUVSOffset = 352 ReadLongAt(records, VSRecOffsetNonDefUVSOffset); 353 NS_ENSURE_TRUE(varSelector <= CMAP_MAX_CODEPOINT && 354 defUVSOffset <= tablelen - 4 && 355 nonDefUVSOffset <= tablelen - 4, 356 NS_ERROR_GFX_CMAP_MALFORMED); 357 358 if (defUVSOffset) { 359 const uint32_t numUnicodeValueRanges = ReadLongAt(aBuf, defUVSOffset); 360 NS_ENSURE_TRUE((tablelen - defUVSOffset) / SizeOfDefUVSTable >= 361 numUnicodeValueRanges, 362 NS_ERROR_GFX_CMAP_MALFORMED); 363 const uint8_t* tables = aBuf + defUVSOffset + 4; 364 uint32_t prevEndUnicode = 0; 365 for (uint32_t j = 0; j < numUnicodeValueRanges; 366 j++, tables += SizeOfDefUVSTable) { 367 const uint32_t startUnicode = 368 ReadUint24At(tables, DefUVSOffsetStartUnicodeValue); 369 const uint32_t endUnicode = 370 startUnicode + tables[DefUVSOffsetAdditionalCount]; 371 NS_ENSURE_TRUE((prevEndUnicode < startUnicode || j == 0) && 372 endUnicode <= CMAP_MAX_CODEPOINT, 373 NS_ERROR_GFX_CMAP_MALFORMED); 374 prevEndUnicode = endUnicode; 375 } 376 } 377 378 if (nonDefUVSOffset) { 379 const uint32_t numUVSMappings = ReadLongAt(aBuf, nonDefUVSOffset); 380 NS_ENSURE_TRUE( 381 (tablelen - nonDefUVSOffset) / SizeOfNonDefUVSTable >= numUVSMappings, 382 NS_ERROR_GFX_CMAP_MALFORMED); 383 const uint8_t* tables = aBuf + nonDefUVSOffset + 4; 384 uint32_t prevUnicode = 0; 385 for (uint32_t j = 0; j < numUVSMappings; 386 j++, tables += SizeOfNonDefUVSTable) { 387 const uint32_t unicodeValue = 388 ReadUint24At(tables, NonDefUVSOffsetUnicodeValue); 389 NS_ENSURE_TRUE((prevUnicode < unicodeValue || j == 0) && 390 unicodeValue <= CMAP_MAX_CODEPOINT, 391 NS_ERROR_GFX_CMAP_MALFORMED); 392 prevUnicode = unicodeValue; 393 } 394 } 395 } 396 397 uint8_t* table = new uint8_t[tablelen]; 398 memcpy(table, aBuf, tablelen); 399 400 aTable = static_cast<const uint8_t*>(table); 401 402 return NS_OK; 403 } 404 405 // For fonts with two format-4 tables, the first one (Unicode platform) is 406 // preferred on the Mac; on other platforms we allow the Microsoft-platform 407 // subtable to replace it. 408 409 #if defined(XP_MACOSX) 410 # define acceptableFormat4(p, e, k) \ 411 (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft && !(k)) || \ 412 ((p) == PLATFORM_ID_UNICODE)) 413 414 # define acceptableUCS4Encoding(p, e, k) \ 415 (((p) == PLATFORM_ID_MICROSOFT && \ 416 (e) == EncodingIDUCS4ForMicrosoftPlatform) && \ 417 (k) != 12 || \ 418 ((p) == PLATFORM_ID_UNICODE && ((e) != EncodingIDUVSForUnicodePlatform))) 419 #else 420 # define acceptableFormat4(p, e, k) \ 421 (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft) || \ 422 ((p) == PLATFORM_ID_UNICODE)) 423 424 # define acceptableUCS4Encoding(p, e, k) \ 425 ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform) 426 #endif 427 428 #define acceptablePlatform(p) \ 429 ((p) == PLATFORM_ID_UNICODE || (p) == PLATFORM_ID_MICROSOFT) 430 #define isSymbol(p, e) ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDSymbol) 431 #define isUVSEncoding(p, e) \ 432 ((p) == PLATFORM_ID_UNICODE && (e) == EncodingIDUVSForUnicodePlatform) 433 434 uint32_t gfxFontUtils::FindPreferredSubtable(const uint8_t* aBuf, 435 uint32_t aBufLength, 436 uint32_t* aTableOffset, 437 uint32_t* aUVSTableOffset, 438 bool* aIsSymbolFont) { 439 enum { 440 OffsetVersion = 0, 441 OffsetNumTables = 2, 442 SizeOfHeader = 4, 443 444 TableOffsetPlatformID = 0, 445 TableOffsetEncodingID = 2, 446 TableOffsetOffset = 4, 447 SizeOfTable = 8, 448 449 SubtableOffsetFormat = 0 450 }; 451 enum { 452 EncodingIDSymbol = 0, 453 EncodingIDMicrosoft = 1, 454 EncodingIDDefaultForUnicodePlatform = 0, 455 EncodingIDUCS4ForUnicodePlatform = 3, 456 EncodingIDUVSForUnicodePlatform = 5, 457 EncodingIDUCS4ForMicrosoftPlatform = 10 458 }; 459 460 if (aUVSTableOffset) { 461 *aUVSTableOffset = 0; 462 } 463 if (aIsSymbolFont) { 464 *aIsSymbolFont = false; 465 } 466 467 if (!aBuf || aBufLength < SizeOfHeader) { 468 // cmap table is missing, or too small to contain header fields! 469 return 0; 470 } 471 472 // uint16_t version = ReadShortAt(aBuf, OffsetVersion); // Unused: 473 // self-documenting. 474 uint16_t numTables = ReadShortAt(aBuf, OffsetNumTables); 475 if (aBufLength < uint32_t(SizeOfHeader + numTables * SizeOfTable)) { 476 return 0; 477 } 478 479 // save the format we want here 480 uint32_t keepFormat = 0; 481 482 const uint8_t* table = aBuf + SizeOfHeader; 483 for (uint16_t i = 0; i < numTables; ++i, table += SizeOfTable) { 484 const uint16_t platformID = ReadShortAt(table, TableOffsetPlatformID); 485 if (!acceptablePlatform(platformID)) continue; 486 487 const uint16_t encodingID = ReadShortAt(table, TableOffsetEncodingID); 488 const uint32_t offset = ReadLongAt(table, TableOffsetOffset); 489 if (aBufLength - 2 < offset) { 490 // this subtable is not valid - beyond end of buffer 491 return 0; 492 } 493 494 const uint8_t* subtable = aBuf + offset; 495 const uint16_t format = ReadShortAt(subtable, SubtableOffsetFormat); 496 497 if (isSymbol(platformID, encodingID)) { 498 keepFormat = format; 499 *aTableOffset = offset; 500 if (aIsSymbolFont) { 501 *aIsSymbolFont = true; 502 } 503 break; 504 } else if (format == 4 && 505 acceptableFormat4(platformID, encodingID, keepFormat)) { 506 keepFormat = format; 507 *aTableOffset = offset; 508 } else if ((format == 10 || format == 12 || format == 13) && 509 acceptableUCS4Encoding(platformID, encodingID, keepFormat)) { 510 keepFormat = format; 511 *aTableOffset = offset; 512 if (platformID > PLATFORM_ID_UNICODE || !aUVSTableOffset || 513 *aUVSTableOffset) { 514 break; // we don't want to try anything else when this format is 515 // available. 516 } 517 } else if (format == 14 && isUVSEncoding(platformID, encodingID) && 518 aUVSTableOffset) { 519 *aUVSTableOffset = offset; 520 if (keepFormat == 10 || keepFormat == 12) { 521 break; 522 } 523 } 524 } 525 526 return keepFormat; 527 } 528 529 nsresult gfxFontUtils::ReadCMAP(const uint8_t* aBuf, uint32_t aBufLength, 530 gfxSparseBitSet& aCharacterMap, 531 uint32_t& aUVSOffset) { 532 uint32_t offset; 533 bool isSymbolFont; 534 uint32_t format = FindPreferredSubtable(aBuf, aBufLength, &offset, 535 &aUVSOffset, &isSymbolFont); 536 537 switch (format) { 538 case 4: 539 return ReadCMAPTableFormat4(aBuf + offset, aBufLength - offset, 540 aCharacterMap, isSymbolFont); 541 542 case 10: 543 return ReadCMAPTableFormat10(aBuf + offset, aBufLength - offset, 544 aCharacterMap); 545 546 case 12: 547 case 13: 548 return ReadCMAPTableFormat12or13(aBuf + offset, aBufLength - offset, 549 aCharacterMap); 550 551 default: 552 break; 553 } 554 555 return NS_ERROR_FAILURE; 556 } 557 558 #pragma pack(1) 559 560 typedef struct { 561 AutoSwap_PRUint16 format; 562 AutoSwap_PRUint16 length; 563 AutoSwap_PRUint16 language; 564 AutoSwap_PRUint16 segCountX2; 565 AutoSwap_PRUint16 searchRange; 566 AutoSwap_PRUint16 entrySelector; 567 AutoSwap_PRUint16 rangeShift; 568 569 AutoSwap_PRUint16 arrays[1]; 570 } Format4Cmap; 571 572 typedef struct Format14Cmap { 573 AutoSwap_PRUint16 format; 574 AutoSwap_PRUint32 length; 575 AutoSwap_PRUint32 numVarSelectorRecords; 576 577 typedef struct { 578 AutoSwap_PRUint24 varSelector; 579 AutoSwap_PRUint32 defaultUVSOffset; 580 AutoSwap_PRUint32 nonDefaultUVSOffset; 581 } VarSelectorRecord; 582 583 VarSelectorRecord varSelectorRecords[1]; 584 } Format14Cmap; 585 586 typedef struct DefUVSTable { 587 AutoSwap_PRUint32 numUnicodeValueRanges; 588 589 typedef struct { 590 AutoSwap_PRUint24 startUnicodeValue; 591 uint8_t additionalCount; 592 } UnicodeRange; 593 594 UnicodeRange ranges[1]; 595 } DefUVSTable; 596 597 typedef struct UnicodeRangeComparator { 598 explicit UnicodeRangeComparator(uint32_t aTarget) : mTarget(aTarget) {} 599 int operator()(std::pair<uint32_t, uint32_t> aVal) const { 600 if (mTarget < aVal.first) { 601 return -1; 602 } 603 if (mTarget > aVal.second) { 604 return 1; 605 } 606 return 0; 607 } 608 const uint32_t mTarget; 609 } UnicodeRangeComparator; 610 611 typedef struct NonDefUVSTable { 612 AutoSwap_PRUint32 numUVSMappings; 613 614 typedef struct { 615 AutoSwap_PRUint24 unicodeValue; 616 AutoSwap_PRUint16 glyphID; 617 } UVSMapping; 618 619 UVSMapping uvsMappings[1]; 620 } NonDefUVSTable; 621 622 #pragma pack() 623 624 uint32_t gfxFontUtils::MapCharToGlyphFormat4(const uint8_t* aBuf, 625 uint32_t aLength, char16_t aCh) { 626 const Format4Cmap* cmap4 = reinterpret_cast<const Format4Cmap*>(aBuf); 627 628 uint16_t segCount = (uint16_t)(cmap4->segCountX2) / 2; 629 630 const AutoSwap_PRUint16* endCodes = &cmap4->arrays[0]; 631 const AutoSwap_PRUint16* startCodes = &cmap4->arrays[segCount + 1]; 632 const AutoSwap_PRUint16* idDelta = &startCodes[segCount]; 633 const AutoSwap_PRUint16* idRangeOffset = &idDelta[segCount]; 634 635 // Sanity-check that the fixed-size arrays don't exceed the buffer. 636 const uint8_t* const limit = aBuf + aLength; 637 if ((const uint8_t*)(&idRangeOffset[segCount]) > limit) { 638 return 0; // broken font, just bail out safely 639 } 640 641 // For most efficient binary search, we want to work on a range of segment 642 // indexes that is a power of 2 so that we can always halve it by shifting. 643 // So we find the largest power of 2 that is <= segCount. 644 // We will offset this range by segOffset so as to reach the end 645 // of the table, provided that doesn't put us beyond the target 646 // value from the outset. 647 uint32_t powerOf2 = mozilla::FindHighestBit(segCount); 648 uint32_t segOffset = segCount - powerOf2; 649 uint32_t idx = 0; 650 651 if (uint16_t(startCodes[segOffset]) <= aCh) { 652 idx = segOffset; 653 } 654 655 // Repeatedly halve the size of the range until we find the target group 656 while (powerOf2 > 1) { 657 powerOf2 >>= 1; 658 if (uint16_t(startCodes[idx + powerOf2]) <= aCh) { 659 idx += powerOf2; 660 } 661 } 662 663 if (aCh >= uint16_t(startCodes[idx]) && aCh <= uint16_t(endCodes[idx])) { 664 uint16_t result; 665 if (uint16_t(idRangeOffset[idx]) == 0) { 666 result = aCh; 667 } else { 668 uint16_t offset = aCh - uint16_t(startCodes[idx]); 669 const AutoSwap_PRUint16* glyphIndexTable = 670 (const AutoSwap_PRUint16*)((const char*)&idRangeOffset[idx] + 671 uint16_t(idRangeOffset[idx])); 672 if ((const uint8_t*)(glyphIndexTable + offset + 1) > limit) { 673 return 0; // broken font, just bail out safely 674 } 675 result = glyphIndexTable[offset]; 676 } 677 678 // Note that this is unsigned 16-bit arithmetic, and may wrap around 679 // (which is required behavior per spec) 680 result += uint16_t(idDelta[idx]); 681 return result; 682 } 683 684 return 0; 685 } 686 687 uint32_t gfxFontUtils::MapCharToGlyphFormat10(const uint8_t* aBuf, 688 uint32_t aCh) { 689 const Format10CmapHeader* cmap10 = 690 reinterpret_cast<const Format10CmapHeader*>(aBuf); 691 692 uint32_t startChar = cmap10->startCharCode; 693 uint32_t numChars = cmap10->numChars; 694 695 if (aCh < startChar || aCh >= startChar + numChars) { 696 return 0; 697 } 698 699 const AutoSwap_PRUint16* glyphs = 700 reinterpret_cast<const AutoSwap_PRUint16*>(cmap10 + 1); 701 702 uint16_t glyph = glyphs[aCh - startChar]; 703 return glyph; 704 } 705 706 uint32_t gfxFontUtils::MapCharToGlyphFormat12or13(const uint8_t* aBuf, 707 uint32_t aCh) { 708 // The only difference between formats 12 and 13 is the interpretation of 709 // the glyphId field. So the code here uses the same "Format12" structures, 710 // etc., to handle both subtable formats. 711 712 const Format12CmapHeader* cmap12 = 713 reinterpret_cast<const Format12CmapHeader*>(aBuf); 714 715 // We know that numGroups is within range for the subtable size 716 // because it was checked by ReadCMAPTableFormat12or13. 717 uint32_t numGroups = cmap12->numGroups; 718 719 // The array of groups immediately follows the subtable header. 720 const Format12Group* groups = 721 reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader)); 722 723 // For most efficient binary search, we want to work on a range that 724 // is a power of 2 so that we can always halve it by shifting. 725 // So we find the largest power of 2 that is <= numGroups. 726 // We will offset this range by rangeOffset so as to reach the end 727 // of the table, provided that doesn't put us beyond the target 728 // value from the outset. 729 uint32_t powerOf2 = mozilla::FindHighestBit(numGroups); 730 uint32_t rangeOffset = numGroups - powerOf2; 731 uint32_t range = 0; 732 uint32_t startCharCode; 733 734 if (groups[rangeOffset].startCharCode <= aCh) { 735 range = rangeOffset; 736 } 737 738 // Repeatedly halve the size of the range until we find the target group 739 while (powerOf2 > 1) { 740 powerOf2 >>= 1; 741 if (groups[range + powerOf2].startCharCode <= aCh) { 742 range += powerOf2; 743 } 744 } 745 746 // Check if the character is actually present in the range and return 747 // the corresponding glyph ID. Here is where formats 12 and 13 interpret 748 // the startGlyphId (12) or glyphId (13) field differently 749 startCharCode = groups[range].startCharCode; 750 if (startCharCode <= aCh && groups[range].endCharCode >= aCh) { 751 return uint16_t(cmap12->format) == 12 752 ? uint16_t(groups[range].startGlyphId) + aCh - startCharCode 753 : uint16_t(groups[range].startGlyphId); 754 } 755 756 // Else it's not present, so return the .notdef glyph 757 return 0; 758 } 759 760 namespace { 761 762 struct Format14CmapWrapper { 763 const Format14Cmap& mCmap14; 764 explicit Format14CmapWrapper(const Format14Cmap& cmap14) : mCmap14(cmap14) {} 765 uint32_t operator[](size_t index) const { 766 return mCmap14.varSelectorRecords[index].varSelector; 767 } 768 }; 769 770 struct DefUVSTableWrapper { 771 const DefUVSTable& mTable; 772 explicit DefUVSTableWrapper(const DefUVSTable& table) : mTable(table) {} 773 std::pair<uint32_t, uint32_t> operator[](size_t index) const { 774 const auto& range = mTable.ranges[index]; 775 return std::make_pair(range.startUnicodeValue, 776 range.startUnicodeValue + range.additionalCount); 777 } 778 }; 779 780 struct NonDefUVSTableWrapper { 781 const NonDefUVSTable& mTable; 782 explicit NonDefUVSTableWrapper(const NonDefUVSTable& table) : mTable(table) {} 783 uint32_t operator[](size_t index) const { 784 return mTable.uvsMappings[index].unicodeValue; 785 } 786 }; 787 788 } // namespace 789 790 uint16_t gfxFontUtils::MapUVSToGlyphFormat14(const uint8_t* aBuf, uint32_t aCh, 791 uint32_t aVS) { 792 using mozilla::BinarySearch; 793 const Format14Cmap* cmap14 = reinterpret_cast<const Format14Cmap*>(aBuf); 794 795 size_t index; 796 if (!BinarySearch(Format14CmapWrapper(*cmap14), 0, 797 cmap14->numVarSelectorRecords, aVS, &index)) { 798 return 0; 799 } 800 801 const uint32_t nonDefUVSOffset = 802 cmap14->varSelectorRecords[index].nonDefaultUVSOffset; 803 if (!nonDefUVSOffset) { 804 return 0; 805 } 806 807 const NonDefUVSTable* table = 808 reinterpret_cast<const NonDefUVSTable*>(aBuf + nonDefUVSOffset); 809 810 if (BinarySearch(NonDefUVSTableWrapper(*table), 0, table->numUVSMappings, aCh, 811 &index)) { 812 return table->uvsMappings[index].glyphID; 813 } 814 815 return 0; 816 } 817 818 bool gfxFontUtils::IsDefaultUVSSequence(const uint8_t* aBuf, uint32_t aCh, 819 uint32_t aVS) { 820 using mozilla::BinarySearch; 821 const Format14Cmap* cmap14 = reinterpret_cast<const Format14Cmap*>(aBuf); 822 823 size_t index; 824 if (!BinarySearch(Format14CmapWrapper(*cmap14), 0, 825 cmap14->numVarSelectorRecords, aVS, &index)) { 826 return false; 827 } 828 829 const uint32_t defUVSOffset = 830 cmap14->varSelectorRecords[index].defaultUVSOffset; 831 if (!defUVSOffset) { 832 return false; 833 } 834 835 const DefUVSTable* table = 836 reinterpret_cast<const DefUVSTable*>(aBuf + defUVSOffset); 837 838 if (BinarySearchIf(DefUVSTableWrapper(*table), 0, 839 table->numUnicodeValueRanges, UnicodeRangeComparator(aCh), 840 &index)) { 841 return true; 842 } 843 844 return false; 845 } 846 847 uint32_t gfxFontUtils::MapCharToGlyph(const uint8_t* aCmapBuf, 848 uint32_t aBufLength, uint32_t aUnicode, 849 uint32_t aVarSelector) { 850 uint32_t offset, uvsOffset; 851 bool isSymbolFont; 852 uint32_t format = FindPreferredSubtable(aCmapBuf, aBufLength, &offset, 853 &uvsOffset, &isSymbolFont); 854 855 uint32_t gid; 856 switch (format) { 857 case 4: 858 gid = aUnicode < UNICODE_BMP_LIMIT 859 ? MapCharToGlyphFormat4(aCmapBuf + offset, aBufLength - offset, 860 char16_t(aUnicode)) 861 : 0; 862 if (!gid && isSymbolFont) { 863 if (auto pua = MapLegacySymbolFontCharToPUA(aUnicode)) { 864 gid = MapCharToGlyphFormat4(aCmapBuf + offset, aBufLength - offset, 865 pua); 866 } 867 } 868 break; 869 case 10: 870 gid = MapCharToGlyphFormat10(aCmapBuf + offset, aUnicode); 871 break; 872 case 12: 873 case 13: 874 gid = MapCharToGlyphFormat12or13(aCmapBuf + offset, aUnicode); 875 break; 876 default: 877 NS_WARNING("unsupported cmap format, glyphs will be missing"); 878 gid = 0; 879 } 880 881 if (aVarSelector && uvsOffset && gid) { 882 uint32_t varGID = gfxFontUtils::MapUVSToGlyphFormat14( 883 aCmapBuf + uvsOffset, aUnicode, aVarSelector); 884 if (!varGID) { 885 aUnicode = gfxFontUtils::GetUVSFallback(aUnicode, aVarSelector); 886 if (aUnicode) { 887 switch (format) { 888 case 4: 889 if (aUnicode < UNICODE_BMP_LIMIT) { 890 varGID = MapCharToGlyphFormat4( 891 aCmapBuf + offset, aBufLength - offset, char16_t(aUnicode)); 892 } 893 break; 894 case 10: 895 varGID = MapCharToGlyphFormat10(aCmapBuf + offset, aUnicode); 896 break; 897 case 12: 898 case 13: 899 varGID = MapCharToGlyphFormat12or13(aCmapBuf + offset, aUnicode); 900 break; 901 } 902 } 903 } 904 if (varGID) { 905 gid = varGID; 906 } 907 908 // else the variation sequence was not supported, use default mapping 909 // of the character code alone 910 } 911 912 return gid; 913 } 914 915 void gfxFontUtils::ParseFontList(const nsACString& aFamilyList, 916 nsTArray<nsCString>& aFontList) { 917 const char kComma = ','; 918 919 // append each font name to the list 920 nsAutoCString fontname; 921 const char *p, *p_end; 922 aFamilyList.BeginReading(p); 923 aFamilyList.EndReading(p_end); 924 925 while (p < p_end) { 926 const char* nameStart = p; 927 while (++p != p_end && *p != kComma) /* nothing */ 928 ; 929 930 // pull out a single name and clean out leading/trailing whitespace 931 fontname = Substring(nameStart, p); 932 fontname.CompressWhitespace(true, true); 933 934 // append it to the list if it's not empty 935 if (!fontname.IsEmpty()) { 936 aFontList.AppendElement(fontname); 937 } 938 ++p; 939 } 940 } 941 942 void gfxFontUtils::GetPrefsFontList(const char* aPrefName, 943 nsTArray<nsCString>& aFontList) { 944 aFontList.Clear(); 945 946 nsAutoCString fontlistValue; 947 nsresult rv = Preferences::GetCString(aPrefName, fontlistValue); 948 if (NS_FAILED(rv)) { 949 return; 950 } 951 952 ParseFontList(fontlistValue, aFontList); 953 } 954 955 // produce a unique font name that is (1) a valid Postscript name and (2) less 956 // than 31 characters in length. Using AddFontMemResourceEx on Windows fails 957 // for names longer than 30 characters in length. 958 959 constexpr uint32_t MAX_B64_LEN = 32; 960 961 nsresult gfxFontUtils::MakeUniqueUserFontName(nsAString& aName) { 962 nsCOMPtr<nsIUUIDGenerator> uuidgen = 963 do_GetService("@mozilla.org/uuid-generator;1"); 964 NS_ENSURE_TRUE(uuidgen, NS_ERROR_OUT_OF_MEMORY); 965 966 nsID guid; 967 968 NS_ASSERTION(sizeof(guid) * 2 <= MAX_B64_LEN, "size of nsID has changed!"); 969 970 nsresult rv = uuidgen->GenerateUUIDInPlace(&guid); 971 NS_ENSURE_SUCCESS(rv, rv); 972 973 char guidB64[MAX_B64_LEN]; 974 975 if (NS_FAILED(mozilla::Base64Encode(reinterpret_cast<char*>(&guid), 976 sizeof(guid), guidB64))) 977 return NS_ERROR_FAILURE; 978 979 // all b64 characters except for '/' are allowed in Postscript names, so 980 // convert / ==> - 981 char* p; 982 for (p = guidB64; *p; p++) { 983 if (*p == '/') *p = '-'; 984 } 985 986 aName.AssignLiteral(u"uf"); 987 aName.AppendASCII(guidB64); 988 return NS_OK; 989 } 990 991 // TrueType/OpenType table handling code 992 993 // need byte aligned structs 994 #pragma pack(1) 995 996 // name table stores set of name record structures, followed by 997 // large block containing all the strings. name record offset and length 998 // indicates the offset and length within that block. 999 // http://www.microsoft.com/typography/otspec/name.htm 1000 struct NameRecordData { 1001 uint32_t offset; 1002 uint32_t length; 1003 }; 1004 1005 #pragma pack() 1006 1007 static bool IsValidSFNTVersion(uint32_t version) { 1008 // normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 1009 // 'true' 'typ1' is also possible for old Type 1 fonts in a SFNT container but 1010 // not supported 1011 return version == 0x10000 || version == TRUETYPE_TAG('O', 'T', 'T', 'O') || 1012 version == TRUETYPE_TAG('t', 'r', 'u', 'e'); 1013 } 1014 1015 gfxUserFontType gfxFontUtils::DetermineFontDataType(const uint8_t* aFontData, 1016 uint32_t aFontDataLength) { 1017 // test for OpenType font data 1018 // problem: EOT-Lite with 0x10000 length will look like TrueType! 1019 if (aFontDataLength >= sizeof(SFNTHeader)) { 1020 const SFNTHeader* sfntHeader = 1021 reinterpret_cast<const SFNTHeader*>(aFontData); 1022 uint32_t sfntVersion = sfntHeader->sfntVersion; 1023 if (IsValidSFNTVersion(sfntVersion)) { 1024 return GFX_USERFONT_OPENTYPE; 1025 } 1026 } 1027 1028 // test for WOFF or WOFF2 1029 if (aFontDataLength >= sizeof(AutoSwap_PRUint32)) { 1030 const AutoSwap_PRUint32* version = 1031 reinterpret_cast<const AutoSwap_PRUint32*>(aFontData); 1032 if (uint32_t(*version) == TRUETYPE_TAG('w', 'O', 'F', 'F')) { 1033 return GFX_USERFONT_WOFF; 1034 } 1035 if (uint32_t(*version) == TRUETYPE_TAG('w', 'O', 'F', '2')) { 1036 return GFX_USERFONT_WOFF2; 1037 } 1038 } 1039 1040 // tests for other formats here 1041 1042 return GFX_USERFONT_UNKNOWN; 1043 } 1044 1045 static int DirEntryCmp(const void* aKey, const void* aItem) { 1046 int32_t tag = *static_cast<const int32_t*>(aKey); 1047 const TableDirEntry* entry = static_cast<const TableDirEntry*>(aItem); 1048 return tag - int32_t(entry->tag); 1049 } 1050 1051 /* static */ 1052 TableDirEntry* gfxFontUtils::FindTableDirEntry(const void* aFontData, 1053 uint32_t aTableTag) { 1054 const SFNTHeader* header = reinterpret_cast<const SFNTHeader*>(aFontData); 1055 const TableDirEntry* dir = reinterpret_cast<const TableDirEntry*>(header + 1); 1056 return static_cast<TableDirEntry*>( 1057 bsearch(&aTableTag, dir, uint16_t(header->numTables), 1058 sizeof(TableDirEntry), DirEntryCmp)); 1059 } 1060 1061 /* static */ 1062 hb_blob_t* gfxFontUtils::GetTableFromFontData(const void* aFontData, 1063 uint32_t aTableTag) { 1064 const TableDirEntry* dir = FindTableDirEntry(aFontData, aTableTag); 1065 if (dir) { 1066 return hb_blob_create( 1067 reinterpret_cast<const char*>(aFontData) + dir->offset, dir->length, 1068 HB_MEMORY_MODE_READONLY, nullptr, nullptr); 1069 } 1070 return nullptr; 1071 } 1072 1073 nsresult gfxFontUtils::RenameFont(const nsAString& aName, 1074 const uint8_t* aFontData, 1075 uint32_t aFontDataLength, 1076 FallibleTArray<uint8_t>* aNewFont) { 1077 NS_ASSERTION(aNewFont, "null font data array"); 1078 1079 uint64_t dataLength(aFontDataLength); 1080 1081 // new name table 1082 static const uint32_t neededNameIDs[] = {NAME_ID_FAMILY, NAME_ID_STYLE, 1083 NAME_ID_UNIQUE, NAME_ID_FULL, 1084 NAME_ID_POSTSCRIPT}; 1085 1086 // calculate new name table size 1087 uint16_t nameCount = std::size(neededNameIDs); 1088 1089 // leave room for null-terminator 1090 uint32_t nameStrLength = (aName.Length() + 1) * sizeof(char16_t); 1091 if (nameStrLength > 65535) { 1092 // The name length _in bytes_ must fit in an unsigned short field; 1093 // therefore, a name longer than this cannot be used. 1094 return NS_ERROR_FAILURE; 1095 } 1096 1097 // round name table size up to 4-byte multiple 1098 uint32_t nameTableSize = 1099 (sizeof(NameHeader) + sizeof(NameRecord) * nameCount + nameStrLength + 1100 3) & 1101 ~3; 1102 1103 if (dataLength + nameTableSize > UINT32_MAX) return NS_ERROR_FAILURE; 1104 1105 // bug 505386 - need to handle unpadded font length 1106 uint32_t paddedFontDataSize = (aFontDataLength + 3) & ~3; 1107 uint32_t adjFontDataSize = paddedFontDataSize + nameTableSize; 1108 1109 // create new buffer: old font data plus new name table 1110 if (!aNewFont->AppendElements(adjFontDataSize, fallible)) 1111 return NS_ERROR_OUT_OF_MEMORY; 1112 1113 // copy the old font data 1114 uint8_t* newFontData = reinterpret_cast<uint8_t*>(aNewFont->Elements()); 1115 1116 // null the last four bytes in case the font length is not a multiple of 4 1117 memset(newFontData + aFontDataLength, 0, 1118 paddedFontDataSize - aFontDataLength); 1119 1120 // copy font data 1121 memcpy(newFontData, aFontData, aFontDataLength); 1122 1123 // null out the last 4 bytes for checksum calculations 1124 memset(newFontData + adjFontDataSize - 4, 0, 4); 1125 1126 NameHeader* nameHeader = 1127 reinterpret_cast<NameHeader*>(newFontData + paddedFontDataSize); 1128 1129 // -- name header 1130 nameHeader->format = 0; 1131 nameHeader->count = nameCount; 1132 nameHeader->stringOffset = 1133 sizeof(NameHeader) + nameCount * sizeof(NameRecord); 1134 1135 // -- name records 1136 uint32_t i; 1137 NameRecord* nameRecord = reinterpret_cast<NameRecord*>(nameHeader + 1); 1138 1139 for (i = 0; i < nameCount; i++, nameRecord++) { 1140 nameRecord->platformID = PLATFORM_ID_MICROSOFT; 1141 nameRecord->encodingID = ENCODING_ID_MICROSOFT_UNICODEBMP; 1142 nameRecord->languageID = LANG_ID_MICROSOFT_EN_US; 1143 nameRecord->nameID = neededNameIDs[i]; 1144 nameRecord->offset = 0; 1145 nameRecord->length = nameStrLength; 1146 } 1147 1148 // -- string data, located after the name records, stored in big-endian form 1149 char16_t* strData = reinterpret_cast<char16_t*>(nameRecord); 1150 1151 mozilla::NativeEndian::copyAndSwapToBigEndian(strData, aName.BeginReading(), 1152 aName.Length()); 1153 strData[aName.Length()] = 0; // add null termination 1154 1155 // adjust name table header to point to the new name table 1156 SFNTHeader* sfntHeader = reinterpret_cast<SFNTHeader*>(newFontData); 1157 1158 // table directory entries begin immediately following SFNT header 1159 TableDirEntry* dirEntry = 1160 FindTableDirEntry(newFontData, TRUETYPE_TAG('n', 'a', 'm', 'e')); 1161 // function only called if font validates, so this should always be true 1162 MOZ_ASSERT(dirEntry, "attempt to rename font with no name table"); 1163 1164 uint32_t numTables = sfntHeader->numTables; 1165 1166 // note: dirEntry now points to 'name' table record 1167 1168 // recalculate name table checksum 1169 uint32_t checkSum = 0; 1170 AutoSwap_PRUint32* nameData = 1171 reinterpret_cast<AutoSwap_PRUint32*>(nameHeader); 1172 AutoSwap_PRUint32* nameDataEnd = nameData + (nameTableSize >> 2); 1173 1174 while (nameData < nameDataEnd) checkSum = checkSum + *nameData++; 1175 1176 // adjust name table entry to point to new name table 1177 dirEntry->offset = paddedFontDataSize; 1178 dirEntry->length = nameTableSize; 1179 dirEntry->checkSum = checkSum; 1180 1181 // fix up checksums 1182 uint32_t checksum = 0; 1183 1184 // checksum for font = (checksum of header) + (checksum of tables) 1185 uint32_t headerLen = sizeof(SFNTHeader) + sizeof(TableDirEntry) * numTables; 1186 const AutoSwap_PRUint32* headerData = 1187 reinterpret_cast<const AutoSwap_PRUint32*>(newFontData); 1188 1189 // header length is in bytes, checksum calculated in longwords 1190 for (i = 0; i < (headerLen >> 2); i++, headerData++) { 1191 checksum += *headerData; 1192 } 1193 1194 uint32_t headOffset = 0; 1195 dirEntry = reinterpret_cast<TableDirEntry*>(newFontData + sizeof(SFNTHeader)); 1196 1197 for (i = 0; i < numTables; i++, dirEntry++) { 1198 if (dirEntry->tag == TRUETYPE_TAG('h', 'e', 'a', 'd')) { 1199 headOffset = dirEntry->offset; 1200 } 1201 checksum += dirEntry->checkSum; 1202 } 1203 1204 NS_ASSERTION(headOffset != 0, "no head table for font"); 1205 1206 HeadTable* headData = reinterpret_cast<HeadTable*>(newFontData + headOffset); 1207 1208 headData->checkSumAdjustment = HeadTable::HEAD_CHECKSUM_CALC_CONST - checksum; 1209 1210 return NS_OK; 1211 } 1212 1213 // This is only called after the basic validity of the downloaded sfnt 1214 // data has been checked, so it should never fail to find the name table 1215 // (though it might fail to read it, if memory isn't available); 1216 // other checks here are just for extra paranoia. 1217 nsresult gfxFontUtils::GetFullNameFromSFNT(const uint8_t* aFontData, 1218 uint32_t aLength, 1219 nsACString& aFullName) { 1220 aFullName = "(MISSING NAME)"; // should always get replaced 1221 1222 const TableDirEntry* dirEntry = 1223 FindTableDirEntry(aFontData, TRUETYPE_TAG('n', 'a', 'm', 'e')); 1224 1225 // should never fail, as we're only called after font validation succeeded 1226 NS_ENSURE_TRUE(dirEntry, NS_ERROR_NOT_AVAILABLE); 1227 1228 uint32_t len = dirEntry->length; 1229 NS_ENSURE_TRUE(aLength > len && aLength - len >= dirEntry->offset, 1230 NS_ERROR_UNEXPECTED); 1231 1232 AutoHBBlob nameBlob(hb_blob_create((const char*)aFontData + dirEntry->offset, 1233 len, HB_MEMORY_MODE_READONLY, nullptr, 1234 nullptr)); 1235 nsresult rv = GetFullNameFromTable(nameBlob, aFullName); 1236 1237 return rv; 1238 } 1239 1240 nsresult gfxFontUtils::GetFullNameFromTable(hb_blob_t* aNameTable, 1241 nsACString& aFullName) { 1242 nsAutoCString name; 1243 nsresult rv = gfxFontUtils::ReadCanonicalName( 1244 aNameTable, gfxFontUtils::NAME_ID_FULL, name); 1245 if (NS_SUCCEEDED(rv) && !name.IsEmpty()) { 1246 aFullName = name; 1247 return NS_OK; 1248 } 1249 rv = gfxFontUtils::ReadCanonicalName(aNameTable, gfxFontUtils::NAME_ID_FAMILY, 1250 name); 1251 if (NS_SUCCEEDED(rv) && !name.IsEmpty()) { 1252 nsAutoCString styleName; 1253 rv = gfxFontUtils::ReadCanonicalName( 1254 aNameTable, gfxFontUtils::NAME_ID_STYLE, styleName); 1255 if (NS_SUCCEEDED(rv) && !styleName.IsEmpty()) { 1256 name.Append(' '); 1257 name.Append(styleName); 1258 aFullName = name; 1259 } 1260 return NS_OK; 1261 } 1262 1263 return NS_ERROR_NOT_AVAILABLE; 1264 } 1265 1266 nsresult gfxFontUtils::GetFamilyNameFromTable(hb_blob_t* aNameTable, 1267 nsACString& aFamilyName) { 1268 nsAutoCString name; 1269 nsresult rv = gfxFontUtils::ReadCanonicalName( 1270 aNameTable, gfxFontUtils::NAME_ID_FAMILY, name); 1271 if (NS_SUCCEEDED(rv) && !name.IsEmpty()) { 1272 aFamilyName = name; 1273 return NS_OK; 1274 } 1275 return NS_ERROR_NOT_AVAILABLE; 1276 } 1277 1278 enum { 1279 #if defined(XP_MACOSX) 1280 CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MAC_ENGLISH, 1281 PLATFORM_ID = gfxFontUtils::PLATFORM_ID_MAC 1282 #else 1283 CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MICROSOFT_EN_US, 1284 PLATFORM_ID = gfxFontUtils::PLATFORM_ID_MICROSOFT 1285 #endif 1286 }; 1287 1288 nsresult gfxFontUtils::ReadNames(const char* aNameData, uint32_t aDataLen, 1289 uint32_t aNameID, int32_t aPlatformID, 1290 nsTArray<nsCString>& aNames) { 1291 return ReadNames(aNameData, aDataLen, aNameID, LANG_ALL, aPlatformID, aNames); 1292 } 1293 1294 nsresult gfxFontUtils::ReadCanonicalName(hb_blob_t* aNameTable, 1295 uint32_t aNameID, nsCString& aName) { 1296 uint32_t nameTableLen; 1297 const char* nameTable = hb_blob_get_data(aNameTable, &nameTableLen); 1298 return ReadCanonicalName(nameTable, nameTableLen, aNameID, aName); 1299 } 1300 1301 nsresult gfxFontUtils::ReadCanonicalName(const char* aNameData, 1302 uint32_t aDataLen, uint32_t aNameID, 1303 nsCString& aName) { 1304 nsresult rv; 1305 1306 nsTArray<nsCString> names; 1307 1308 // first, look for the English name (this will succeed 99% of the time) 1309 rv = ReadNames(aNameData, aDataLen, aNameID, CANONICAL_LANG_ID, PLATFORM_ID, 1310 names); 1311 NS_ENSURE_SUCCESS(rv, rv); 1312 1313 // otherwise, grab names for all languages 1314 if (names.Length() == 0) { 1315 rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ALL, PLATFORM_ID, names); 1316 NS_ENSURE_SUCCESS(rv, rv); 1317 } 1318 1319 #if defined(XP_MACOSX) 1320 // may be dealing with font that only has Microsoft name entries 1321 if (names.Length() == 0) { 1322 rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ID_MICROSOFT_EN_US, 1323 PLATFORM_ID_MICROSOFT, names); 1324 NS_ENSURE_SUCCESS(rv, rv); 1325 1326 // getting really desperate now, take anything! 1327 if (names.Length() == 0) { 1328 rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ALL, 1329 PLATFORM_ID_MICROSOFT, names); 1330 NS_ENSURE_SUCCESS(rv, rv); 1331 } 1332 } 1333 #endif 1334 1335 // return the first name (99.9% of the time names will 1336 // contain a single English name) 1337 if (names.Length()) { 1338 aName.Assign(names[0]); 1339 return NS_OK; 1340 } 1341 1342 return NS_ERROR_FAILURE; 1343 } 1344 1345 // Charsets to use for decoding Mac platform font names. 1346 // This table is sorted by {encoding, language}, with the wildcard "ANY" being 1347 // greater than any defined values for each field; we use a binary search on 1348 // both fields, and fall back to matching only encoding if necessary 1349 1350 // Some "redundant" entries for specific combinations are included such as 1351 // encoding=roman, lang=english, in order that common entries will be found 1352 // on the first search. 1353 1354 const uint16_t ANY = 0xffff; 1355 MOZ_RUNINIT const gfxFontUtils::MacFontNameCharsetMapping 1356 gfxFontUtils::gMacFontNameCharsets[] = { 1357 {ENCODING_ID_MAC_ROMAN, LANG_ID_MAC_ENGLISH, MACINTOSH_ENCODING}, 1358 {ENCODING_ID_MAC_ROMAN, LANG_ID_MAC_ICELANDIC, X_USER_DEFINED_ENCODING}, 1359 {ENCODING_ID_MAC_ROMAN, LANG_ID_MAC_TURKISH, X_USER_DEFINED_ENCODING}, 1360 {ENCODING_ID_MAC_ROMAN, LANG_ID_MAC_POLISH, X_USER_DEFINED_ENCODING}, 1361 {ENCODING_ID_MAC_ROMAN, LANG_ID_MAC_ROMANIAN, X_USER_DEFINED_ENCODING}, 1362 {ENCODING_ID_MAC_ROMAN, LANG_ID_MAC_CZECH, X_USER_DEFINED_ENCODING}, 1363 {ENCODING_ID_MAC_ROMAN, LANG_ID_MAC_SLOVAK, X_USER_DEFINED_ENCODING}, 1364 {ENCODING_ID_MAC_ROMAN, ANY, MACINTOSH_ENCODING}, 1365 {ENCODING_ID_MAC_JAPANESE, LANG_ID_MAC_JAPANESE, SHIFT_JIS_ENCODING}, 1366 {ENCODING_ID_MAC_JAPANESE, ANY, SHIFT_JIS_ENCODING}, 1367 {ENCODING_ID_MAC_TRAD_CHINESE, LANG_ID_MAC_TRAD_CHINESE, BIG5_ENCODING}, 1368 {ENCODING_ID_MAC_TRAD_CHINESE, ANY, BIG5_ENCODING}, 1369 {ENCODING_ID_MAC_KOREAN, LANG_ID_MAC_KOREAN, EUC_KR_ENCODING}, 1370 {ENCODING_ID_MAC_KOREAN, ANY, EUC_KR_ENCODING}, 1371 {ENCODING_ID_MAC_ARABIC, LANG_ID_MAC_ARABIC, X_USER_DEFINED_ENCODING}, 1372 {ENCODING_ID_MAC_ARABIC, LANG_ID_MAC_URDU, X_USER_DEFINED_ENCODING}, 1373 {ENCODING_ID_MAC_ARABIC, LANG_ID_MAC_FARSI, X_USER_DEFINED_ENCODING}, 1374 {ENCODING_ID_MAC_ARABIC, ANY, X_USER_DEFINED_ENCODING}, 1375 {ENCODING_ID_MAC_HEBREW, LANG_ID_MAC_HEBREW, X_USER_DEFINED_ENCODING}, 1376 {ENCODING_ID_MAC_HEBREW, ANY, X_USER_DEFINED_ENCODING}, 1377 {ENCODING_ID_MAC_GREEK, ANY, X_USER_DEFINED_ENCODING}, 1378 {ENCODING_ID_MAC_CYRILLIC, ANY, X_MAC_CYRILLIC_ENCODING}, 1379 {ENCODING_ID_MAC_DEVANAGARI, ANY, X_USER_DEFINED_ENCODING}, 1380 {ENCODING_ID_MAC_GURMUKHI, ANY, X_USER_DEFINED_ENCODING}, 1381 {ENCODING_ID_MAC_GUJARATI, ANY, X_USER_DEFINED_ENCODING}, 1382 {ENCODING_ID_MAC_SIMP_CHINESE, LANG_ID_MAC_SIMP_CHINESE, 1383 GB18030_ENCODING}, 1384 {ENCODING_ID_MAC_SIMP_CHINESE, ANY, GB18030_ENCODING}}; 1385 1386 MOZ_RUNINIT const Encoding* gfxFontUtils::gISOFontNameCharsets[] = { 1387 /* 0 */ WINDOWS_1252_ENCODING, /* US-ASCII */ 1388 /* 1 */ nullptr, /* spec says "ISO 10646" but does not specify encoding 1389 form! */ 1390 /* 2 */ WINDOWS_1252_ENCODING /* ISO-8859-1 */ 1391 }; 1392 1393 MOZ_RUNINIT const Encoding* gfxFontUtils::gMSFontNameCharsets[] = { 1394 /* [0] ENCODING_ID_MICROSOFT_SYMBOL */ UTF_16BE_ENCODING, 1395 /* [1] ENCODING_ID_MICROSOFT_UNICODEBMP */ UTF_16BE_ENCODING, 1396 /* [2] ENCODING_ID_MICROSOFT_SHIFTJIS */ SHIFT_JIS_ENCODING, 1397 /* [3] ENCODING_ID_MICROSOFT_PRC */ nullptr, 1398 /* [4] ENCODING_ID_MICROSOFT_BIG5 */ BIG5_ENCODING, 1399 /* [5] ENCODING_ID_MICROSOFT_WANSUNG */ nullptr, 1400 /* [6] ENCODING_ID_MICROSOFT_JOHAB */ nullptr, 1401 /* [7] reserved */ nullptr, 1402 /* [8] reserved */ nullptr, 1403 /* [9] reserved */ nullptr, 1404 /*[10] ENCODING_ID_MICROSOFT_UNICODEFULL */ UTF_16BE_ENCODING}; 1405 1406 struct MacCharsetMappingComparator { 1407 typedef gfxFontUtils::MacFontNameCharsetMapping MacFontNameCharsetMapping; 1408 const MacFontNameCharsetMapping& mSearchValue; 1409 explicit MacCharsetMappingComparator( 1410 const MacFontNameCharsetMapping& aSearchValue) 1411 : mSearchValue(aSearchValue) {} 1412 int operator()(const MacFontNameCharsetMapping& aEntry) const { 1413 if (mSearchValue < aEntry) { 1414 return -1; 1415 } 1416 if (aEntry < mSearchValue) { 1417 return 1; 1418 } 1419 return 0; 1420 } 1421 }; 1422 1423 // Return the Encoding object we should use to decode a font name 1424 // given the name table attributes. 1425 // Special return values: 1426 // X_USER_DEFINED_ENCODING One of Mac legacy encodings that is not a part 1427 // of Encoding Standard 1428 // nullptr unknown charset, do not attempt conversion 1429 const Encoding* gfxFontUtils::GetCharsetForFontName(uint16_t aPlatform, 1430 uint16_t aScript, 1431 uint16_t aLanguage) { 1432 switch (aPlatform) { 1433 case PLATFORM_ID_UNICODE: 1434 return UTF_16BE_ENCODING; 1435 1436 case PLATFORM_ID_MAC: { 1437 MacFontNameCharsetMapping searchValue = {aScript, aLanguage, nullptr}; 1438 for (uint32_t i = 0; i < 2; ++i) { 1439 size_t idx; 1440 if (BinarySearchIf(gMacFontNameCharsets, 0, 1441 std::size(gMacFontNameCharsets), 1442 MacCharsetMappingComparator(searchValue), &idx)) { 1443 return gMacFontNameCharsets[idx].mEncoding; 1444 } 1445 1446 // no match, so try again finding one in any language 1447 searchValue.mLanguage = ANY; 1448 } 1449 } break; 1450 1451 case PLATFORM_ID_ISO: 1452 if (aScript < std::size(gISOFontNameCharsets)) { 1453 return gISOFontNameCharsets[aScript]; 1454 } 1455 break; 1456 1457 case PLATFORM_ID_MICROSOFT: 1458 if (aScript < std::size(gMSFontNameCharsets)) { 1459 return gMSFontNameCharsets[aScript]; 1460 } 1461 break; 1462 } 1463 1464 return nullptr; 1465 } 1466 1467 template <int N> 1468 static bool StartsWith(const nsACString& string, const char (&prefix)[N]) { 1469 if (N - 1 > string.Length()) { 1470 return false; 1471 } 1472 return memcmp(string.Data(), prefix, N - 1) == 0; 1473 } 1474 1475 // convert a raw name from the name table to an nsString, if possible; 1476 // return value indicates whether conversion succeeded 1477 bool gfxFontUtils::DecodeFontName(const char* aNameData, int32_t aByteLen, 1478 uint32_t aPlatformCode, uint32_t aScriptCode, 1479 uint32_t aLangCode, nsACString& aName) { 1480 if (aByteLen <= 0) { 1481 NS_WARNING("empty font name"); 1482 aName.SetLength(0); 1483 return true; 1484 } 1485 1486 auto encoding = GetCharsetForFontName(aPlatformCode, aScriptCode, aLangCode); 1487 1488 if (!encoding) { 1489 // nullptr -> unknown charset 1490 #ifdef DEBUG 1491 char warnBuf[128]; 1492 if (aByteLen > 64) aByteLen = 64; 1493 SprintfLiteral(warnBuf, 1494 "skipping font name, unknown charset %d:%d:%d for <%.*s>", 1495 aPlatformCode, aScriptCode, aLangCode, aByteLen, aNameData); 1496 NS_WARNING(warnBuf); 1497 #endif 1498 return false; 1499 } 1500 1501 if (encoding == X_USER_DEFINED_ENCODING) { 1502 #ifdef XP_DARWIN 1503 // Special case for macOS only: support legacy Mac encodings 1504 // that aren't part of the Encoding Standard. 1505 if (aPlatformCode == PLATFORM_ID_MAC) { 1506 CFStringRef str = 1507 CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)aNameData, 1508 aByteLen, aScriptCode, false); 1509 if (str) { 1510 CFIndex length = CFStringGetLength(str); 1511 nsAutoString name16; 1512 name16.SetLength(length); 1513 CFStringGetCharacters(str, CFRangeMake(0, length), 1514 (UniChar*)name16.BeginWriting()); 1515 CFRelease(str); 1516 CopyUTF16toUTF8(name16, aName); 1517 return true; 1518 } 1519 } 1520 #endif 1521 NS_WARNING("failed to get the decoder for a font name string"); 1522 return false; 1523 } 1524 1525 auto rv = encoding->DecodeWithoutBOMHandling( 1526 nsDependentCSubstring(aNameData, aByteLen), aName); 1527 return NS_SUCCEEDED(rv); 1528 } 1529 1530 nsresult gfxFontUtils::ReadNames(const char* aNameData, uint32_t aDataLen, 1531 uint32_t aNameID, int32_t aLangID, 1532 int32_t aPlatformID, 1533 nsTArray<nsCString>& aNames) { 1534 NS_ASSERTION(aDataLen != 0, "null name table"); 1535 1536 if (!aDataLen) { 1537 return NS_ERROR_FAILURE; 1538 } 1539 1540 // -- name table data 1541 const NameHeader* nameHeader = reinterpret_cast<const NameHeader*>(aNameData); 1542 1543 uint32_t nameCount = nameHeader->count; 1544 1545 // -- sanity check the number of name records 1546 if (uint64_t(nameCount) * sizeof(NameRecord) > aDataLen) { 1547 NS_WARNING("invalid font (name table data)"); 1548 return NS_ERROR_FAILURE; 1549 } 1550 1551 // -- iterate through name records 1552 const NameRecord* nameRecord = 1553 reinterpret_cast<const NameRecord*>(aNameData + sizeof(NameHeader)); 1554 uint64_t nameStringsBase = uint64_t(nameHeader->stringOffset); 1555 1556 uint32_t i; 1557 for (i = 0; i < nameCount; i++, nameRecord++) { 1558 uint32_t platformID; 1559 1560 // skip over unwanted nameID's 1561 if (uint32_t(nameRecord->nameID) != aNameID) { 1562 continue; 1563 } 1564 1565 // skip over unwanted platform data 1566 platformID = nameRecord->platformID; 1567 if (aPlatformID != PLATFORM_ALL && platformID != uint32_t(aPlatformID)) { 1568 continue; 1569 } 1570 1571 // skip over unwanted languages 1572 if (aLangID != LANG_ALL && 1573 uint32_t(nameRecord->languageID) != uint32_t(aLangID)) { 1574 continue; 1575 } 1576 1577 // add name to names array 1578 1579 // -- calculate string location 1580 uint32_t namelen = nameRecord->length; 1581 uint32_t nameoff = 1582 nameRecord->offset; // offset from base of string storage 1583 1584 if (nameStringsBase + uint64_t(nameoff) + uint64_t(namelen) > aDataLen) { 1585 NS_WARNING("invalid font (name table strings)"); 1586 return NS_ERROR_FAILURE; 1587 } 1588 1589 // -- decode if necessary and make nsString 1590 nsAutoCString name; 1591 1592 DecodeFontName(aNameData + nameStringsBase + nameoff, namelen, platformID, 1593 uint32_t(nameRecord->encodingID), 1594 uint32_t(nameRecord->languageID), name); 1595 1596 uint32_t k, numNames; 1597 bool foundName = false; 1598 1599 numNames = aNames.Length(); 1600 for (k = 0; k < numNames; k++) { 1601 if (name.Equals(aNames[k])) { 1602 foundName = true; 1603 break; 1604 } 1605 } 1606 1607 if (!foundName) aNames.AppendElement(name); 1608 } 1609 1610 return NS_OK; 1611 } 1612 1613 void gfxFontUtils::GetVariationData( 1614 gfxFontEntry* aFontEntry, nsTArray<gfxFontVariationAxis>* aAxes, 1615 nsTArray<gfxFontVariationInstance>* aInstances) { 1616 MOZ_ASSERT(!aAxes || aAxes->IsEmpty()); 1617 MOZ_ASSERT(!aInstances || aInstances->IsEmpty()); 1618 1619 if (!aFontEntry->HasVariations()) { 1620 return; 1621 } 1622 1623 // Some platforms don't offer a simple API to return the list of instances, 1624 // so we have to interpret the 'fvar' table ourselves. 1625 1626 // https://www.microsoft.com/typography/otspec/fvar.htm#fvarHeader 1627 struct FvarHeader { 1628 AutoSwap_PRUint16 majorVersion; 1629 AutoSwap_PRUint16 minorVersion; 1630 AutoSwap_PRUint16 axesArrayOffset; 1631 AutoSwap_PRUint16 reserved; 1632 AutoSwap_PRUint16 axisCount; 1633 AutoSwap_PRUint16 axisSize; 1634 AutoSwap_PRUint16 instanceCount; 1635 AutoSwap_PRUint16 instanceSize; 1636 }; 1637 1638 // https://www.microsoft.com/typography/otspec/fvar.htm#variationAxisRecord 1639 struct AxisRecord { 1640 AutoSwap_PRUint32 axisTag; 1641 AutoSwap_PRInt32 minValue; 1642 AutoSwap_PRInt32 defaultValue; 1643 AutoSwap_PRInt32 maxValue; 1644 AutoSwap_PRUint16 flags; 1645 AutoSwap_PRUint16 axisNameID; 1646 }; 1647 const uint16_t HIDDEN_AXIS = 0x0001; // AxisRecord flags value 1648 1649 // https://www.microsoft.com/typography/otspec/fvar.htm#instanceRecord 1650 struct InstanceRecord { 1651 AutoSwap_PRUint16 subfamilyNameID; 1652 AutoSwap_PRUint16 flags; 1653 AutoSwap_PRInt32 coordinates[1]; // variable-size array [axisCount] 1654 // The variable-length 'coordinates' array may be followed by an 1655 // optional extra field 'postScriptNameID'. We can't directly 1656 // represent this in the struct, because its offset varies depending 1657 // on the number of axes present. 1658 // (Not currently used by our code here anyhow.) 1659 // AutoSwap_PRUint16 postScriptNameID; 1660 }; 1661 1662 // Load the two font tables we need as harfbuzz blobs; if either is absent, 1663 // just bail out. 1664 AutoHBBlob fvarTable( 1665 aFontEntry->GetFontTable(TRUETYPE_TAG('f', 'v', 'a', 'r'))); 1666 AutoHBBlob nameTable( 1667 aFontEntry->GetFontTable(TRUETYPE_TAG('n', 'a', 'm', 'e'))); 1668 if (!fvarTable || !nameTable) { 1669 return; 1670 } 1671 unsigned int len; 1672 const char* data = hb_blob_get_data(fvarTable, &len); 1673 if (len < sizeof(FvarHeader)) { 1674 return; 1675 } 1676 // Read the fields of the table header; bail out if it looks broken. 1677 auto fvar = reinterpret_cast<const FvarHeader*>(data); 1678 if (uint16_t(fvar->majorVersion) != 1 || uint16_t(fvar->minorVersion) != 0 || 1679 uint16_t(fvar->reserved) != 2) { 1680 return; 1681 } 1682 uint16_t axisCount = fvar->axisCount; 1683 uint16_t axisSize = fvar->axisSize; 1684 uint16_t instanceCount = fvar->instanceCount; 1685 uint16_t instanceSize = fvar->instanceSize; 1686 if (axisCount == 1687 0 || // no axes? 1688 // https://www.microsoft.com/typography/otspec/fvar.htm#axisSize 1689 axisSize != 20 || // required value for current table version 1690 // https://www.microsoft.com/typography/otspec/fvar.htm#instanceSize 1691 (instanceSize != axisCount * sizeof(int32_t) + 4 && 1692 instanceSize != axisCount * sizeof(int32_t) + 6)) { 1693 return; 1694 } 1695 // Check that axis array will not exceed table size 1696 uint16_t axesOffset = fvar->axesArrayOffset; 1697 if (axesOffset + uint32_t(axisCount) * axisSize > len) { 1698 return; 1699 } 1700 // Get pointer to the array of axis records 1701 auto axes = reinterpret_cast<const AxisRecord*>(data + axesOffset); 1702 // Get address of instance array, and check it doesn't overflow table size. 1703 // https://www.microsoft.com/typography/otspec/fvar.htm#axisAndInstanceArrays 1704 auto instData = data + axesOffset + axisCount * axisSize; 1705 if (instData + uint32_t(instanceCount) * instanceSize > data + len) { 1706 return; 1707 } 1708 if (aInstances) { 1709 aInstances->SetCapacity(instanceCount); 1710 for (unsigned i = 0; i < instanceCount; ++i, instData += instanceSize) { 1711 // Typed pointer to the current instance record, to read its fields. 1712 auto inst = reinterpret_cast<const InstanceRecord*>(instData); 1713 // Pointer to the coordinates array within the instance record. 1714 // This array has axisCount elements, and is included in instanceSize 1715 // (which depends on axisCount, and was validated above) so we know 1716 // access to coords[j] below will not be outside the table bounds. 1717 auto coords = &inst->coordinates[0]; 1718 gfxFontVariationInstance instance; 1719 uint16_t nameID = inst->subfamilyNameID; 1720 nsresult rv = ReadCanonicalName(nameTable, nameID, instance.mName); 1721 if (NS_FAILED(rv)) { 1722 // If no name was available for the instance, ignore it. 1723 continue; 1724 } 1725 instance.mValues.SetCapacity(axisCount); 1726 for (unsigned j = 0; j < axisCount; ++j) { 1727 gfxFontVariationValue value = {axes[j].axisTag, 1728 int32_t(coords[j]) / 65536.0f}; 1729 instance.mValues.AppendElement(value); 1730 } 1731 aInstances->AppendElement(std::move(instance)); 1732 } 1733 } 1734 if (aAxes) { 1735 aAxes->SetCapacity(axisCount); 1736 for (unsigned i = 0; i < axisCount; ++i) { 1737 if (uint16_t(axes[i].flags) & HIDDEN_AXIS) { 1738 continue; 1739 } 1740 gfxFontVariationAxis axis; 1741 axis.mTag = axes[i].axisTag; 1742 uint16_t nameID = axes[i].axisNameID; 1743 nsresult rv = ReadCanonicalName(nameTable, nameID, axis.mName); 1744 if (NS_FAILED(rv)) { 1745 axis.mName.Truncate(0); 1746 } 1747 // Convert values from 16.16 fixed-point to float 1748 axis.mMinValue = int32_t(axes[i].minValue) / 65536.0f; 1749 axis.mDefaultValue = int32_t(axes[i].defaultValue) / 65536.0f; 1750 axis.mMaxValue = int32_t(axes[i].maxValue) / 65536.0f; 1751 aAxes->AppendElement(axis); 1752 } 1753 } 1754 } 1755 1756 void gfxFontUtils::ReadOtherFamilyNamesForFace( 1757 const nsACString& aFamilyName, const char* aNameData, uint32_t aDataLength, 1758 nsTArray<nsCString>& aOtherFamilyNames, bool useFullName) { 1759 const NameHeader* nameHeader = reinterpret_cast<const NameHeader*>(aNameData); 1760 1761 uint32_t nameCount = nameHeader->count; 1762 if (nameCount * sizeof(NameRecord) > aDataLength) { 1763 NS_WARNING("invalid font (name records)"); 1764 return; 1765 } 1766 1767 const NameRecord* nameRecord = 1768 reinterpret_cast<const NameRecord*>(aNameData + sizeof(NameHeader)); 1769 uint32_t stringsBase = uint32_t(nameHeader->stringOffset); 1770 1771 for (uint32_t i = 0; i < nameCount; i++, nameRecord++) { 1772 uint32_t nameLen = nameRecord->length; 1773 uint32_t nameOff = 1774 nameRecord->offset; // offset from base of string storage 1775 1776 if (stringsBase + nameOff + nameLen > aDataLength) { 1777 NS_WARNING("invalid font (name table strings)"); 1778 return; 1779 } 1780 1781 uint16_t nameID = nameRecord->nameID; 1782 if ((useFullName && nameID == NAME_ID_FULL) || 1783 (!useFullName && 1784 (nameID == NAME_ID_FAMILY || nameID == NAME_ID_PREFERRED_FAMILY))) { 1785 nsAutoCString otherFamilyName; 1786 bool ok = DecodeFontName( 1787 aNameData + stringsBase + nameOff, nameLen, 1788 uint32_t(nameRecord->platformID), uint32_t(nameRecord->encodingID), 1789 uint32_t(nameRecord->languageID), otherFamilyName); 1790 // add if not same as canonical family name 1791 if (ok && otherFamilyName != aFamilyName && 1792 !aOtherFamilyNames.Contains(otherFamilyName)) { 1793 aOtherFamilyNames.AppendElement(otherFamilyName); 1794 } 1795 } 1796 } 1797 } 1798 1799 #ifdef XP_WIN 1800 1801 /* static */ 1802 bool gfxFontUtils::IsCffFont(const uint8_t* aFontData) { 1803 // this is only called after aFontData has passed basic validation, 1804 // so we know there is enough data present to allow us to read the version! 1805 const SFNTHeader* sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData); 1806 return (sfntHeader->sfntVersion == TRUETYPE_TAG('O', 'T', 'T', 'O')); 1807 } 1808 1809 #endif 1810 1811 /* static */ bool gfxFontUtils::IsInServoTraversal() { 1812 if (NS_IsMainThread()) { 1813 return ServoStyleSet::IsInServoTraversal(); 1814 } 1815 1816 if (dom::GetCurrentThreadWorkerPrivate()) { 1817 return false; 1818 } 1819 1820 // The only permissible threads are the main thread, the worker thread, the 1821 // servo threads. If the latter, we must be traversing. 1822 bool traversing = ServoStyleSet::IsInServoTraversal(); 1823 MOZ_ASSERT(traversing); 1824 return traversing; 1825 } 1826 1827 /* static */ ServoStyleSet* gfxFontUtils::CurrentServoStyleSet() { 1828 // If we are on a worker thread, we must not check for the current set since 1829 // the main/servo threads may be busy in parallel. 1830 if (dom::GetCurrentThreadWorkerPrivate()) { 1831 return nullptr; 1832 } 1833 1834 return ServoStyleSet::Current(); 1835 } 1836 1837 #ifdef DEBUG 1838 /* static */ void gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked() { 1839 if (!dom::GetCurrentThreadWorkerPrivate()) { 1840 AssertIsMainThreadOrServoFontMetricsLocked(); 1841 } 1842 } 1843 #endif 1844 1845 #undef acceptablePlatform 1846 #undef isSymbol 1847 #undef isUVSEncoding 1848 #undef LOG 1849 #undef LOG_ENABLED