| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "Sk4fGradientPriv.h" |
| 8 #include "Sk4fLinearGradient.h" | 9 #include "Sk4fLinearGradient.h" |
| 9 | 10 |
| 10 namespace { | 11 namespace { |
| 11 | 12 |
| 12 Sk4f premul_4f(const Sk4f& c) { | |
| 13 const float alpha = c[SkPM4f::A]; | |
| 14 // FIXME: portable swizzle? | |
| 15 return c * Sk4f(alpha, alpha, alpha, 1); | |
| 16 } | |
| 17 | |
| 18 template <bool do_premul> | |
| 19 SkPMColor trunc_from_255(const Sk4f& c) { | |
| 20 SkPMColor pmc; | |
| 21 SkNx_cast<uint8_t>(c).store(&pmc); | |
| 22 if (do_premul) { | |
| 23 pmc = SkPreMultiplyARGB(SkGetPackedA32(pmc), SkGetPackedR32(pmc), | |
| 24 SkGetPackedG32(pmc), SkGetPackedB32(pmc)); | |
| 25 } | |
| 26 return pmc; | |
| 27 } | |
| 28 | |
| 29 template<typename DstType, bool do_premul> | 13 template<typename DstType, bool do_premul> |
| 30 void fill(const Sk4f& c, DstType* dst, int n); | 14 void fill(const Sk4f& c, DstType* dst, int n); |
| 31 | 15 |
| 32 template<> | 16 template<> |
| 33 void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) { | 17 void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) { |
| 34 while (n > 0) { | 18 while (n > 0) { |
| 35 c.store(dst++); | 19 c.store(dst++); |
| 36 n--; | 20 n--; |
| 37 } | 21 } |
| 38 } | 22 } |
| 39 | 23 |
| 40 template<> | 24 template<> |
| 41 void fill<SkPM4f, true>(const Sk4f& c, SkPM4f* dst, int n) { | 25 void fill<SkPM4f, true>(const Sk4f& c, SkPM4f* dst, int n) { |
| 42 fill<SkPM4f, false>(premul_4f(c), dst, n); | 26 fill<SkPM4f, false>(premul_4f(c), dst, n); |
| 43 } | 27 } |
| 44 | 28 |
| 45 template<> | 29 template<> |
| 46 void fill<SkPMColor, false>(const Sk4f& c, SkPMColor* dst, int n) { | 30 void fill<SkPMColor, false>(const Sk4f& c, SkPMColor* dst, int n) { |
| 47 sk_memset32(dst, trunc_from_255<false>(c), n); | 31 sk_memset32(dst, trunc_from_255<false>(c), n); |
| 48 } | 32 } |
| 49 | 33 |
| 50 template<> | 34 template<> |
| 51 void fill<SkPMColor, true>(const Sk4f& c, SkPMColor* dst, int n) { | 35 void fill<SkPMColor, true>(const Sk4f& c, SkPMColor* dst, int n) { |
| 52 sk_memset32(dst, trunc_from_255<true>(c), n); | 36 sk_memset32(dst, trunc_from_255<true>(c), n); |
| 53 } | 37 } |
| 54 | 38 |
| 55 template<typename DstType, bool do_premul> | 39 template<typename DstType, bool do_premul> |
| 56 void store(const Sk4f& color, DstType* dst); | |
| 57 | |
| 58 template<> | |
| 59 void store<SkPM4f, false>(const Sk4f& c, SkPM4f* dst) { | |
| 60 c.store(dst); | |
| 61 } | |
| 62 | |
| 63 template<> | |
| 64 void store<SkPM4f, true>(const Sk4f& c, SkPM4f* dst) { | |
| 65 store<SkPM4f, false>(premul_4f(c), dst); | |
| 66 } | |
| 67 | |
| 68 template<> | |
| 69 void store<SkPMColor, false>(const Sk4f& c, SkPMColor* dst) { | |
| 70 *dst = trunc_from_255<false>(c); | |
| 71 } | |
| 72 | |
| 73 template<> | |
| 74 void store<SkPMColor, true>(const Sk4f& c, SkPMColor* dst) { | |
| 75 *dst = trunc_from_255<true>(c); | |
| 76 } | |
| 77 | |
| 78 template<typename DstType, bool do_premul> | |
| 79 void store4x(const Sk4f& c0, | |
| 80 const Sk4f& c1, | |
| 81 const Sk4f& c2, | |
| 82 const Sk4f& c3, | |
| 83 DstType* dst) { | |
| 84 store<DstType, do_premul>(c0, dst++); | |
| 85 store<DstType, do_premul>(c1, dst++); | |
| 86 store<DstType, do_premul>(c2, dst++); | |
| 87 store<DstType, do_premul>(c3, dst++); | |
| 88 } | |
| 89 | |
| 90 template<> | |
| 91 void store4x<SkPMColor, false>(const Sk4f& c0, | |
| 92 const Sk4f& c1, | |
| 93 const Sk4f& c2, | |
| 94 const Sk4f& c3, | |
| 95 SkPMColor* dst) { | |
| 96 Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3); | |
| 97 } | |
| 98 | |
| 99 template<typename DstType, bool do_premul> | |
| 100 void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { | 40 void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { |
| 101 SkASSERT(n > 0); | 41 SkASSERT(n > 0); |
| 102 | 42 |
| 103 const Sk4f dc2 = dc + dc; | 43 const Sk4f dc2 = dc + dc; |
| 104 const Sk4f dc4 = dc2 + dc2; | 44 const Sk4f dc4 = dc2 + dc2; |
| 105 | 45 |
| 106 Sk4f c0 = c ; | 46 Sk4f c0 = c ; |
| 107 Sk4f c1 = c + dc; | 47 Sk4f c1 = c + dc; |
| 108 Sk4f c2 = c0 + dc2; | 48 Sk4f c2 = c0 + dc2; |
| 109 Sk4f c3 = c1 + dc2; | 49 Sk4f c3 = c1 + dc2; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 const SkScalar f = SkScalarFraction(fx); | 81 const SkScalar f = SkScalarFraction(fx); |
| 142 return f < 0 ? f + 1 : f; | 82 return f < 0 ? f + 1 : f; |
| 143 } | 83 } |
| 144 | 84 |
| 145 template<> | 85 template<> |
| 146 SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) { | 86 SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) { |
| 147 const SkScalar f = SkScalarMod(fx, 2.0f); | 87 const SkScalar f = SkScalarMod(fx, 2.0f); |
| 148 return f < 0 ? f + 2 : f; | 88 return f < 0 ? f + 2 : f; |
| 149 } | 89 } |
| 150 | 90 |
| 151 template<typename DstType> | |
| 152 float dst_component_scale(); | |
| 153 | |
| 154 template<> | |
| 155 float dst_component_scale<SkPM4f>() { | |
| 156 return 1; | |
| 157 } | |
| 158 | |
| 159 template<> | |
| 160 float dst_component_scale<SkPMColor>() { | |
| 161 return 255; | |
| 162 } | |
| 163 | |
| 164 template<typename DstType> | |
| 165 Sk4f dst_swizzle(const SkPM4f&); | |
| 166 | |
| 167 template<> | |
| 168 Sk4f dst_swizzle<SkPM4f>(const SkPM4f& c) { | |
| 169 return c.to4f(); | |
| 170 } | |
| 171 | |
| 172 template<> | |
| 173 Sk4f dst_swizzle<SkPMColor>(const SkPM4f& c) { | |
| 174 return c.to4f_pmorder(); | |
| 175 } | |
| 176 | |
| 177 SkPMColor pack_color(SkColor c, bool premul) { | |
| 178 return premul | |
| 179 ? SkPreMultiplyColor(c) | |
| 180 : SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), Sk
ColorGetB(c)); | |
| 181 } | |
| 182 | |
| 183 // true when x is in [k1,k2) | 91 // true when x is in [k1,k2) |
| 184 bool in_range(SkScalar x, SkScalar k1, SkScalar k2) { | 92 bool in_range(SkScalar x, SkScalar k1, SkScalar k2) { |
| 185 SkASSERT(k1 != k2); | 93 SkASSERT(k1 != k2); |
| 186 return (k1 < k2) | 94 return (k1 < k2) |
| 187 ? (x >= k1 && x < k2) | 95 ? (x >= k1 && x < k2) |
| 188 : (x >= k2 && x < k1); | 96 : (x >= k2 && x < k1); |
| 189 } | 97 } |
| 190 | 98 |
| 191 class IntervalBuilder { | |
| 192 public: | |
| 193 IntervalBuilder(const SkColor* colors, const SkScalar* pos, int count, bool
reverse) | |
| 194 : fColors(colors) | |
| 195 , fPos(pos) | |
| 196 , fCount(count) | |
| 197 , fFirstPos(reverse ? SK_Scalar1 : 0) | |
| 198 , fBegin(reverse ? count - 1 : 0) | |
| 199 , fAdvance(reverse ? -1 : 1) { | |
| 200 SkASSERT(colors); | |
| 201 SkASSERT(count > 1); | |
| 202 } | |
| 203 | |
| 204 template<typename F> | |
| 205 void build(F func) const { | |
| 206 if (!fPos) { | |
| 207 this->buildImplicitPos(func); | |
| 208 return; | |
| 209 } | |
| 210 | |
| 211 const int end = fBegin + fAdvance * (fCount - 1); | |
| 212 const SkScalar lastPos = 1 - fFirstPos; | |
| 213 int prev = fBegin; | |
| 214 SkScalar prevPos = fFirstPos; | |
| 215 | |
| 216 do { | |
| 217 const int curr = prev + fAdvance; | |
| 218 SkASSERT(curr >= 0 && curr < fCount); | |
| 219 | |
| 220 // TODO: this sanitization should be done in SkGradientShaderBase | |
| 221 const SkScalar currPos = (fAdvance > 0) | |
| 222 ? SkTPin(fPos[curr], prevPos, lastPos) | |
| 223 : SkTPin(fPos[curr], lastPos, prevPos); | |
| 224 | |
| 225 if (currPos != prevPos) { | |
| 226 SkASSERT((currPos - prevPos > 0) == (fAdvance > 0)); | |
| 227 func(fColors[prev], fColors[curr], prevPos, currPos); | |
| 228 } | |
| 229 | |
| 230 prev = curr; | |
| 231 prevPos = currPos; | |
| 232 } while (prev != end); | |
| 233 } | |
| 234 | |
| 235 private: | |
| 236 template<typename F> | |
| 237 void buildImplicitPos(F func) const { | |
| 238 // When clients don't provide explicit color stop positions (fPos == nul
lptr), | |
| 239 // the color stops are distributed evenly across the unit interval | |
| 240 // (implicit positioning). | |
| 241 const SkScalar dt = fAdvance * SK_Scalar1 / (fCount - 1); | |
| 242 const int end = fBegin + fAdvance * (fCount - 2); | |
| 243 int prev = fBegin; | |
| 244 SkScalar prevPos = fFirstPos; | |
| 245 | |
| 246 while (prev != end) { | |
| 247 const int curr = prev + fAdvance; | |
| 248 SkASSERT(curr >= 0 && curr < fCount); | |
| 249 | |
| 250 const SkScalar currPos = prevPos + dt; | |
| 251 func(fColors[prev], fColors[curr], prevPos, currPos); | |
| 252 prev = curr; | |
| 253 prevPos = currPos; | |
| 254 } | |
| 255 | |
| 256 // emit the last interval with a pinned end position, to avoid precision
issues | |
| 257 func(fColors[prev], fColors[prev + fAdvance], prevPos, 1 - fFirstPos); | |
| 258 } | |
| 259 | |
| 260 const SkColor* fColors; | |
| 261 const SkScalar* fPos; | |
| 262 const int fCount; | |
| 263 const SkScalar fFirstPos; | |
| 264 const int fBegin; | |
| 265 const int fAdvance; | |
| 266 }; | |
| 267 | |
| 268 } // anonymous namespace | 99 } // anonymous namespace |
| 269 | 100 |
| 270 SkLinearGradient:: | 101 SkLinearGradient:: |
| 271 LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader, | 102 LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader, |
| 272 const ContextRec& rec) | 103 const ContextRec& rec) |
| 273 : INHERITED(shader, rec) { | 104 : INHERITED(shader, rec) { |
| 274 // The main job here is to build a specialized interval list: a different | |
| 275 // representation of the color stops data, optimized for efficient scan line | |
| 276 // access during shading. | |
| 277 // | |
| 278 // [{P0,C0} , {P1,C1}) [{P1,C2} , {P2,c3}) ... [{Pn,C2n} , {Pn+1,C2n+1}) | |
| 279 // | |
| 280 // The list is sorted in increasing dst order, i.e. X(Pk) < X(Pk+1). This | |
| 281 // allows us to always traverse left->right when iterating over a scan line. | |
| 282 // It also means that the interval order matches the color stops when dx >=
0, | |
| 283 // and is the inverse (pos, colors, order are flipped) when dx < 0. | |
| 284 // | |
| 285 // Note: the current representation duplicates pos data; we could refactor t
o | |
| 286 // avoid this if interval storage size becomes a concern. | |
| 287 // | |
| 288 // Aside from reordering, we also perform two more pre-processing steps at | |
| 289 // this stage: | |
| 290 // | |
| 291 // 1) scale the color components depending on paint alpha and the requeste
d | |
| 292 // interpolation space (note: the interval color storage is SkPM4f, but | |
| 293 // that doesn't necessarily mean the colors are premultiplied; that | |
| 294 // property is tracked in fColorsArePremul) | |
| 295 // | |
| 296 // 2) inject synthetic intervals to support tiling. | |
| 297 // | |
| 298 // * for kRepeat, no extra intervals are needed - the iterator just | |
| 299 // wraps around at the end: | |
| 300 // | |
| 301 // ->[P0,P1)->..[Pn-1,Pn)-> | |
| 302 // | |
| 303 // * for kClamp, we add two "infinite" intervals before/after: | |
| 304 // | |
| 305 // [-/+inf , P0)->[P0 , P1)->..[Pn-1 , Pn)->[Pn , +/-inf) | |
| 306 // | |
| 307 // (the iterator should never run off the end in this mode) | |
| 308 // | |
| 309 // * for kMirror, we extend the range to [0..2] and add a flipped | |
| 310 // interval series - then the iterator operates just as in the | |
| 311 // kRepeat case: | |
| 312 // | |
| 313 // ->[P0,P1)->..[Pn-1,Pn)->[2 - Pn,2 - Pn-1)->..[2 - P1,2 - P0)-> | |
| 314 // | |
| 315 // TODO: investigate collapsing intervals << 1px. | |
| 316 | 105 |
| 317 SkASSERT(shader.fColorCount > 1); | 106 // Our fast path expects interval points to be monotonically increasing in x
. |
| 318 SkASSERT(shader.fOrigColors); | 107 const bool reverseIntervals = this->isFast() && fDstToPos.getScaleX() < 0; |
| 319 | 108 this->buildIntervals(shader, rec, reverseIntervals); |
| 320 const float paintAlpha = rec.fPaint->getAlpha() * (1.0f / 255); | |
| 321 const Sk4f componentScale = fColorsArePremul | |
| 322 ? Sk4f(paintAlpha) | |
| 323 : Sk4f(1.0f, 1.0f, 1.0f, paintAlpha); | |
| 324 const bool dx_is_pos = fDstToPos.getScaleX() >= 0; | |
| 325 const int first_index = dx_is_pos ? 0 : shader.fColorCount - 1; | |
| 326 const int last_index = shader.fColorCount - 1 - first_index; | |
| 327 const SkScalar first_pos = dx_is_pos ? 0 : SK_Scalar1; | |
| 328 const SkScalar last_pos = 1 - first_pos; | |
| 329 | |
| 330 if (shader.fTileMode == SkShader::kClamp_TileMode) { | |
| 331 // synthetic edge interval: -/+inf .. P0 | |
| 332 const SkPMColor clamp_color = pack_color(shader.fOrigColors[first_index]
, | |
| 333 fColorsArePremul); | |
| 334 const SkScalar clamp_pos = dx_is_pos ? SK_ScalarMin : SK_ScalarMax; | |
| 335 fIntervals.emplace_back(clamp_color, clamp_pos, | |
| 336 clamp_color, first_pos, | |
| 337 componentScale); | |
| 338 } else if (shader.fTileMode == SkShader::kMirror_TileMode && !dx_is_pos) { | |
| 339 // synthetic mirror intervals injected before main intervals: (2 .. 1] | |
| 340 addMirrorIntervals(shader, componentScale, dx_is_pos); | |
| 341 } | |
| 342 | |
| 343 const IntervalBuilder builder(shader.fOrigColors, | |
| 344 shader.fOrigPos, | |
| 345 shader.fColorCount, | |
| 346 !dx_is_pos); | |
| 347 builder.build([this, &componentScale] (SkColor c0, SkColor c1, SkScalar p0,
SkScalar p1) { | |
| 348 SkASSERT(fIntervals.empty() || fIntervals.back().fP1 == p0); | |
| 349 | |
| 350 fIntervals.emplace_back(pack_color(c0, fColorsArePremul), | |
| 351 p0, | |
| 352 pack_color(c1, fColorsArePremul), | |
| 353 p1, | |
| 354 componentScale); | |
| 355 }); | |
| 356 | |
| 357 if (shader.fTileMode == SkShader::kClamp_TileMode) { | |
| 358 // synthetic edge interval: Pn .. +/-inf | |
| 359 const SkPMColor clamp_color = | |
| 360 pack_color(shader.fOrigColors[last_index], fColorsArePremul); | |
| 361 const SkScalar clamp_pos = dx_is_pos ? SK_ScalarMax : SK_ScalarMin; | |
| 362 fIntervals.emplace_back(clamp_color, last_pos, | |
| 363 clamp_color, clamp_pos, | |
| 364 componentScale); | |
| 365 } else if (shader.fTileMode == SkShader::kMirror_TileMode && dx_is_pos) { | |
| 366 // synthetic mirror intervals injected after main intervals: [1 .. 2) | |
| 367 addMirrorIntervals(shader, componentScale, dx_is_pos); | |
| 368 } | |
| 369 | 109 |
| 370 SkASSERT(fIntervals.count() > 0); | 110 SkASSERT(fIntervals.count() > 0); |
| 371 fCachedInterval = fIntervals.begin(); | 111 fCachedInterval = fIntervals.begin(); |
| 372 } | 112 } |
| 373 | 113 |
| 374 void SkLinearGradient:: | |
| 375 LinearGradient4fContext::addMirrorIntervals(const SkLinearGradient& shader, | |
| 376 const Sk4f& componentScale, bool dx_
is_pos) { | |
| 377 // Iterates in reverse order (vs main interval builder) and adds intervals r
eflected in 2. | |
| 378 const IntervalBuilder builder(shader.fOrigColors, | |
| 379 shader.fOrigPos, | |
| 380 shader.fColorCount, | |
| 381 dx_is_pos); | |
| 382 builder.build([this, &componentScale] (SkColor c0, SkColor c1, SkScalar p0,
SkScalar p1) { | |
| 383 SkASSERT(fIntervals.empty() || fIntervals.back().fP1 == 2 - p0); | |
| 384 | |
| 385 fIntervals.emplace_back(pack_color(c0, fColorsArePremul), | |
| 386 2 - p0, | |
| 387 pack_color(c1, fColorsArePremul), | |
| 388 2 - p1, | |
| 389 componentScale); | |
| 390 }); | |
| 391 } | |
| 392 | |
| 393 const SkGradientShaderBase::GradientShaderBase4fContext::Interval* | 114 const SkGradientShaderBase::GradientShaderBase4fContext::Interval* |
| 394 SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const { | 115 SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const { |
| 395 SkASSERT(in_range(fx, fIntervals.front().fP0, fIntervals.back().fP1)); | 116 SkASSERT(in_range(fx, fIntervals.front().fP0, fIntervals.back().fP1)); |
| 396 | 117 |
| 397 if (1) { | 118 if (1) { |
| 398 // Linear search, using the last scanline interval as a starting point. | 119 // Linear search, using the last scanline interval as a starting point. |
| 399 SkASSERT(fCachedInterval >= fIntervals.begin()); | 120 SkASSERT(fCachedInterval >= fIntervals.begin()); |
| 400 SkASSERT(fCachedInterval < fIntervals.end()); | 121 SkASSERT(fCachedInterval < fIntervals.end()); |
| 401 const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1; | 122 const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1; |
| 402 while (!in_range(fx, fCachedInterval->fP0, fCachedInterval->fP1)) { | 123 while (!in_range(fx, fCachedInterval->fP0, fCachedInterval->fP1)) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 427 } | 148 } |
| 428 } | 149 } |
| 429 | 150 |
| 430 SkASSERT(in_range(fx, i0->fP0, i0->fP1)); | 151 SkASSERT(in_range(fx, i0->fP0, i0->fP1)); |
| 431 return i0; | 152 return i0; |
| 432 } | 153 } |
| 433 } | 154 } |
| 434 | 155 |
| 435 void SkLinearGradient:: | 156 void SkLinearGradient:: |
| 436 LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { | 157 LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { |
| 158 if (!this->isFast()) { |
| 159 this->INHERITED::shadeSpan(x, y, dst, count); |
| 160 return; |
| 161 } |
| 162 |
| 437 // TODO: plumb dithering | 163 // TODO: plumb dithering |
| 438 SkASSERT(count > 0); | 164 SkASSERT(count > 0); |
| 439 if (fColorsArePremul) { | 165 if (fColorsArePremul) { |
| 440 this->shadePremulSpan<SkPMColor, false>(x, y, dst, count); | 166 this->shadePremulSpan<SkPMColor, false>(x, y, dst, count); |
| 441 } else { | 167 } else { |
| 442 this->shadePremulSpan<SkPMColor, true>(x, y, dst, count); | 168 this->shadePremulSpan<SkPMColor, true>(x, y, dst, count); |
| 443 } | 169 } |
| 444 } | 170 } |
| 445 | 171 |
| 446 void SkLinearGradient:: | 172 void SkLinearGradient:: |
| 447 LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { | 173 LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { |
| 174 if (!this->isFast()) { |
| 175 this->INHERITED::shadeSpan4f(x, y, dst, count); |
| 176 return; |
| 177 } |
| 178 |
| 448 // TONOTDO: plumb dithering | 179 // TONOTDO: plumb dithering |
| 449 SkASSERT(count > 0); | 180 SkASSERT(count > 0); |
| 450 if (fColorsArePremul) { | 181 if (fColorsArePremul) { |
| 451 this->shadePremulSpan<SkPM4f, false>(x, y, dst, count); | 182 this->shadePremulSpan<SkPM4f, false>(x, y, dst, count); |
| 452 } else { | 183 } else { |
| 453 this->shadePremulSpan<SkPM4f, true>(x, y, dst, count); | 184 this->shadePremulSpan<SkPM4f, true>(x, y, dst, count); |
| 454 } | 185 } |
| 455 } | 186 } |
| 456 | 187 |
| 457 template<typename DstType, bool do_premul> | 188 template<typename DstType, bool do_premul> |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 bool is_vertical) | 269 bool is_vertical) |
| 539 : fDstComponentScale(dst_component_scale<DstType>()) | 270 : fDstComponentScale(dst_component_scale<DstType>()) |
| 540 , fAdvX((i->fP1 - fx) / dx) | 271 , fAdvX((i->fP1 - fx) / dx) |
| 541 , fFirstInterval(firstInterval) | 272 , fFirstInterval(firstInterval) |
| 542 , fLastInterval(lastInterval) | 273 , fLastInterval(lastInterval) |
| 543 , fInterval(i) | 274 , fInterval(i) |
| 544 , fDx(dx) | 275 , fDx(dx) |
| 545 , fIsVertical(is_vertical) | 276 , fIsVertical(is_vertical) |
| 546 { | 277 { |
| 547 SkASSERT(firstInterval <= lastInterval); | 278 SkASSERT(firstInterval <= lastInterval); |
| 548 SkASSERT(i->contains(fx)); | 279 SkASSERT(in_range(fx, i->fP0, i->fP1)); |
| 549 this->compute_interval_props(fx - i->fP0); | 280 this->compute_interval_props(fx - i->fP0); |
| 550 } | 281 } |
| 551 | 282 |
| 552 SkScalar currentAdvance() const { | 283 SkScalar currentAdvance() const { |
| 553 SkASSERT(fAdvX >= 0); | 284 SkASSERT(fAdvX >= 0); |
| 554 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx); | 285 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx); |
| 555 return fAdvX; | 286 return fAdvX; |
| 556 } | 287 } |
| 557 | 288 |
| 558 bool currentRampIsZero() const { return fZeroRamp; } | 289 bool currentRampIsZero() const { return fZeroRamp; } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 619 Sk4f fCc; // current color, interpolated in dst | 350 Sk4f fCc; // current color, interpolated in dst |
| 620 SkScalar fAdvX; // remaining interval advance in dst | 351 SkScalar fAdvX; // remaining interval advance in dst |
| 621 bool fZeroRamp; // current interval color grad is 0 | 352 bool fZeroRamp; // current interval color grad is 0 |
| 622 | 353 |
| 623 const Interval* fFirstInterval; | 354 const Interval* fFirstInterval; |
| 624 const Interval* fLastInterval; | 355 const Interval* fLastInterval; |
| 625 const Interval* fInterval; // current interval | 356 const Interval* fInterval; // current interval |
| 626 const SkScalar fDx; // 'dx' for consistency with other impls; actual
ly dt/dx | 357 const SkScalar fDx; // 'dx' for consistency with other impls; actual
ly dt/dx |
| 627 const bool fIsVertical; | 358 const bool fIsVertical; |
| 628 }; | 359 }; |
| 360 |
| 361 void SkLinearGradient:: |
| 362 LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const { |
| 363 SkASSERT(count > 0); |
| 364 SkASSERT(fDstToPosClass != kLinear_MatrixClass); |
| 365 |
| 366 SkScalar sx = x + SK_ScalarHalf; |
| 367 const SkScalar sy = y + SK_ScalarHalf; |
| 368 SkPoint pt; |
| 369 |
| 370 if (fDstToPosClass != kPerspective_MatrixClass) { |
| 371 // kLinear_MatrixClass, kFixedStepInX_MatrixClass => fixed dt per scanli
ne |
| 372 const SkScalar dtdx = fDstToPos.fixedStepInX(sy).x(); |
| 373 fDstToPosProc(fDstToPos, sx, sy, &pt); |
| 374 |
| 375 const Sk4f dtdx4 = Sk4f(4 * dtdx); |
| 376 Sk4f t4 = Sk4f(pt.x() + 0 * dtdx, |
| 377 pt.x() + 1 * dtdx, |
| 378 pt.x() + 2 * dtdx, |
| 379 pt.x() + 3 * dtdx); |
| 380 |
| 381 while (count >= 4) { |
| 382 t4.store(ts); |
| 383 t4 = t4 + dtdx4; |
| 384 ts += 4; |
| 385 count -= 4; |
| 386 } |
| 387 |
| 388 if (count & 2) { |
| 389 *ts++ = t4[0]; |
| 390 *ts++ = t4[1]; |
| 391 t4 = SkNx_shuffle<2, 0, 1, 3>(t4); |
| 392 } |
| 393 |
| 394 if (count & 1) { |
| 395 *ts++ = t4[0]; |
| 396 } |
| 397 } else { |
| 398 for (int i = 0; i < count; ++i) { |
| 399 fDstToPosProc(fDstToPos, sx, sy, &pt); |
| 400 ts[i] = pt.x(); |
| 401 sx += SK_Scalar1; |
| 402 } |
| 403 } |
| 404 } |
| OLD | NEW |