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