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 "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 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 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 static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) { |
| 43 if (emSize == 1000) { |
| 44 return scaled; |
| 45 } else { |
| 46 return SkScalarMulDiv(scaled, 1000, emSize); |
| 47 } |
| 48 } |
| 49 |
| 50 static SkScalar scale_from_font_units(int16_t val, uint16_t emSize) { |
| 51 return from_font_units(SkIntToScalar(val), emSize); |
| 52 } |
| 53 |
| 54 static void strip_uninteresting_trailing_advances_from_range( |
| 55 AdvanceMetric* range) { |
| 56 SkASSERT(range); |
| 57 |
| 58 int expectedAdvanceCount = range->fEndId - range->fStartId + 1; |
| 59 if (range->fAdvance.count() < expectedAdvanceCount) { |
| 60 return; |
| 61 } |
| 62 |
| 63 for (int i = expectedAdvanceCount - 1; i >= 0; --i) { |
| 64 if (range->fAdvance[i] != kDontCareAdvance && |
| 65 range->fAdvance[i] != kInvalidAdvance && |
| 66 range->fAdvance[i] != 0) { |
| 67 range->fEndId = range->fStartId + i; |
| 68 break; |
| 69 } |
| 70 } |
| 71 } |
| 72 |
| 73 static void zero_wildcards_in_range(AdvanceMetric* range) { |
| 74 SkASSERT(range); |
| 75 if (range->fType != AdvanceMetric::kRange) { |
| 76 return; |
| 77 } |
| 78 SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1); |
| 79 |
| 80 // Zero out wildcards. |
| 81 for (int i = 0; i < range->fAdvance.count(); ++i) { |
| 82 if (range->fAdvance[i] == kDontCareAdvance) { |
| 83 range->fAdvance[i] = 0; |
| 84 } |
| 85 } |
| 86 } |
| 87 |
| 88 static void finish_range( |
| 89 AdvanceMetric* range, |
| 90 int endId, |
| 91 AdvanceMetric::MetricType type) { |
| 92 range->fEndId = endId; |
| 93 range->fType = type; |
| 94 strip_uninteresting_trailing_advances_from_range(range); |
| 95 int newLength; |
| 96 if (type == AdvanceMetric::kRange) { |
| 97 newLength = range->fEndId - range->fStartId + 1; |
| 98 } else { |
| 99 if (range->fEndId == range->fStartId) { |
| 100 range->fType = AdvanceMetric::kRange; |
| 101 } |
| 102 newLength = 1; |
| 103 } |
| 104 SkASSERT(range->fAdvance.count() >= newLength); |
| 105 range->fAdvance.setCount(newLength); |
| 106 zero_wildcards_in_range(range); |
| 107 } |
| 108 |
| 109 static void compose_advance_data(const AdvanceMetric& range, |
| 110 uint16_t emSize, |
| 111 int16_t* defaultAdvance, |
| 112 SkPDFArray* result) { |
| 113 switch (range.fType) { |
| 114 case AdvanceMetric::kDefault: { |
| 115 SkASSERT(range.fAdvance.count() == 1); |
| 116 *defaultAdvance = range.fAdvance[0]; |
| 117 break; |
| 118 } |
| 119 case AdvanceMetric::kRange: { |
| 120 auto advanceArray = sk_make_sp<SkPDFArray>(); |
| 121 for (int j = 0; j < range.fAdvance.count(); j++) |
| 122 advanceArray->appendScalar( |
| 123 scale_from_font_units(range.fAdvance[j], emSize)); |
| 124 result->appendInt(range.fStartId); |
| 125 result->appendObject(std::move(advanceArray)); |
| 126 break; |
| 127 } |
| 128 case AdvanceMetric::kRun: { |
| 129 SkASSERT(range.fAdvance.count() == 1); |
| 130 result->appendInt(range.fStartId); |
| 131 result->appendInt(range.fEndId); |
| 132 result->appendScalar( |
| 133 scale_from_font_units(range.fAdvance[0], emSize)); |
| 134 break; |
| 135 } |
| 136 } |
| 137 } |
| 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 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 auto result = sk_make_sp<SkPDFArray>(); |
| 162 int num_glyphs = SkToInt(cache->getGlyphCount()); |
| 163 |
| 164 bool prevRange = false; |
| 165 |
| 166 int16_t lastAdvance = kInvalidAdvance; |
| 167 int repeatedAdvances = 0; |
| 168 int wildCardsInRun = 0; |
| 169 int trailingWildCards = 0; |
| 170 |
| 171 // Limit the loop count to glyph id ranges provided. |
| 172 int lastIndex = num_glyphs; |
| 173 if (subset) { |
| 174 while (!subset->isBitSet(lastIndex - 1) && lastIndex > 0) { |
| 175 --lastIndex; |
| 176 } |
| 177 } |
| 178 AdvanceMetric curRange(0); |
| 179 |
| 180 for (int gId = 0; gId <= lastIndex; gId++) { |
| 181 int16_t advance = kInvalidAdvance; |
| 182 if (gId < lastIndex) { |
| 183 if (!subset || 0 == gId || subset->isBitSet(gId)) { |
| 184 advance = (int16_t)cache->getGlyphIDAdvance(gId).fAdvanceX; |
| 185 } else { |
| 186 advance = kDontCareAdvance; |
| 187 } |
| 188 } |
| 189 if (advance == lastAdvance) { |
| 190 repeatedAdvances++; |
| 191 trailingWildCards = 0; |
| 192 } else if (advance == kDontCareAdvance) { |
| 193 wildCardsInRun++; |
| 194 trailingWildCards++; |
| 195 } else if (curRange.fAdvance.count() == |
| 196 repeatedAdvances + 1 + wildCardsInRun) { // All in run. |
| 197 if (lastAdvance == 0) { |
| 198 curRange.fStartId = gId; // reset |
| 199 curRange.fAdvance.setCount(0); |
| 200 trailingWildCards = 0; |
| 201 } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) { |
| 202 finish_range(&curRange, gId - 1, AdvanceMetric::kRun); |
| 203 compose_advance_data(curRange, emSize, defaultAdvance, result.ge
t()); |
| 204 prevRange = true; |
| 205 curRange = AdvanceMetric(gId); |
| 206 trailingWildCards = 0; |
| 207 } |
| 208 repeatedAdvances = 0; |
| 209 wildCardsInRun = trailingWildCards; |
| 210 trailingWildCards = 0; |
| 211 } else { |
| 212 if (lastAdvance == 0 && |
| 213 repeatedAdvances + 1 + wildCardsInRun >= 4) { |
| 214 finish_range(&curRange, |
| 215 gId - repeatedAdvances - wildCardsInRun - 2, |
| 216 AdvanceMetric::kRange); |
| 217 compose_advance_data(curRange, emSize, defaultAdvance, result.ge
t()); |
| 218 prevRange = true; |
| 219 curRange = AdvanceMetric(gId); |
| 220 trailingWildCards = 0; |
| 221 } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) { |
| 222 finish_range(&curRange, gId - trailingWildCards - 1, |
| 223 AdvanceMetric::kRange); |
| 224 compose_advance_data(curRange, emSize, defaultAdvance, result.ge
t()); |
| 225 prevRange = true; |
| 226 curRange = AdvanceMetric(gId); |
| 227 trailingWildCards = 0; |
| 228 } else if (lastAdvance != 0 && |
| 229 (repeatedAdvances + 1 >= 3 || |
| 230 (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) { |
| 231 finish_range(&curRange, |
| 232 gId - repeatedAdvances - wildCardsInRun - 2, |
| 233 AdvanceMetric::kRange); |
| 234 compose_advance_data(curRange, emSize, defaultAdvance, result.ge
t()); |
| 235 curRange = |
| 236 AdvanceMetric(gId - repeatedAdvances - wildCardsInRun -
1); |
| 237 curRange.fAdvance.append(1, &lastAdvance); |
| 238 finish_range(&curRange, gId - 1, AdvanceMetric::kRun); |
| 239 compose_advance_data(curRange, emSize, defaultAdvance, result.ge
t()); |
| 240 prevRange = true; |
| 241 curRange = AdvanceMetric(gId); |
| 242 trailingWildCards = 0; |
| 243 } |
| 244 repeatedAdvances = 0; |
| 245 wildCardsInRun = trailingWildCards; |
| 246 trailingWildCards = 0; |
| 247 } |
| 248 curRange.fAdvance.append(1, &advance); |
| 249 if (advance != kDontCareAdvance) { |
| 250 lastAdvance = advance; |
| 251 } |
| 252 } |
| 253 if (curRange.fStartId == lastIndex) { |
| 254 if (!prevRange) { |
| 255 return nullptr; // https://crbug.com/567031 |
| 256 } |
| 257 } else { |
| 258 finish_range(&curRange, lastIndex - 1, AdvanceMetric::kRange); |
| 259 compose_advance_data(curRange, emSize, defaultAdvance, result.get()); |
| 260 } |
| 261 return result; |
| 262 } |
OLD | NEW |