18eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary/* 28eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary * Copyright 2011 Google Inc. 38eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary * 48eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary * Use of this source code is governed by a BSD-style license that can be 58eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary * found in the LICENSE file. 68eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary */ 78eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 88eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary#include "SkPDFMakeToUnicodeCmap.h" 98eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary#include "SkPDFUtils.h" 108eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary#include "SkUtils.h" 118eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 128eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanarystatic void append_tounicode_header(SkDynamicMemoryWStream* cmap, 133d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary bool multibyte) { 148eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // 12 dict begin: 12 is an Adobe-suggested value. Shall not change. 158eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // It's there to prevent old version Adobe Readers from malfunctioning. 168eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary const char* kHeader = 178eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "/CIDInit /ProcSet findresource begin\n" 188eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "12 dict begin\n" 198eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "begincmap\n"; 208eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText(kHeader); 218eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 228eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // The /CIDSystemInfo must be consistent to the one in 238eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // SkPDFFont::populateCIDFont(). 248eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // We can not pass over the system info object here because the format is 258eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // different. This is not a reference object. 268eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary const char* kSysInfo = 278eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "/CIDSystemInfo\n" 2859be20c8d532a81992a9ec73b6a39265a479fce5halcanary "<< /Registry (Adobe)\n" 2959be20c8d532a81992a9ec73b6a39265a479fce5halcanary "/Ordering (UCS)\n" 308eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "/Supplement 0\n" 318eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary ">> def\n"; 328eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText(kSysInfo); 338eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 348eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // The CMapName must be consistent to /CIDSystemInfo above. 358eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // /CMapType 2 means ToUnicode. 368eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // Codespace range just tells the PDF processor the valid range. 378eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary const char* kTypeInfoHeader = 3859be20c8d532a81992a9ec73b6a39265a479fce5halcanary "/CMapName /Adobe-Identity-UCS def\n" 398eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "/CMapType 2 def\n" 408eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "1 begincodespacerange\n"; 418eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText(kTypeInfoHeader); 423d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary if (multibyte) { 433d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary cmap->writeText("<0000> <FFFF>\n"); 443d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary } else { 453d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary cmap->writeText("<00> <FF>\n"); 463d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary } 473d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary cmap->writeText("endcodespacerange\n"); 488eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary} 498eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 508eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanarystatic void append_cmap_footer(SkDynamicMemoryWStream* cmap) { 518eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary const char kFooter[] = 528eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "endcmap\n" 538eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "CMapName currentdict /CMap defineresource pop\n" 548eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "end\n" 558eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary "end"; 568eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText(kFooter); 578eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary} 588eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 598eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanarynamespace { 608eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanarystruct BFChar { 618eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkGlyphID fGlyphId; 628eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkUnichar fUnicode; 638eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary}; 648eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 658eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanarystruct BFRange { 668eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkGlyphID fStart; 678eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkGlyphID fEnd; 688eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkUnichar fUnicode; 698eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary}; 708eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary} // namespace 718eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 723d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanarystatic void write_glyph(SkDynamicMemoryWStream* cmap, 733d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary bool multiByte, 743d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary SkGlyphID gid) { 753d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary if (multiByte) { 763d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary SkPDFUtils::WriteUInt16BE(cmap, gid); 773d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary } else { 783d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary SkPDFUtils::WriteUInt8(cmap, SkToU8(gid)); 793d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary } 803d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary} 813d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary 828eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanarystatic void append_bfchar_section(const SkTDArray<BFChar>& bfchar, 833d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary bool multiByte, 848eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkDynamicMemoryWStream* cmap) { 858eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // PDF spec defines that every bf* list can have at most 100 entries. 868eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary for (int i = 0; i < bfchar.count(); i += 100) { 878eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary int count = bfchar.count() - i; 888eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary count = SkMin32(count, 100); 898eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeDecAsText(count); 908eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText(" beginbfchar\n"); 918eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary for (int j = 0; j < count; ++j) { 928eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText("<"); 933d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary write_glyph(cmap, multiByte, bfchar[i + j].fGlyphId); 948eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText("> <"); 95f59d18a4ea5ad56975502faf50eae43418ea9c2ahalcanary SkPDFUtils::WriteUTF16beHex(cmap, bfchar[i + j].fUnicode); 968eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText(">\n"); 978eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 988eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText("endbfchar\n"); 998eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 1008eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary} 1018eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 1028eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanarystatic void append_bfrange_section(const SkTDArray<BFRange>& bfrange, 1033d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary bool multiByte, 1048eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkDynamicMemoryWStream* cmap) { 1058eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // PDF spec defines that every bf* list can have at most 100 entries. 1068eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary for (int i = 0; i < bfrange.count(); i += 100) { 1078eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary int count = bfrange.count() - i; 1088eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary count = SkMin32(count, 100); 1098eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeDecAsText(count); 1108eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText(" beginbfrange\n"); 1118eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary for (int j = 0; j < count; ++j) { 1128eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText("<"); 1133d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary write_glyph(cmap, multiByte, bfrange[i + j].fStart); 1148eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText("> <"); 1153d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary write_glyph(cmap, multiByte, bfrange[i + j].fEnd); 1168eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText("> <"); 117f59d18a4ea5ad56975502faf50eae43418ea9c2ahalcanary SkPDFUtils::WriteUTF16beHex(cmap, bfrange[i + j].fUnicode); 1188eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText(">\n"); 1198eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 1208eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary cmap->writeText("endbfrange\n"); 1218eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 1228eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary} 1238eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 1248eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// Generate <bfchar> and <bfrange> table according to PDF spec 1.4 and Adobe 1258eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// Technote 5014. 1268eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// The function is not static so we can test it in unit tests. 1278eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// 1288eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// Current implementation guarantees bfchar and bfrange entries do not overlap. 1298eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// 1308eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// Current implementation does not attempt aggresive optimizations against 1318eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// following case because the specification is not clear. 1328eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// 1338eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// 4 beginbfchar 1 beginbfchar 1348eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// <0003> <0013> <0020> <0014> 1358eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// <0005> <0015> to endbfchar 1368eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// <0007> <0017> 1 beginbfrange 1378eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// <0020> <0014> <0003> <0007> <0013> 1388eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// endbfchar endbfrange 1398eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// 1408eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// Adobe Technote 5014 said: "Code mappings (unlike codespace ranges) may 1418eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// overlap, but succeeding maps supersede preceding maps." 1428eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// 1438eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// In case of searching text in PDF, bfrange will have higher precedence so 1448eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// typing char id 0x0014 in search box will get glyph id 0x0004 first. However, 1458eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// the spec does not mention how will this kind of conflict being resolved. 1468eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// 1478eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// For the worst case (having 65536 continuous unicode and we use every other 1488eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// one of them), the possible savings by aggressive optimization is 416KB 1498eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary// pre-compressed and does not provide enough motivation for implementation. 1508eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanaryvoid SkPDFAppendCmapSections(const SkTDArray<SkUnichar>& glyphToUnicode, 151530032a18e373ee673ae96fdbfa1fae6292f8f08halcanary const SkBitSet* subset, 1528eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkDynamicMemoryWStream* cmap, 1538eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary bool multiByteGlyphs, 1548eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkGlyphID firstGlyphID, 1558eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkGlyphID lastGlyphID) { 1568eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary if (glyphToUnicode.isEmpty()) { 1578eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary return; 1588eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 1598eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary int glyphOffset = 0; 1608eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary if (!multiByteGlyphs) { 1618eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary glyphOffset = firstGlyphID - 1; 1628eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 1638eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 1648eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkTDArray<BFChar> bfcharEntries; 1658eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkTDArray<BFRange> bfrangeEntries; 1668eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 1678eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary BFRange currentRangeEntry = {0, 0, 0}; 1688eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary bool rangeEmpty = true; 1698eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary const int limit = 1708eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkMin32(lastGlyphID + 1, glyphToUnicode.count()) - glyphOffset; 1718eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 1728eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary for (int i = firstGlyphID - glyphOffset; i < limit + 1; ++i) { 1738eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary bool inSubset = i < limit && 1748eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary (subset == nullptr || subset->has(i + glyphOffset)); 1758eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary if (!rangeEmpty) { 1768eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // PDF spec requires bfrange not changing the higher byte, 1778eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // e.g. <1035> <10FF> <2222> is ok, but 1788eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // <1035> <1100> <2222> is no good 1798eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary bool inRange = 1808eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary i == currentRangeEntry.fEnd + 1 && 1818eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary i >> 8 == currentRangeEntry.fStart >> 8 && 1828eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary i < limit && 1838eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary glyphToUnicode[i + glyphOffset] == 1848eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary currentRangeEntry.fUnicode + i - currentRangeEntry.fStart; 1858eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary if (!inSubset || !inRange) { 1868eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary if (currentRangeEntry.fEnd > currentRangeEntry.fStart) { 1878eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary bfrangeEntries.push(currentRangeEntry); 1888eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } else { 1898eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary BFChar* entry = bfcharEntries.append(); 1908eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary entry->fGlyphId = currentRangeEntry.fStart; 1918eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary entry->fUnicode = currentRangeEntry.fUnicode; 1928eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 1938eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary rangeEmpty = true; 1948eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 1958eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 1968eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary if (inSubset) { 1978eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary currentRangeEntry.fEnd = i; 1988eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary if (rangeEmpty) { 1998eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary currentRangeEntry.fStart = i; 2008eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary currentRangeEntry.fUnicode = glyphToUnicode[i + glyphOffset]; 2018eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary rangeEmpty = false; 2028eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 2038eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 2048eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary } 2058eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 2068eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // The spec requires all bfchar entries for a font must come before bfrange 2078eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary // entries. 2083d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary append_bfchar_section(bfcharEntries, multiByteGlyphs, cmap); 2093d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary append_bfrange_section(bfrangeEntries, multiByteGlyphs, cmap); 2108eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary} 2118eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary 2128eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanarysk_sp<SkPDFStream> SkPDFMakeToUnicodeCmap( 2138eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary const SkTDArray<SkUnichar>& glyphToUnicode, 214530032a18e373ee673ae96fdbfa1fae6292f8f08halcanary const SkBitSet* subset, 2158eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary bool multiByteGlyphs, 2168eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkGlyphID firstGlyphID, 2178eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkGlyphID lastGlyphID) { 2188eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkDynamicMemoryWStream cmap; 2193d01c62e19df9f369cdfaeff82ec8af2c0be75f1halcanary append_tounicode_header(&cmap, multiByteGlyphs); 2208eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary SkPDFAppendCmapSections(glyphToUnicode, subset, &cmap, multiByteGlyphs, 2218eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary firstGlyphID, lastGlyphID); 2228eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary append_cmap_footer(&cmap); 2238eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary return sk_make_sp<SkPDFStream>( 2248eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary std::unique_ptr<SkStreamAsset>(cmap.detachAsStream())); 2258eccc308c8adcdf26ffc7c4dd538b71f33c6f22bhalcanary} 226