Chromium Code Reviews| 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 |