Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(421)

Side by Side Diff: src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp

Issue 2251803002: SkPDF: pull out SkPDFMakeCIDGlyphWidthsArray.cpp (Closed) Base URL: https://skia.googlesource.com/skia.git@SkPdfEliminateSkPDFCIDfont
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "SkBitSet.h"
9 #include "SkPDFMakeCIDGlyphWidthsArray.h"
10 #include "SkSinglyLinkedList.h"
11 #include "SkPaint.h"
12 #include "SkGlyphCache.h"
13
14 // TODO(halcanary): Write unit tests for SkPDFMakeCIDGlyphWidthsArray().
15
16 // TODO(halcanary): The logic in this file originated in several
17 // disparate places. I feel sure that someone could simplify this
18 // down to a single easy-to-read function.
19
20 namespace {
21
22 // scale from em-units to base-1000, returning as a SkScalar
23 static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
24 if (emSize == 1000) {
25 return scaled;
26 } else {
27 return SkScalarMulDiv(scaled, 1000, emSize);
28 }
29 }
30
31 static SkScalar scale_from_font_units(int16_t val, uint16_t emSize) {
32 return from_font_units(SkIntToScalar(val), emSize);
33 }
34
35 struct AdvanceMetric {
36 enum MetricType {
37 kDefault, // Default advance: fAdvance.count = 1
38 kRange, // Advances for a range: fAdvance.count = fEndID-fStartID
39 kRun // fStartID-fEndID have same advance: fAdvance.count = 1
40 };
41 MetricType fType;
42 uint16_t fStartId;
43 uint16_t fEndId;
44 SkTDArray<int16_t> fAdvance;
45 AdvanceMetric(uint16_t startId) : fStartId(startId) {}
46 AdvanceMetric(AdvanceMetric&&) = default;
47 AdvanceMetric& operator=(AdvanceMetric&& other) = default;
48 AdvanceMetric(const AdvanceMetric&) = delete;
49 AdvanceMetric& operator=(const AdvanceMetric&) = delete;
50 };
51
52 const int16_t kInvalidAdvance = SK_MinS16;
53 const int16_t kDontCareAdvance = SK_MinS16 + 1;
54
55 static void strip_uninteresting_trailing_advances_from_range(
56 AdvanceMetric* range) {
57 SkASSERT(range);
58
59 int expectedAdvanceCount = range->fEndId - range->fStartId + 1;
60 if (range->fAdvance.count() < expectedAdvanceCount) {
61 return;
62 }
63
64 for (int i = expectedAdvanceCount - 1; i >= 0; --i) {
65 if (range->fAdvance[i] != kDontCareAdvance &&
66 range->fAdvance[i] != kInvalidAdvance &&
67 range->fAdvance[i] != 0) {
68 range->fEndId = range->fStartId + i;
69 break;
70 }
71 }
72 }
73
74 static void zero_wildcards_in_range(AdvanceMetric* range) {
75 SkASSERT(range);
76 if (range->fType != AdvanceMetric::kRange) {
77 return;
78 }
79 SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1);
80
81 // Zero out wildcards.
82 for (int i = 0; i < range->fAdvance.count(); ++i) {
83 if (range->fAdvance[i] == kDontCareAdvance) {
84 range->fAdvance[i] = 0;
85 }
86 }
87 }
88
89 static void finish_range(
90 AdvanceMetric* range,
91 int endId,
92 AdvanceMetric::MetricType type) {
93 range->fEndId = endId;
94 range->fType = type;
95 strip_uninteresting_trailing_advances_from_range(range);
96 int newLength;
97 if (type == AdvanceMetric::kRange) {
98 newLength = range->fEndId - range->fStartId + 1;
99 } else {
100 if (range->fEndId == range->fStartId) {
101 range->fType = AdvanceMetric::kRange;
102 }
103 newLength = 1;
104 }
105 SkASSERT(range->fAdvance.count() >= newLength);
106 range->fAdvance.setCount(newLength);
107 zero_wildcards_in_range(range);
108 }
109
110 /** Retrieve advance data for glyphs. Used by the PDF backend. */
111 // TODO(halcanary): this function is complex enough to need its logic
112 // tested with unit tests. On the other hand, I want to do another
113 // round of re-factoring before figuring out how to mock this.
114 // TODO(halcanary): this function should be combined with
115 // compose_advance_data() so that we don't need to produce a linked list
116 // of intermediate values. Or we could make the intermediate value
117 // something other than a linked list.
118 template <typename T>
119 static void set_glyph_widths(T advancer,
120 const SkBitSet* subset,
121 SkSinglyLinkedList<AdvanceMetric>* glyphWidths) {
122 // Assuming that on average, the ASCII representation of an advance plus
123 // a space is 8 characters and the ASCII representation of a glyph id is 3
124 // characters, then the following cut offs for using different range types
125 // apply:
126 // The cost of stopping and starting the range is 7 characers
127 // a. Removing 4 0's or don't care's is a win
128 // The cost of stopping and starting the range plus a run is 22
129 // characters
130 // b. Removing 3 repeating advances is a win
131 // c. Removing 2 repeating advances and 3 don't cares is a win
132 // When not currently in a range the cost of a run over a range is 16
133 // characaters, so:
134 // d. Removing a leading 0/don't cares is a win because it is omitted
135 // e. Removing 2 repeating advances is a win
136
137 int num_glyphs = advancer.count();
138
139 AdvanceMetric* prevRange = nullptr;
140 int16_t lastAdvance = kInvalidAdvance;
141 int repeatedAdvances = 0;
142 int wildCardsInRun = 0;
143 int trailingWildCards = 0;
144
145 // Limit the loop count to glyph id ranges provided.
146 int lastIndex = num_glyphs;
147 if (subset) {
148 while (!subset->isBitSet(lastIndex - 1) && lastIndex > 0) {
149 --lastIndex;
150 }
151 }
152 AdvanceMetric curRange(0);
153
154 for (int gId = 0; gId <= lastIndex; gId++) {
155 int16_t advance = kInvalidAdvance;
156 if (gId < lastIndex) {
157 if (!subset || 0 == gId || subset->isBitSet(gId)) {
158 advance = (int16_t)advancer(gId);
159 } else {
160 advance = kDontCareAdvance;
161 }
162 }
163 if (advance == lastAdvance) {
164 repeatedAdvances++;
165 trailingWildCards = 0;
166 } else if (advance == kDontCareAdvance) {
167 wildCardsInRun++;
168 trailingWildCards++;
169 } else if (curRange.fAdvance.count() ==
170 repeatedAdvances + 1 + wildCardsInRun) { // All in run.
171 if (lastAdvance == 0) {
172 curRange.fStartId = gId; // reset
173 curRange.fAdvance.setCount(0);
174 trailingWildCards = 0;
175 } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) {
176 finish_range(&curRange, gId - 1, AdvanceMetric::kRun);
177 prevRange = glyphWidths->emplace_back(std::move(curRange));
178 curRange = AdvanceMetric(gId);
179 trailingWildCards = 0;
180 }
181 repeatedAdvances = 0;
182 wildCardsInRun = trailingWildCards;
183 trailingWildCards = 0;
184 } else {
185 if (lastAdvance == 0 &&
186 repeatedAdvances + 1 + wildCardsInRun >= 4) {
187 finish_range(&curRange,
188 gId - repeatedAdvances - wildCardsInRun - 2,
189 AdvanceMetric::kRange);
190 prevRange = glyphWidths->emplace_back(std::move(curRange));
191 curRange = AdvanceMetric(gId);
192 trailingWildCards = 0;
193 } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
194 finish_range(&curRange, gId - trailingWildCards - 1,
195 AdvanceMetric::kRange);
196 prevRange = glyphWidths->emplace_back(std::move(curRange));
197 curRange = AdvanceMetric(gId);
198 trailingWildCards = 0;
199 } else if (lastAdvance != 0 &&
200 (repeatedAdvances + 1 >= 3 ||
201 (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
202 finish_range(&curRange,
203 gId - repeatedAdvances - wildCardsInRun - 2,
204 AdvanceMetric::kRange);
205 (void)glyphWidths->emplace_back(std::move(curRange));
206 curRange =
207 AdvanceMetric(gId - repeatedAdvances - wildCardsInRun - 1);
208 curRange.fAdvance.append(1, &lastAdvance);
209 finish_range(&curRange, gId - 1, AdvanceMetric::kRun);
210 prevRange = glyphWidths->emplace_back(std::move(curRange));
211 curRange = AdvanceMetric(gId);
212 trailingWildCards = 0;
213 }
214 repeatedAdvances = 0;
215 wildCardsInRun = trailingWildCards;
216 trailingWildCards = 0;
217 }
218 curRange.fAdvance.append(1, &advance);
219 if (advance != kDontCareAdvance) {
220 lastAdvance = advance;
221 }
222 }
223 if (curRange.fStartId == lastIndex) {
224 if (!prevRange) {
225 glyphWidths->reset();
226 return; // https://crbug.com/567031
227 }
228 } else {
229 finish_range(&curRange, lastIndex - 1, AdvanceMetric::kRange);
230 glyphWidths->emplace_back(std::move(curRange));
231 }
232 }
233
234 sk_sp<SkPDFArray> compose_advance_data(
235 const SkSinglyLinkedList<AdvanceMetric>& advanceInfo,
236 uint16_t emSize,
237 int16_t* defaultAdvance) {
238 auto result = sk_make_sp<SkPDFArray>();
239 for (const AdvanceMetric& range : advanceInfo) {
240 switch (range.fType) {
241 case AdvanceMetric::kDefault: {
242 SkASSERT(range.fAdvance.count() == 1);
243 *defaultAdvance = range.fAdvance[0];
244 break;
245 }
246 case AdvanceMetric::kRange: {
247 auto advanceArray = sk_make_sp<SkPDFArray>();
248 for (int j = 0; j < range.fAdvance.count(); j++)
249 advanceArray->appendScalar(
250 scale_from_font_units(range.fAdvance[j], emSize));
251 result->appendInt(range.fStartId);
252 result->appendObject(std::move(advanceArray));
253 break;
254 }
255 case AdvanceMetric::kRun: {
256 SkASSERT(range.fAdvance.count() == 1);
257 result->appendInt(range.fStartId);
258 result->appendInt(range.fEndId);
259 result->appendScalar(
260 scale_from_font_units(range.fAdvance[0], emSize));
261 break;
262 }
263 }
264 }
265 return result;
266 }
267
268 struct Advancer {
269 SkGlyphCache* fCache;
270 SkScalar operator()(SkGlyphID gId) const {
271 return fCache->getGlyphIDAdvance(gId).fAdvanceX;
272 }
273 int count() const { return SkToInt(fCache->getGlyphCount()); }
274 };
275
276 template <typename T>
277 sk_sp<SkPDFArray> make_cid_glyph_widths_array(T advancer,
278 const SkBitSet* subset,
279 uint16_t emSize,
280 int16_t* defaultWidth) {
281 SkSinglyLinkedList<AdvanceMetric> glyphWidths;
282 set_glyph_widths<T>(advancer, subset, &glyphWidths);
283 return compose_advance_data(glyphWidths, emSize, defaultWidth);
284 }
285 } // namespace
286
287 sk_sp<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(SkGlyphCache* cache,
bungeman-skia 2016/08/16 19:16:25 It is nice to pull out this call and all it's supp
288 const SkBitSet* subset,
289 uint16_t emSize,
290 int16_t* defaultWidth) {
291 return make_cid_glyph_widths_array<Advancer>(
292 Advancer{cache},
293 subset, emSize, defaultWidth);
294 }
295
296 sk_sp<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(const SkPDFAdvancerMock& mock,
297 const SkBitSet* subset,
298 uint16_t emSize,
299 int16_t* defaultWidth) {
300 return make_cid_glyph_widths_array<const SkPDFAdvancerMock&>(
301 mock, subset, emSize, defaultWidth);
302 }
OLDNEW
« src/pdf/SkPDFMakeCIDGlyphWidthsArray.h ('K') | « src/pdf/SkPDFMakeCIDGlyphWidthsArray.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698