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