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