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 
writeU8(uint8_t x,uint8_t * out,size_t offset)33 size_t writeU8(uint8_t x, uint8_t* out, size_t offset) {
34     out[offset] = x;
35     return offset + 1;
36 }
37 
writeU16(uint16_t x,uint8_t * out,size_t offset)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 
writeI16(int16_t sx,uint8_t * out,size_t offset)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 
writeU24(uint32_t x,uint8_t * out,size_t offset)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 
writeU32(uint32_t x,uint8_t * out,size_t offset)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.
buildCmapFormat4Table(const std::vector<uint16_t> & ranges)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.
buildCmapFormat12Table(const std::vector<uint32_t> & ranges)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 
getDefaultUVSAsBinaryminikin::VariationSelectorRecord154     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 
getNonDefaultUVSAsBinaryminikin::VariationSelectorRecord175     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 
buildCmapFormat14Table(const std::vector<VariationSelectorRecord> & vsRecords)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 
CmapBuilder(int numTables)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 
appendTable(uint16_t platformId,uint16_t encodingId,const std::vector<uint8_t> & table)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 
build()249     std::vector<uint8_t> build() {
250         LOG_ALWAYS_FATAL_IF(mCurrentTableIndex != mNumTables);
251         return out;
252     }
253 
254     // Helper functions.
buildSingleFormat4Cmap(uint16_t platformId,uint16_t encodingId,const std::vector<uint16_t> & ranges)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 
buildSingleFormat12Cmap(uint16_t platformId,uint16_t encodingId,const std::vector<uint32_t> & ranges)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:
appendEncodingTable(uint16_t platformId,uint16_t encodingId,uint32_t offset)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 
TEST(CmapCoverageTest,SingleFormat4_brokenCmap)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 
TEST(CmapCoverageTest,SingleFormat4)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 
TEST(CmapCoverageTest,SingleFormat12)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 
TEST(CmapCoverageTest,Format12_beyondTheUnicodeLimit)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 
TEST(CmapCoverageTest,notSupportedEncodings)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 
TEST(CmapCoverageTest,brokenFormat4Table)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 
TEST(CmapCoverageTest,duplicatedCmap4EntryTest)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 
TEST(CmapCoverageTest,brokenFormat12Table)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 
TEST(CmapCoverageTest,TableSelection_Priority)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 
TEST(CmapCoverageTest,TableSelection_SkipBrokenFormat4Table)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 
TEST(CmapCoverageTest,TableSelection_SkipBrokenFormat12Table)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 
TEST(CmapCoverageTest,TableSelection_VSTable)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 
TEST(CmapCoverageTest,TableSelection_InterSection)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 
TEST(CmapCoverageTest,TableSelection_brokenVSTable)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 
TEST(CmapCoverageTest,TableSelection_brokenVSTable_bestEffort)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 
TEST(CmapCoverageTest,TableSelection_defaultUVSPointMissingGlyph)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 
TEST(CmapCoverageTest,TableSelection_vsTableOnly)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