CmapCoverage.cpp revision db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11
19cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien/*
29cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Copyright (C) 2013 The Android Open Source Project
39cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien *
49cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Licensed under the Apache License, Version 2.0 (the "License");
59cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * you may not use this file except in compliance with the License.
69cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * You may obtain a copy of the License at
79cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien *
89cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien *      http://www.apache.org/licenses/LICENSE-2.0
99cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien *
109cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Unless required by applicable law or agreed to in writing, software
119cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * distributed under the License is distributed on an "AS IS" BASIS,
129cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * See the License for the specific language governing permissions and
149cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * limitations under the License.
159cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien */
169cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
179cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien// Determine coverage of font given its raw "cmap" OpenType table
189cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
195f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien#define LOG_TAG "Minikin"
209cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
219cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <vector>
229cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienusing std::vector;
239cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
24555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn#include <log/log.h>
25555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn
269cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <minikin/SparseBitSet.h>
279cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <minikin/CmapCoverage.h>
289cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
2914e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakanamespace minikin {
309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
319cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien// These could perhaps be optimized to use __builtin_bswap16 and friends.
329cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic uint32_t readU16(const uint8_t* data, size_t offset) {
336299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien    return ((uint32_t)data[offset]) << 8 | ((uint32_t)data[offset + 1]);
349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
359cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic uint32_t readU32(const uint8_t* data, size_t offset) {
376299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien    return ((uint32_t)data[offset]) << 24 | ((uint32_t)data[offset + 1]) << 16 |
386299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien        ((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]);
399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
409cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
419cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) {
425f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien#ifdef VERBOSE_DEBUG
435f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien    ALOGD("adding range %d-%d\n", start, end);
449cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif
459cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (coverage.empty() || coverage.back() < start) {
469cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        coverage.push_back(start);
479cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        coverage.push_back(end);
489cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    } else {
499cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        coverage.back() = end;
509cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
519cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
529cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
53ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien// Get the coverage information out of a Format 4 subtable, storing it in the coverage vector
549cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
559cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kSegCountOffset = 6;
569cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kEndCountOffset = 14;
579cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kHeaderSize = 16;
589cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kSegmentSize = 8;  // total size of array elements for one segment
599cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (kEndCountOffset > size) {
609cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
619cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
629cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    size_t segCount = readU16(data, kSegCountOffset) >> 1;
639cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (kHeaderSize + segCount * kSegmentSize > size) {
649cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
659cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
669cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    for (size_t i = 0; i < segCount; i++) {
67ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        uint32_t end = readU16(data, kEndCountOffset + 2 * i);
68ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        uint32_t start = readU16(data, kHeaderSize + 2 * (segCount + i));
69ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        if (end < start) {
70ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            // invalid segment range: size must be positive
71734f037130e14b3d44bc74026d3d065c025a8280Raph Levien            android_errorWriteLog(0x534e4554, "26413177");
72ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            return false;
73ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        }
74ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        uint32_t rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));
759cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        if (rangeOffset == 0) {
76ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            uint32_t delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
779cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            if (((end + delta) & 0xffff) > end - start) {
789cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                addRange(coverage, start, end + 1);
799cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            } else {
80ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien                for (uint32_t j = start; j < end + 1; j++) {
819cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    if (((j + delta) & 0xffff) != 0) {
829cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                        addRange(coverage, j, j + 1);
839cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    }
849cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                }
859cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            }
869cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        } else {
87ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            for (uint32_t j = start; j < end + 1; j++) {
889cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                uint32_t actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset +
899cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    (i + j - start) * 2;
909cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                if (actualRangeOffset + 2 > size) {
915f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien                    // invalid rangeOffset is considered a "warning" by OpenType Sanitizer
925f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien                    continue;
939cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                }
94ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien                uint32_t glyphId = readU16(data, actualRangeOffset);
959cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                if (glyphId != 0) {
969cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    addRange(coverage, j, j + 1);
979cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                }
989cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            }
999cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
1009cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1019cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    return true;
1029cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
1039cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
1049cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector
1059cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
1069cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kNGroupsOffset = 12;
1079cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kFirstGroupOffset = 16;
1089cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kGroupSize = 12;
1099cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kStartCharCodeOffset = 0;
1109cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kEndCharCodeOffset = 4;
1116299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien    const size_t kMaxNGroups = 0xfffffff0 / kGroupSize;  // protection against overflow
1126299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien    // For all values < kMaxNGroups, kFirstGroupOffset + nGroups * kGroupSize fits in 32 bits.
1139cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (kFirstGroupOffset > size) {
1149cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
1159cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1169cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t nGroups = readU32(data, kNGroupsOffset);
1176299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien    if (nGroups >= kMaxNGroups || kFirstGroupOffset + nGroups * kGroupSize > size) {
118734f037130e14b3d44bc74026d3d065c025a8280Raph Levien        android_errorWriteLog(0x534e4554, "25645298");
1199cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
1209cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1219cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    for (uint32_t i = 0; i < nGroups; i++) {
1229cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize;
1239cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset);
1249cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset);
125ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        if (end < start) {
126ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            // invalid group range: size must be positive
127734f037130e14b3d44bc74026d3d065c025a8280Raph Levien            android_errorWriteLog(0x534e4554, "26413177");
128ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            return false;
129ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        }
1309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        addRange(coverage, start, end + 1);  // file is inclusive, vector is exclusive
1319cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1329cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    return true;
1339cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
1349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
135db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka// Lower value has higher priority. 0 for the highest priority table.
136db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka// kLowestPriority for unsupported tables.
137db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka// This order comes from HarfBuzz's hb-ot-font.cc and needs to be kept in sync with it.
138db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonakaconstexpr uint8_t kLowestPriority = 255;
139db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonakauint8_t getTablePriority(uint16_t platformId, uint16_t encodingId) {
140db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    if (platformId == 3 && encodingId == 10) {
141db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return 0;
142db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    }
143db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    if (platformId == 0 && encodingId == 6) {
144db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return 1;
145db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    }
146db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    if (platformId == 0 && encodingId == 4) {
147db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return 2;
148db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    }
149db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    if (platformId == 3 && encodingId == 1) {
150db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return 3;
151db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    }
152db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    if (platformId == 0 && encodingId == 3) {
153db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return 4;
154db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    }
155db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    if (platformId == 0 && encodingId == 2) {
156db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return 5;
157db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    }
158db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    if (platformId == 0 && encodingId == 1) {
159db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return 6;
160db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    }
161db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    if (platformId == 0 && encodingId == 0) {
162db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return 7;
163db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    }
164db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    // Tables other than above are not supported.
165db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    return kLowestPriority;
166db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka}
167db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka
168db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo NonakaSparseBitSet CmapCoverage::getCoverage(const uint8_t* cmap_data, size_t cmap_size,
1696b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka        bool* has_cmap_format14_subtable) {
170db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    constexpr size_t kHeaderSize = 4;
171db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    constexpr size_t kNumTablesOffset = 2;
172db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    constexpr size_t kTableSize = 8;
173db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    constexpr size_t kPlatformIdOffset = 0;
174db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    constexpr size_t kEncodingIdOffset = 2;
175db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    constexpr size_t kOffsetOffset = 4;
176db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    constexpr size_t kFormatOffset = 0;
177db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    constexpr uint32_t kInvalidOffset = UINT32_MAX;
178db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka
1799cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (kHeaderSize > cmap_size) {
180db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return SparseBitSet();
1819cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
182ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien    uint32_t numTables = readU16(cmap_data, kNumTablesOffset);
1839cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (kHeaderSize + numTables * kTableSize > cmap_size) {
184db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return SparseBitSet();
1859cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
186db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka
187db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    uint32_t bestTableOffset = kInvalidOffset;
188db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    uint16_t bestTableFormat = 0;
189db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    uint8_t bestTablePriority = kLowestPriority;
190db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    *has_cmap_format14_subtable = false;
191db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    for (uint32_t i = 0; i < numTables; ++i) {
192db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        const uint32_t tableHeadOffset = kHeaderSize + i * kTableSize;
193db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        const uint16_t platformId = readU16(cmap_data, tableHeadOffset + kPlatformIdOffset);
194db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        const uint16_t encodingId = readU16(cmap_data, tableHeadOffset + kEncodingIdOffset);
195db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        const uint32_t offset = readU32(cmap_data, tableHeadOffset + kOffsetOffset);
196db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka
197db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        if (offset > cmap_size - 2) {
198db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            continue;  // Invalid table: not enough space to read.
199db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        }
200db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        const uint16_t format = readU16(cmap_data, offset + kFormatOffset);
201db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka
202db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        if (platformId == 0 /* Unicode */ && encodingId == 5 /* Variation Sequences */) {
203db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            if (!(*has_cmap_format14_subtable) && format == 14) {
204db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                *has_cmap_format14_subtable = true;
205db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            } else {
206db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                // Ignore the (0, 5) table if we have already seen another valid one or it's in a
207db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                // format we don't understand.
208db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            }
209db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        } else {
210db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            uint32_t length;
211db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            uint32_t language;
212db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka
213db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            if (format == 4) {
214db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                constexpr size_t lengthOffset = 2;
215db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                constexpr size_t languageOffset = 4;
216db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                constexpr size_t minTableSize = languageOffset + 2;
217db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                if (offset > cmap_size - minTableSize) {
218db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                    continue;  // Invalid table: not enough space to read.
219db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                }
220db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                length = readU16(cmap_data, offset + lengthOffset);
221db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                language = readU16(cmap_data, offset + languageOffset);
222db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            } else if (format == 12) {
223db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                constexpr size_t lengthOffset = 4;
224db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                constexpr size_t languageOffset = 8;
225db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                constexpr size_t minTableSize = languageOffset + 4;
226db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                if (offset > cmap_size - minTableSize) {
227db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                    continue;  // Invalid table: not enough space to read.
228db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                }
229db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                length = readU32(cmap_data, offset + lengthOffset);
230db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                language = readU32(cmap_data, offset + languageOffset);
231db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            } else {
232db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                continue;
233db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            }
234db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka
235db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            if (length > cmap_size - offset) {
236db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                continue;  // Invalid table: table length is larger than whole cmap data size.
237db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            }
238db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            if (language != 0) {
239db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                // Unsupported or invalid table: this is either a subtable for the Macintosh
240db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                // platform (which we don't support), or an invalid subtable since language field
241db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                // should be zero for non-Macintosh subtables.
242db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                continue;
243db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            }
244db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            const uint8_t priority = getTablePriority(platformId, encodingId);
245db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            if (priority < bestTablePriority) {
246db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                bestTableOffset = offset;
247db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                bestTablePriority = priority;
248db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka                bestTableFormat = format;
2496b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka            }
2509cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
251db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        if (*has_cmap_format14_subtable && bestTablePriority == 0 /* highest priority */) {
252db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            // Already found the highest priority table and variation sequences table. No need to
253db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            // look at remaining tables.
254db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka            break;
255db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        }
2569cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
257db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    if (bestTableOffset == kInvalidOffset) {
258db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return SparseBitSet();
2599cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
260db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    const uint8_t* tableData = cmap_data + bestTableOffset;
261db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    const size_t tableSize = cmap_size - bestTableOffset;
262db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    vector<uint32_t> coverageVec;
263db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    bool success;
264db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    if (bestTableFormat == 4) {
2659cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        success = getCoverageFormat4(coverageVec, tableData, tableSize);
266db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    } else {
2679cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        success = getCoverageFormat12(coverageVec, tableData, tableSize);
2689cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
2699cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (success) {
270db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return SparseBitSet(&coverageVec.front(), coverageVec.size() >> 1);
271db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka    } else {
272db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka        return SparseBitSet();
2739cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
274db1b6cb7765091453d9b4dc7f6c2fb4d7123ab11Seigo Nonaka
2759cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
2769cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
27714e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka}  // namespace minikin
278