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 "Sk4fLinearGradient.h" | 8 #include "Sk4fLinearGradient.h" |
9 #include "Sk4x4f.h" | 9 #include "Sk4x4f.h" |
10 #include "SkXfermode.h" | 10 #include "SkXfermode.h" |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) { | 98 SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) { |
99 const SkScalar f = SkScalarMod(fx, 2.0f); | 99 const SkScalar f = SkScalarMod(fx, 2.0f); |
100 return f < 0 ? f + 2 : f; | 100 return f < 0 ? f + 2 : f; |
101 } | 101 } |
102 | 102 |
103 // true when x is in [k1,k2), or [k2, k1) when the interval is reversed. | 103 // true when x is in [k1,k2), or [k2, k1) when the interval is reversed. |
104 // TODO(fmalita): hoist the reversed interval check out of this helper. | 104 // TODO(fmalita): hoist the reversed interval check out of this helper. |
105 bool in_range(SkScalar x, SkScalar k1, SkScalar k2) { | 105 bool in_range(SkScalar x, SkScalar k1, SkScalar k2) { |
106 SkASSERT(k1 != k2); | 106 SkASSERT(k1 != k2); |
107 return (k1 < k2) | 107 return (k1 < k2) |
108 ? (x >= k1 && x < k2) | 108 ? (x >= k1 && x < k2) |
109 : (x > k2 && x <= k1); | 109 : (x >= k2 && x < k1); |
110 } | 110 } |
111 | 111 |
112 } // anonymous namespace | 112 } // anonymous namespace |
113 | 113 |
114 SkLinearGradient:: | 114 SkLinearGradient:: |
115 LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader, | 115 LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader, |
116 const ContextRec& rec) | 116 const ContextRec& rec) |
117 : INHERITED(shader, rec) { | 117 : INHERITED(shader, rec) { |
118 | 118 |
119 // Our fast path expects interval points to be monotonically increasing in x
. | 119 // Our fast path expects interval points to be monotonically increasing in x
. |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 : fAdvX((i->fP1 - fx) / dx) | 287 : fAdvX((i->fP1 - fx) / dx) |
288 , fFirstInterval(firstInterval) | 288 , fFirstInterval(firstInterval) |
289 , fLastInterval(lastInterval) | 289 , fLastInterval(lastInterval) |
290 , fInterval(i) | 290 , fInterval(i) |
291 , fDx(dx) | 291 , fDx(dx) |
292 , fIsVertical(is_vertical) | 292 , fIsVertical(is_vertical) |
293 { | 293 { |
294 SkASSERT(fAdvX >= 0); | 294 SkASSERT(fAdvX >= 0); |
295 SkASSERT(firstInterval <= lastInterval); | 295 SkASSERT(firstInterval <= lastInterval); |
296 SkASSERT(in_range(fx, i->fP0, i->fP1)); | 296 SkASSERT(in_range(fx, i->fP0, i->fP1)); |
| 297 |
| 298 if (tileMode != kClamp_TileMode && !is_vertical) { |
| 299 const auto spanX = (lastInterval->fP1 - firstInterval->fP0) / dx; |
| 300 SkASSERT(spanX >= 0); |
| 301 |
| 302 // If we're in a repeating tile mode and the whole gradient is compr
essed into a |
| 303 // fraction of a pixel, we just use the average color in zero-ramp m
ode. |
| 304 // This also avoids cases where we make no progress due to interval
advances being |
| 305 // close to zero. |
| 306 static constexpr SkScalar kMinSpanX = .25f; |
| 307 if (spanX < kMinSpanX) { |
| 308 this->init_average_props(); |
| 309 return; |
| 310 } |
| 311 } |
| 312 |
297 this->compute_interval_props(fx - i->fP0); | 313 this->compute_interval_props(fx - i->fP0); |
298 } | 314 } |
299 | 315 |
300 SkScalar currentAdvance() const { | 316 SkScalar currentAdvance() const { |
301 SkASSERT(fAdvX >= 0); | 317 SkASSERT(fAdvX >= 0); |
302 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx); | 318 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx || !isfinite(f
AdvX)); |
303 return fAdvX; | 319 return fAdvX; |
304 } | 320 } |
305 | 321 |
306 bool currentRampIsZero() const { return fZeroRamp; } | 322 bool currentRampIsZero() const { return fZeroRamp; } |
307 const Sk4f& currentColor() const { return fCc; } | 323 const Sk4f& currentColor() const { return fCc; } |
308 const Sk4f& currentColorGrad() const { return fDcDx; } | 324 const Sk4f& currentColorGrad() const { return fDcDx; } |
309 | 325 |
310 void advance(SkScalar advX) { | 326 void advance(SkScalar advX) { |
311 SkASSERT(advX > 0); | 327 SkASSERT(advX > 0); |
312 SkASSERT(fAdvX >= 0); | 328 SkASSERT(fAdvX >= 0); |
(...skipping 14 matching lines...) Expand all Loading... |
327 | 343 |
328 if (fInterval->isZeroRamp()) { | 344 if (fInterval->isZeroRamp()) { |
329 fDcDx = 0; | 345 fDcDx = 0; |
330 } else { | 346 } else { |
331 const Sk4f dC = DstTraits<dstType, premul>::load(fInterval->fDc); | 347 const Sk4f dC = DstTraits<dstType, premul>::load(fInterval->fDc); |
332 fCc = fCc + dC * Sk4f(t); | 348 fCc = fCc + dC * Sk4f(t); |
333 fDcDx = dC * fDx; | 349 fDcDx = dC * fDx; |
334 } | 350 } |
335 } | 351 } |
336 | 352 |
| 353 void init_average_props() { |
| 354 fAdvX = SK_ScalarInfinity; |
| 355 fZeroRamp = true; |
| 356 fDcDx = 0; |
| 357 fCc = Sk4f(0); |
| 358 |
| 359 // TODO: precompute the average at interval setup time? |
| 360 for (const auto* i = fFirstInterval; i <= fLastInterval; ++i) { |
| 361 // Each interval contributes its average color to the total/weighted
average: |
| 362 // |
| 363 // C = (c0 + c1) / 2 = (c0 + c0 + dc * (p1 - p0)) / 2 |
| 364 // |
| 365 // Avg += C * (p1 - p0) |
| 366 // |
| 367 const auto dp = i->fP1 - i->fP0; |
| 368 auto c = DstTraits<dstType, premul>::load(i->fC0); |
| 369 if (!i->fZeroRamp) { |
| 370 c = c + DstTraits<dstType, premul>::load(i->fDc) * dp * 0.5f; |
| 371 } |
| 372 fCc = fCc + c * dp; |
| 373 } |
| 374 } |
| 375 |
337 const Interval* next_interval(const Interval* i) const { | 376 const Interval* next_interval(const Interval* i) const { |
338 SkASSERT(i >= fFirstInterval); | 377 SkASSERT(i >= fFirstInterval); |
339 SkASSERT(i <= fLastInterval); | 378 SkASSERT(i <= fLastInterval); |
340 i++; | 379 i++; |
341 | 380 |
342 if (tileMode == kClamp_TileMode) { | 381 if (tileMode == kClamp_TileMode) { |
343 SkASSERT(i <= fLastInterval); | 382 SkASSERT(i <= fLastInterval); |
344 return i; | 383 return i; |
345 } | 384 } |
346 | 385 |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 static_cast<const LinearGradient4fContext*>(state->fCtx); | 518 static_cast<const LinearGradient4fContext*>(state->fCtx); |
480 | 519 |
481 if (ctx->fColorsArePremul) { | 520 if (ctx->fColorsArePremul) { |
482 ctx->shadePremulSpan<DstType::F16, ApplyPremul::False>( | 521 ctx->shadePremulSpan<DstType::F16, ApplyPremul::False>( |
483 x, y, dst.writable_addr64(x, y), count); | 522 x, y, dst.writable_addr64(x, y), count); |
484 } else { | 523 } else { |
485 ctx->shadePremulSpan<DstType::F16, ApplyPremul::True>( | 524 ctx->shadePremulSpan<DstType::F16, ApplyPremul::True>( |
486 x, y, dst.writable_addr64(x, y), count); | 525 x, y, dst.writable_addr64(x, y), count); |
487 } | 526 } |
488 } | 527 } |
OLD | NEW |