Home | History | Annotate | Download | only in unittest
      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