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) {
326299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien    return ((uint32_t)data[offset]) << 8 | ((uint32_t)data[offset + 1]);
339cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
359cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic uint32_t readU32(const uint8_t* data, size_t offset) {
366299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien    return ((uint32_t)data[offset]) << 24 | ((uint32_t)data[offset + 1]) << 16 |
376299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien        ((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]);
389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
409cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) {
415f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien#ifdef VERBOSE_DEBUG
425f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien    ALOGD("adding range %d-%d\n", start, end);
439cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif
449cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (coverage.empty() || coverage.back() < start) {
459cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        coverage.push_back(start);
469cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        coverage.push_back(end);
479cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    } else {
489cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        coverage.back() = end;
499cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
509cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
519cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
52ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien// Get the coverage information out of a Format 4 subtable, storing it in the coverage vector
539cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
549cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kSegCountOffset = 6;
559cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kEndCountOffset = 14;
569cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kHeaderSize = 16;
579cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kSegmentSize = 8;  // total size of array elements for one segment
589cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (kEndCountOffset > size) {
599cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
609cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
619cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    size_t segCount = readU16(data, kSegCountOffset) >> 1;
629cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (kHeaderSize + segCount * kSegmentSize > size) {
639cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
649cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
659cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    for (size_t i = 0; i < segCount; i++) {
66ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        uint32_t end = readU16(data, kEndCountOffset + 2 * i);
67ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        uint32_t start = readU16(data, kHeaderSize + 2 * (segCount + i));
68ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        if (end < start) {
69ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            // invalid segment range: size must be positive
70734f037130e14b3d44bc74026d3d065c025a8280Raph Levien            android_errorWriteLog(0x534e4554, "26413177");
71ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            return false;
72ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        }
73ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        uint32_t rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));
749cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        if (rangeOffset == 0) {
75ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            uint32_t delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
769cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            if (((end + delta) & 0xffff) > end - start) {
779cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                addRange(coverage, start, end + 1);
789cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            } else {
79ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien                for (uint32_t j = start; j < end + 1; j++) {
809cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    if (((j + delta) & 0xffff) != 0) {
819cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                        addRange(coverage, j, j + 1);
829cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    }
839cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                }
849cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            }
859cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        } else {
86ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            for (uint32_t j = start; j < end + 1; j++) {
879cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                uint32_t actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset +
889cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    (i + j - start) * 2;
899cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                if (actualRangeOffset + 2 > size) {
905f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien                    // invalid rangeOffset is considered a "warning" by OpenType Sanitizer
915f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien                    continue;
929cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                }
93ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien                uint32_t glyphId = readU16(data, actualRangeOffset);
949cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                if (glyphId != 0) {
959cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                    addRange(coverage, j, j + 1);
969cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien                }
979cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            }
989cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
999cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1009cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    return true;
1019cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
1029cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
1039cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector
1049cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
1059cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kNGroupsOffset = 12;
1069cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kFirstGroupOffset = 16;
1079cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kGroupSize = 12;
1089cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kStartCharCodeOffset = 0;
1099cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kEndCharCodeOffset = 4;
1106299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien    const size_t kMaxNGroups = 0xfffffff0 / kGroupSize;  // protection against overflow
1116299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien    // For all values < kMaxNGroups, kFirstGroupOffset + nGroups * kGroupSize fits in 32 bits.
1129cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (kFirstGroupOffset > size) {
1139cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
1149cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1159cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t nGroups = readU32(data, kNGroupsOffset);
1166299a6ba13906c695f7a4f6748f7bc5856a110e5Raph Levien    if (nGroups >= kMaxNGroups || kFirstGroupOffset + nGroups * kGroupSize > size) {
117734f037130e14b3d44bc74026d3d065c025a8280Raph Levien        android_errorWriteLog(0x534e4554, "25645298");
1189cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
1199cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1209cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    for (uint32_t i = 0; i < nGroups; i++) {
1219cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize;
1229cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset);
1239cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset);
124ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        if (end < start) {
125ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            // invalid group range: size must be positive
126734f037130e14b3d44bc74026d3d065c025a8280Raph Levien            android_errorWriteLog(0x534e4554, "26413177");
127ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien            return false;
128ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien        }
1299cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        addRange(coverage, start, end + 1);  // file is inclusive, vector is exclusive
1309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1319cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    return true;
1329cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
1339cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
1346b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonakabool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data, size_t cmap_size,
1356b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka        bool* has_cmap_format14_subtable) {
1369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    vector<uint32_t> coverageVec;
1379cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kHeaderSize = 4;
1389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kNumTablesOffset = 2;
1399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kTableSize = 8;
1409cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kPlatformIdOffset = 0;
1419cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kEncodingIdOffset = 2;
1429cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t kOffsetOffset = 4;
1436b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka    const uint16_t kUnicodePlatformId = 0;
144ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien    const uint16_t kMicrosoftPlatformId = 3;
145ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien    const uint16_t kUnicodeBmpEncodingId = 1;
1466b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka    const uint16_t kVariationSequencesEncodingId = 5;
147ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien    const uint16_t kUnicodeUcs4EncodingId = 10;
148ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien    const uint32_t kNoTable = UINT32_MAX;
1499cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (kHeaderSize > cmap_size) {
1509cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
1519cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
152ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien    uint32_t numTables = readU16(cmap_data, kNumTablesOffset);
1539cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (kHeaderSize + numTables * kTableSize > cmap_size) {
1549cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
1559cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
156ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien    uint32_t bestTable = kNoTable;
1576b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka    bool hasCmapFormat14Subtable = false;
158ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien    for (uint32_t i = 0; i < numTables; i++) {
1599cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint16_t platformId = readU16(cmap_data, kHeaderSize + i * kTableSize + kPlatformIdOffset);
1609cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        uint16_t encodingId = readU16(cmap_data, kHeaderSize + i * kTableSize + kEncodingIdOffset);
1619cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeUcs4EncodingId) {
1629cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            bestTable = i;
1639cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            break;
1649cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        } else if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeBmpEncodingId) {
1659cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            bestTable = i;
1666b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka        } else if (platformId == kUnicodePlatformId &&
1676b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka                encodingId == kVariationSequencesEncodingId) {
1686b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka            uint32_t offset = readU32(cmap_data, kHeaderSize + i * kTableSize + kOffsetOffset);
1696b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka            if (offset <= cmap_size - 2 && readU16(cmap_data, offset) == 14) {
1706b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka                hasCmapFormat14Subtable = true;
1716b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka            }
1729cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
1739cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1746b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka    *has_cmap_format14_subtable = hasCmapFormat14Subtable;
1755f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien#ifdef VERBOSE_DEBUG
1765f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien    ALOGD("best table = %d\n", bestTable);
1779cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif
178ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien    if (bestTable == kNoTable) {
1799cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
1809cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1819cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint32_t offset = readU32(cmap_data, kHeaderSize + bestTable * kTableSize + kOffsetOffset);
182ca8ac8acdad662230ae37998c6c4091bb39402b6Raph Levien    if (offset > cmap_size - 2) {
1839cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        return false;
1849cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1859cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    uint16_t format = readU16(cmap_data, offset);
1869cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    bool success = false;
1879cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const uint8_t* tableData = cmap_data + offset;
1889cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    const size_t tableSize = cmap_size - offset;
1899cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (format == 4) {
1909cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        success = getCoverageFormat4(coverageVec, tableData, tableSize);
1919cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    } else if (format == 12) {
1929cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        success = getCoverageFormat12(coverageVec, tableData, tableSize);
1939cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1949cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (success) {
1959cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        coverage.initFromRanges(&coverageVec.front(), coverageVec.size() >> 1);
1969cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1975f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien#ifdef VERBOSE_DEBUG
1985f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien    for (size_t i = 0; i < coverageVec.size(); i += 2) {
1995f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien        ALOGD("%x:%x\n", coverageVec[i], coverageVec[i + 1]);
2009cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
2015f11abd31fa8cfa723f54bd1c98ce4e27e7d3c77Raph Levien    ALOGD("success = %d", success);
2029cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif
2039cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    return success;
2049cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
2059cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
2069cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}  // namespace android
207