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