OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 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 "SkLinearGradient.h" | 8 #include "SkLinearGradient.h" |
9 | 9 |
10 static inline int repeat_bits(int x, const int bits) { | 10 static inline int repeat_bits(int x, const int bits) { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
93 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; | 93 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; |
94 if ((fDstToIndex.getType() & ~mask) == 0) { | 94 if ((fDstToIndex.getType() & ~mask) == 0) { |
95 // when we dither, we are (usually) not const-in-Y | 95 // when we dither, we are (usually) not const-in-Y |
96 if ((fFlags & SkShader::kHasSpan16_Flag) && !rec.fPaint->isDither()) { | 96 if ((fFlags & SkShader::kHasSpan16_Flag) && !rec.fPaint->isDither()) { |
97 // only claim this if we do have a 16bit mode (i.e. none of our | 97 // only claim this if we do have a 16bit mode (i.e. none of our |
98 // colors have alpha), and if we are not dithering (which obviously | 98 // colors have alpha), and if we are not dithering (which obviously |
99 // is not const in Y). | 99 // is not const in Y). |
100 fFlags |= SkShader::kConstInY16_Flag; | 100 fFlags |= SkShader::kConstInY16_Flag; |
101 } | 101 } |
102 } | 102 } |
103 | |
104 // setup for Sk4f | |
105 int count = shader.fColorCount; | |
106 fColorCount = count; | |
107 fColors4 = new Sk4f[count]; | |
108 fPos = new float[count * 2]; | |
109 fPosScale = fPos + count; | |
110 if (shader.fOrigPos) { | |
111 fPos[0] = 0; | |
112 fPosScale[0] = 0; // should never get used | |
113 for (int i = 1; i < count; ++i) { | |
114 fPos[i] = SkTMin(SkTMax(fPos[i - 1], shader.fOrigPos[i]), 1.0f); | |
115 fPosScale[i] = 1.0f / (fPos[i] - fPos[i - 1]); | |
116 } | |
117 fPos[count - 1] = 1; // overwrite the last value just to be sure we e nd at 1.0 | |
118 } else { | |
119 float invScale = 1.0f / (count - 1); | |
120 for (int i = 0; i < count; ++i) { | |
121 fPos[i] = i * invScale; | |
122 fPosScale[i] = count - 1; | |
123 } | |
124 } | |
125 for (int i = 0; i < count; ++i) { | |
126 SkPMColor pmc = SkPreMultiplyColor(shader.fOrigColors[i]); | |
127 fColors4[i] = Sk4f::FromBytes((const uint8_t*)&pmc); | |
128 if (i > 0) { | |
129 SkASSERT(fPos[i - 1] <= fPos[i]); | |
130 } | |
131 } | |
103 } | 132 } |
104 | 133 |
134 SkLinearGradient::LinearGradientContext::~LinearGradientContext() { | |
135 delete[] fPos; | |
136 delete[] fColors4; | |
137 } | |
138 | |
105 #define NO_CHECK_ITER \ | 139 #define NO_CHECK_ITER \ |
106 do { \ | 140 do { \ |
107 unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift; \ | 141 unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift; \ |
108 SkASSERT(fi <= 0xFF); \ | 142 SkASSERT(fi <= 0xFF); \ |
109 fx += dx; \ | 143 fx += dx; \ |
110 *dstC++ = cache[toggle + fi]; \ | 144 *dstC++ = cache[toggle + fi]; \ |
111 toggle = next_dither_toggle(toggle); \ | 145 toggle = next_dither_toggle(toggle); \ |
112 } while (0) | 146 } while (0) |
113 | 147 |
114 namespace { | 148 namespace { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
204 fx += dx; | 238 fx += dx; |
205 *dstC++ = cache[toggle + fi]; | 239 *dstC++ = cache[toggle + fi]; |
206 toggle = next_dither_toggle(toggle); | 240 toggle = next_dither_toggle(toggle); |
207 } while (--count != 0); | 241 } while (--count != 0); |
208 } | 242 } |
209 | 243 |
210 } | 244 } |
211 | 245 |
212 void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, | 246 void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, |
213 int count) { | 247 int count) { |
248 if (true) { | |
249 this->shadeSpan4(x, y, dstC, count); | |
250 return; | |
251 } | |
252 | |
214 SkASSERT(count > 0); | 253 SkASSERT(count > 0); |
215 | 254 |
216 const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient& >(fShader); | 255 const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient& >(fShader); |
217 | 256 |
218 SkPoint srcPt; | 257 SkPoint srcPt; |
219 SkMatrix::MapXYProc dstProc = fDstToIndexProc; | 258 SkMatrix::MapXYProc dstProc = fDstToIndexProc; |
220 TileProc proc = linearGradient.fTileProc; | 259 TileProc proc = linearGradient.fTileProc; |
221 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); | 260 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); |
222 int toggle = init_dither_toggle(x, y); | 261 int toggle = init_dither_toggle(x, y); |
223 | 262 |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
569 str->append("SkLinearGradient ("); | 608 str->append("SkLinearGradient ("); |
570 | 609 |
571 str->appendf("start: (%f, %f)", fStart.fX, fStart.fY); | 610 str->appendf("start: (%f, %f)", fStart.fX, fStart.fY); |
572 str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY); | 611 str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY); |
573 | 612 |
574 this->INHERITED::toString(str); | 613 this->INHERITED::toString(str); |
575 | 614 |
576 str->append(")"); | 615 str->append(")"); |
577 } | 616 } |
578 #endif | 617 #endif |
618 | |
619 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
620 | |
621 #include "SkNx.h" | |
622 | |
623 #if 0 | |
624 static Sk4f premul(const Sk4f& x) { | |
625 return x * scale_rgb(x.kth<SK_A32_SHIFT/8>()); | |
626 } | |
627 | |
628 static Sk4f unpremul(const Sk4f& x) { | |
629 return x * scale_rgb(1 / x.kth<SK_A32_SHIFT/8>()); // TODO: fast/approx inv ert? | |
630 } | |
631 | |
632 static Sk4f clamp_0_1(const Sk4f& x) { | |
633 return Sk4f::Max(Sk4f::Min(x, Sk4f(1)), Sk4f(0)); | |
634 } | |
635 #endif | |
636 | |
637 static SkPMColor round_from_255(const Sk4f& x) { | |
638 SkPMColor c; | |
639 (x + Sk4f(0.5f)).toBytes((uint8_t*)&c); | |
640 return c; | |
641 } | |
642 | |
643 static Sk4f lerp(Sk4f a, Sk4f b, float t) { | |
644 return a + Sk4f(t) * (b - a); | |
645 } | |
646 | |
647 static int find(float tiledX, const float pos[], int count) { | |
648 SkASSERT(count > 1); | |
649 SkASSERT(0 == pos[0]); | |
650 SkASSERT(1 == pos[count - 1]); | |
651 SkASSERT(tiledX >= 0 && tiledX <= 1); | |
652 | |
653 int i = 1; | |
654 while (pos[i] < tiledX) { | |
655 i += 1; | |
656 } | |
657 return i - 1; | |
658 } | |
659 | |
660 /* | |
661 * TODOs | |
662 * | |
663 * - tilemodes | |
664 * - interp before or after premul | |
665 * - apply paint's alpha (available when we create the context | |
666 * - perspective | |
667 * - dithering | |
668 * - optimizations | |
669 * - even spacing (how common is that?) | |
670 * - use fixed (32bit or 16bit) instead of floats? | |
671 */ | |
672 void SkLinearGradient::LinearGradientContext::shadeSpan4(int x, int y, SkPMColor * SK_RESTRICT dstC, | |
673 int count) { | |
674 SkASSERT(count > 0); | |
675 | |
676 const Sk4f* colors4 = fColors4; | |
677 const float* pos = fPos; | |
678 const float* posScale = fPosScale; | |
679 | |
680 SkPoint srcPt; | |
681 SkMatrix::MapXYProc dstProc = fDstToIndexProc; | |
682 // int toggle = init_dither_toggle(x, y); | |
683 | |
684 float dx, fx; | |
685 if (fDstToIndexClass != kPerspective_MatrixClass || true) { | |
686 dstProc(fDstToIndex, x + SK_ScalarHalf, y + SK_ScalarHalf, &srcPt); | |
687 fx = srcPt.x(); | |
688 | |
689 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { | |
690 SkFixed dxStorage[1]; | |
691 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, nullptr) ; | |
692 // todo: do we need a real/high-precision value for dx here? | |
693 dx = SkFixedToFloat(dxStorage[0]); | |
694 } else { | |
695 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); | |
696 dx = fDstToIndex.getScaleX(); | |
697 } | |
698 } | |
699 | |
700 int prevIndex = 0; | |
701 for (int i = 0; i < count; ++i) { | |
702 float tiledX = fx; | |
703 | |
704 // Apply the TileMode | |
705 if (tiledX < 0) { | |
706 tiledX = 0; | |
707 } | |
708 if (tiledX > 1) { | |
709 tiledX = 1; | |
710 } | |
711 | |
712 // Are we in the same relative interval, or do we need to search | |
713 if (pos[prevIndex] > tiledX || tiledX > pos[prevIndex + 1]) { | |
f(malita)
2015/11/11 05:14:16
What if instead of projecting the span pixels onto
| |
714 prevIndex = find(tiledX, pos, fColorCount); | |
715 } | |
716 | |
717 // Compute the color | |
718 float t = (fx - pos[prevIndex]) * posScale[prevIndex + 1]; | |
719 Sk4f c = lerp(colors4[prevIndex], colors4[prevIndex + 1], t); | |
720 dstC[i] = round_from_255(c); | |
721 | |
722 fx += dx; | |
723 } | |
724 } | |
725 | |
OLD | NEW |