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 "Sk4fGradientBase.h" | 8 #include "Sk4fGradientBase.h" |
9 | 9 |
10 #include <functional> | 10 #include <functional> |
11 | 11 |
12 namespace { | 12 namespace { |
13 | 13 |
14 Sk4f pack_color(SkColor c, bool premul, const Sk4f& component_scale) { | 14 Sk4f pack_color(SkColor c, bool premul, const Sk4f& component_scale) { |
15 const SkColor4f c4f = SkColor4f::FromColor(c); | 15 const SkColor4f c4f = SkColor4f::FromColor(c); |
16 const Sk4f pm4f = premul | 16 const Sk4f pm4f = premul |
17 ? c4f.premul().to4f() | 17 ? c4f.premul().to4f() |
18 : Sk4f{c4f.fR, c4f.fG, c4f.fB, c4f.fA}; | 18 : Sk4f{c4f.fR, c4f.fG, c4f.fB, c4f.fA}; |
19 | 19 |
20 return pm4f * component_scale; | 20 return pm4f * component_scale; |
21 } | 21 } |
22 | 22 |
23 template<SkShader::TileMode> | |
24 SkScalar tileProc(SkScalar t); | |
25 | |
26 template<> | |
27 SkScalar tileProc<SkShader::kClamp_TileMode>(SkScalar t) { | |
28 // synthetic clamp-mode edge intervals allow for a free-floating t: | |
29 // [-inf..0)[0..1)[1..+inf) | |
30 return t; | |
31 } | |
32 | |
33 template<> | |
34 SkScalar tileProc<SkShader::kRepeat_TileMode>(SkScalar t) { | |
35 // t % 1 (intervals range: [0..1)) | |
36 return t - SkScalarFloorToScalar(t); | |
37 } | |
38 | |
39 template<> | |
40 SkScalar tileProc<SkShader::kMirror_TileMode>(SkScalar t) { | |
41 // t % 2 (synthetic mirror intervals expand the range to [0..2) | |
42 return t - SkScalarFloorToScalar(t / 2) * 2; | |
43 } | |
44 | |
45 class IntervalIterator { | 23 class IntervalIterator { |
46 public: | 24 public: |
47 IntervalIterator(const SkColor* colors, const SkScalar* pos, int count, bool reverse) | 25 IntervalIterator(const SkColor* colors, const SkScalar* pos, int count, bool reverse) |
48 : fColors(colors) | 26 : fColors(colors) |
49 , fPos(pos) | 27 , fPos(pos) |
50 , fCount(count) | 28 , fCount(count) |
51 , fFirstPos(reverse ? SK_Scalar1 : 0) | 29 , fFirstPos(reverse ? SK_Scalar1 : 0) |
52 , fBegin(reverse ? count - 1 : 0) | 30 , fBegin(reverse ? count - 1 : 0) |
53 , fAdvance(reverse ? -1 : 1) { | 31 , fAdvance(reverse ? -1 : 1) { |
54 SkASSERT(colors); | 32 SkASSERT(colors); |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
347 count -= n; | 325 count -= n; |
348 } while (count > 0); | 326 } while (count > 0); |
349 } | 327 } |
350 | 328 |
351 template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode> | 329 template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode> |
352 class SkGradientShaderBase::GradientShaderBase4fContext::TSampler { | 330 class SkGradientShaderBase::GradientShaderBase4fContext::TSampler { |
353 public: | 331 public: |
354 TSampler(const GradientShaderBase4fContext& ctx) | 332 TSampler(const GradientShaderBase4fContext& ctx) |
355 : fFirstInterval(ctx.fIntervals.begin()) | 333 : fFirstInterval(ctx.fIntervals.begin()) |
356 , fLastInterval(ctx.fIntervals.end() - 1) | 334 , fLastInterval(ctx.fIntervals.end() - 1) |
357 , fInterval(nullptr) { | 335 , fInterval(nullptr) |
336 , fLargestLessThanTwo(nextafterf(2, 0)) { | |
358 SkASSERT(fLastInterval >= fFirstInterval); | 337 SkASSERT(fLastInterval >= fFirstInterval); |
359 } | 338 } |
360 | 339 |
361 Sk4f sample(SkScalar t) { | 340 Sk4f sample(SkScalar t) { |
362 const SkScalar tiled_t = tileProc<tileMode>(t); | 341 const auto tiled_t = tileProc(t); |
363 | 342 |
364 if (!fInterval) { | 343 if (!fInterval) { |
365 // Very first sample => locate the initial interval. | 344 // Very first sample => locate the initial interval. |
366 // TODO: maybe do this in ctor to remove a branch? | 345 // TODO: maybe do this in ctor to remove a branch? |
367 fInterval = this->findFirstInterval(tiled_t); | 346 fInterval = this->findFirstInterval(tiled_t); |
368 this->loadIntervalData(fInterval); | 347 this->loadIntervalData(fInterval); |
369 } else if (tiled_t < fInterval->fP0 || tiled_t >= fInterval->fP1) { | 348 } else if (tiled_t < fInterval->fP0 || tiled_t >= fInterval->fP1) { |
370 fInterval = this->findNextInterval(t, tiled_t); | 349 fInterval = this->findNextInterval(t, tiled_t); |
371 this->loadIntervalData(fInterval); | 350 this->loadIntervalData(fInterval); |
372 } | 351 } |
373 | 352 |
374 fPrevT = t; | 353 fPrevT = t; |
375 return lerp(tiled_t); | 354 return lerp(tiled_t); |
376 } | 355 } |
377 | 356 |
378 private: | 357 private: |
358 SkScalar tileProc(SkScalar t) const { | |
359 switch (tileMode) { | |
360 case kClamp_TileMode: | |
361 // synthetic clamp-mode edge intervals allow for a free-floating t: | |
362 // [-inf..0)[0..1)[1..+inf) | |
363 return t; | |
364 case kRepeat_TileMode: | |
365 // t % 1 (intervals range: [0..1)) | |
366 return t - SkScalarFloorToScalar(t); | |
367 case kMirror_TileMode: | |
368 // t % 2 (synthetic mirror intervals expand the range to [0..2) | |
369 // Due to the extra arithmetic, we must clamp to ensure the value re mains less than 2. | |
370 return SkTMin(t - SkScalarFloorToScalar(t / 2) * 2, fLargestLessThan Two); | |
371 } | |
372 | |
373 SK_ABORT("Unhandled tile mode."); | |
374 return 0; | |
375 } | |
376 | |
379 Sk4f lerp(SkScalar t) { | 377 Sk4f lerp(SkScalar t) { |
380 SkASSERT(t >= fInterval->fP0 && t < fInterval->fP1); | 378 SkASSERT(t >= fInterval->fP0 && t < fInterval->fP1); |
381 return fCc + fDc * (t - fInterval->fP0); | 379 return fCc + fDc * (t - fInterval->fP0); |
382 } | 380 } |
383 | 381 |
384 const Interval* findFirstInterval(SkScalar t) const { | 382 const Interval* findFirstInterval(SkScalar t) const { |
385 // Binary search. | 383 // Binary search. |
386 const Interval* i0 = fFirstInterval; | 384 const Interval* i0 = fFirstInterval; |
387 const Interval* i1 = fLastInterval; | 385 const Interval* i1 = fLastInterval; |
388 | 386 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
432 | 430 |
433 void loadIntervalData(const Interval* i) { | 431 void loadIntervalData(const Interval* i) { |
434 fCc = DstTraits<dstType, premul>::load(i->fC0); | 432 fCc = DstTraits<dstType, premul>::load(i->fC0); |
435 fDc = DstTraits<dstType, premul>::load(i->fDc); | 433 fDc = DstTraits<dstType, premul>::load(i->fDc); |
436 } | 434 } |
437 | 435 |
438 const Interval* fFirstInterval; | 436 const Interval* fFirstInterval; |
439 const Interval* fLastInterval; | 437 const Interval* fLastInterval; |
440 const Interval* fInterval; | 438 const Interval* fInterval; |
441 SkScalar fPrevT; | 439 SkScalar fPrevT; |
440 SkScalar fLargestLessThanTwo; | |
herb_g
2016/11/04 14:58:44
Can this be static constexpr?
f(malita)
2016/11/04 15:05:53
Unfortunately not, nextafterf is not constexpr :(
| |
442 Sk4f fCc; | 441 Sk4f fCc; |
443 Sk4f fDc; | 442 Sk4f fDc; |
444 }; | 443 }; |
OLD | NEW |