CmapCoverage.cpp revision 5f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77
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" 205f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien#include <cutils/log.h> 219cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 229cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <vector> 239cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienusing std::vector; 249cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 259cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <minikin/SparseBitSet.h> 269cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <minikin/CmapCoverage.h> 279cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 289cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Leviennamespace android { 299cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien// These could perhaps be optimized to use __builtin_bswap16 and friends. 319cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic uint32_t readU16(const uint8_t* data, size_t offset) { 329cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return data[offset] << 8 | data[offset + 1]; 339cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 359cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic uint32_t readU32(const uint8_t* data, size_t offset) { 369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]; 379cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) { 405f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien#ifdef VERBOSE_DEBUG 415f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien ALOGD("adding range %d-%d\n", start, end); 429cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif 439cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (coverage.empty() || coverage.back() < start) { 449cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien coverage.push_back(start); 459cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien coverage.push_back(end); 469cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } else { 479cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien coverage.back() = end; 489cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 499cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 509cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 519cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector 529cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data, size_t size) { 539cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kSegCountOffset = 6; 549cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kEndCountOffset = 14; 559cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kHeaderSize = 16; 569cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kSegmentSize = 8; // total size of array elements for one segment 579cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (kEndCountOffset > size) { 589cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return false; 599cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 609cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien size_t segCount = readU16(data, kSegCountOffset) >> 1; 619cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (kHeaderSize + segCount * kSegmentSize > size) { 629cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return false; 639cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 649cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien for (size_t i = 0; i < segCount; i++) { 659cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int end = readU16(data, kEndCountOffset + 2 * i); 669cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int start = readU16(data, kHeaderSize + 2 * (segCount + i)); 679cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i)); 689cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (rangeOffset == 0) { 699cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i)); 709cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (((end + delta) & 0xffff) > end - start) { 719cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien addRange(coverage, start, end + 1); 729cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } else { 739cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien for (int j = start; j < end + 1; j++) { 749cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (((j + delta) & 0xffff) != 0) { 759cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien addRange(coverage, j, j + 1); 769cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 779cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 789cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 799cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } else { 809cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien for (int j = start; j < end + 1; j++) { 819cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien uint32_t actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset + 829cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien (i + j - start) * 2; 839cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (actualRangeOffset + 2 > size) { 845f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien // invalid rangeOffset is considered a "warning" by OpenType Sanitizer 855f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien continue; 869cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 879cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int glyphId = readU16(data, actualRangeOffset); 889cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (glyphId != 0) { 899cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien addRange(coverage, j, j + 1); 909cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 919cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 929cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 939cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 949cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return true; 959cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 969cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 979cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector 989cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data, size_t size) { 999cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kNGroupsOffset = 12; 1009cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kFirstGroupOffset = 16; 1019cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kGroupSize = 12; 1029cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kStartCharCodeOffset = 0; 1039cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kEndCharCodeOffset = 4; 1049cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (kFirstGroupOffset > size) { 1059cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return false; 1069cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1079cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien uint32_t nGroups = readU32(data, kNGroupsOffset); 1089cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (kFirstGroupOffset + nGroups * kGroupSize > size) { 1099cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return false; 1109cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1119cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien for (uint32_t i = 0; i < nGroups; i++) { 1129cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize; 1139cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset); 1149cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset); 1159cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien addRange(coverage, start, end + 1); // file is inclusive, vector is exclusive 1169cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1179cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return true; 1189cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 1199cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 1209cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienbool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data, size_t cmap_size) { 1219cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien vector<uint32_t> coverageVec; 1229cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kHeaderSize = 4; 1239cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kNumTablesOffset = 2; 1249cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kTableSize = 8; 1259cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kPlatformIdOffset = 0; 1269cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kEncodingIdOffset = 2; 1279cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t kOffsetOffset = 4; 1289cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const int kMicrosoftPlatformId = 3; 1299cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const int kUnicodeBmpEncodingId = 1; 1309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const int kUnicodeUcs4EncodingId = 10; 1319cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (kHeaderSize > cmap_size) { 1329cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return false; 1339cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int numTables = readU16(cmap_data, kNumTablesOffset); 1359cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (kHeaderSize + numTables * kTableSize > cmap_size) { 1369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return false; 1379cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int bestTable = -1; 1399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien for (int i = 0; i < numTables; i++) { 1409cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien uint16_t platformId = readU16(cmap_data, kHeaderSize + i * kTableSize + kPlatformIdOffset); 1419cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien uint16_t encodingId = readU16(cmap_data, kHeaderSize + i * kTableSize + kEncodingIdOffset); 1429cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeUcs4EncodingId) { 1439cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien bestTable = i; 1449cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien break; 1459cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } else if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeBmpEncodingId) { 1469cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien bestTable = i; 1479cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1489cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1495f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien#ifdef VERBOSE_DEBUG 1505f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien ALOGD("best table = %d\n", bestTable); 1519cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif 1529cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (bestTable < 0) { 1539cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return false; 1549cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1559cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien uint32_t offset = readU32(cmap_data, kHeaderSize + bestTable * kTableSize + kOffsetOffset); 1569cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (offset + 2 > cmap_size) { 1579cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return false; 1589cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1599cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien uint16_t format = readU16(cmap_data, offset); 1609cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien bool success = false; 1619cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const uint8_t* tableData = cmap_data + offset; 1629cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const size_t tableSize = cmap_size - offset; 1639cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (format == 4) { 1649cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien success = getCoverageFormat4(coverageVec, tableData, tableSize); 1659cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } else if (format == 12) { 1669cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien success = getCoverageFormat12(coverageVec, tableData, tableSize); 1679cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1689cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (success) { 1699cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien coverage.initFromRanges(&coverageVec.front(), coverageVec.size() >> 1); 1709cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1715f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien#ifdef VERBOSE_DEBUG 1725f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien for (size_t i = 0; i < coverageVec.size(); i += 2) { 1735f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien ALOGD("%x:%x\n", coverageVec[i], coverageVec[i + 1]); 1749cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1755f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien ALOGD("success = %d", success); 1769cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif 1779cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return success; 1789cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 1799cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 1809cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} // namespace android 181