1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "minikin/CmapCoverage.h" 18 19 #include <random> 20 21 #include <gtest/gtest.h> 22 #include <log/log.h> 23 24 #include "minikin/SparseBitSet.h" 25 26 #include "MinikinInternal.h" 27 28 namespace minikin { 29 30 static constexpr uint16_t VS_PLATFORM_ID = 0; 31 static constexpr uint16_t VS_ENCODING_ID = 5; 32 33 size_t writeU8(uint8_t x, uint8_t* out, size_t offset) { 34 out[offset] = x; 35 return offset + 1; 36 } 37 38 size_t writeU16(uint16_t x, uint8_t* out, size_t offset) { 39 out[offset] = x >> 8; 40 out[offset + 1] = x; 41 return offset + 2; 42 } 43 44 size_t writeI16(int16_t sx, uint8_t* out, size_t offset) { 45 return writeU16(static_cast<uint16_t>(sx), out, offset); 46 } 47 48 size_t writeU24(uint32_t x, uint8_t* out, size_t offset) { 49 out[offset] = x >> 16; 50 out[offset + 1] = x >> 8; 51 out[offset + 2] = x; 52 return offset + 3; 53 } 54 55 size_t writeU32(uint32_t x, uint8_t* out, size_t offset) { 56 out[offset] = x >> 24; 57 out[offset + 1] = x >> 16; 58 out[offset + 2] = x >> 8; 59 out[offset + 3] = x; 60 return offset + 4; 61 } 62 63 // Returns valid cmap format 4 table contents. All glyph ID is same value as code point. (e.g. 64 // 'a' (U+0061) is mapped to Glyph ID = 0x0061). 65 // 'range' should be specified with inclusive-inclusive values. 66 static std::vector<uint8_t> buildCmapFormat4Table(const std::vector<uint16_t>& ranges) { 67 uint16_t segmentCount = ranges.size() / 2 + 1 /* +1 for end marker */; 68 69 const size_t numOfUint16 = 8 /* format, length, languages, segCountX2, searchRange, 70 entrySelector, rangeShift, pad */ 71 + 72 segmentCount * 4 /* endCount, startCount, idRange, idRangeOffset */; 73 const size_t finalLength = sizeof(uint16_t) * numOfUint16; 74 75 std::vector<uint8_t> out(finalLength); 76 size_t head = 0; 77 head = writeU16(4, out.data(), head); // format 78 head = writeU16(finalLength, out.data(), head); // length 79 head = writeU16(0, out.data(), head); // langauge 80 81 const uint16_t searchRange = 2 * (1 << static_cast<int>(floor(log2(segmentCount)))); 82 83 head = writeU16(segmentCount * 2, out.data(), head); // segCountX2 84 head = writeU16(searchRange, out.data(), head); // searchRange 85 head = writeU16(__builtin_ctz(searchRange) - 1, out.data(), head); // entrySelector 86 head = writeU16(segmentCount * 2 - searchRange, out.data(), head); // rangeShift 87 88 size_t endCountHead = head; 89 size_t startCountHead = head + segmentCount * sizeof(uint16_t) + 2 /* padding */; 90 size_t idDeltaHead = startCountHead + segmentCount * sizeof(uint16_t); 91 size_t idRangeOffsetHead = idDeltaHead + segmentCount * sizeof(uint16_t); 92 93 for (size_t i = 0; i < ranges.size() / 2; ++i) { 94 const uint16_t begin = ranges[i * 2]; 95 const uint16_t end = ranges[i * 2 + 1]; 96 startCountHead = writeU16(begin, out.data(), startCountHead); 97 endCountHead = writeU16(end, out.data(), endCountHead); 98 // map glyph ID as the same value of the code point. 99 idDeltaHead = writeU16(0, out.data(), idDeltaHead); 100 idRangeOffsetHead = writeU16(0 /* we don't use this */, out.data(), idRangeOffsetHead); 101 } 102 103 // fill end marker 104 endCountHead = writeU16(0xFFFF, out.data(), endCountHead); 105 startCountHead = writeU16(0xFFFF, out.data(), startCountHead); 106 idDeltaHead = writeU16(1, out.data(), idDeltaHead); 107 idRangeOffsetHead = writeU16(0, out.data(), idRangeOffsetHead); 108 LOG_ALWAYS_FATAL_IF(endCountHead > finalLength); 109 LOG_ALWAYS_FATAL_IF(startCountHead > finalLength); 110 LOG_ALWAYS_FATAL_IF(idDeltaHead > finalLength); 111 LOG_ALWAYS_FATAL_IF(idRangeOffsetHead != finalLength); 112 return out; 113 } 114 115 // Returns valid cmap format 4 table contents. All glyph ID is same value as code point. (e.g. 116 // 'a' (U+0061) is mapped to Glyph ID = 0x0061). 117 // 'range' should be specified with inclusive-inclusive values. 118 static std::vector<uint8_t> buildCmapFormat12Table(const std::vector<uint32_t>& ranges) { 119 uint32_t numGroups = ranges.size() / 2; 120 121 const size_t finalLength = 2 /* format */ + 2 /* reserved */ + 4 /* length */ + 122 4 /* languages */ + 4 /* numGroups */ + 123 12 /* size of a group */ * numGroups; 124 125 std::vector<uint8_t> out(finalLength); 126 size_t head = 0; 127 head = writeU16(12, out.data(), head); // format 128 head = writeU16(0, out.data(), head); // reserved 129 head = writeU32(finalLength, out.data(), head); // length 130 head = writeU32(0, out.data(), head); // langauge 131 head = writeU32(numGroups, out.data(), head); // numGroups 132 133 for (uint32_t i = 0; i < numGroups; ++i) { 134 const uint32_t start = ranges[2 * i]; 135 const uint32_t end = ranges[2 * i + 1]; 136 head = writeU32(start, out.data(), head); 137 head = writeU32(end, out.data(), head); 138 // map glyph ID as the same value of the code point. 139 // TODO: Use glyph IDs lower than 65535. 140 // Cmap can store 32 bit glyph ID but due to the size of numGlyph, a font file can contain 141 // up to 65535 glyphs in a file. 142 head = writeU32(start, out.data(), head); 143 } 144 145 LOG_ALWAYS_FATAL_IF(head != finalLength); 146 return out; 147 } 148 149 struct VariationSelectorRecord { 150 uint32_t codePoint; 151 std::vector<uint32_t> defaultUVSRanges; 152 std::vector<uint32_t> nonDefaultUVS; 153 154 std::vector<uint8_t> getDefaultUVSAsBinary() const { 155 if (defaultUVSRanges.empty()) { 156 return std::vector<uint8_t>(); 157 } 158 const size_t numOfRanges = defaultUVSRanges.size() / 2; 159 const size_t length = sizeof(uint32_t) /* numUnicodeValueRanges */ + 160 numOfRanges * 4 /* size of Unicode Range Table */; 161 162 std::vector<uint8_t> out(length); 163 size_t head = 0; 164 head = writeU32(numOfRanges, out.data(), head); 165 for (size_t i = 0; i < numOfRanges; ++i) { 166 const uint32_t startUnicodeValue = defaultUVSRanges[i * 2]; 167 const uint32_t endUnicodeValue = defaultUVSRanges[i * 2 + 1]; 168 head = writeU24(startUnicodeValue, out.data(), head); 169 head = writeU8(endUnicodeValue - startUnicodeValue, out.data(), head); 170 } 171 LOG_ALWAYS_FATAL_IF(head != length); 172 return out; 173 } 174 175 std::vector<uint8_t> getNonDefaultUVSAsBinary() const { 176 if (nonDefaultUVS.empty()) { 177 return std::vector<uint8_t>(); 178 } 179 const size_t length = sizeof(uint32_t) /* numUnicodeValueRanges */ + 180 nonDefaultUVS.size() * 5 /* size of UVS Mapping Record */; 181 182 std::vector<uint8_t> out(length); 183 size_t head = 0; 184 head = writeU32(nonDefaultUVS.size(), out.data(), head); 185 for (uint32_t codePoint : nonDefaultUVS) { 186 head = writeU24(codePoint, out.data(), head); 187 head = writeU16(4 /* fixed glyph id */, out.data(), head); 188 } 189 LOG_ALWAYS_FATAL_IF(head != length); 190 return out; 191 } 192 }; 193 194 static std::vector<uint8_t> buildCmapFormat14Table( 195 const std::vector<VariationSelectorRecord>& vsRecords) { 196 const size_t headerLength = sizeof(uint16_t) /* format */ + sizeof(uint32_t) /* length */ + 197 sizeof(uint32_t) /* numVarSelectorRecords */ + 198 11 /* size of variation selector record */ * vsRecords.size(); 199 200 std::vector<uint8_t> out(headerLength); 201 size_t head = 0; 202 head = writeU16(14, out.data(), head); // format 203 head += sizeof(uint32_t); // length will be filled later 204 head = writeU32(vsRecords.size(), out.data(), head); // numVarSelectorRecords; 205 206 for (const auto& record : vsRecords) { 207 const uint32_t vsCodePoint = record.codePoint; 208 head = writeU24(vsCodePoint, out.data(), head); 209 210 std::vector<uint8_t> defaultUVS = record.getDefaultUVSAsBinary(); 211 if (defaultUVS.empty()) { 212 head = writeU32(0, out.data(), head); 213 } else { 214 head = writeU32(out.size(), out.data(), head); 215 out.insert(out.end(), defaultUVS.begin(), defaultUVS.end()); 216 } 217 218 std::vector<uint8_t> nonDefaultUVS = record.getNonDefaultUVSAsBinary(); 219 if (nonDefaultUVS.empty()) { 220 head = writeU32(0, out.data(), head); 221 } else { 222 head = writeU32(out.size(), out.data(), head); 223 out.insert(out.end(), nonDefaultUVS.begin(), nonDefaultUVS.end()); 224 } 225 } 226 LOG_ALWAYS_FATAL_IF(head != headerLength); 227 writeU32(out.size(), out.data(), 2); // fill the length. 228 return out; 229 } 230 231 class CmapBuilder { 232 public: 233 static constexpr size_t kEncodingTableHead = 4; 234 static constexpr size_t kEncodingTableSize = 8; 235 236 CmapBuilder(int numTables) : mNumTables(numTables), mCurrentTableIndex(0) { 237 const size_t headerSize = 238 2 /* version */ + 2 /* numTables */ + kEncodingTableSize * numTables; 239 out.resize(headerSize); 240 writeU16(0, out.data(), 0); 241 writeU16(numTables, out.data(), 2); 242 } 243 244 void appendTable(uint16_t platformId, uint16_t encodingId, const std::vector<uint8_t>& table) { 245 appendEncodingTable(platformId, encodingId, out.size()); 246 out.insert(out.end(), table.begin(), table.end()); 247 } 248 249 std::vector<uint8_t> build() { 250 LOG_ALWAYS_FATAL_IF(mCurrentTableIndex != mNumTables); 251 return out; 252 } 253 254 // Helper functions. 255 static std::vector<uint8_t> buildSingleFormat4Cmap(uint16_t platformId, uint16_t encodingId, 256 const std::vector<uint16_t>& ranges) { 257 CmapBuilder builder(1); 258 builder.appendTable(platformId, encodingId, buildCmapFormat4Table(ranges)); 259 return builder.build(); 260 } 261 262 static std::vector<uint8_t> buildSingleFormat12Cmap(uint16_t platformId, uint16_t encodingId, 263 const std::vector<uint32_t>& ranges) { 264 CmapBuilder builder(1); 265 builder.appendTable(platformId, encodingId, buildCmapFormat12Table(ranges)); 266 return builder.build(); 267 } 268 269 private: 270 void appendEncodingTable(uint16_t platformId, uint16_t encodingId, uint32_t offset) { 271 LOG_ALWAYS_FATAL_IF(mCurrentTableIndex == mNumTables); 272 273 const size_t currentEncodingTableHead = 274 kEncodingTableHead + mCurrentTableIndex * kEncodingTableSize; 275 size_t head = writeU16(platformId, out.data(), currentEncodingTableHead); 276 head = writeU16(encodingId, out.data(), head); 277 head = writeU32(offset, out.data(), head); 278 LOG_ALWAYS_FATAL_IF((head - currentEncodingTableHead) != kEncodingTableSize); 279 mCurrentTableIndex++; 280 } 281 282 int mNumTables; 283 int mCurrentTableIndex; 284 std::vector<uint8_t> out; 285 }; 286 287 TEST(CmapCoverageTest, SingleFormat4_brokenCmap) { 288 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 289 { 290 SCOPED_TRACE("Reading beyond buffer size - Too small cmap size"); 291 std::vector<uint8_t> cmap = 292 CmapBuilder::buildSingleFormat4Cmap(0, 0, std::vector<uint16_t>({'a', 'a'})); 293 294 SparseBitSet coverage = 295 CmapCoverage::getCoverage(cmap.data(), 3 /* too small */, &vsTables); 296 EXPECT_EQ(0U, coverage.length()); 297 EXPECT_TRUE(vsTables.empty()); 298 } 299 { 300 SCOPED_TRACE("Reading beyond buffer size - space needed for tables goes beyond cmap size"); 301 std::vector<uint8_t> cmap = 302 CmapBuilder::buildSingleFormat4Cmap(0, 0, std::vector<uint16_t>({'a', 'a'})); 303 304 writeU16(1000, cmap.data(), 2 /* offset of num tables in cmap header */); 305 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 306 EXPECT_EQ(0U, coverage.length()); 307 EXPECT_TRUE(vsTables.empty()); 308 } 309 { 310 SCOPED_TRACE("Reading beyond buffer size - Invalid offset in encoding table"); 311 std::vector<uint8_t> cmap = 312 CmapBuilder::buildSingleFormat4Cmap(0, 0, std::vector<uint16_t>({'a', 'a'})); 313 314 writeU16(1000, cmap.data(), 8 /* offset of the offset in the first encoding record */); 315 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 316 EXPECT_EQ(0U, coverage.length()); 317 EXPECT_TRUE(vsTables.empty()); 318 } 319 { 320 SCOPED_TRACE("Reversed range"); 321 std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat4Cmap( 322 0, 0, std::vector<uint16_t>({'b', 'b', 'a', 'a'})); 323 324 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 325 EXPECT_EQ(0U, coverage.length()); 326 EXPECT_TRUE(vsTables.empty()); 327 } 328 { 329 SCOPED_TRACE("Reversed range - partially readable"); 330 std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat4Cmap( 331 0, 0, std::vector<uint16_t>({'a', 'a', 'c', 'c', 'b', 'b'})); 332 333 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 334 EXPECT_EQ(0U, coverage.length()); 335 EXPECT_TRUE(vsTables.empty()); 336 } 337 } 338 339 TEST(CmapCoverageTest, SingleFormat4) { 340 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 341 struct TestCast { 342 std::string testTitle; 343 uint16_t platformId; 344 uint16_t encodingId; 345 } TEST_CASES[] = { 346 {"Platform 0, Encoding 0", 0, 0}, {"Platform 0, Encoding 1", 0, 1}, 347 {"Platform 0, Encoding 2", 0, 2}, {"Platform 0, Encoding 3", 0, 3}, 348 {"Platform 3, Encoding 1", 3, 1}, 349 }; 350 351 for (const auto& testCase : TEST_CASES) { 352 SCOPED_TRACE(testCase.testTitle.c_str()); 353 std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat4Cmap( 354 testCase.platformId, testCase.encodingId, std::vector<uint16_t>({'a', 'a'})); 355 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 356 EXPECT_TRUE(coverage.get('a')); 357 EXPECT_FALSE(coverage.get('b')); 358 EXPECT_TRUE(vsTables.empty()); 359 } 360 } 361 362 TEST(CmapCoverageTest, SingleFormat12) { 363 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 364 365 struct TestCast { 366 std::string testTitle; 367 uint16_t platformId; 368 uint16_t encodingId; 369 } TEST_CASES[] = { 370 {"Platform 0, Encoding 4", 0, 4}, 371 {"Platform 0, Encoding 6", 0, 6}, 372 {"Platform 3, Encoding 10", 3, 10}, 373 }; 374 375 for (const auto& testCase : TEST_CASES) { 376 SCOPED_TRACE(testCase.testTitle.c_str()); 377 std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat12Cmap( 378 testCase.platformId, testCase.encodingId, std::vector<uint32_t>({'a', 'a'})); 379 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 380 EXPECT_TRUE(coverage.get('a')); 381 EXPECT_FALSE(coverage.get('b')); 382 EXPECT_TRUE(vsTables.empty()); 383 } 384 } 385 386 TEST(CmapCoverageTest, Format12_beyondTheUnicodeLimit) { 387 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 388 { 389 SCOPED_TRACE("Starting range is out of Unicode code point. Should be ignored."); 390 std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat12Cmap( 391 0, 0, std::vector<uint32_t>({'a', 'a', 0x110000, 0x110000})); 392 393 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 394 EXPECT_TRUE(coverage.get('a')); 395 EXPECT_FALSE(coverage.get(0x110000)); 396 EXPECT_TRUE(vsTables.empty()); 397 } 398 { 399 SCOPED_TRACE("Ending range is out of Unicode code point. Should be ignored."); 400 std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat12Cmap( 401 0, 0, std::vector<uint32_t>({'a', 'a', 0x10FF00, 0x110000})); 402 403 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 404 EXPECT_TRUE(coverage.get('a')); 405 EXPECT_TRUE(coverage.get(0x10FF00)); 406 EXPECT_TRUE(coverage.get(0x10FFFF)); 407 EXPECT_FALSE(coverage.get(0x110000)); 408 EXPECT_TRUE(vsTables.empty()); 409 } 410 } 411 412 TEST(CmapCoverageTest, notSupportedEncodings) { 413 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 414 415 struct TestCast { 416 std::string testTitle; 417 uint16_t platformId; 418 uint16_t encodingId; 419 } TEST_CASES[] = { 420 // Any encodings with platform 2 is not supported. 421 {"Platform 2, Encoding 0", 2, 0}, 422 {"Platform 2, Encoding 1", 2, 1}, 423 {"Platform 2, Encoding 2", 2, 2}, 424 {"Platform 2, Encoding 3", 2, 3}, 425 // UCS-2 or UCS-4 are supported on Platform == 3. Others are not supported. 426 {"Platform 3, Encoding 0", 3, 0}, // Symbol 427 {"Platform 3, Encoding 2", 3, 2}, // ShiftJIS 428 {"Platform 3, Encoding 3", 3, 3}, // RPC 429 {"Platform 3, Encoding 4", 3, 4}, // Big5 430 {"Platform 3, Encoding 5", 3, 5}, // Wansung 431 {"Platform 3, Encoding 6", 3, 6}, // Johab 432 {"Platform 3, Encoding 7", 3, 7}, // Reserved 433 {"Platform 3, Encoding 8", 3, 8}, // Reserved 434 {"Platform 3, Encoding 9", 3, 9}, // Reserved 435 // Uknown platforms 436 {"Platform 4, Encoding 0", 4, 0}, 437 {"Platform 5, Encoding 1", 5, 1}, 438 {"Platform 6, Encoding 0", 6, 0}, 439 {"Platform 7, Encoding 1", 7, 1}, 440 }; 441 442 for (const auto& testCase : TEST_CASES) { 443 SCOPED_TRACE(testCase.testTitle.c_str()); 444 CmapBuilder builder(1); 445 std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat4Cmap( 446 testCase.platformId, testCase.encodingId, std::vector<uint16_t>({'a', 'a'})); 447 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 448 EXPECT_EQ(0U, coverage.length()); 449 EXPECT_TRUE(vsTables.empty()); 450 } 451 } 452 453 TEST(CmapCoverageTest, brokenFormat4Table) { 454 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 455 { 456 SCOPED_TRACE("Too small table cmap size"); 457 std::vector<uint8_t> table = buildCmapFormat4Table(std::vector<uint16_t>({'a', 'a'})); 458 table.resize(2); // Remove trailing data. 459 460 CmapBuilder builder(1); 461 builder.appendTable(0, 0, table); 462 std::vector<uint8_t> cmap = builder.build(); 463 464 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 465 EXPECT_EQ(0U, coverage.length()); 466 EXPECT_TRUE(vsTables.empty()); 467 } 468 { 469 SCOPED_TRACE("Too many segments"); 470 std::vector<uint8_t> table = buildCmapFormat4Table(std::vector<uint16_t>({'a', 'a'})); 471 writeU16(5000, table.data(), 6 /* segment count offset */); // 5000 segments. 472 CmapBuilder builder(1); 473 builder.appendTable(0, 0, table); 474 std::vector<uint8_t> cmap = builder.build(); 475 476 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 477 EXPECT_EQ(0U, coverage.length()); 478 EXPECT_TRUE(vsTables.empty()); 479 } 480 { 481 SCOPED_TRACE("Inversed range"); 482 std::vector<uint8_t> table = buildCmapFormat4Table(std::vector<uint16_t>({'b', 'b'})); 483 // Put smaller end code point to inverse the range. 484 writeU16('a', table.data(), 14 /* the first element of endCount offset */); 485 CmapBuilder builder(1); 486 builder.appendTable(0, 0, table); 487 std::vector<uint8_t> cmap = builder.build(); 488 489 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 490 EXPECT_EQ(0U, coverage.length()); 491 EXPECT_TRUE(vsTables.empty()); 492 } 493 { 494 SCOPED_TRACE("Reversed end code points"); 495 std::vector<uint8_t> table = 496 buildCmapFormat4Table(std::vector<uint16_t>({'b', 'b', 'a', 'a'})); 497 CmapBuilder builder(1); 498 builder.appendTable(0, 0, table); 499 std::vector<uint8_t> cmap = builder.build(); 500 501 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 502 EXPECT_EQ(0U, coverage.length()); 503 EXPECT_TRUE(vsTables.empty()); 504 } 505 } 506 507 TEST(CmapCoverageTest, duplicatedCmap4EntryTest) { 508 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 509 std::vector<uint8_t> table = buildCmapFormat4Table(std::vector<uint16_t>({'a', 'b', 'b', 'b'})); 510 CmapBuilder builder(1); 511 builder.appendTable(0, 0, table); 512 std::vector<uint8_t> cmap = builder.build(); 513 514 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 515 EXPECT_TRUE(coverage.get('a')); 516 EXPECT_TRUE(coverage.get('b')); 517 EXPECT_TRUE(vsTables.empty()); 518 } 519 520 TEST(CmapCoverageTest, brokenFormat12Table) { 521 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 522 { 523 SCOPED_TRACE("Too small cmap size"); 524 std::vector<uint8_t> table = buildCmapFormat12Table(std::vector<uint32_t>({'a', 'a'})); 525 table.resize(2); // Remove trailing data. 526 527 CmapBuilder builder(1); 528 builder.appendTable(0, 0, table); 529 std::vector<uint8_t> cmap = builder.build(); 530 531 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 532 EXPECT_EQ(0U, coverage.length()); 533 EXPECT_TRUE(vsTables.empty()); 534 } 535 { 536 SCOPED_TRACE("Too many groups"); 537 std::vector<uint8_t> table = buildCmapFormat12Table(std::vector<uint32_t>({'a', 'a'})); 538 writeU32(5000, table.data(), 12 /* num group offset */); // 5000 groups. 539 540 CmapBuilder builder(1); 541 builder.appendTable(0, 0, table); 542 std::vector<uint8_t> cmap = builder.build(); 543 544 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 545 EXPECT_EQ(0U, coverage.length()); 546 EXPECT_TRUE(vsTables.empty()); 547 } 548 { 549 SCOPED_TRACE("Inversed range."); 550 std::vector<uint8_t> table = buildCmapFormat12Table(std::vector<uint32_t>({'a', 'a'})); 551 // Put larger start code point to inverse the range. 552 writeU32('b', table.data(), 16 /* start code point offset in the first group */); 553 554 CmapBuilder builder(1); 555 builder.appendTable(0, 0, table); 556 std::vector<uint8_t> cmap = builder.build(); 557 558 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 559 EXPECT_EQ(0U, coverage.length()); 560 EXPECT_TRUE(vsTables.empty()); 561 } 562 { 563 SCOPED_TRACE("Too large code point"); 564 std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat12Cmap( 565 0, 0, std::vector<uint32_t>({0x110000, 0x110000})); 566 567 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 568 EXPECT_EQ(0U, coverage.length()); 569 EXPECT_TRUE(vsTables.empty()); 570 } 571 { 572 SCOPED_TRACE("Reversed range"); 573 std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat12Cmap( 574 0, 0, std::vector<uint32_t>({'b', 'b', 'a', 'a'})); 575 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 576 EXPECT_EQ(0U, coverage.length()); 577 EXPECT_TRUE(vsTables.empty()); 578 } 579 { 580 SCOPED_TRACE("Reversed range - partially readable"); 581 std::vector<uint8_t> cmap = CmapBuilder::buildSingleFormat12Cmap( 582 0, 0, std::vector<uint32_t>({'a', 'a', 'c', 'c', 'b', 'b'})); 583 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 584 EXPECT_EQ(0U, coverage.length()); 585 EXPECT_TRUE(vsTables.empty()); 586 } 587 } 588 589 TEST(CmapCoverageTest, TableSelection_Priority) { 590 std::vector<uint8_t> highestFormat12Table = 591 buildCmapFormat12Table(std::vector<uint32_t>({'a', 'a'})); 592 std::vector<uint8_t> highestFormat4Table = 593 buildCmapFormat4Table(std::vector<uint16_t>({'a', 'a'})); 594 std::vector<uint8_t> format4 = buildCmapFormat4Table(std::vector<uint16_t>({'b', 'b'})); 595 std::vector<uint8_t> format12 = buildCmapFormat12Table(std::vector<uint32_t>({'b', 'b'})); 596 597 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 598 { 599 SCOPED_TRACE("(platform, encoding) = (3, 10) is the highest priority."); 600 601 struct LowerPriorityTable { 602 uint16_t platformId; 603 uint16_t encodingId; 604 const std::vector<uint8_t>& table; 605 } LOWER_PRIORITY_TABLES[] = { 606 {0, 0, format4}, {0, 1, format4}, {0, 2, format4}, {0, 3, format4}, 607 {0, 4, format12}, {0, 6, format12}, {3, 1, format4}, 608 }; 609 610 for (const auto& table : LOWER_PRIORITY_TABLES) { 611 CmapBuilder builder(2); 612 builder.appendTable(table.platformId, table.encodingId, table.table); 613 builder.appendTable(3, 10, highestFormat12Table); 614 std::vector<uint8_t> cmap = builder.build(); 615 616 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 617 EXPECT_TRUE(coverage.get('a')); // comes from highest table 618 EXPECT_FALSE(coverage.get('b')); // should not use other table. 619 EXPECT_TRUE(vsTables.empty()); 620 } 621 } 622 { 623 SCOPED_TRACE("(platform, encoding) = (3, 1) case"); 624 625 struct LowerPriorityTable { 626 uint16_t platformId; 627 uint16_t encodingId; 628 const std::vector<uint8_t>& table; 629 } LOWER_PRIORITY_TABLES[] = { 630 {0, 0, format4}, {0, 1, format4}, {0, 2, format4}, {0, 3, format4}, 631 }; 632 633 for (const auto& table : LOWER_PRIORITY_TABLES) { 634 CmapBuilder builder(2); 635 builder.appendTable(table.platformId, table.encodingId, table.table); 636 builder.appendTable(3, 1, highestFormat4Table); 637 std::vector<uint8_t> cmap = builder.build(); 638 639 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 640 EXPECT_TRUE(coverage.get('a')); // comes from highest table 641 EXPECT_FALSE(coverage.get('b')); // should not use other table. 642 EXPECT_TRUE(vsTables.empty()); 643 } 644 } 645 } 646 647 TEST(CmapCoverageTest, TableSelection_SkipBrokenFormat4Table) { 648 std::vector<uint8_t> validTable = buildCmapFormat4Table(std::vector<uint16_t>({'a', 'a'})); 649 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 650 { 651 SCOPED_TRACE("Unsupported format"); 652 CmapBuilder builder(2); 653 std::vector<uint8_t> table = buildCmapFormat4Table(std::vector<uint16_t>({'b', 'b'})); 654 writeU16(0, table.data(), 0 /* format offset */); 655 builder.appendTable(3, 1, table); 656 builder.appendTable(0, 0, validTable); 657 std::vector<uint8_t> cmap = builder.build(); 658 659 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 660 EXPECT_TRUE(coverage.get('a')); // comes from valid table 661 EXPECT_FALSE(coverage.get('b')); // should not use invalid table. 662 EXPECT_TRUE(vsTables.empty()); 663 } 664 { 665 SCOPED_TRACE("Invalid language"); 666 CmapBuilder builder(2); 667 std::vector<uint8_t> table = buildCmapFormat4Table(std::vector<uint16_t>({'b', 'b'})); 668 writeU16(1, table.data(), 4 /* language offset */); 669 builder.appendTable(3, 1, table); 670 builder.appendTable(0, 0, validTable); 671 std::vector<uint8_t> cmap = builder.build(); 672 673 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 674 EXPECT_TRUE(coverage.get('a')); // comes from valid table 675 EXPECT_FALSE(coverage.get('b')); // should not use invalid table. 676 EXPECT_TRUE(vsTables.empty()); 677 } 678 { 679 SCOPED_TRACE("Invalid length"); 680 CmapBuilder builder(2); 681 std::vector<uint8_t> table = buildCmapFormat4Table(std::vector<uint16_t>({'b', 'b'})); 682 writeU16(5000, table.data(), 2 /* length offset */); 683 builder.appendTable(3, 1, table); 684 builder.appendTable(0, 0, validTable); 685 std::vector<uint8_t> cmap = builder.build(); 686 687 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 688 EXPECT_TRUE(coverage.get('a')); // comes from valid table 689 EXPECT_FALSE(coverage.get('b')); // should not use invalid table. 690 EXPECT_TRUE(vsTables.empty()); 691 } 692 } 693 694 TEST(CmapCoverageTest, TableSelection_SkipBrokenFormat12Table) { 695 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 696 std::vector<uint8_t> validTable = buildCmapFormat12Table(std::vector<uint32_t>({'a', 'a'})); 697 { 698 SCOPED_TRACE("Unsupported format"); 699 CmapBuilder builder(2); 700 std::vector<uint8_t> table = buildCmapFormat12Table(std::vector<uint32_t>({'b', 'b'})); 701 writeU16(0, table.data(), 0 /* format offset */); 702 builder.appendTable(3, 1, table); 703 builder.appendTable(0, 0, validTable); 704 std::vector<uint8_t> cmap = builder.build(); 705 706 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 707 EXPECT_TRUE(coverage.get('a')); // comes from valid table 708 EXPECT_FALSE(coverage.get('b')); // should not use invalid table. 709 EXPECT_TRUE(vsTables.empty()); 710 } 711 { 712 SCOPED_TRACE("Invalid language"); 713 CmapBuilder builder(2); 714 std::vector<uint8_t> table = buildCmapFormat12Table(std::vector<uint32_t>({'b', 'b'})); 715 writeU32(1, table.data(), 8 /* language offset */); 716 builder.appendTable(3, 1, table); 717 builder.appendTable(0, 0, validTable); 718 std::vector<uint8_t> cmap = builder.build(); 719 720 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 721 EXPECT_TRUE(coverage.get('a')); // comes from valid table 722 EXPECT_FALSE(coverage.get('b')); // should not use invalid table. 723 EXPECT_TRUE(vsTables.empty()); 724 } 725 { 726 SCOPED_TRACE("Invalid length"); 727 CmapBuilder builder(2); 728 std::vector<uint8_t> table = buildCmapFormat12Table(std::vector<uint32_t>({'b', 'b'})); 729 writeU32(5000, table.data(), 4 /* length offset */); 730 builder.appendTable(3, 1, table); 731 builder.appendTable(0, 0, validTable); 732 std::vector<uint8_t> cmap = builder.build(); 733 734 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 735 EXPECT_TRUE(coverage.get('a')); // comes from valid table 736 EXPECT_FALSE(coverage.get('b')); // should not use invalid table. 737 EXPECT_TRUE(vsTables.empty()); 738 } 739 } 740 741 TEST(CmapCoverageTest, TableSelection_VSTable) { 742 std::vector<uint8_t> smallLetterTable = 743 buildCmapFormat12Table(std::vector<uint32_t>({'a', 'z'})); 744 std::vector<uint8_t> vsTable = buildCmapFormat14Table(std::vector<VariationSelectorRecord>({ 745 {0xFE0E, {'a', 'b'}, {} /* no non-default UVS table */}, 746 {0xFE0F, {} /* no default UVS table */, {'a', 'b'}}, 747 {0xE0100, {'a', 'a'}, {'b'}}, 748 })); 749 CmapBuilder builder(2); 750 builder.appendTable(3, 1, smallLetterTable); 751 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 752 std::vector<uint8_t> cmap = builder.build(); 753 754 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 755 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 756 EXPECT_TRUE(coverage.get('a')); 757 ASSERT_FALSE(vsTables.empty()); 758 759 const uint16_t vs15Index = getVsIndex(0xFE0E); 760 ASSERT_LT(vs15Index, vsTables.size()); 761 ASSERT_TRUE(vsTables[vs15Index]); 762 EXPECT_TRUE(vsTables[vs15Index]->get('a')); 763 EXPECT_TRUE(vsTables[vs15Index]->get('b')); 764 765 const uint16_t vs16Index = getVsIndex(0xFE0F); 766 ASSERT_LT(vs16Index, vsTables.size()); 767 ASSERT_TRUE(vsTables[vs16Index]); 768 EXPECT_TRUE(vsTables[vs16Index]->get('a')); 769 EXPECT_TRUE(vsTables[vs16Index]->get('b')); 770 771 const uint16_t vs17Index = getVsIndex(0xE0100); 772 ASSERT_LT(vs17Index, vsTables.size()); 773 ASSERT_TRUE(vsTables[vs17Index]); 774 EXPECT_TRUE(vsTables[vs17Index]->get('a')); 775 EXPECT_TRUE(vsTables[vs17Index]->get('b')); 776 } 777 778 TEST(CmapCoverageTest, TableSelection_InterSection) { 779 std::vector<uint8_t> smallLetterTable = 780 buildCmapFormat12Table(std::vector<uint32_t>({'a', 'z'})); 781 std::vector<uint8_t> vsTable = buildCmapFormat14Table(std::vector<VariationSelectorRecord>({ 782 {0xFE0E, 783 {'a', 'e'}, 784 { 785 'c', 'd', 786 }}, 787 {0xFE0F, {'c', 'e'}, {'a', 'b', 'c', 'd', 'e'}}, 788 {0xE0100, {'a', 'c'}, {'b', 'c', 'd'}}, 789 {0xE0101, {'b', 'd'}, {'a', 'b', 'c', 'd'}}, 790 {0xE0102, {'a', 'c', 'd', 'g'}, {'b', 'c', 'd', 'e', 'f', 'g', 'h'}}, 791 {0xE0103, 792 {'a', 'f'}, 793 { 794 'b', 'd', 795 }}, 796 })); 797 CmapBuilder builder(2); 798 builder.appendTable(3, 1, smallLetterTable); 799 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 800 std::vector<uint8_t> cmap = builder.build(); 801 802 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 803 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 804 EXPECT_TRUE(coverage.get('a')); 805 ASSERT_FALSE(vsTables.empty()); 806 807 const uint16_t vs15Index = getVsIndex(0xFE0E); 808 ASSERT_LT(vs15Index, vsTables.size()); 809 ASSERT_TRUE(vsTables[vs15Index]); 810 EXPECT_TRUE(vsTables[vs15Index]->get('a')); 811 EXPECT_TRUE(vsTables[vs15Index]->get('b')); 812 EXPECT_TRUE(vsTables[vs15Index]->get('c')); 813 EXPECT_TRUE(vsTables[vs15Index]->get('d')); 814 EXPECT_TRUE(vsTables[vs15Index]->get('e')); 815 816 const uint16_t vs16Index = getVsIndex(0xFE0F); 817 ASSERT_LT(vs16Index, vsTables.size()); 818 ASSERT_TRUE(vsTables[vs16Index]); 819 EXPECT_TRUE(vsTables[vs16Index]->get('a')); 820 EXPECT_TRUE(vsTables[vs16Index]->get('b')); 821 EXPECT_TRUE(vsTables[vs16Index]->get('c')); 822 EXPECT_TRUE(vsTables[vs16Index]->get('d')); 823 EXPECT_TRUE(vsTables[vs16Index]->get('e')); 824 825 const uint16_t vs17Index = getVsIndex(0xE0100); 826 ASSERT_LT(vs17Index, vsTables.size()); 827 ASSERT_TRUE(vsTables[vs17Index]); 828 EXPECT_TRUE(vsTables[vs17Index]->get('a')); 829 EXPECT_TRUE(vsTables[vs17Index]->get('b')); 830 EXPECT_TRUE(vsTables[vs17Index]->get('c')); 831 EXPECT_TRUE(vsTables[vs17Index]->get('d')); 832 833 const uint16_t vs18Index = getVsIndex(0xE0101); 834 ASSERT_LT(vs18Index, vsTables.size()); 835 ASSERT_TRUE(vsTables[vs18Index]); 836 EXPECT_TRUE(vsTables[vs18Index]->get('a')); 837 EXPECT_TRUE(vsTables[vs18Index]->get('b')); 838 EXPECT_TRUE(vsTables[vs18Index]->get('c')); 839 EXPECT_TRUE(vsTables[vs18Index]->get('d')); 840 841 const uint16_t vs19Index = getVsIndex(0xE0102); 842 ASSERT_LT(vs19Index, vsTables.size()); 843 ASSERT_TRUE(vsTables[vs19Index]); 844 EXPECT_TRUE(vsTables[vs19Index]->get('a')); 845 EXPECT_TRUE(vsTables[vs19Index]->get('b')); 846 EXPECT_TRUE(vsTables[vs19Index]->get('c')); 847 EXPECT_TRUE(vsTables[vs19Index]->get('d')); 848 EXPECT_TRUE(vsTables[vs19Index]->get('e')); 849 EXPECT_TRUE(vsTables[vs19Index]->get('f')); 850 EXPECT_TRUE(vsTables[vs19Index]->get('g')); 851 EXPECT_TRUE(vsTables[vs19Index]->get('h')); 852 853 const uint16_t vs20Index = getVsIndex(0xE0103); 854 ASSERT_LT(vs20Index, vsTables.size()); 855 ASSERT_TRUE(vsTables[vs20Index]); 856 EXPECT_TRUE(vsTables[vs20Index]->get('a')); 857 EXPECT_TRUE(vsTables[vs20Index]->get('b')); 858 EXPECT_TRUE(vsTables[vs20Index]->get('c')); 859 EXPECT_TRUE(vsTables[vs20Index]->get('d')); 860 EXPECT_TRUE(vsTables[vs20Index]->get('e')); 861 EXPECT_TRUE(vsTables[vs20Index]->get('f')); 862 } 863 864 TEST(CmapCoverageTest, TableSelection_brokenVSTable) { 865 std::vector<uint8_t> cmap12Table = buildCmapFormat12Table(std::vector<uint32_t>({'a', 'z'})); 866 { 867 SCOPED_TRACE("Too small cmap size"); 868 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 869 std::vector<VariationSelectorRecord>({{0xFE0E, {'a', 'a'}, {'b'}}})); 870 CmapBuilder builder(2); 871 builder.appendTable(3, 1, cmap12Table); 872 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 873 std::vector<uint8_t> cmap = builder.build(); 874 875 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 876 SparseBitSet coverage = 877 CmapCoverage::getCoverage(cmap.data(), 3 /* too small size */, &vsTables); 878 EXPECT_FALSE(coverage.get('a')); 879 ASSERT_TRUE(vsTables.empty()); 880 } 881 { 882 SCOPED_TRACE("Too many variation records"); 883 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 884 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 885 writeU32(5000, vsTable.data(), 6 /* numVarSelectorRecord offset */); 886 CmapBuilder builder(2); 887 builder.appendTable(3, 1, cmap12Table); 888 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 889 std::vector<uint8_t> cmap = builder.build(); 890 891 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 892 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 893 ASSERT_TRUE(vsTables.empty()); 894 } 895 { 896 SCOPED_TRACE("Invalid default UVS offset in variation records"); 897 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 898 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 899 writeU32(5000, vsTable.data(), 13 /* defaultUVSffset offset in the first record */); 900 CmapBuilder builder(2); 901 builder.appendTable(3, 1, cmap12Table); 902 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 903 std::vector<uint8_t> cmap = builder.build(); 904 905 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 906 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 907 ASSERT_TRUE(vsTables.empty()); 908 } 909 { 910 SCOPED_TRACE("Invalid non default UVS offset in variation records"); 911 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 912 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 913 writeU32(5000, vsTable.data(), 17 /* nonDefaultUVSffset offset in the first record */); 914 CmapBuilder builder(2); 915 builder.appendTable(3, 1, cmap12Table); 916 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 917 std::vector<uint8_t> cmap = builder.build(); 918 919 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 920 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 921 ASSERT_TRUE(vsTables.empty()); 922 } 923 { 924 SCOPED_TRACE("Too many ranges entry in default UVS table"); 925 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 926 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 927 // 21 is the offset of the numUnicodeValueRanges in the fist defulat UVS table. 928 writeU32(5000, vsTable.data(), 21); 929 CmapBuilder builder(2); 930 builder.appendTable(3, 1, cmap12Table); 931 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 932 std::vector<uint8_t> cmap = builder.build(); 933 934 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 935 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 936 ASSERT_TRUE(vsTables.empty()); 937 } 938 { 939 SCOPED_TRACE("Too many ranges entry in non default UVS table"); 940 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 941 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 942 // 29 is the offset of the numUnicodeValueRanges in the fist defulat UVS table. 943 writeU32(5000, vsTable.data(), 29); 944 CmapBuilder builder(2); 945 builder.appendTable(3, 1, cmap12Table); 946 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 947 std::vector<uint8_t> cmap = builder.build(); 948 949 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 950 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 951 ASSERT_TRUE(vsTables.empty()); 952 } 953 { 954 SCOPED_TRACE("Reversed range in default UVS table"); 955 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 956 std::vector<VariationSelectorRecord>({{0xFE0F, {'b', 'b', 'a', 'a'}, {}}})); 957 CmapBuilder builder(2); 958 builder.appendTable(3, 1, cmap12Table); 959 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 960 std::vector<uint8_t> cmap = builder.build(); 961 962 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 963 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 964 ASSERT_TRUE(vsTables.empty()); 965 } 966 { 967 SCOPED_TRACE("Reversed range in default UVS table - partially readable"); 968 std::vector<uint8_t> vsTable = buildCmapFormat14Table(std::vector<VariationSelectorRecord>( 969 {{0xFE0F, {'a', 'a', 'c', 'c', 'b', 'b'}, {}}})); 970 CmapBuilder builder(2); 971 builder.appendTable(3, 1, cmap12Table); 972 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 973 std::vector<uint8_t> cmap = builder.build(); 974 975 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 976 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 977 ASSERT_TRUE(vsTables.empty()); 978 } 979 { 980 SCOPED_TRACE("Reversed mapping entries in non default UVS table"); 981 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 982 std::vector<VariationSelectorRecord>({{0xFE0F, {}, {'b', 'a'}}})); 983 CmapBuilder builder(2); 984 builder.appendTable(3, 1, cmap12Table); 985 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 986 std::vector<uint8_t> cmap = builder.build(); 987 988 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 989 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 990 ASSERT_TRUE(vsTables.empty()); 991 } 992 { 993 SCOPED_TRACE("Reversed mapping entries in non default UVS table"); 994 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 995 std::vector<VariationSelectorRecord>({{0xFE0F, {}, {'a', 'c', 'b'}}})); 996 CmapBuilder builder(2); 997 builder.appendTable(3, 1, cmap12Table); 998 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 999 std::vector<uint8_t> cmap = builder.build(); 1000 1001 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1002 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1003 ASSERT_TRUE(vsTables.empty()); 1004 } 1005 { 1006 // http://b/70808908 1007 SCOPED_TRACE("OOB access due to integer overflow in non default UVS table"); 1008 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 1009 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 1010 // 6 is the offset of the numRecords in the Cmap format14 subtable header. 1011 writeU32(0x1745d174 /* 2^32 / kRecordSize(=11) */, vsTable.data(), 6); 1012 CmapBuilder builder(2); 1013 builder.appendTable(3, 1, cmap12Table); 1014 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1015 std::vector<uint8_t> cmap = builder.build(); 1016 1017 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1018 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1019 ASSERT_TRUE(vsTables.empty()); 1020 } 1021 { 1022 // http://b/70808908 1023 SCOPED_TRACE("OOB access due to integer overflow in non default UVS table"); 1024 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 1025 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 1026 // 29 is the offset of the numUVSMappings in the fist non defulat UVS table. 1027 writeU32(0x33333333 /* 2^32 / kUVSMappingRecordSize(=5) */, vsTable.data(), 29); 1028 CmapBuilder builder(2); 1029 builder.appendTable(3, 1, cmap12Table); 1030 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1031 std::vector<uint8_t> cmap = builder.build(); 1032 1033 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1034 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1035 ASSERT_TRUE(vsTables.empty()); 1036 } 1037 { 1038 // http://b/70808908 1039 SCOPED_TRACE("OOB access due to integer overflow in default UVS table"); 1040 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 1041 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 1042 // 21 is the offset of the numUnicodeValueRanges in the fist defulat UVS table. 1043 writeU32(0x40000000 /* 2^32 / kUnicodeRangeRecordSize(=4) */, vsTable.data(), 21); 1044 CmapBuilder builder(2); 1045 builder.appendTable(3, 1, cmap12Table); 1046 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1047 std::vector<uint8_t> cmap = builder.build(); 1048 1049 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1050 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1051 ASSERT_TRUE(vsTables.empty()); 1052 } 1053 { 1054 // http://b/70808908 1055 SCOPED_TRACE("OOB access due to integer overflow in non default UVS table"); 1056 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 1057 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 1058 // 6 is the offset of the numRecords in the Cmap format14 subtable header. 1059 writeU32(0x1745d174 /* 2^32 / kRecordSize(=11) */, vsTable.data(), 6); 1060 CmapBuilder builder(2); 1061 builder.appendTable(3, 1, cmap12Table); 1062 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1063 std::vector<uint8_t> cmap = builder.build(); 1064 1065 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1066 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1067 ASSERT_TRUE(vsTables.empty()); 1068 } 1069 { 1070 // http://b/70808908 1071 SCOPED_TRACE("OOB access due to integer overflow in non default UVS table"); 1072 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 1073 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 1074 // 29 is the offset of the numUVSMappings in the fist non defulat UVS table. 1075 writeU32(0x33333333 /* 2^32 / kUVSMappingRecordSize(=5) */, vsTable.data(), 29); 1076 CmapBuilder builder(2); 1077 builder.appendTable(3, 1, cmap12Table); 1078 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1079 std::vector<uint8_t> cmap = builder.build(); 1080 1081 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1082 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1083 ASSERT_TRUE(vsTables.empty()); 1084 } 1085 { 1086 // http://b/70808908 1087 SCOPED_TRACE("OOB access due to integer overflow in default UVS table"); 1088 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 1089 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'a'}, {'b'}}})); 1090 // 21 is the offset of the numUnicodeValueRanges in the fist defulat UVS table. 1091 writeU32(0x40000000 /* 2^32 / kUnicodeRangeRecordSize(=4) */, vsTable.data(), 21); 1092 CmapBuilder builder(2); 1093 builder.appendTable(3, 1, cmap12Table); 1094 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1095 std::vector<uint8_t> cmap = builder.build(); 1096 1097 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1098 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1099 ASSERT_TRUE(vsTables.empty()); 1100 } 1101 } 1102 1103 TEST(CmapCoverageTest, TableSelection_brokenVSTable_bestEffort) { 1104 std::vector<uint8_t> cmap12Table = buildCmapFormat12Table(std::vector<uint32_t>({'a', 'a'})); 1105 { 1106 SCOPED_TRACE("Invalid default UVS offset in variation records"); 1107 std::vector<uint8_t> vsTable = buildCmapFormat14Table(std::vector<VariationSelectorRecord>({ 1108 {0xFE0E, {'a', 'a'}, {'b'}}, {0xFE0F, {'a', 'a'}, {'b'}}, 1109 })); 1110 writeU32(5000, vsTable.data(), 13 /* defaultUVSffset offset in the record for 0xFE0E */); 1111 CmapBuilder builder(2); 1112 builder.appendTable(3, 1, cmap12Table); 1113 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1114 std::vector<uint8_t> cmap = builder.build(); 1115 1116 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1117 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1118 1119 const uint16_t vs16Index = getVsIndex(0xFE0F); 1120 ASSERT_LT(vs16Index, vsTables.size()); 1121 ASSERT_TRUE(vsTables[vs16Index]); 1122 EXPECT_TRUE(vsTables[vs16Index]->get('a')); 1123 EXPECT_TRUE(vsTables[vs16Index]->get('b')); 1124 1125 const uint16_t vs15Index = getVsIndex(0xFE0E); 1126 EXPECT_FALSE(vsTables[vs15Index]); 1127 } 1128 { 1129 SCOPED_TRACE("Invalid non default UVS offset in variation records"); 1130 std::vector<uint8_t> vsTable = buildCmapFormat14Table(std::vector<VariationSelectorRecord>({ 1131 {0xFE0E, {'a', 'a'}, {'b'}}, {0xFE0F, {'a', 'a'}, {'b'}}, 1132 })); 1133 writeU32(5000, vsTable.data(), 17 /* nonDefaultUVSffset offset in the first record */); 1134 CmapBuilder builder(2); 1135 builder.appendTable(3, 1, cmap12Table); 1136 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1137 std::vector<uint8_t> cmap = builder.build(); 1138 1139 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1140 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1141 1142 const uint16_t vs16Index = getVsIndex(0xFE0F); 1143 ASSERT_LT(vs16Index, vsTables.size()); 1144 ASSERT_TRUE(vsTables[vs16Index]); 1145 EXPECT_TRUE(vsTables[vs16Index]->get('a')); 1146 EXPECT_TRUE(vsTables[vs16Index]->get('b')); 1147 1148 const uint16_t vs15Index = getVsIndex(0xFE0E); 1149 EXPECT_FALSE(vsTables[vs15Index]); 1150 } 1151 { 1152 SCOPED_TRACE("Unknown variation selectors."); 1153 std::vector<uint8_t> vsTable = buildCmapFormat14Table(std::vector<VariationSelectorRecord>({ 1154 {0xFE0F, {'a', 'a'}, {'b'}}, {0xEFFFF, {'a', 'a'}, {'b'}}, 1155 })); 1156 CmapBuilder builder(2); 1157 builder.appendTable(3, 1, cmap12Table); 1158 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1159 std::vector<uint8_t> cmap = builder.build(); 1160 1161 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1162 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1163 1164 const uint16_t vs16Index = getVsIndex(0xFE0F); 1165 ASSERT_LT(vs16Index, vsTables.size()); 1166 ASSERT_TRUE(vsTables[vs16Index]); 1167 EXPECT_TRUE(vsTables[vs16Index]->get('a')); 1168 EXPECT_TRUE(vsTables[vs16Index]->get('b')); 1169 } 1170 } 1171 1172 // Used only for better looking of range definition. 1173 #define RANGE(x, y) x, y 1174 1175 TEST(CmapCoverageTest, TableSelection_defaultUVSPointMissingGlyph) { 1176 std::vector<uint8_t> baseTable = buildCmapFormat12Table(std::vector<uint32_t>( 1177 {RANGE('a', 'e'), RANGE('g', 'h'), RANGE('j', 'j'), RANGE('m', 'z')})); 1178 std::vector<uint8_t> vsTable = buildCmapFormat14Table( 1179 std::vector<VariationSelectorRecord>({{0xFE0F, {'a', 'z'}, {}}})); 1180 1181 CmapBuilder builder(2); 1182 builder.appendTable(3, 1, baseTable); 1183 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1184 std::vector<uint8_t> cmap = builder.build(); 1185 1186 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1187 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1188 const uint16_t vsIndex = getVsIndex(0xFE0F); 1189 ASSERT_LT(vsIndex, vsTables.size()); 1190 ASSERT_TRUE(vsTables[vsIndex]); 1191 1192 for (char c = 'a'; c <= 'z'; ++c) { 1193 // Default UVS table points the variation sequence to the glyph of the base code point. 1194 // Thus, if the base code point is not supported, we should exclude them. 1195 EXPECT_EQ(coverage.get(c), vsTables[vsIndex]->get(c)) << c; 1196 } 1197 } 1198 1199 #undef RANGE 1200 1201 TEST(CmapCoverageTest, TableSelection_vsTableOnly) { 1202 std::vector<uint8_t> vsTable = 1203 buildCmapFormat14Table(std::vector<VariationSelectorRecord>({{0xFE0F, {}, {'a'}}})); 1204 1205 CmapBuilder builder(1); 1206 builder.appendTable(VS_PLATFORM_ID, VS_ENCODING_ID, vsTable); 1207 std::vector<uint8_t> cmap = builder.build(); 1208 1209 std::vector<std::unique_ptr<SparseBitSet>> vsTables; 1210 SparseBitSet coverage = CmapCoverage::getCoverage(cmap.data(), cmap.size(), &vsTables); 1211 const uint16_t vsIndex = getVsIndex(0xFE0F); 1212 ASSERT_LT(vsIndex, vsTables.size()); 1213 ASSERT_TRUE(vsTables[vsIndex]); 1214 EXPECT_TRUE(vsTables[vsIndex]->get('a')); 1215 } 1216 } // namespace minikin 1217