• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
23 using std::vector;
24 
25 #include <minikin/SparseBitSet.h>
26 #include <minikin/CmapCoverage.h>
27 
28 namespace android {
29 
30 // These could perhaps be optimized to use __builtin_bswap16 and friends.
readU16(const uint8_t * data,size_t offset)31 static uint32_t readU16(const uint8_t* data, size_t offset) {
32     return data[offset] << 8 | data[offset + 1];
33 }
34 
readU32(const uint8_t * data,size_t offset)35 static 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 
addRange(vector<uint32_t> & coverage,uint32_t start,uint32_t end)39 static 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
getCoverageFormat4(vector<uint32_t> & coverage,const uint8_t * data,size_t size)52 static 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
getCoverageFormat12(vector<uint32_t> & coverage,const uint8_t * data,size_t size)98 static 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 
getCoverage(SparseBitSet & coverage,const uint8_t * cmap_data,size_t cmap_size)120 bool 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