180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/* 380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2012 Google Inc. 480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * 580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be 680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file. 780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */ 880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkLinearGradient.h" 1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline int repeat_bits(int x, const int bits) { 1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return x & ((1 << bits) - 1); 1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline int repeat_8bits(int x) { 1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return x & 0xFF; 1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly. 2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// See http://code.google.com/p/skia/issues/detail?id=472 2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if defined(_MSC_VER) && (_MSC_VER >= 1600) 2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#pragma optimize("", off) 2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline int mirror_bits(int x, const int bits) { 2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#ifdef SK_CPU_HAS_CONDITIONAL_INSTR 2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (x & (1 << bits)) 2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru x = ~x; 2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return x & ((1 << bits) - 1); 3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else 3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int s = x << (31 - bits) >> 31; 3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return (x ^ s) & ((1 << bits) - 1); 3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline int mirror_8bits(int x) { 3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#ifdef SK_CPU_HAS_CONDITIONAL_INSTR 3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (x & 256) { 3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru x = ~x; 4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return x & 255; 4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else 4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int s = x << 23 >> 31; 4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return (x ^ s) & 0xFF; 4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if defined(_MSC_VER) && (_MSC_VER >= 1600) 4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#pragma optimize("", on) 5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) { 5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkVector vec = pts[1] - pts[0]; 5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar mag = vec.length(); 5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar inv = mag ? SkScalarInvert(mag) : 0; 5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru vec.scale(inv); 5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); 5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru matrix->postTranslate(-pts[0].fX, -pts[0].fY); 6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru matrix->postScale(inv, inv); 6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////////////// 6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkLinearGradient::SkLinearGradient(const SkPoint pts[2], 6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkColor colors[], 6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkScalar pos[], 6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int colorCount, 6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkShader::TileMode mode, 7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkUnitMapper* mapper) 7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru : SkGradientShaderBase(colors, pos, colorCount, mode, mapper) 7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru , fStart(pts[0]) 7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru , fEnd(pts[1]) { 7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru pts_to_unit_matrix(pts, &fPtsToUnit); 7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkLinearGradient::SkLinearGradient(SkFlattenableReadBuffer& buffer) 7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru : INHERITED(buffer) 7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru , fStart(buffer.readPoint()) 8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru , fEnd(buffer.readPoint()) { 8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkLinearGradient::flatten(SkFlattenableWriteBuffer& buffer) const { 8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru this->INHERITED::flatten(buffer); 8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru buffer.writePoint(fStart); 8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru buffer.writePoint(fEnd); 8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool SkLinearGradient::setContext(const SkBitmap& device, const SkPaint& paint, 9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkMatrix& matrix) { 9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!this->INHERITED::setContext(device, paint, matrix)) { 9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((fDstToIndex.getType() & ~mask) == 0) { 9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fFlags |= SkShader::kConstInY32_Flag; 9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) { 9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // only claim this if we do have a 16bit mode (i.e. none of our 10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // colors have alpha), and if we are not dithering (which obviously 10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // is not const in Y). 10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fFlags |= SkShader::kConstInY16_Flag; 10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return true; 10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define NO_CHECK_ITER \ 10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru do { \ 11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned fi = fx >> SkGradientShaderBase::kCache32Shift; \ 11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fi <= 0xFF); \ 11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fx += dx; \ 11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dstC++ = cache[toggle + fi]; \ 114d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger toggle = next_dither_toggle(toggle); \ 11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } while (0) 11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querunamespace { 11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querutypedef void (*LinearShadeProc)(TileProc proc, SkFixed dx, SkFixed fx, 12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPMColor* dstC, const SkPMColor* cache, 12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle, int count); 12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Linear interpolation (lerp) is unnecessary if there are no sharp 12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// discontinuities in the gradient - which must be true if there are 12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// only 2 colors - but it's cheap. 12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx, 12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPMColor* SK_RESTRICT dstC, 12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkPMColor* SK_RESTRICT cache, 12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle, int count) { 13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // We're a vertical gradient, so no change in a span. 13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // If colors change sharply across the gradient, dithering is 13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // insufficient (it subsamples the color space) and we need to lerp. 13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned fullIndex = proc(fx); 134d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift; 135d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1); 136d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 137d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger int index0 = fi + toggle; 138d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger int index1 = index0; 139d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger if (fi < SkGradientShaderBase::kCache32Count - 1) { 140d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger index1 += 1; 141d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger } 142d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder); 143d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger index0 ^= SkGradientShaderBase::kDitherStride32; 144d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger index1 ^= SkGradientShaderBase::kDitherStride32; 145d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder); 14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sk_memset32_dither(dstC, lerp, dlerp, count); 14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx, 15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPMColor* SK_RESTRICT dstC, 15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkPMColor* SK_RESTRICT cache, 15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle, int count) { 15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkClampRange range; 154d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1); 15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((count = range.fCount0) > 0) { 15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sk_memset32_dither(dstC, 15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru cache[toggle + range.fV0], 159d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger cache[next_dither_toggle(toggle) + range.fV0], 16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru count); 16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dstC += count; 16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((count = range.fCount1) > 0) { 16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int unroll = count >> 3; 16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fx = range.fFx1; 16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int i = 0; i < unroll; i++) { 16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NO_CHECK_ITER; NO_CHECK_ITER; 16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NO_CHECK_ITER; NO_CHECK_ITER; 16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NO_CHECK_ITER; NO_CHECK_ITER; 17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NO_CHECK_ITER; NO_CHECK_ITER; 17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((count &= 7) > 0) { 17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru do { 17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NO_CHECK_ITER; 17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } while (--count != 0); 17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((count = range.fCount2) > 0) { 17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sk_memset32_dither(dstC, 18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru cache[toggle + range.fV1], 181d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger cache[next_dither_toggle(toggle) + range.fV1], 18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru count); 18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx, 18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPMColor* SK_RESTRICT dstC, 18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkPMColor* SK_RESTRICT cache, 18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle, int count) { 19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru do { 19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned fi = mirror_8bits(fx >> 8); 19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fi <= 0xFF); 19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fx += dx; 19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dstC++ = cache[toggle + fi]; 195d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger toggle = next_dither_toggle(toggle); 19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } while (--count != 0); 19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx, 20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPMColor* SK_RESTRICT dstC, 20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkPMColor* SK_RESTRICT cache, 20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle, int count) { 20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru do { 20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned fi = repeat_8bits(fx >> 8); 20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fi <= 0xFF); 20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fx += dx; 20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dstC++ = cache[toggle + fi]; 208d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger toggle = next_dither_toggle(toggle); 20980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } while (--count != 0); 21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 21380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkLinearGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, 21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int count) { 21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(count > 0); 21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPoint srcPt; 21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkMatrix::MapXYProc dstProc = fDstToIndexProc; 22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru TileProc proc = fTileProc; 22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkPMColor* SK_RESTRICT cache = this->getCache32(); 22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#ifdef USE_DITHER_32BIT_GRADIENT 223d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger int toggle = init_dither_toggle(x, y); 22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else 22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle = 0; 22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (fDstToIndexClass != kPerspective_MatrixClass) { 22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkFixed dx, fx = SkScalarToFixed(srcPt.fX); 23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkFixed dxStorage[1]; 23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL); 23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dx = dxStorage[0]; 23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dx = SkScalarToFixed(fDstToIndex.getScaleX()); 24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru LinearShadeProc shadeProc = shadeSpan_linear_repeat; 2436699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru if (SkFixedNearlyZero(dx, (SK_Fixed1 >> 14))) { 24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru shadeProc = shadeSpan_linear_vertical_lerp; 24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (SkShader::kClamp_TileMode == fTileMode) { 24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru shadeProc = shadeSpan_linear_clamp; 24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (SkShader::kMirror_TileMode == fTileMode) { 24880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru shadeProc = shadeSpan_linear_mirror; 24980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 25080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(SkShader::kRepeat_TileMode == fTileMode); 25180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 25280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); 25380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 25480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar dstX = SkIntToScalar(x); 25580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar dstY = SkIntToScalar(y); 25680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru do { 25780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dstProc(fDstToIndex, dstX, dstY, &srcPt); 25880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned fi = proc(SkScalarToFixed(srcPt.fX)); 25980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fi <= 0xFFFF); 26080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dstC++ = cache[toggle + (fi >> kCache32Shift)]; 261d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger toggle = next_dither_toggle(toggle); 26280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dstX += SK_Scalar1; 26380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } while (--count != 0); 26480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 26580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 26680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 26780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkShader::BitmapType SkLinearGradient::asABitmap(SkBitmap* bitmap, 26880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkMatrix* matrix, 26980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru TileMode xy[]) const { 27080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (bitmap) { 27180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru this->getGradientTableBitmap(bitmap); 27280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 27380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (matrix) { 27480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru matrix->preConcat(fPtsToUnit); 27580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 27680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (xy) { 27780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru xy[0] = fTileMode; 27880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru xy[1] = kClamp_TileMode; 27980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 28080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return kLinear_BitmapType; 28180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 28280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 28380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { 28480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (info) { 28580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru commonAsAGradient(info); 28680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru info->fPoint[0] = fStart; 28780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru info->fPoint[1] = fEnd; 28880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 28980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return kLinear_GradientType; 29080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 29180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 29280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other, 29380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int count) { 29480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (reinterpret_cast<uintptr_t>(dst) & 2) { 29580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dst++ = value; 29680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru count -= 1; 29780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkTSwap(value, other); 29880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 29980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 30080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1); 30180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 30280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (count & 1) { 30380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dst[count - 1] = value; 30480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 30580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 30680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 30780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define NO_CHECK_ITER_16 \ 30880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru do { \ 30980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned fi = fx >> SkGradientShaderBase::kCache16Shift; \ 31080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fi < SkGradientShaderBase::kCache16Count); \ 31180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fx += dx; \ 31280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dstC++ = cache[toggle + fi]; \ 313d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger toggle = next_dither_toggle16(toggle); \ 31480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } while (0) 31580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 31680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querunamespace { 31780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 31880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querutypedef void (*LinearShade16Proc)(TileProc proc, SkFixed dx, SkFixed fx, 31980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint16_t* dstC, const uint16_t* cache, 32080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle, int count); 32180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 32280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx, 32380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint16_t* SK_RESTRICT dstC, 32480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const uint16_t* SK_RESTRICT cache, 32580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle, int count) { 32680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // we're a vertical gradient, so no change in a span 32780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned fi = proc(fx) >> SkGradientShaderBase::kCache16Shift; 32880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fi < SkGradientShaderBase::kCache16Count); 32980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dither_memset16(dstC, cache[toggle + fi], 330d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger cache[next_dither_toggle16(toggle) + fi], count); 33180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 33280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 33380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 33480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx, 33580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint16_t* SK_RESTRICT dstC, 33680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const uint16_t* SK_RESTRICT cache, 33780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle, int count) { 33880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkClampRange range; 339d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1); 34080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 34180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((count = range.fCount0) > 0) { 34280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dither_memset16(dstC, 34380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru cache[toggle + range.fV0], 344d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger cache[next_dither_toggle16(toggle) + range.fV0], 34580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru count); 34680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dstC += count; 34780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 34880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((count = range.fCount1) > 0) { 34980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int unroll = count >> 3; 35080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fx = range.fFx1; 35180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int i = 0; i < unroll; i++) { 35280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NO_CHECK_ITER_16; NO_CHECK_ITER_16; 35380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NO_CHECK_ITER_16; NO_CHECK_ITER_16; 35480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NO_CHECK_ITER_16; NO_CHECK_ITER_16; 35580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NO_CHECK_ITER_16; NO_CHECK_ITER_16; 35680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 35780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((count &= 7) > 0) { 35880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru do { 35980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru NO_CHECK_ITER_16; 36080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } while (--count != 0); 36180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 36280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 36380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if ((count = range.fCount2) > 0) { 36480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dither_memset16(dstC, 36580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru cache[toggle + range.fV1], 366d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger cache[next_dither_toggle16(toggle) + range.fV1], 36780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru count); 36880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 36980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 37080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 37180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx, 37280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint16_t* SK_RESTRICT dstC, 37380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const uint16_t* SK_RESTRICT cache, 37480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle, int count) { 37580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru do { 37680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned fi = mirror_bits(fx >> SkGradientShaderBase::kCache16Shift, 37780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkGradientShaderBase::kCache16Bits); 37880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fi < SkGradientShaderBase::kCache16Count); 37980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fx += dx; 38080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dstC++ = cache[toggle + fi]; 381d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger toggle = next_dither_toggle16(toggle); 38280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } while (--count != 0); 38380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 38480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 38580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan16_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx, 38680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint16_t* SK_RESTRICT dstC, 38780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const uint16_t* SK_RESTRICT cache, 38880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int toggle, int count) { 38980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru do { 39080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned fi = repeat_bits(fx >> SkGradientShaderBase::kCache16Shift, 39180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkGradientShaderBase::kCache16Bits); 39280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fi < SkGradientShaderBase::kCache16Count); 39380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fx += dx; 39480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dstC++ = cache[toggle + fi]; 395d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger toggle = next_dither_toggle16(toggle); 39680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } while (--count != 0); 39780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 39880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 39980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 40080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkLinearGradient::shadeSpan16(int x, int y, 40180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint16_t* SK_RESTRICT dstC, int count) { 40280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(count > 0); 40380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 40480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPoint srcPt; 40580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkMatrix::MapXYProc dstProc = fDstToIndexProc; 40680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru TileProc proc = fTileProc; 40780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const uint16_t* SK_RESTRICT cache = this->getCache16(); 408d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger int toggle = init_dither_toggle16(x, y); 40980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 41080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (fDstToIndexClass != kPerspective_MatrixClass) { 41180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 41280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 41380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkFixed dx, fx = SkScalarToFixed(srcPt.fX); 41480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 41580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 41680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkFixed dxStorage[1]; 41780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL); 41880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dx = dxStorage[0]; 41980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 42080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 42180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dx = SkScalarToFixed(fDstToIndex.getScaleX()); 42280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 42380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 42480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru LinearShade16Proc shadeProc = shadeSpan16_linear_repeat; 42580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (SkFixedNearlyZero(dx)) { 42680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru shadeProc = shadeSpan16_linear_vertical; 42780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (SkShader::kClamp_TileMode == fTileMode) { 42880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru shadeProc = shadeSpan16_linear_clamp; 42980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (SkShader::kMirror_TileMode == fTileMode) { 43080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru shadeProc = shadeSpan16_linear_mirror; 43180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 43280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(SkShader::kRepeat_TileMode == fTileMode); 43380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 43480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); 43580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 43680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar dstX = SkIntToScalar(x); 43780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar dstY = SkIntToScalar(y); 43880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru do { 43980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dstProc(fDstToIndex, dstX, dstY, &srcPt); 44080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru unsigned fi = proc(SkScalarToFixed(srcPt.fX)); 44180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(fi <= 0xFFFF); 44280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 44380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int index = fi >> kCache16Shift; 44480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *dstC++ = cache[toggle + index]; 445d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger toggle = next_dither_toggle16(toggle); 44680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 44780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dstX += SK_Scalar1; 44880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } while (--count != 0); 44980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 45080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 45180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 45280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if SK_SUPPORT_GPU 45380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 454363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "GrTBackendEffectFactory.h" 455363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 45680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////// 45780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 458363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerclass GrGLLinearGradient : public GrGLGradientEffect { 45980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic: 46080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 461d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger GrGLLinearGradient(const GrBackendEffectFactory& factory, const GrEffectRef&) 46280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru : INHERITED (factory) { } 46380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 46480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru virtual ~GrGLLinearGradient() { } 46580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 466363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger virtual void emitCode(GrGLShaderBuilder*, 467363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const GrEffectStage&, 468363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger EffectKey, 469363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* vertexCoords, 470363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* outputColor, 471363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* inputColor, 472363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const TextureSamplerArray&) SK_OVERRIDE; 473363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 474363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) { 475363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return GenMatrixKey(stage); 476363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 47780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 47880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate: 47980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 480363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger typedef GrGLGradientEffect INHERITED; 48180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}; 48280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 48380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////// 48480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 48580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass GrLinearGradient : public GrGradientEffect { 48680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic: 48780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 488d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger static GrEffectRef* Create(GrContext* ctx, 489d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const SkLinearGradient& shader, 490d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const SkMatrix& matrix, 491d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkShader::TileMode tm) { 492d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger AutoEffectUnref effect(SkNEW_ARGS(GrLinearGradient, (ctx, shader, matrix, tm))); 493d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger return CreateEffectRef(effect); 494d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger } 495d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 49680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru virtual ~GrLinearGradient() { } 49780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 49880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru static const char* Name() { return "Linear Gradient"; } 499363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 500363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return GrTBackendEffectFactory<GrLinearGradient>::getInstance(); 50180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 50280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 503363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger typedef GrGLLinearGradient GLEffect; 50480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 50580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate: 506d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger GrLinearGradient(GrContext* ctx, 507d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const SkLinearGradient& shader, 508d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger const SkMatrix& matrix, 509d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkShader::TileMode tm) 510d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger : INHERITED(ctx, shader, matrix, tm) { } 511363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger GR_DECLARE_EFFECT_TEST; 51280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 51380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru typedef GrGradientEffect INHERITED; 51480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}; 51580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 51680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////// 51780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 518363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerGR_DEFINE_EFFECT_TEST(GrLinearGradient); 51980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 520d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek SollenbergerGrEffectRef* GrLinearGradient::TestCreate(SkRandom* random, 521d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger GrContext* context, 522d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger GrTexture**) { 52380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkPoint points[] = {{random->nextUScalar1(), random->nextUScalar1()}, 52480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru {random->nextUScalar1(), random->nextUScalar1()}}; 52580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 52680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkColor colors[kMaxRandomGradientColors]; 52780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar stopsArray[kMaxRandomGradientColors]; 52880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkScalar* stops = stopsArray; 52980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkShader::TileMode tm; 53080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int colorCount = RandomGradientParams(random, colors, &stops, &tm); 53180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkAutoTUnref<SkShader> shader(SkGradientShader::CreateLinear(points, 53280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru colors, stops, colorCount, 53380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru tm)); 534d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkPaint paint; 535d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger return shader->asNewEffect(context, paint); 53680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 53780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 53880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////// 53980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 540363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid GrGLLinearGradient::emitCode(GrGLShaderBuilder* builder, 541363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const GrEffectStage& stage, 542363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger EffectKey key, 543363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* vertexCoords, 544363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* outputColor, 545363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* inputColor, 546363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const TextureSamplerArray& samplers) { 547363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger this->emitYCoordUniform(builder); 548363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* coords; 549363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger this->setupMatrix(builder, key, vertexCoords, &coords); 55080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkString t; 551363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger t.append(coords); 552363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger t.append(".x"); 55380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]); 55480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 55580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 55680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////// 55780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 558d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek SollenbergerGrEffectRef* SkLinearGradient::asNewEffect(GrContext* context, const SkPaint&) const { 559d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger SkASSERT(NULL != context); 56080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkMatrix matrix; 561363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!this->getLocalMatrix().invert(&matrix)) { 562d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger return NULL; 56380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 564363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger matrix.postConcat(fPtsToUnit); 565d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger return GrLinearGradient::Create(context, *this, matrix, fTileMode); 56680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 56780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 56880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else 56980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 570d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek SollenbergerGrEffectRef* SkLinearGradient::asNewEffect(GrContext*, const SkPaint&) const { 57180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkDEBUGFAIL("Should not call in GPU-less build"); 572d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger return NULL; 57380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 57480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 57580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 576d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 577d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger#ifdef SK_DEVELOPER 578d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenbergervoid SkLinearGradient::toString(SkString* str) const { 579d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger str->append("SkLinearGradient ("); 580d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 581d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger str->appendf("start: (%f, %f)", fStart.fX, fStart.fY); 582d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY); 583d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 584d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger this->INHERITED::toString(str); 585d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger 586d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger str->append(")"); 587d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger} 588d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger#endif 589