• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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