Flutter Engine
The Flutter Engine
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
SkPDFMakeCIDGlyphWidthsArray.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
11#include "include/core/SkSpan.h"
14#include "src/core/SkGlyph.h"
17#include "src/pdf/SkPDFTypes.h"
18
19#include <algorithm>
20#include <cstddef>
21#include <utility>
22#include <vector>
23
24namespace {
25
26// Scale from em-units to 1000-units.
27SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
28 if (emSize == 1000) {
29 return scaled;
30 } else {
31 return scaled * 1000 / emSize;
32 }
33}
34
35SkScalar find_mode_or_0(SkSpan<const SkScalar> advances) {
36 if (advances.empty()) {
37 return 0;
38 }
39
40 SkScalar currentAdvance = advances[0];
41 SkScalar currentModeAdvance = advances[0];
42 size_t currentCount = 1;
43 size_t currentModeCount = 1;
44
45 for (size_t i = 1; i < advances.size(); ++i) {
46 if (advances[i] == currentAdvance) {
47 ++currentCount;
48 } else {
49 if (currentCount > currentModeCount) {
50 currentModeAdvance = currentAdvance;
51 currentModeCount = currentCount;
52 }
53 currentAdvance = advances[i];
54 currentCount = 1;
55 }
56 }
57 return currentCount > currentModeCount ? currentAdvance : currentModeAdvance;
58}
59
60} // namespace
61
62std::unique_ptr<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(const SkTypeface& typeface,
63 const SkPDFGlyphUse& subset,
64 int32_t* defaultAdvance) {
65 // There are two ways of expressing advances
66 //
67 // range: " gfid [adv.ances adv.ances ... adv.ances]"
68 // run: " gfid gfid adv.ances"
69 //
70 // Assuming that on average
71 // the ASCII representation of an advance plus a space is 10 characters
72 // the ASCII representation of a glyph id plus a space is 4 characters
73 // the ASCII representation of unused gid plus a space in a range is 2 characters
74 //
75 // When not in a range or run
76 // a. Skipping don't cares or defaults is a win (trivial)
77 // b. Run wins for 2+ repeats " gid gid adv.ances"
78 // " gid [adv.ances adv.ances]"
79 // rule: 2+ repeats create run as long as possible, else start range
80 //
81 // When in a range
82 // Cost of stopping and starting a range is 8 characters "] gid ["
83 // c. Skipping defaults is always a win " adv.ances"
84 // rule: end range if default seen
85 // d. Skipping 4+ don't cares is a win " 0 0 0 0"
86 // rule: end range if 4+ don't cares
87 // Cost of stop and start range plus run is 28 characters "] gid gid adv.ances gid ["
88 // e. Switching for 2+ repeats and 4+ don't cares wins " 0 0 adv.ances 0 0 adv.ances"
89 // rule: end range for 2+ repeats with 4+ don't cares
90 // f. Switching for 3+ repeats wins " adv.ances adv.ances adv.ances"
91 // rule: end range for 3+ repeats
92
93 int emSize;
94 SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(typeface, &emSize);
95 SkBulkGlyphMetricsAndPaths paths{strikeSpec};
96
97 auto result = SkPDFMakeArray();
98
99 std::vector<SkGlyphID> glyphIDs;
100 subset.getSetValues([&](unsigned index) {
101 glyphIDs.push_back(SkToU16(index));
102 });
103 auto glyphs = paths.glyphs(SkSpan(glyphIDs));
104
105 // C++20 = make_unique_for_overwrite<SkScalar[]>(glyphs.size());
106 auto advances = std::unique_ptr<SkScalar[]>(new SkScalar[glyphs.size()]);
107
108 // Find the pdf integer mode (most common pdf integer advance).
109 // Unfortunately, poppler enforces DW (default width) must be an integer,
110 // so only consider integer pdf advances when finding the mode.
111 size_t numIntAdvances = 0;
112 for (const SkGlyph* glyph : glyphs) {
113 SkScalar currentAdvance = from_font_units(glyph->advanceX(), emSize);
114 if ((int32_t)currentAdvance == currentAdvance) {
115 advances[numIntAdvances++] = currentAdvance;
116 }
117 }
118 std::sort(advances.get(), advances.get() + numIntAdvances);
119 int32_t modeAdvance = (int32_t)find_mode_or_0(SkSpan(advances.get(), numIntAdvances));
120 *defaultAdvance = modeAdvance;
121
122 // Pre-convert to pdf advances.
123 for (size_t i = 0; i < glyphs.size(); ++i) {
124 advances[i] = from_font_units(glyphs[i]->advanceX(), emSize);
125 }
126
127 for (size_t i = 0; i < glyphs.size(); ++i) {
128 SkScalar advance = advances[i];
129
130 // a. Skipping don't cares or defaults is a win (trivial)
131 if (advance == modeAdvance) {
132 continue;
133 }
134
135 // b. 2+ repeats create run as long as possible, else start range
136 {
137 size_t j = i + 1; // j is always one past the last known repeat
138 for (; j < glyphs.size(); ++j) {
139 SkScalar next_advance = advances[j];
140 if (advance != next_advance) {
141 break;
142 }
143 }
144 if (j - i >= 2) {
145 result->appendInt(glyphs[i]->getGlyphID());
146 result->appendInt(glyphs[j - 1]->getGlyphID());
147 result->appendScalar(advance);
148 i = j - 1;
149 continue;
150 }
151 }
152
153 {
154 result->appendInt(glyphs[i]->getGlyphID());
155 auto advanceArray = SkPDFMakeArray();
156 advanceArray->appendScalar(advance);
157 size_t j = i + 1; // j is always one past the last output
158 for (; j < glyphs.size(); ++j) {
159 advance = advances[j];
160
161 // c. end range if default seen
162 if (advance == modeAdvance) {
163 break;
164 }
165
166 int dontCares = glyphs[j]->getGlyphID() - glyphs[j - 1]->getGlyphID() - 1;
167 // d. end range if 4+ don't cares
168 if (dontCares >= 4) {
169 break;
170 }
171
172 SkScalar next_advance = 0;
173 // e. end range for 2+ repeats with 4+ don't cares
174 if (j + 1 < glyphs.size()) {
175 next_advance = advances[j+1];
176 int next_dontCares = glyphs[j+1]->getGlyphID() - glyphs[j]->getGlyphID() - 1;
177 if (advance == next_advance && dontCares + next_dontCares >= 4) {
178 break;
179 }
180 }
181
182 // f. end range for 3+ repeats
183 if (j + 2 < glyphs.size() && advance == next_advance) {
184 next_advance = advances[j+2];
185 if (advance == next_advance) {
186 break;
187 }
188 }
189
190 while (dontCares --> 0) {
191 advanceArray->appendScalar(0);
192 }
193 advanceArray->appendScalar(advance);
194 }
195 result->appendObject(std::move(advanceArray));
196 i = j - 1;
197 }
198 }
199
200 return result;
201}
uint16_t glyphs[5]
Definition: FontMgrTest.cpp:46
static std::vector< SkPDFIndirectReference > sort(const THashSet< SkPDFIndirectReference > &src)
std::unique_ptr< SkPDFArray > SkPDFMakeCIDGlyphWidthsArray(const SkTypeface &typeface, const SkPDFGlyphUse &subset, int32_t *defaultAdvance)
static SkScalar from_font_units(SkScalar scaled, uint16_t emSize)
static std::unique_ptr< SkPDFArray > SkPDFMakeArray(Args... args)
Definition: SkPDFTypes.h:125
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
constexpr uint16_t SkToU16(S x)
Definition: SkTo.h:24
void getSetValues(FN f) const
Definition: SkPDFGlyphUse.h:26
constexpr bool empty() const
Definition: SkSpan_impl.h:96
constexpr size_t size() const
Definition: SkSpan_impl.h:95
static SkStrikeSpec MakePDFVector(const SkTypeface &typeface, int *size)
float SkScalar
Definition: extension.cpp:12
GAsyncResult * result