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