Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 } | |
| OLD | NEW |