1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/effects/gradients/SkLinearGradient.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,570 @@ 1.4 +/* 1.5 + * Copyright 2012 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkLinearGradient.h" 1.12 + 1.13 +static inline int repeat_bits(int x, const int bits) { 1.14 + return x & ((1 << bits) - 1); 1.15 +} 1.16 + 1.17 +static inline int repeat_8bits(int x) { 1.18 + return x & 0xFF; 1.19 +} 1.20 + 1.21 +// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly. 1.22 +// See http://code.google.com/p/skia/issues/detail?id=472 1.23 +#if defined(_MSC_VER) && (_MSC_VER >= 1600) 1.24 +#pragma optimize("", off) 1.25 +#endif 1.26 + 1.27 +static inline int mirror_bits(int x, const int bits) { 1.28 + if (x & (1 << bits)) { 1.29 + x = ~x; 1.30 + } 1.31 + return x & ((1 << bits) - 1); 1.32 +} 1.33 + 1.34 +static inline int mirror_8bits(int x) { 1.35 + if (x & 256) { 1.36 + x = ~x; 1.37 + } 1.38 + return x & 255; 1.39 +} 1.40 + 1.41 +#if defined(_MSC_VER) && (_MSC_VER >= 1600) 1.42 +#pragma optimize("", on) 1.43 +#endif 1.44 + 1.45 +static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) { 1.46 + SkVector vec = pts[1] - pts[0]; 1.47 + SkScalar mag = vec.length(); 1.48 + SkScalar inv = mag ? SkScalarInvert(mag) : 0; 1.49 + 1.50 + vec.scale(inv); 1.51 + matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); 1.52 + matrix->postTranslate(-pts[0].fX, -pts[0].fY); 1.53 + matrix->postScale(inv, inv); 1.54 +} 1.55 + 1.56 +/////////////////////////////////////////////////////////////////////////////// 1.57 + 1.58 +SkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc) 1.59 + : SkGradientShaderBase(desc) 1.60 + , fStart(pts[0]) 1.61 + , fEnd(pts[1]) { 1.62 + pts_to_unit_matrix(pts, &fPtsToUnit); 1.63 +} 1.64 + 1.65 +SkLinearGradient::SkLinearGradient(SkReadBuffer& buffer) 1.66 + : INHERITED(buffer) 1.67 + , fStart(buffer.readPoint()) 1.68 + , fEnd(buffer.readPoint()) { 1.69 +} 1.70 + 1.71 +void SkLinearGradient::flatten(SkWriteBuffer& buffer) const { 1.72 + this->INHERITED::flatten(buffer); 1.73 + buffer.writePoint(fStart); 1.74 + buffer.writePoint(fEnd); 1.75 +} 1.76 + 1.77 +bool SkLinearGradient::setContext(const SkBitmap& device, const SkPaint& paint, 1.78 + const SkMatrix& matrix) { 1.79 + if (!this->INHERITED::setContext(device, paint, matrix)) { 1.80 + return false; 1.81 + } 1.82 + 1.83 + unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 1.84 + if ((fDstToIndex.getType() & ~mask) == 0) { 1.85 + // when we dither, we are (usually) not const-in-Y 1.86 + if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) { 1.87 + // only claim this if we do have a 16bit mode (i.e. none of our 1.88 + // colors have alpha), and if we are not dithering (which obviously 1.89 + // is not const in Y). 1.90 + fFlags |= SkShader::kConstInY16_Flag; 1.91 + } 1.92 + } 1.93 + return true; 1.94 +} 1.95 + 1.96 +#define NO_CHECK_ITER \ 1.97 + do { \ 1.98 + unsigned fi = fx >> SkGradientShaderBase::kCache32Shift; \ 1.99 + SkASSERT(fi <= 0xFF); \ 1.100 + fx += dx; \ 1.101 + *dstC++ = cache[toggle + fi]; \ 1.102 + toggle = next_dither_toggle(toggle); \ 1.103 + } while (0) 1.104 + 1.105 +namespace { 1.106 + 1.107 +typedef void (*LinearShadeProc)(TileProc proc, SkFixed dx, SkFixed fx, 1.108 + SkPMColor* dstC, const SkPMColor* cache, 1.109 + int toggle, int count); 1.110 + 1.111 +// Linear interpolation (lerp) is unnecessary if there are no sharp 1.112 +// discontinuities in the gradient - which must be true if there are 1.113 +// only 2 colors - but it's cheap. 1.114 +void shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx, 1.115 + SkPMColor* SK_RESTRICT dstC, 1.116 + const SkPMColor* SK_RESTRICT cache, 1.117 + int toggle, int count) { 1.118 + // We're a vertical gradient, so no change in a span. 1.119 + // If colors change sharply across the gradient, dithering is 1.120 + // insufficient (it subsamples the color space) and we need to lerp. 1.121 + unsigned fullIndex = proc(fx); 1.122 + unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift; 1.123 + unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1); 1.124 + 1.125 + int index0 = fi + toggle; 1.126 + int index1 = index0; 1.127 + if (fi < SkGradientShaderBase::kCache32Count - 1) { 1.128 + index1 += 1; 1.129 + } 1.130 + SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder); 1.131 + index0 ^= SkGradientShaderBase::kDitherStride32; 1.132 + index1 ^= SkGradientShaderBase::kDitherStride32; 1.133 + SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder); 1.134 + sk_memset32_dither(dstC, lerp, dlerp, count); 1.135 +} 1.136 + 1.137 +void shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx, 1.138 + SkPMColor* SK_RESTRICT dstC, 1.139 + const SkPMColor* SK_RESTRICT cache, 1.140 + int toggle, int count) { 1.141 + SkClampRange range; 1.142 + range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1); 1.143 + 1.144 + if ((count = range.fCount0) > 0) { 1.145 + sk_memset32_dither(dstC, 1.146 + cache[toggle + range.fV0], 1.147 + cache[next_dither_toggle(toggle) + range.fV0], 1.148 + count); 1.149 + dstC += count; 1.150 + } 1.151 + if ((count = range.fCount1) > 0) { 1.152 + int unroll = count >> 3; 1.153 + fx = range.fFx1; 1.154 + for (int i = 0; i < unroll; i++) { 1.155 + NO_CHECK_ITER; NO_CHECK_ITER; 1.156 + NO_CHECK_ITER; NO_CHECK_ITER; 1.157 + NO_CHECK_ITER; NO_CHECK_ITER; 1.158 + NO_CHECK_ITER; NO_CHECK_ITER; 1.159 + } 1.160 + if ((count &= 7) > 0) { 1.161 + do { 1.162 + NO_CHECK_ITER; 1.163 + } while (--count != 0); 1.164 + } 1.165 + } 1.166 + if ((count = range.fCount2) > 0) { 1.167 + sk_memset32_dither(dstC, 1.168 + cache[toggle + range.fV1], 1.169 + cache[next_dither_toggle(toggle) + range.fV1], 1.170 + count); 1.171 + } 1.172 +} 1.173 + 1.174 +void shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx, 1.175 + SkPMColor* SK_RESTRICT dstC, 1.176 + const SkPMColor* SK_RESTRICT cache, 1.177 + int toggle, int count) { 1.178 + do { 1.179 + unsigned fi = mirror_8bits(fx >> 8); 1.180 + SkASSERT(fi <= 0xFF); 1.181 + fx += dx; 1.182 + *dstC++ = cache[toggle + fi]; 1.183 + toggle = next_dither_toggle(toggle); 1.184 + } while (--count != 0); 1.185 +} 1.186 + 1.187 +void shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx, 1.188 + SkPMColor* SK_RESTRICT dstC, 1.189 + const SkPMColor* SK_RESTRICT cache, 1.190 + int toggle, int count) { 1.191 + do { 1.192 + unsigned fi = repeat_8bits(fx >> 8); 1.193 + SkASSERT(fi <= 0xFF); 1.194 + fx += dx; 1.195 + *dstC++ = cache[toggle + fi]; 1.196 + toggle = next_dither_toggle(toggle); 1.197 + } while (--count != 0); 1.198 +} 1.199 + 1.200 +} 1.201 + 1.202 +void SkLinearGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, 1.203 + int count) { 1.204 + SkASSERT(count > 0); 1.205 + 1.206 + SkPoint srcPt; 1.207 + SkMatrix::MapXYProc dstProc = fDstToIndexProc; 1.208 + TileProc proc = fTileProc; 1.209 + const SkPMColor* SK_RESTRICT cache = this->getCache32(); 1.210 + int toggle = init_dither_toggle(x, y); 1.211 + 1.212 + if (fDstToIndexClass != kPerspective_MatrixClass) { 1.213 + dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 1.214 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.215 + SkFixed dx, fx = SkScalarToFixed(srcPt.fX); 1.216 + 1.217 + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 1.218 + SkFixed dxStorage[1]; 1.219 + (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL); 1.220 + dx = dxStorage[0]; 1.221 + } else { 1.222 + SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 1.223 + dx = SkScalarToFixed(fDstToIndex.getScaleX()); 1.224 + } 1.225 + 1.226 + LinearShadeProc shadeProc = shadeSpan_linear_repeat; 1.227 + if (0 == dx) { 1.228 + shadeProc = shadeSpan_linear_vertical_lerp; 1.229 + } else if (SkShader::kClamp_TileMode == fTileMode) { 1.230 + shadeProc = shadeSpan_linear_clamp; 1.231 + } else if (SkShader::kMirror_TileMode == fTileMode) { 1.232 + shadeProc = shadeSpan_linear_mirror; 1.233 + } else { 1.234 + SkASSERT(SkShader::kRepeat_TileMode == fTileMode); 1.235 + } 1.236 + (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); 1.237 + } else { 1.238 + SkScalar dstX = SkIntToScalar(x); 1.239 + SkScalar dstY = SkIntToScalar(y); 1.240 + do { 1.241 + dstProc(fDstToIndex, dstX, dstY, &srcPt); 1.242 + unsigned fi = proc(SkScalarToFixed(srcPt.fX)); 1.243 + SkASSERT(fi <= 0xFFFF); 1.244 + *dstC++ = cache[toggle + (fi >> kCache32Shift)]; 1.245 + toggle = next_dither_toggle(toggle); 1.246 + dstX += SK_Scalar1; 1.247 + } while (--count != 0); 1.248 + } 1.249 +} 1.250 + 1.251 +SkShader::BitmapType SkLinearGradient::asABitmap(SkBitmap* bitmap, 1.252 + SkMatrix* matrix, 1.253 + TileMode xy[]) const { 1.254 + if (bitmap) { 1.255 + this->getGradientTableBitmap(bitmap); 1.256 + } 1.257 + if (matrix) { 1.258 + matrix->preConcat(fPtsToUnit); 1.259 + } 1.260 + if (xy) { 1.261 + xy[0] = fTileMode; 1.262 + xy[1] = kClamp_TileMode; 1.263 + } 1.264 + return kLinear_BitmapType; 1.265 +} 1.266 + 1.267 +SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { 1.268 + if (info) { 1.269 + commonAsAGradient(info); 1.270 + info->fPoint[0] = fStart; 1.271 + info->fPoint[1] = fEnd; 1.272 + } 1.273 + return kLinear_GradientType; 1.274 +} 1.275 + 1.276 +static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other, 1.277 + int count) { 1.278 + if (reinterpret_cast<uintptr_t>(dst) & 2) { 1.279 + *dst++ = value; 1.280 + count -= 1; 1.281 + SkTSwap(value, other); 1.282 + } 1.283 + 1.284 + sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1); 1.285 + 1.286 + if (count & 1) { 1.287 + dst[count - 1] = value; 1.288 + } 1.289 +} 1.290 + 1.291 +#define NO_CHECK_ITER_16 \ 1.292 + do { \ 1.293 + unsigned fi = fx >> SkGradientShaderBase::kCache16Shift; \ 1.294 + SkASSERT(fi < SkGradientShaderBase::kCache16Count); \ 1.295 + fx += dx; \ 1.296 + *dstC++ = cache[toggle + fi]; \ 1.297 + toggle = next_dither_toggle16(toggle); \ 1.298 + } while (0) 1.299 + 1.300 +namespace { 1.301 + 1.302 +typedef void (*LinearShade16Proc)(TileProc proc, SkFixed dx, SkFixed fx, 1.303 + uint16_t* dstC, const uint16_t* cache, 1.304 + int toggle, int count); 1.305 + 1.306 +void shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx, 1.307 + uint16_t* SK_RESTRICT dstC, 1.308 + const uint16_t* SK_RESTRICT cache, 1.309 + int toggle, int count) { 1.310 + // we're a vertical gradient, so no change in a span 1.311 + unsigned fi = proc(fx) >> SkGradientShaderBase::kCache16Shift; 1.312 + SkASSERT(fi < SkGradientShaderBase::kCache16Count); 1.313 + dither_memset16(dstC, cache[toggle + fi], 1.314 + cache[next_dither_toggle16(toggle) + fi], count); 1.315 +} 1.316 + 1.317 +void shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx, 1.318 + uint16_t* SK_RESTRICT dstC, 1.319 + const uint16_t* SK_RESTRICT cache, 1.320 + int toggle, int count) { 1.321 + SkClampRange range; 1.322 + range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1); 1.323 + 1.324 + if ((count = range.fCount0) > 0) { 1.325 + dither_memset16(dstC, 1.326 + cache[toggle + range.fV0], 1.327 + cache[next_dither_toggle16(toggle) + range.fV0], 1.328 + count); 1.329 + dstC += count; 1.330 + } 1.331 + if ((count = range.fCount1) > 0) { 1.332 + int unroll = count >> 3; 1.333 + fx = range.fFx1; 1.334 + for (int i = 0; i < unroll; i++) { 1.335 + NO_CHECK_ITER_16; NO_CHECK_ITER_16; 1.336 + NO_CHECK_ITER_16; NO_CHECK_ITER_16; 1.337 + NO_CHECK_ITER_16; NO_CHECK_ITER_16; 1.338 + NO_CHECK_ITER_16; NO_CHECK_ITER_16; 1.339 + } 1.340 + if ((count &= 7) > 0) { 1.341 + do { 1.342 + NO_CHECK_ITER_16; 1.343 + } while (--count != 0); 1.344 + } 1.345 + } 1.346 + if ((count = range.fCount2) > 0) { 1.347 + dither_memset16(dstC, 1.348 + cache[toggle + range.fV1], 1.349 + cache[next_dither_toggle16(toggle) + range.fV1], 1.350 + count); 1.351 + } 1.352 +} 1.353 + 1.354 +void shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx, 1.355 + uint16_t* SK_RESTRICT dstC, 1.356 + const uint16_t* SK_RESTRICT cache, 1.357 + int toggle, int count) { 1.358 + do { 1.359 + unsigned fi = mirror_bits(fx >> SkGradientShaderBase::kCache16Shift, 1.360 + SkGradientShaderBase::kCache16Bits); 1.361 + SkASSERT(fi < SkGradientShaderBase::kCache16Count); 1.362 + fx += dx; 1.363 + *dstC++ = cache[toggle + fi]; 1.364 + toggle = next_dither_toggle16(toggle); 1.365 + } while (--count != 0); 1.366 +} 1.367 + 1.368 +void shadeSpan16_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx, 1.369 + uint16_t* SK_RESTRICT dstC, 1.370 + const uint16_t* SK_RESTRICT cache, 1.371 + int toggle, int count) { 1.372 + do { 1.373 + unsigned fi = repeat_bits(fx >> SkGradientShaderBase::kCache16Shift, 1.374 + SkGradientShaderBase::kCache16Bits); 1.375 + SkASSERT(fi < SkGradientShaderBase::kCache16Count); 1.376 + fx += dx; 1.377 + *dstC++ = cache[toggle + fi]; 1.378 + toggle = next_dither_toggle16(toggle); 1.379 + } while (--count != 0); 1.380 +} 1.381 +} 1.382 + 1.383 +static bool fixed_nearly_zero(SkFixed x) { 1.384 + return SkAbs32(x) < (SK_Fixed1 >> 12); 1.385 +} 1.386 + 1.387 +void SkLinearGradient::shadeSpan16(int x, int y, 1.388 + uint16_t* SK_RESTRICT dstC, int count) { 1.389 + SkASSERT(count > 0); 1.390 + 1.391 + SkPoint srcPt; 1.392 + SkMatrix::MapXYProc dstProc = fDstToIndexProc; 1.393 + TileProc proc = fTileProc; 1.394 + const uint16_t* SK_RESTRICT cache = this->getCache16(); 1.395 + int toggle = init_dither_toggle16(x, y); 1.396 + 1.397 + if (fDstToIndexClass != kPerspective_MatrixClass) { 1.398 + dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 1.399 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.400 + SkFixed dx, fx = SkScalarToFixed(srcPt.fX); 1.401 + 1.402 + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 1.403 + SkFixed dxStorage[1]; 1.404 + (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL); 1.405 + dx = dxStorage[0]; 1.406 + } else { 1.407 + SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 1.408 + dx = SkScalarToFixed(fDstToIndex.getScaleX()); 1.409 + } 1.410 + 1.411 + LinearShade16Proc shadeProc = shadeSpan16_linear_repeat; 1.412 + if (fixed_nearly_zero(dx)) { 1.413 + shadeProc = shadeSpan16_linear_vertical; 1.414 + } else if (SkShader::kClamp_TileMode == fTileMode) { 1.415 + shadeProc = shadeSpan16_linear_clamp; 1.416 + } else if (SkShader::kMirror_TileMode == fTileMode) { 1.417 + shadeProc = shadeSpan16_linear_mirror; 1.418 + } else { 1.419 + SkASSERT(SkShader::kRepeat_TileMode == fTileMode); 1.420 + } 1.421 + (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); 1.422 + } else { 1.423 + SkScalar dstX = SkIntToScalar(x); 1.424 + SkScalar dstY = SkIntToScalar(y); 1.425 + do { 1.426 + dstProc(fDstToIndex, dstX, dstY, &srcPt); 1.427 + unsigned fi = proc(SkScalarToFixed(srcPt.fX)); 1.428 + SkASSERT(fi <= 0xFFFF); 1.429 + 1.430 + int index = fi >> kCache16Shift; 1.431 + *dstC++ = cache[toggle + index]; 1.432 + toggle = next_dither_toggle16(toggle); 1.433 + 1.434 + dstX += SK_Scalar1; 1.435 + } while (--count != 0); 1.436 + } 1.437 +} 1.438 + 1.439 +#if SK_SUPPORT_GPU 1.440 + 1.441 +#include "GrTBackendEffectFactory.h" 1.442 + 1.443 +///////////////////////////////////////////////////////////////////// 1.444 + 1.445 +class GrGLLinearGradient : public GrGLGradientEffect { 1.446 +public: 1.447 + 1.448 + GrGLLinearGradient(const GrBackendEffectFactory& factory, const GrDrawEffect&) 1.449 + : INHERITED (factory) { } 1.450 + 1.451 + virtual ~GrGLLinearGradient() { } 1.452 + 1.453 + virtual void emitCode(GrGLShaderBuilder*, 1.454 + const GrDrawEffect&, 1.455 + EffectKey, 1.456 + const char* outputColor, 1.457 + const char* inputColor, 1.458 + const TransformedCoordsArray&, 1.459 + const TextureSamplerArray&) SK_OVERRIDE; 1.460 + 1.461 + static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 1.462 + return GenBaseGradientKey(drawEffect); 1.463 + } 1.464 + 1.465 +private: 1.466 + 1.467 + typedef GrGLGradientEffect INHERITED; 1.468 +}; 1.469 + 1.470 +///////////////////////////////////////////////////////////////////// 1.471 + 1.472 +class GrLinearGradient : public GrGradientEffect { 1.473 +public: 1.474 + 1.475 + static GrEffectRef* Create(GrContext* ctx, 1.476 + const SkLinearGradient& shader, 1.477 + const SkMatrix& matrix, 1.478 + SkShader::TileMode tm) { 1.479 + AutoEffectUnref effect(SkNEW_ARGS(GrLinearGradient, (ctx, shader, matrix, tm))); 1.480 + return CreateEffectRef(effect); 1.481 + } 1.482 + 1.483 + virtual ~GrLinearGradient() { } 1.484 + 1.485 + static const char* Name() { return "Linear Gradient"; } 1.486 + const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 1.487 + return GrTBackendEffectFactory<GrLinearGradient>::getInstance(); 1.488 + } 1.489 + 1.490 + typedef GrGLLinearGradient GLEffect; 1.491 + 1.492 +private: 1.493 + GrLinearGradient(GrContext* ctx, 1.494 + const SkLinearGradient& shader, 1.495 + const SkMatrix& matrix, 1.496 + SkShader::TileMode tm) 1.497 + : INHERITED(ctx, shader, matrix, tm) { } 1.498 + GR_DECLARE_EFFECT_TEST; 1.499 + 1.500 + typedef GrGradientEffect INHERITED; 1.501 +}; 1.502 + 1.503 +///////////////////////////////////////////////////////////////////// 1.504 + 1.505 +GR_DEFINE_EFFECT_TEST(GrLinearGradient); 1.506 + 1.507 +GrEffectRef* GrLinearGradient::TestCreate(SkRandom* random, 1.508 + GrContext* context, 1.509 + const GrDrawTargetCaps&, 1.510 + GrTexture**) { 1.511 + SkPoint points[] = {{random->nextUScalar1(), random->nextUScalar1()}, 1.512 + {random->nextUScalar1(), random->nextUScalar1()}}; 1.513 + 1.514 + SkColor colors[kMaxRandomGradientColors]; 1.515 + SkScalar stopsArray[kMaxRandomGradientColors]; 1.516 + SkScalar* stops = stopsArray; 1.517 + SkShader::TileMode tm; 1.518 + int colorCount = RandomGradientParams(random, colors, &stops, &tm); 1.519 + SkAutoTUnref<SkShader> shader(SkGradientShader::CreateLinear(points, 1.520 + colors, stops, colorCount, 1.521 + tm)); 1.522 + SkPaint paint; 1.523 + return shader->asNewEffect(context, paint); 1.524 +} 1.525 + 1.526 +///////////////////////////////////////////////////////////////////// 1.527 + 1.528 +void GrGLLinearGradient::emitCode(GrGLShaderBuilder* builder, 1.529 + const GrDrawEffect&, 1.530 + EffectKey key, 1.531 + const char* outputColor, 1.532 + const char* inputColor, 1.533 + const TransformedCoordsArray& coords, 1.534 + const TextureSamplerArray& samplers) { 1.535 + this->emitUniforms(builder, key); 1.536 + SkString t = builder->ensureFSCoords2D(coords, 0); 1.537 + t.append(".x"); 1.538 + this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers); 1.539 +} 1.540 + 1.541 +///////////////////////////////////////////////////////////////////// 1.542 + 1.543 +GrEffectRef* SkLinearGradient::asNewEffect(GrContext* context, const SkPaint&) const { 1.544 + SkASSERT(NULL != context); 1.545 + SkMatrix matrix; 1.546 + if (!this->getLocalMatrix().invert(&matrix)) { 1.547 + return NULL; 1.548 + } 1.549 + matrix.postConcat(fPtsToUnit); 1.550 + return GrLinearGradient::Create(context, *this, matrix, fTileMode); 1.551 +} 1.552 + 1.553 +#else 1.554 + 1.555 +GrEffectRef* SkLinearGradient::asNewEffect(GrContext*, const SkPaint&) const { 1.556 + SkDEBUGFAIL("Should not call in GPU-less build"); 1.557 + return NULL; 1.558 +} 1.559 + 1.560 +#endif 1.561 + 1.562 +#ifndef SK_IGNORE_TO_STRING 1.563 +void SkLinearGradient::toString(SkString* str) const { 1.564 + str->append("SkLinearGradient ("); 1.565 + 1.566 + str->appendf("start: (%f, %f)", fStart.fX, fStart.fY); 1.567 + str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY); 1.568 + 1.569 + this->INHERITED::toString(str); 1.570 + 1.571 + str->append(")"); 1.572 +} 1.573 +#endif