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