gfx/skia/trunk/src/effects/gradients/SkLinearGradient.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 * Copyright 2012 Google Inc.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7
michael@0 8 #include "SkLinearGradient.h"
michael@0 9
michael@0 10 static inline int repeat_bits(int x, const int bits) {
michael@0 11 return x & ((1 << bits) - 1);
michael@0 12 }
michael@0 13
michael@0 14 static inline int repeat_8bits(int x) {
michael@0 15 return x & 0xFF;
michael@0 16 }
michael@0 17
michael@0 18 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
michael@0 19 // See http://code.google.com/p/skia/issues/detail?id=472
michael@0 20 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
michael@0 21 #pragma optimize("", off)
michael@0 22 #endif
michael@0 23
michael@0 24 static inline int mirror_bits(int x, const int bits) {
michael@0 25 if (x & (1 << bits)) {
michael@0 26 x = ~x;
michael@0 27 }
michael@0 28 return x & ((1 << bits) - 1);
michael@0 29 }
michael@0 30
michael@0 31 static inline int mirror_8bits(int x) {
michael@0 32 if (x & 256) {
michael@0 33 x = ~x;
michael@0 34 }
michael@0 35 return x & 255;
michael@0 36 }
michael@0 37
michael@0 38 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
michael@0 39 #pragma optimize("", on)
michael@0 40 #endif
michael@0 41
michael@0 42 static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
michael@0 43 SkVector vec = pts[1] - pts[0];
michael@0 44 SkScalar mag = vec.length();
michael@0 45 SkScalar inv = mag ? SkScalarInvert(mag) : 0;
michael@0 46
michael@0 47 vec.scale(inv);
michael@0 48 matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
michael@0 49 matrix->postTranslate(-pts[0].fX, -pts[0].fY);
michael@0 50 matrix->postScale(inv, inv);
michael@0 51 }
michael@0 52
michael@0 53 ///////////////////////////////////////////////////////////////////////////////
michael@0 54
michael@0 55 SkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc)
michael@0 56 : SkGradientShaderBase(desc)
michael@0 57 , fStart(pts[0])
michael@0 58 , fEnd(pts[1]) {
michael@0 59 pts_to_unit_matrix(pts, &fPtsToUnit);
michael@0 60 }
michael@0 61
michael@0 62 SkLinearGradient::SkLinearGradient(SkReadBuffer& buffer)
michael@0 63 : INHERITED(buffer)
michael@0 64 , fStart(buffer.readPoint())
michael@0 65 , fEnd(buffer.readPoint()) {
michael@0 66 }
michael@0 67
michael@0 68 void SkLinearGradient::flatten(SkWriteBuffer& buffer) const {
michael@0 69 this->INHERITED::flatten(buffer);
michael@0 70 buffer.writePoint(fStart);
michael@0 71 buffer.writePoint(fEnd);
michael@0 72 }
michael@0 73
michael@0 74 bool SkLinearGradient::setContext(const SkBitmap& device, const SkPaint& paint,
michael@0 75 const SkMatrix& matrix) {
michael@0 76 if (!this->INHERITED::setContext(device, paint, matrix)) {
michael@0 77 return false;
michael@0 78 }
michael@0 79
michael@0 80 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
michael@0 81 if ((fDstToIndex.getType() & ~mask) == 0) {
michael@0 82 // when we dither, we are (usually) not const-in-Y
michael@0 83 if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
michael@0 84 // only claim this if we do have a 16bit mode (i.e. none of our
michael@0 85 // colors have alpha), and if we are not dithering (which obviously
michael@0 86 // is not const in Y).
michael@0 87 fFlags |= SkShader::kConstInY16_Flag;
michael@0 88 }
michael@0 89 }
michael@0 90 return true;
michael@0 91 }
michael@0 92
michael@0 93 #define NO_CHECK_ITER \
michael@0 94 do { \
michael@0 95 unsigned fi = fx >> SkGradientShaderBase::kCache32Shift; \
michael@0 96 SkASSERT(fi <= 0xFF); \
michael@0 97 fx += dx; \
michael@0 98 *dstC++ = cache[toggle + fi]; \
michael@0 99 toggle = next_dither_toggle(toggle); \
michael@0 100 } while (0)
michael@0 101
michael@0 102 namespace {
michael@0 103
michael@0 104 typedef void (*LinearShadeProc)(TileProc proc, SkFixed dx, SkFixed fx,
michael@0 105 SkPMColor* dstC, const SkPMColor* cache,
michael@0 106 int toggle, int count);
michael@0 107
michael@0 108 // Linear interpolation (lerp) is unnecessary if there are no sharp
michael@0 109 // discontinuities in the gradient - which must be true if there are
michael@0 110 // only 2 colors - but it's cheap.
michael@0 111 void shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx,
michael@0 112 SkPMColor* SK_RESTRICT dstC,
michael@0 113 const SkPMColor* SK_RESTRICT cache,
michael@0 114 int toggle, int count) {
michael@0 115 // We're a vertical gradient, so no change in a span.
michael@0 116 // If colors change sharply across the gradient, dithering is
michael@0 117 // insufficient (it subsamples the color space) and we need to lerp.
michael@0 118 unsigned fullIndex = proc(fx);
michael@0 119 unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift;
michael@0 120 unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1);
michael@0 121
michael@0 122 int index0 = fi + toggle;
michael@0 123 int index1 = index0;
michael@0 124 if (fi < SkGradientShaderBase::kCache32Count - 1) {
michael@0 125 index1 += 1;
michael@0 126 }
michael@0 127 SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder);
michael@0 128 index0 ^= SkGradientShaderBase::kDitherStride32;
michael@0 129 index1 ^= SkGradientShaderBase::kDitherStride32;
michael@0 130 SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder);
michael@0 131 sk_memset32_dither(dstC, lerp, dlerp, count);
michael@0 132 }
michael@0 133
michael@0 134 void shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
michael@0 135 SkPMColor* SK_RESTRICT dstC,
michael@0 136 const SkPMColor* SK_RESTRICT cache,
michael@0 137 int toggle, int count) {
michael@0 138 SkClampRange range;
michael@0 139 range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1);
michael@0 140
michael@0 141 if ((count = range.fCount0) > 0) {
michael@0 142 sk_memset32_dither(dstC,
michael@0 143 cache[toggle + range.fV0],
michael@0 144 cache[next_dither_toggle(toggle) + range.fV0],
michael@0 145 count);
michael@0 146 dstC += count;
michael@0 147 }
michael@0 148 if ((count = range.fCount1) > 0) {
michael@0 149 int unroll = count >> 3;
michael@0 150 fx = range.fFx1;
michael@0 151 for (int i = 0; i < unroll; i++) {
michael@0 152 NO_CHECK_ITER; NO_CHECK_ITER;
michael@0 153 NO_CHECK_ITER; NO_CHECK_ITER;
michael@0 154 NO_CHECK_ITER; NO_CHECK_ITER;
michael@0 155 NO_CHECK_ITER; NO_CHECK_ITER;
michael@0 156 }
michael@0 157 if ((count &= 7) > 0) {
michael@0 158 do {
michael@0 159 NO_CHECK_ITER;
michael@0 160 } while (--count != 0);
michael@0 161 }
michael@0 162 }
michael@0 163 if ((count = range.fCount2) > 0) {
michael@0 164 sk_memset32_dither(dstC,
michael@0 165 cache[toggle + range.fV1],
michael@0 166 cache[next_dither_toggle(toggle) + range.fV1],
michael@0 167 count);
michael@0 168 }
michael@0 169 }
michael@0 170
michael@0 171 void shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
michael@0 172 SkPMColor* SK_RESTRICT dstC,
michael@0 173 const SkPMColor* SK_RESTRICT cache,
michael@0 174 int toggle, int count) {
michael@0 175 do {
michael@0 176 unsigned fi = mirror_8bits(fx >> 8);
michael@0 177 SkASSERT(fi <= 0xFF);
michael@0 178 fx += dx;
michael@0 179 *dstC++ = cache[toggle + fi];
michael@0 180 toggle = next_dither_toggle(toggle);
michael@0 181 } while (--count != 0);
michael@0 182 }
michael@0 183
michael@0 184 void shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
michael@0 185 SkPMColor* SK_RESTRICT dstC,
michael@0 186 const SkPMColor* SK_RESTRICT cache,
michael@0 187 int toggle, int count) {
michael@0 188 do {
michael@0 189 unsigned fi = repeat_8bits(fx >> 8);
michael@0 190 SkASSERT(fi <= 0xFF);
michael@0 191 fx += dx;
michael@0 192 *dstC++ = cache[toggle + fi];
michael@0 193 toggle = next_dither_toggle(toggle);
michael@0 194 } while (--count != 0);
michael@0 195 }
michael@0 196
michael@0 197 }
michael@0 198
michael@0 199 void SkLinearGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
michael@0 200 int count) {
michael@0 201 SkASSERT(count > 0);
michael@0 202
michael@0 203 SkPoint srcPt;
michael@0 204 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
michael@0 205 TileProc proc = fTileProc;
michael@0 206 const SkPMColor* SK_RESTRICT cache = this->getCache32();
michael@0 207 int toggle = init_dither_toggle(x, y);
michael@0 208
michael@0 209 if (fDstToIndexClass != kPerspective_MatrixClass) {
michael@0 210 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
michael@0 211 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
michael@0 212 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
michael@0 213
michael@0 214 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
michael@0 215 SkFixed dxStorage[1];
michael@0 216 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
michael@0 217 dx = dxStorage[0];
michael@0 218 } else {
michael@0 219 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
michael@0 220 dx = SkScalarToFixed(fDstToIndex.getScaleX());
michael@0 221 }
michael@0 222
michael@0 223 LinearShadeProc shadeProc = shadeSpan_linear_repeat;
michael@0 224 if (0 == dx) {
michael@0 225 shadeProc = shadeSpan_linear_vertical_lerp;
michael@0 226 } else if (SkShader::kClamp_TileMode == fTileMode) {
michael@0 227 shadeProc = shadeSpan_linear_clamp;
michael@0 228 } else if (SkShader::kMirror_TileMode == fTileMode) {
michael@0 229 shadeProc = shadeSpan_linear_mirror;
michael@0 230 } else {
michael@0 231 SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
michael@0 232 }
michael@0 233 (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
michael@0 234 } else {
michael@0 235 SkScalar dstX = SkIntToScalar(x);
michael@0 236 SkScalar dstY = SkIntToScalar(y);
michael@0 237 do {
michael@0 238 dstProc(fDstToIndex, dstX, dstY, &srcPt);
michael@0 239 unsigned fi = proc(SkScalarToFixed(srcPt.fX));
michael@0 240 SkASSERT(fi <= 0xFFFF);
michael@0 241 *dstC++ = cache[toggle + (fi >> kCache32Shift)];
michael@0 242 toggle = next_dither_toggle(toggle);
michael@0 243 dstX += SK_Scalar1;
michael@0 244 } while (--count != 0);
michael@0 245 }
michael@0 246 }
michael@0 247
michael@0 248 SkShader::BitmapType SkLinearGradient::asABitmap(SkBitmap* bitmap,
michael@0 249 SkMatrix* matrix,
michael@0 250 TileMode xy[]) const {
michael@0 251 if (bitmap) {
michael@0 252 this->getGradientTableBitmap(bitmap);
michael@0 253 }
michael@0 254 if (matrix) {
michael@0 255 matrix->preConcat(fPtsToUnit);
michael@0 256 }
michael@0 257 if (xy) {
michael@0 258 xy[0] = fTileMode;
michael@0 259 xy[1] = kClamp_TileMode;
michael@0 260 }
michael@0 261 return kLinear_BitmapType;
michael@0 262 }
michael@0 263
michael@0 264 SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {
michael@0 265 if (info) {
michael@0 266 commonAsAGradient(info);
michael@0 267 info->fPoint[0] = fStart;
michael@0 268 info->fPoint[1] = fEnd;
michael@0 269 }
michael@0 270 return kLinear_GradientType;
michael@0 271 }
michael@0 272
michael@0 273 static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
michael@0 274 int count) {
michael@0 275 if (reinterpret_cast<uintptr_t>(dst) & 2) {
michael@0 276 *dst++ = value;
michael@0 277 count -= 1;
michael@0 278 SkTSwap(value, other);
michael@0 279 }
michael@0 280
michael@0 281 sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
michael@0 282
michael@0 283 if (count & 1) {
michael@0 284 dst[count - 1] = value;
michael@0 285 }
michael@0 286 }
michael@0 287
michael@0 288 #define NO_CHECK_ITER_16 \
michael@0 289 do { \
michael@0 290 unsigned fi = fx >> SkGradientShaderBase::kCache16Shift; \
michael@0 291 SkASSERT(fi < SkGradientShaderBase::kCache16Count); \
michael@0 292 fx += dx; \
michael@0 293 *dstC++ = cache[toggle + fi]; \
michael@0 294 toggle = next_dither_toggle16(toggle); \
michael@0 295 } while (0)
michael@0 296
michael@0 297 namespace {
michael@0 298
michael@0 299 typedef void (*LinearShade16Proc)(TileProc proc, SkFixed dx, SkFixed fx,
michael@0 300 uint16_t* dstC, const uint16_t* cache,
michael@0 301 int toggle, int count);
michael@0 302
michael@0 303 void shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
michael@0 304 uint16_t* SK_RESTRICT dstC,
michael@0 305 const uint16_t* SK_RESTRICT cache,
michael@0 306 int toggle, int count) {
michael@0 307 // we're a vertical gradient, so no change in a span
michael@0 308 unsigned fi = proc(fx) >> SkGradientShaderBase::kCache16Shift;
michael@0 309 SkASSERT(fi < SkGradientShaderBase::kCache16Count);
michael@0 310 dither_memset16(dstC, cache[toggle + fi],
michael@0 311 cache[next_dither_toggle16(toggle) + fi], count);
michael@0 312 }
michael@0 313
michael@0 314 void shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
michael@0 315 uint16_t* SK_RESTRICT dstC,
michael@0 316 const uint16_t* SK_RESTRICT cache,
michael@0 317 int toggle, int count) {
michael@0 318 SkClampRange range;
michael@0 319 range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1);
michael@0 320
michael@0 321 if ((count = range.fCount0) > 0) {
michael@0 322 dither_memset16(dstC,
michael@0 323 cache[toggle + range.fV0],
michael@0 324 cache[next_dither_toggle16(toggle) + range.fV0],
michael@0 325 count);
michael@0 326 dstC += count;
michael@0 327 }
michael@0 328 if ((count = range.fCount1) > 0) {
michael@0 329 int unroll = count >> 3;
michael@0 330 fx = range.fFx1;
michael@0 331 for (int i = 0; i < unroll; i++) {
michael@0 332 NO_CHECK_ITER_16; NO_CHECK_ITER_16;
michael@0 333 NO_CHECK_ITER_16; NO_CHECK_ITER_16;
michael@0 334 NO_CHECK_ITER_16; NO_CHECK_ITER_16;
michael@0 335 NO_CHECK_ITER_16; NO_CHECK_ITER_16;
michael@0 336 }
michael@0 337 if ((count &= 7) > 0) {
michael@0 338 do {
michael@0 339 NO_CHECK_ITER_16;
michael@0 340 } while (--count != 0);
michael@0 341 }
michael@0 342 }
michael@0 343 if ((count = range.fCount2) > 0) {
michael@0 344 dither_memset16(dstC,
michael@0 345 cache[toggle + range.fV1],
michael@0 346 cache[next_dither_toggle16(toggle) + range.fV1],
michael@0 347 count);
michael@0 348 }
michael@0 349 }
michael@0 350
michael@0 351 void shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
michael@0 352 uint16_t* SK_RESTRICT dstC,
michael@0 353 const uint16_t* SK_RESTRICT cache,
michael@0 354 int toggle, int count) {
michael@0 355 do {
michael@0 356 unsigned fi = mirror_bits(fx >> SkGradientShaderBase::kCache16Shift,
michael@0 357 SkGradientShaderBase::kCache16Bits);
michael@0 358 SkASSERT(fi < SkGradientShaderBase::kCache16Count);
michael@0 359 fx += dx;
michael@0 360 *dstC++ = cache[toggle + fi];
michael@0 361 toggle = next_dither_toggle16(toggle);
michael@0 362 } while (--count != 0);
michael@0 363 }
michael@0 364
michael@0 365 void shadeSpan16_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
michael@0 366 uint16_t* SK_RESTRICT dstC,
michael@0 367 const uint16_t* SK_RESTRICT cache,
michael@0 368 int toggle, int count) {
michael@0 369 do {
michael@0 370 unsigned fi = repeat_bits(fx >> SkGradientShaderBase::kCache16Shift,
michael@0 371 SkGradientShaderBase::kCache16Bits);
michael@0 372 SkASSERT(fi < SkGradientShaderBase::kCache16Count);
michael@0 373 fx += dx;
michael@0 374 *dstC++ = cache[toggle + fi];
michael@0 375 toggle = next_dither_toggle16(toggle);
michael@0 376 } while (--count != 0);
michael@0 377 }
michael@0 378 }
michael@0 379
michael@0 380 static bool fixed_nearly_zero(SkFixed x) {
michael@0 381 return SkAbs32(x) < (SK_Fixed1 >> 12);
michael@0 382 }
michael@0 383
michael@0 384 void SkLinearGradient::shadeSpan16(int x, int y,
michael@0 385 uint16_t* SK_RESTRICT dstC, int count) {
michael@0 386 SkASSERT(count > 0);
michael@0 387
michael@0 388 SkPoint srcPt;
michael@0 389 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
michael@0 390 TileProc proc = fTileProc;
michael@0 391 const uint16_t* SK_RESTRICT cache = this->getCache16();
michael@0 392 int toggle = init_dither_toggle16(x, y);
michael@0 393
michael@0 394 if (fDstToIndexClass != kPerspective_MatrixClass) {
michael@0 395 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
michael@0 396 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
michael@0 397 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
michael@0 398
michael@0 399 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
michael@0 400 SkFixed dxStorage[1];
michael@0 401 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
michael@0 402 dx = dxStorage[0];
michael@0 403 } else {
michael@0 404 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
michael@0 405 dx = SkScalarToFixed(fDstToIndex.getScaleX());
michael@0 406 }
michael@0 407
michael@0 408 LinearShade16Proc shadeProc = shadeSpan16_linear_repeat;
michael@0 409 if (fixed_nearly_zero(dx)) {
michael@0 410 shadeProc = shadeSpan16_linear_vertical;
michael@0 411 } else if (SkShader::kClamp_TileMode == fTileMode) {
michael@0 412 shadeProc = shadeSpan16_linear_clamp;
michael@0 413 } else if (SkShader::kMirror_TileMode == fTileMode) {
michael@0 414 shadeProc = shadeSpan16_linear_mirror;
michael@0 415 } else {
michael@0 416 SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
michael@0 417 }
michael@0 418 (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
michael@0 419 } else {
michael@0 420 SkScalar dstX = SkIntToScalar(x);
michael@0 421 SkScalar dstY = SkIntToScalar(y);
michael@0 422 do {
michael@0 423 dstProc(fDstToIndex, dstX, dstY, &srcPt);
michael@0 424 unsigned fi = proc(SkScalarToFixed(srcPt.fX));
michael@0 425 SkASSERT(fi <= 0xFFFF);
michael@0 426
michael@0 427 int index = fi >> kCache16Shift;
michael@0 428 *dstC++ = cache[toggle + index];
michael@0 429 toggle = next_dither_toggle16(toggle);
michael@0 430
michael@0 431 dstX += SK_Scalar1;
michael@0 432 } while (--count != 0);
michael@0 433 }
michael@0 434 }
michael@0 435
michael@0 436 #if SK_SUPPORT_GPU
michael@0 437
michael@0 438 #include "GrTBackendEffectFactory.h"
michael@0 439
michael@0 440 /////////////////////////////////////////////////////////////////////
michael@0 441
michael@0 442 class GrGLLinearGradient : public GrGLGradientEffect {
michael@0 443 public:
michael@0 444
michael@0 445 GrGLLinearGradient(const GrBackendEffectFactory& factory, const GrDrawEffect&)
michael@0 446 : INHERITED (factory) { }
michael@0 447
michael@0 448 virtual ~GrGLLinearGradient() { }
michael@0 449
michael@0 450 virtual void emitCode(GrGLShaderBuilder*,
michael@0 451 const GrDrawEffect&,
michael@0 452 EffectKey,
michael@0 453 const char* outputColor,
michael@0 454 const char* inputColor,
michael@0 455 const TransformedCoordsArray&,
michael@0 456 const TextureSamplerArray&) SK_OVERRIDE;
michael@0 457
michael@0 458 static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
michael@0 459 return GenBaseGradientKey(drawEffect);
michael@0 460 }
michael@0 461
michael@0 462 private:
michael@0 463
michael@0 464 typedef GrGLGradientEffect INHERITED;
michael@0 465 };
michael@0 466
michael@0 467 /////////////////////////////////////////////////////////////////////
michael@0 468
michael@0 469 class GrLinearGradient : public GrGradientEffect {
michael@0 470 public:
michael@0 471
michael@0 472 static GrEffectRef* Create(GrContext* ctx,
michael@0 473 const SkLinearGradient& shader,
michael@0 474 const SkMatrix& matrix,
michael@0 475 SkShader::TileMode tm) {
michael@0 476 AutoEffectUnref effect(SkNEW_ARGS(GrLinearGradient, (ctx, shader, matrix, tm)));
michael@0 477 return CreateEffectRef(effect);
michael@0 478 }
michael@0 479
michael@0 480 virtual ~GrLinearGradient() { }
michael@0 481
michael@0 482 static const char* Name() { return "Linear Gradient"; }
michael@0 483 const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
michael@0 484 return GrTBackendEffectFactory<GrLinearGradient>::getInstance();
michael@0 485 }
michael@0 486
michael@0 487 typedef GrGLLinearGradient GLEffect;
michael@0 488
michael@0 489 private:
michael@0 490 GrLinearGradient(GrContext* ctx,
michael@0 491 const SkLinearGradient& shader,
michael@0 492 const SkMatrix& matrix,
michael@0 493 SkShader::TileMode tm)
michael@0 494 : INHERITED(ctx, shader, matrix, tm) { }
michael@0 495 GR_DECLARE_EFFECT_TEST;
michael@0 496
michael@0 497 typedef GrGradientEffect INHERITED;
michael@0 498 };
michael@0 499
michael@0 500 /////////////////////////////////////////////////////////////////////
michael@0 501
michael@0 502 GR_DEFINE_EFFECT_TEST(GrLinearGradient);
michael@0 503
michael@0 504 GrEffectRef* GrLinearGradient::TestCreate(SkRandom* random,
michael@0 505 GrContext* context,
michael@0 506 const GrDrawTargetCaps&,
michael@0 507 GrTexture**) {
michael@0 508 SkPoint points[] = {{random->nextUScalar1(), random->nextUScalar1()},
michael@0 509 {random->nextUScalar1(), random->nextUScalar1()}};
michael@0 510
michael@0 511 SkColor colors[kMaxRandomGradientColors];
michael@0 512 SkScalar stopsArray[kMaxRandomGradientColors];
michael@0 513 SkScalar* stops = stopsArray;
michael@0 514 SkShader::TileMode tm;
michael@0 515 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
michael@0 516 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateLinear(points,
michael@0 517 colors, stops, colorCount,
michael@0 518 tm));
michael@0 519 SkPaint paint;
michael@0 520 return shader->asNewEffect(context, paint);
michael@0 521 }
michael@0 522
michael@0 523 /////////////////////////////////////////////////////////////////////
michael@0 524
michael@0 525 void GrGLLinearGradient::emitCode(GrGLShaderBuilder* builder,
michael@0 526 const GrDrawEffect&,
michael@0 527 EffectKey key,
michael@0 528 const char* outputColor,
michael@0 529 const char* inputColor,
michael@0 530 const TransformedCoordsArray& coords,
michael@0 531 const TextureSamplerArray& samplers) {
michael@0 532 this->emitUniforms(builder, key);
michael@0 533 SkString t = builder->ensureFSCoords2D(coords, 0);
michael@0 534 t.append(".x");
michael@0 535 this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers);
michael@0 536 }
michael@0 537
michael@0 538 /////////////////////////////////////////////////////////////////////
michael@0 539
michael@0 540 GrEffectRef* SkLinearGradient::asNewEffect(GrContext* context, const SkPaint&) const {
michael@0 541 SkASSERT(NULL != context);
michael@0 542 SkMatrix matrix;
michael@0 543 if (!this->getLocalMatrix().invert(&matrix)) {
michael@0 544 return NULL;
michael@0 545 }
michael@0 546 matrix.postConcat(fPtsToUnit);
michael@0 547 return GrLinearGradient::Create(context, *this, matrix, fTileMode);
michael@0 548 }
michael@0 549
michael@0 550 #else
michael@0 551
michael@0 552 GrEffectRef* SkLinearGradient::asNewEffect(GrContext*, const SkPaint&) const {
michael@0 553 SkDEBUGFAIL("Should not call in GPU-less build");
michael@0 554 return NULL;
michael@0 555 }
michael@0 556
michael@0 557 #endif
michael@0 558
michael@0 559 #ifndef SK_IGNORE_TO_STRING
michael@0 560 void SkLinearGradient::toString(SkString* str) const {
michael@0 561 str->append("SkLinearGradient (");
michael@0 562
michael@0 563 str->appendf("start: (%f, %f)", fStart.fX, fStart.fY);
michael@0 564 str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY);
michael@0 565
michael@0 566 this->INHERITED::toString(str);
michael@0 567
michael@0 568 str->append(")");
michael@0 569 }
michael@0 570 #endif

mercurial