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