1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* 2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2011 Google Inc. 3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be 5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file. 6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPDFMakeToUnicodeCmap.h" 9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPDFUtils.h" 10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkUtils.h" 11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void append_tounicode_header(SkDynamicMemoryWStream* cmap, 13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool multibyte) { 14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // 12 dict begin: 12 is an Adobe-suggested value. Shall not change. 15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // It's there to prevent old version Adobe Readers from malfunctioning. 16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const char* kHeader = 17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "/CIDInit /ProcSet findresource begin\n" 18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "12 dict begin\n" 19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "begincmap\n"; 20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText(kHeader); 21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // The /CIDSystemInfo must be consistent to the one in 23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // SkPDFFont::populateCIDFont(). 24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // We can not pass over the system info object here because the format is 25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // different. This is not a reference object. 26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const char* kSysInfo = 27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "/CIDSystemInfo\n" 28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "<< /Registry (Adobe)\n" 29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "/Ordering (UCS)\n" 30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "/Supplement 0\n" 31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ">> def\n"; 32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText(kSysInfo); 33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // The CMapName must be consistent to /CIDSystemInfo above. 35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // /CMapType 2 means ToUnicode. 36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Codespace range just tells the PDF processor the valid range. 37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const char* kTypeInfoHeader = 38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "/CMapName /Adobe-Identity-UCS def\n" 39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "/CMapType 2 def\n" 40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "1 begincodespacerange\n"; 41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText(kTypeInfoHeader); 42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (multibyte) { 43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText("<0000> <FFFF>\n"); 44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText("<00> <FF>\n"); 46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText("endcodespacerange\n"); 48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void append_cmap_footer(SkDynamicMemoryWStream* cmap) { 51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const char kFooter[] = 52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "endcmap\n" 53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "CMapName currentdict /CMap defineresource pop\n" 54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "end\n" 55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "end"; 56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText(kFooter); 57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace { 60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct BFChar { 61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkGlyphID fGlyphId; 62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkUnichar fUnicode; 63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct BFRange { 66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkGlyphID fStart; 67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkGlyphID fEnd; 68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkUnichar fUnicode; 69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} // namespace 71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void write_glyph(SkDynamicMemoryWStream* cmap, 73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool multiByte, 74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkGlyphID gid) { 75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (multiByte) { 76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPDFUtils::WriteUInt16BE(cmap, gid); 77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPDFUtils::WriteUInt8(cmap, SkToU8(gid)); 79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void append_bfchar_section(const SkTDArray<BFChar>& bfchar, 83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool multiByte, 84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream* cmap) { 85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // PDF spec defines that every bf* list can have at most 100 entries. 86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (int i = 0; i < bfchar.count(); i += 100) { 87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int count = bfchar.count() - i; 88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot count = SkMin32(count, 100); 89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeDecAsText(count); 90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText(" beginbfchar\n"); 91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (int j = 0; j < count; ++j) { 92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText("<"); 93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot write_glyph(cmap, multiByte, bfchar[i + j].fGlyphId); 94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText("> <"); 95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPDFUtils::WriteUTF16beHex(cmap, bfchar[i + j].fUnicode); 96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText(">\n"); 97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText("endbfchar\n"); 99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void append_bfrange_section(const SkTDArray<BFRange>& bfrange, 103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool multiByte, 104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream* cmap) { 105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // PDF spec defines that every bf* list can have at most 100 entries. 106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (int i = 0; i < bfrange.count(); i += 100) { 107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int count = bfrange.count() - i; 108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot count = SkMin32(count, 100); 109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeDecAsText(count); 110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText(" beginbfrange\n"); 111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (int j = 0; j < count; ++j) { 112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText("<"); 113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot write_glyph(cmap, multiByte, bfrange[i + j].fStart); 114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText("> <"); 115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot write_glyph(cmap, multiByte, bfrange[i + j].fEnd); 116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText("> <"); 117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPDFUtils::WriteUTF16beHex(cmap, bfrange[i + j].fUnicode); 118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText(">\n"); 119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot cmap->writeText("endbfrange\n"); 121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Generate <bfchar> and <bfrange> table according to PDF spec 1.4 and Adobe 125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Technote 5014. 126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// The function is not static so we can test it in unit tests. 127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Current implementation guarantees bfchar and bfrange entries do not overlap. 129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Current implementation does not attempt aggresive optimizations against 131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// following case because the specification is not clear. 132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 4 beginbfchar 1 beginbfchar 134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// <0003> <0013> <0020> <0014> 135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// <0005> <0015> to endbfchar 136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// <0007> <0017> 1 beginbfrange 137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// <0020> <0014> <0003> <0007> <0013> 138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// endbfchar endbfrange 139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Adobe Technote 5014 said: "Code mappings (unlike codespace ranges) may 141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// overlap, but succeeding maps supersede preceding maps." 142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// In case of searching text in PDF, bfrange will have higher precedence so 144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// typing char id 0x0014 in search box will get glyph id 0x0004 first. However, 145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// the spec does not mention how will this kind of conflict being resolved. 146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// 147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// For the worst case (having 65536 continuous unicode and we use every other 148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// one of them), the possible savings by aggressive optimization is 416KB 149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// pre-compressed and does not provide enough motivation for implementation. 150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPDFAppendCmapSections(const SkTDArray<SkUnichar>& glyphToUnicode, 151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkBitSet* subset, 152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream* cmap, 153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool multiByteGlyphs, 154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkGlyphID firstGlyphID, 155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkGlyphID lastGlyphID) { 156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (glyphToUnicode.isEmpty()) { 157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int glyphOffset = 0; 160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!multiByteGlyphs) { 161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot glyphOffset = firstGlyphID - 1; 162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTDArray<BFChar> bfcharEntries; 165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTDArray<BFRange> bfrangeEntries; 166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot BFRange currentRangeEntry = {0, 0, 0}; 168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool rangeEmpty = true; 169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const int limit = 170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkMin32(lastGlyphID + 1, glyphToUnicode.count()) - glyphOffset; 171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (int i = firstGlyphID - glyphOffset; i < limit + 1; ++i) { 173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool inSubset = i < limit && 174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot (subset == nullptr || subset->has(i + glyphOffset)); 175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!rangeEmpty) { 176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // PDF spec requires bfrange not changing the higher byte, 177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // e.g. <1035> <10FF> <2222> is ok, but 178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // <1035> <1100> <2222> is no good 179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool inRange = 180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot i == currentRangeEntry.fEnd + 1 && 181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot i >> 8 == currentRangeEntry.fStart >> 8 && 182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot i < limit && 183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot glyphToUnicode[i + glyphOffset] == 184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot currentRangeEntry.fUnicode + i - currentRangeEntry.fStart; 185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!inSubset || !inRange) { 186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (currentRangeEntry.fEnd > currentRangeEntry.fStart) { 187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bfrangeEntries.push(currentRangeEntry); 188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot BFChar* entry = bfcharEntries.append(); 190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot entry->fGlyphId = currentRangeEntry.fStart; 191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot entry->fUnicode = currentRangeEntry.fUnicode; 192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot rangeEmpty = true; 194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (inSubset) { 197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot currentRangeEntry.fEnd = i; 198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (rangeEmpty) { 199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot currentRangeEntry.fStart = i; 200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot currentRangeEntry.fUnicode = glyphToUnicode[i + glyphOffset]; 201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot rangeEmpty = false; 202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // The spec requires all bfchar entries for a font must come before bfrange 207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // entries. 208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot append_bfchar_section(bfcharEntries, multiByteGlyphs, cmap); 209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot append_bfrange_section(bfrangeEntries, multiByteGlyphs, cmap); 210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkPDFStream> SkPDFMakeToUnicodeCmap( 213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkTDArray<SkUnichar>& glyphToUnicode, 214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkBitSet* subset, 215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool multiByteGlyphs, 216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkGlyphID firstGlyphID, 217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkGlyphID lastGlyphID) { 218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream cmap; 219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot append_tounicode_header(&cmap, multiByteGlyphs); 220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkPDFAppendCmapSections(glyphToUnicode, subset, &cmap, multiByteGlyphs, 221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot firstGlyphID, lastGlyphID); 222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot append_cmap_footer(&cmap); 223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return sk_make_sp<SkPDFStream>( 224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot std::unique_ptr<SkStreamAsset>(cmap.detachAsStream())); 225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 226