CmapCoverage.cpp revision 5f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17// Determine coverage of font given its raw "cmap" OpenType table 18 19#define LOG_TAG "Minikin" 20#include <cutils/log.h> 21 22#include <vector> 23using std::vector; 24 25#include <minikin/SparseBitSet.h> 26#include <minikin/CmapCoverage.h> 27 28namespace android { 29 30// These could perhaps be optimized to use __builtin_bswap16 and friends. 31static uint32_t readU16(const uint8_t* data, size_t offset) { 32 return data[offset] << 8 | data[offset + 1]; 33} 34 35static uint32_t readU32(const uint8_t* data, size_t offset) { 36 return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]; 37} 38 39static void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) { 40#ifdef VERBOSE_DEBUG 41 ALOGD("adding range %d-%d\n", start, end); 42#endif 43 if (coverage.empty() || coverage.back() < start) { 44 coverage.push_back(start); 45 coverage.push_back(end); 46 } else { 47 coverage.back() = end; 48 } 49} 50 51// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector 52static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data, size_t size) { 53 const size_t kSegCountOffset = 6; 54 const size_t kEndCountOffset = 14; 55 const size_t kHeaderSize = 16; 56 const size_t kSegmentSize = 8; // total size of array elements for one segment 57 if (kEndCountOffset > size) { 58 return false; 59 } 60 size_t segCount = readU16(data, kSegCountOffset) >> 1; 61 if (kHeaderSize + segCount * kSegmentSize > size) { 62 return false; 63 } 64 for (size_t i = 0; i < segCount; i++) { 65 int end = readU16(data, kEndCountOffset + 2 * i); 66 int start = readU16(data, kHeaderSize + 2 * (segCount + i)); 67 int rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i)); 68 if (rangeOffset == 0) { 69 int delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i)); 70 if (((end + delta) & 0xffff) > end - start) { 71 addRange(coverage, start, end + 1); 72 } else { 73 for (int j = start; j < end + 1; j++) { 74 if (((j + delta) & 0xffff) != 0) { 75 addRange(coverage, j, j + 1); 76 } 77 } 78 } 79 } else { 80 for (int j = start; j < end + 1; j++) { 81 uint32_t actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset + 82 (i + j - start) * 2; 83 if (actualRangeOffset + 2 > size) { 84 // invalid rangeOffset is considered a "warning" by OpenType Sanitizer 85 continue; 86 } 87 int glyphId = readU16(data, actualRangeOffset); 88 if (glyphId != 0) { 89 addRange(coverage, j, j + 1); 90 } 91 } 92 } 93 } 94 return true; 95} 96 97// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector 98static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data, size_t size) { 99 const size_t kNGroupsOffset = 12; 100 const size_t kFirstGroupOffset = 16; 101 const size_t kGroupSize = 12; 102 const size_t kStartCharCodeOffset = 0; 103 const size_t kEndCharCodeOffset = 4; 104 if (kFirstGroupOffset > size) { 105 return false; 106 } 107 uint32_t nGroups = readU32(data, kNGroupsOffset); 108 if (kFirstGroupOffset + nGroups * kGroupSize > size) { 109 return false; 110 } 111 for (uint32_t i = 0; i < nGroups; i++) { 112 uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize; 113 uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset); 114 uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset); 115 addRange(coverage, start, end + 1); // file is inclusive, vector is exclusive 116 } 117 return true; 118} 119 120bool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data, size_t cmap_size) { 121 vector<uint32_t> coverageVec; 122 const size_t kHeaderSize = 4; 123 const size_t kNumTablesOffset = 2; 124 const size_t kTableSize = 8; 125 const size_t kPlatformIdOffset = 0; 126 const size_t kEncodingIdOffset = 2; 127 const size_t kOffsetOffset = 4; 128 const int kMicrosoftPlatformId = 3; 129 const int kUnicodeBmpEncodingId = 1; 130 const int kUnicodeUcs4EncodingId = 10; 131 if (kHeaderSize > cmap_size) { 132 return false; 133 } 134 int numTables = readU16(cmap_data, kNumTablesOffset); 135 if (kHeaderSize + numTables * kTableSize > cmap_size) { 136 return false; 137 } 138 int bestTable = -1; 139 for (int i = 0; i < numTables; i++) { 140 uint16_t platformId = readU16(cmap_data, kHeaderSize + i * kTableSize + kPlatformIdOffset); 141 uint16_t encodingId = readU16(cmap_data, kHeaderSize + i * kTableSize + kEncodingIdOffset); 142 if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeUcs4EncodingId) { 143 bestTable = i; 144 break; 145 } else if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeBmpEncodingId) { 146 bestTable = i; 147 } 148 } 149#ifdef VERBOSE_DEBUG 150 ALOGD("best table = %d\n", bestTable); 151#endif 152 if (bestTable < 0) { 153 return false; 154 } 155 uint32_t offset = readU32(cmap_data, kHeaderSize + bestTable * kTableSize + kOffsetOffset); 156 if (offset + 2 > cmap_size) { 157 return false; 158 } 159 uint16_t format = readU16(cmap_data, offset); 160 bool success = false; 161 const uint8_t* tableData = cmap_data + offset; 162 const size_t tableSize = cmap_size - offset; 163 if (format == 4) { 164 success = getCoverageFormat4(coverageVec, tableData, tableSize); 165 } else if (format == 12) { 166 success = getCoverageFormat12(coverageVec, tableData, tableSize); 167 } 168 if (success) { 169 coverage.initFromRanges(&coverageVec.front(), coverageVec.size() >> 1); 170 } 171#ifdef VERBOSE_DEBUG 172 for (size_t i = 0; i < coverageVec.size(); i += 2) { 173 ALOGD("%x:%x\n", coverageVec[i], coverageVec[i + 1]); 174 } 175 ALOGD("success = %d", success); 176#endif 177 return success; 178} 179 180} // namespace android 181