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
8 #include "src/pdf/SkPDFMakeCIDGlyphWidthsArray.h"
9
10 #include "include/core/SkPaint.h"
11 #include "include/private/SkTo.h"
12 #include "src/core/SkStrike.h"
13 #include "src/core/SkStrikeSpec.h"
14 #include "src/pdf/SkPDFGlyphUse.h"
15
16 #include <vector>
17
18 // TODO(halcanary): Write unit tests for SkPDFMakeCIDGlyphWidthsArray().
19
20 // TODO(halcanary): The logic in this file originated in several
21 // disparate places. I feel sure that someone could simplify this
22 // down to a single easy-to-read function.
23
24 namespace {
25
26 struct AdvanceMetric {
27 enum MetricType {
28 kDefault, // Default advance: fAdvance.count = 1
29 kRange, // Advances for a range: fAdvance.count = fEndID-fStartID
30 kRun // fStartID-fEndID have same advance: fAdvance.count = 1
31 };
32 MetricType fType;
33 uint16_t fStartId;
34 uint16_t fEndId;
35 std::vector<int16_t> fAdvance;
AdvanceMetric__anon1ef98c9d0111::AdvanceMetric36 AdvanceMetric(uint16_t startId) : fStartId(startId) {}
37 AdvanceMetric(AdvanceMetric&&) = default;
38 AdvanceMetric& operator=(AdvanceMetric&& other) = default;
39 AdvanceMetric(const AdvanceMetric&) = delete;
40 AdvanceMetric& operator=(const AdvanceMetric&) = delete;
41 };
42 const int16_t kInvalidAdvance = SK_MinS16;
43 const int16_t kDontCareAdvance = SK_MinS16 + 1;
44 } // namespace
45
46 // scale from em-units to base-1000, returning as a SkScalar
from_font_units(SkScalar scaled,uint16_t emSize)47 static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
48 if (emSize == 1000) {
49 return scaled;
50 } else {
51 return scaled * 1000 / emSize;
52 }
53 }
54
scale_from_font_units(int16_t val,uint16_t emSize)55 static SkScalar scale_from_font_units(int16_t val, uint16_t emSize) {
56 return from_font_units(SkIntToScalar(val), emSize);
57 }
58
strip_uninteresting_trailing_advances_from_range(AdvanceMetric * range)59 static void strip_uninteresting_trailing_advances_from_range(
60 AdvanceMetric* range) {
61 SkASSERT(range);
62
63 int expectedAdvanceCount = range->fEndId - range->fStartId + 1;
64 if (SkToInt(range->fAdvance.size()) < expectedAdvanceCount) {
65 return;
66 }
67
68 for (int i = expectedAdvanceCount - 1; i >= 0; --i) {
69 if (range->fAdvance[i] != kDontCareAdvance &&
70 range->fAdvance[i] != kInvalidAdvance &&
71 range->fAdvance[i] != 0) {
72 range->fEndId = range->fStartId + i;
73 break;
74 }
75 }
76 }
77
zero_wildcards_in_range(AdvanceMetric * range)78 static void zero_wildcards_in_range(AdvanceMetric* range) {
79 SkASSERT(range);
80 if (range->fType != AdvanceMetric::kRange) {
81 return;
82 }
83 SkASSERT(SkToInt(range->fAdvance.size()) == range->fEndId - range->fStartId + 1);
84
85 // Zero out wildcards.
86 for (size_t i = 0; i < range->fAdvance.size(); ++i) {
87 if (range->fAdvance[i] == kDontCareAdvance) {
88 range->fAdvance[i] = 0;
89 }
90 }
91 }
92
finish_range(AdvanceMetric * range,int endId,AdvanceMetric::MetricType type)93 static void finish_range(
94 AdvanceMetric* range,
95 int endId,
96 AdvanceMetric::MetricType type) {
97 range->fEndId = endId;
98 range->fType = type;
99 strip_uninteresting_trailing_advances_from_range(range);
100 size_t newLength;
101 if (type == AdvanceMetric::kRange) {
102 newLength = range->fEndId - range->fStartId + 1;
103 } else {
104 if (range->fEndId == range->fStartId) {
105 range->fType = AdvanceMetric::kRange;
106 }
107 newLength = 1;
108 }
109 SkASSERT(range->fAdvance.size() >= newLength);
110 range->fAdvance.resize(newLength);
111 zero_wildcards_in_range(range);
112 }
113
compose_advance_data(const AdvanceMetric & range,uint16_t emSize,SkScalar * defaultAdvance,SkPDFArray * result)114 static void compose_advance_data(const AdvanceMetric& range,
115 uint16_t emSize,
116 SkScalar* defaultAdvance,
117 SkPDFArray* result) {
118 switch (range.fType) {
119 case AdvanceMetric::kDefault: {
120 SkASSERT(range.fAdvance.size() == 1);
121 *defaultAdvance = scale_from_font_units(range.fAdvance[0], emSize);
122 break;
123 }
124 case AdvanceMetric::kRange: {
125 auto advanceArray = SkPDFMakeArray();
126 for (size_t j = 0; j < range.fAdvance.size(); j++)
127 advanceArray->appendScalar(scale_from_font_units(range.fAdvance[j], emSize));
128 result->appendInt(range.fStartId);
129 result->appendObject(std::move(advanceArray));
130 break;
131 }
132 case AdvanceMetric::kRun: {
133 SkASSERT(range.fAdvance.size() == 1);
134 result->appendInt(range.fStartId);
135 result->appendInt(range.fEndId);
136 result->appendScalar(scale_from_font_units(range.fAdvance[0], emSize));
137 break;
138 }
139 }
140 }
141
142 /** Retrieve advance data for glyphs. Used by the PDF backend. */
143 // TODO(halcanary): this function is complex enough to need its logic
144 // tested with unit tests.
SkPDFMakeCIDGlyphWidthsArray(const SkTypeface & typeface,const SkPDFGlyphUse * subset,SkScalar * defaultAdvance)145 std::unique_ptr<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(const SkTypeface& typeface,
146 const SkPDFGlyphUse* subset,
147 SkScalar* defaultAdvance) {
148 // Assuming that on average, the ASCII representation of an advance plus
149 // a space is 8 characters and the ASCII representation of a glyph id is 3
150 // characters, then the following cut offs for using different range types
151 // apply:
152 // The cost of stopping and starting the range is 7 characters
153 // a. Removing 4 0's or don't care's is a win
154 // The cost of stopping and starting the range plus a run is 22
155 // characters
156 // b. Removing 3 repeating advances is a win
157 // c. Removing 2 repeating advances and 3 don't cares is a win
158 // When not currently in a range the cost of a run over a range is 16
159 // characters, so:
160 // d. Removing a leading 0/don't cares is a win because it is omitted
161 // e. Removing 2 repeating advances is a win
162
163 int emSize;
164 SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(typeface, &emSize);
165 SkBulkGlyphMetricsAndPaths paths{strikeSpec};
166
167 auto result = SkPDFMakeArray();
168 int num_glyphs = SkToInt(typeface.countGlyphs());
169
170 bool prevRange = false;
171
172 int16_t lastAdvance = kInvalidAdvance;
173 int repeatedAdvances = 0;
174 int wildCardsInRun = 0;
175 int trailingWildCards = 0;
176
177 // Limit the loop count to glyph id ranges provided.
178 int lastIndex = num_glyphs;
179 if (subset) {
180 while (!subset->has(lastIndex - 1) && lastIndex > 0) {
181 --lastIndex;
182 }
183 }
184 AdvanceMetric curRange(0);
185
186 SkAutoTArray<SkGlyphID> glyphIDs{lastIndex + 1};
187 for (int gId = 0; gId <= lastIndex; gId++) {
188 glyphIDs[gId] = gId;
189 }
190
191 auto glyphs = paths.glyphs(SkMakeSpan(glyphIDs.get(), lastIndex + 1));
192
193 for (int gId = 0; gId <= lastIndex; gId++) {
194 int16_t advance = kInvalidAdvance;
195 if (gId < lastIndex) {
196 if (!subset || 0 == gId || subset->has(gId)) {
197 advance = (int16_t)glyphs[gId]->advanceX();
198 } else {
199 advance = kDontCareAdvance;
200 }
201 }
202 if (advance == lastAdvance) {
203 repeatedAdvances++;
204 trailingWildCards = 0;
205 } else if (advance == kDontCareAdvance) {
206 wildCardsInRun++;
207 trailingWildCards++;
208 } else if (SkToInt(curRange.fAdvance.size()) ==
209 repeatedAdvances + 1 + wildCardsInRun) { // All in run.
210 if (lastAdvance == 0) {
211 curRange.fStartId = gId; // reset
212 curRange.fAdvance.resize(0);
213 trailingWildCards = 0;
214 } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) {
215 finish_range(&curRange, gId - 1, AdvanceMetric::kRun);
216 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
217 prevRange = true;
218 curRange = AdvanceMetric(gId);
219 trailingWildCards = 0;
220 }
221 repeatedAdvances = 0;
222 wildCardsInRun = trailingWildCards;
223 trailingWildCards = 0;
224 } else {
225 if (lastAdvance == 0 &&
226 repeatedAdvances + 1 + wildCardsInRun >= 4) {
227 finish_range(&curRange,
228 gId - repeatedAdvances - wildCardsInRun - 2,
229 AdvanceMetric::kRange);
230 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
231 prevRange = true;
232 curRange = AdvanceMetric(gId);
233 trailingWildCards = 0;
234 } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
235 finish_range(&curRange, gId - trailingWildCards - 1,
236 AdvanceMetric::kRange);
237 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
238 prevRange = true;
239 curRange = AdvanceMetric(gId);
240 trailingWildCards = 0;
241 } else if (lastAdvance != 0 &&
242 (repeatedAdvances + 1 >= 3 ||
243 (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
244 finish_range(&curRange,
245 gId - repeatedAdvances - wildCardsInRun - 2,
246 AdvanceMetric::kRange);
247 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
248 curRange =
249 AdvanceMetric(gId - repeatedAdvances - wildCardsInRun - 1);
250 curRange.fAdvance.push_back(lastAdvance);
251 finish_range(&curRange, gId - 1, AdvanceMetric::kRun);
252 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
253 prevRange = true;
254 curRange = AdvanceMetric(gId);
255 trailingWildCards = 0;
256 }
257 repeatedAdvances = 0;
258 wildCardsInRun = trailingWildCards;
259 trailingWildCards = 0;
260 }
261 curRange.fAdvance.push_back(advance);
262 if (advance != kDontCareAdvance) {
263 lastAdvance = advance;
264 }
265 }
266 if (curRange.fStartId == lastIndex) {
267 if (!prevRange) {
268 return nullptr; // https://crbug.com/567031
269 }
270 } else {
271 finish_range(&curRange, lastIndex - 1, AdvanceMetric::kRange);
272 compose_advance_data(curRange, emSize, defaultAdvance, result.get());
273 }
274 return result;
275 }
276