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