c7d52fb0d9d27ee4d819939ca24f8312bd408dc2
[platform/upstream/libSkiaSharp.git] / src / effects / gradients / SkLinearGradient.cpp
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 const float kInv255Float = 1.0f / 255;
11
12 static inline int repeat_bits(int x, const int bits) {
13     return x & ((1 << bits) - 1);
14 }
15
16 static inline int repeat_8bits(int x) {
17     return x & 0xFF;
18 }
19
20 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
21 // See http://code.google.com/p/skia/issues/detail?id=472
22 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
23 #pragma optimize("", off)
24 #endif
25
26 static inline int mirror_bits(int x, const int bits) {
27     if (x & (1 << bits)) {
28         x = ~x;
29     }
30     return x & ((1 << bits) - 1);
31 }
32
33 static inline int mirror_8bits(int x) {
34     if (x & 256) {
35         x = ~x;
36     }
37     return x & 255;
38 }
39
40 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
41 #pragma optimize("", on)
42 #endif
43
44 static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) {
45     SkVector    vec = pts[1] - pts[0];
46     SkScalar    mag = vec.length();
47     SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
48
49     vec.scale(inv);
50     SkMatrix matrix;
51     matrix.setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
52     matrix.postTranslate(-pts[0].fX, -pts[0].fY);
53     matrix.postScale(inv, inv);
54     return matrix;
55 }
56
57 ///////////////////////////////////////////////////////////////////////////////
58
59 SkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc)
60     : SkGradientShaderBase(desc, pts_to_unit_matrix(pts))
61     , fStart(pts[0])
62     , fEnd(pts[1]) {
63 }
64
65 SkFlattenable* SkLinearGradient::CreateProc(SkReadBuffer& buffer) {
66     DescriptorScope desc;
67     if (!desc.unflatten(buffer)) {
68         return nullptr;
69     }
70     SkPoint pts[2];
71     pts[0] = buffer.readPoint();
72     pts[1] = buffer.readPoint();
73     return SkGradientShader::CreateLinear(pts, desc.fColors, desc.fPos, desc.fCount,
74                                           desc.fTileMode, desc.fGradFlags, desc.fLocalMatrix);
75 }
76
77 void SkLinearGradient::flatten(SkWriteBuffer& buffer) const {
78     this->INHERITED::flatten(buffer);
79     buffer.writePoint(fStart);
80     buffer.writePoint(fEnd);
81 }
82
83 size_t SkLinearGradient::contextSize() const {
84     return sizeof(LinearGradientContext);
85 }
86
87 SkShader::Context* SkLinearGradient::onCreateContext(const ContextRec& rec, void* storage) const {
88     return new (storage) LinearGradientContext(*this, rec);
89 }
90
91 // This swizzles SkColor into the same component order as SkPMColor, but does not actually
92 // "pre" multiply the color components.
93 //
94 // This allows us to map directly to Sk4f, and eventually scale down to bytes to output a
95 // SkPMColor from the floats, without having to swizzle each time.
96 //
97 static uint32_t SkSwizzle_Color_to_PMColor(SkColor c) {
98     return SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
99 }
100
101 SkLinearGradient::LinearGradientContext::LinearGradientContext(
102         const SkLinearGradient& shader, const ContextRec& ctx)
103     : INHERITED(shader, ctx)
104 {
105     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
106     if ((fDstToIndex.getType() & ~mask) == 0) {
107         // when we dither, we are (usually) not const-in-Y
108         if ((fFlags & SkShader::kHasSpan16_Flag) && !ctx.fPaint->isDither()) {
109             // only claim this if we do have a 16bit mode (i.e. none of our
110             // colors have alpha), and if we are not dithering (which obviously
111             // is not const in Y).
112             fFlags |= SkShader::kConstInY16_Flag;
113         }
114     }
115
116     // setup for Sk4f
117     int count = shader.fColorCount;
118     fRecs.setCount(count);
119     Rec* rec = fRecs.begin();
120     if (shader.fOrigPos) {
121         rec[0].fPos = 0;
122         SkDEBUGCODE(rec[0].fPosScale = SK_FloatNaN;)   // should never get used
123         for (int i = 1; i < count; ++i) {
124             rec[i].fPos = SkTPin(shader.fOrigPos[i], rec[i - 1].fPos, 1.0f);
125             rec[i].fPosScale = 1.0f / (rec[i].fPos - rec[i - 1].fPos);
126         }
127         rec[count - 1].fPos = 1;    // overwrite the last value just to be sure we end at 1.0
128     } else {
129         // no pos specified, so we compute evenly spaced values
130         const float scale = float(count - 1);
131         float invScale = 1.0f / scale;
132         for (int i = 0; i < count; ++i) {
133             rec[i].fPos = i * invScale;
134             rec[i].fPosScale = scale;
135         }
136     }
137
138     fApplyAlphaAfterInterp = true;
139     if ((shader.getGradFlags() & SkGradientShader::kInterpolateColorsInPremul_Flag) ||
140         shader.colorsAreOpaque())
141     {
142         fApplyAlphaAfterInterp = false;
143     }
144
145     if (fApplyAlphaAfterInterp) {
146         // Our fColor values are in PMColor order, but are still unpremultiplied, allowing us to
147         // interpolate in unpremultiplied space first, and then scale by alpha right before we
148         // convert to SkPMColor bytes.
149         const float paintAlpha = ctx.fPaint->getAlpha() * kInv255Float;
150         const Sk4f scale(1, 1, 1, paintAlpha);
151         for (int i = 0; i < count; ++i) {
152             uint32_t c = SkSwizzle_Color_to_PMColor(shader.fOrigColors[i]);
153             rec[i].fColor = Sk4f::FromBytes((const uint8_t*)&c) * scale;
154             if (i > 0) {
155                 SkASSERT(rec[i - 1].fPos <= rec[i].fPos);
156             }
157         }
158     } else {
159         // Our fColor values are premultiplied, so converting to SkPMColor is just a matter
160         // of converting the floats down to bytes.
161         unsigned alphaScale = ctx.fPaint->getAlpha() + (ctx.fPaint->getAlpha() >> 7);
162         for (int i = 0; i < count; ++i) {
163             SkPMColor pmc = SkPreMultiplyColor(shader.fOrigColors[i]);
164             pmc = SkAlphaMulQ(pmc, alphaScale);
165             rec[i].fColor = Sk4f::FromBytes((const uint8_t*)&pmc);
166             if (i > 0) {
167                 SkASSERT(rec[i - 1].fPos <= rec[i].fPos);
168             }
169         }
170     }
171 }
172
173 #define NO_CHECK_ITER               \
174     do {                            \
175     unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift; \
176     SkASSERT(fi <= 0xFF);           \
177     fx += dx;                       \
178     *dstC++ = cache[toggle + fi];   \
179     toggle = next_dither_toggle(toggle); \
180     } while (0)
181
182 namespace {
183
184 typedef void (*LinearShadeProc)(TileProc proc, SkGradFixed dx, SkGradFixed fx,
185                                 SkPMColor* dstC, const SkPMColor* cache,
186                                 int toggle, int count);
187
188 // Linear interpolation (lerp) is unnecessary if there are no sharp
189 // discontinuities in the gradient - which must be true if there are
190 // only 2 colors - but it's cheap.
191 void shadeSpan_linear_vertical_lerp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
192                                     SkPMColor* SK_RESTRICT dstC,
193                                     const SkPMColor* SK_RESTRICT cache,
194                                     int toggle, int count) {
195     // We're a vertical gradient, so no change in a span.
196     // If colors change sharply across the gradient, dithering is
197     // insufficient (it subsamples the color space) and we need to lerp.
198     unsigned fullIndex = proc(SkGradFixedToFixed(fx));
199     unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift;
200     unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1);
201
202     int index0 = fi + toggle;
203     int index1 = index0;
204     if (fi < SkGradientShaderBase::kCache32Count - 1) {
205         index1 += 1;
206     }
207     SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder);
208     index0 ^= SkGradientShaderBase::kDitherStride32;
209     index1 ^= SkGradientShaderBase::kDitherStride32;
210     SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder);
211     sk_memset32_dither(dstC, lerp, dlerp, count);
212 }
213
214 void shadeSpan_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
215                             SkPMColor* SK_RESTRICT dstC,
216                             const SkPMColor* SK_RESTRICT cache,
217                             int toggle, int count) {
218     SkClampRange range;
219     range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1);
220     range.validate(count);
221
222     if ((count = range.fCount0) > 0) {
223         sk_memset32_dither(dstC,
224             cache[toggle + range.fV0],
225             cache[next_dither_toggle(toggle) + range.fV0],
226             count);
227         dstC += count;
228     }
229     if ((count = range.fCount1) > 0) {
230         int unroll = count >> 3;
231         fx = range.fFx1;
232         for (int i = 0; i < unroll; i++) {
233             NO_CHECK_ITER;  NO_CHECK_ITER;
234             NO_CHECK_ITER;  NO_CHECK_ITER;
235             NO_CHECK_ITER;  NO_CHECK_ITER;
236             NO_CHECK_ITER;  NO_CHECK_ITER;
237         }
238         if ((count &= 7) > 0) {
239             do {
240                 NO_CHECK_ITER;
241             } while (--count != 0);
242         }
243     }
244     if ((count = range.fCount2) > 0) {
245         sk_memset32_dither(dstC,
246             cache[toggle + range.fV1],
247             cache[next_dither_toggle(toggle) + range.fV1],
248             count);
249     }
250 }
251
252 void shadeSpan_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx,
253                              SkPMColor* SK_RESTRICT dstC,
254                              const SkPMColor* SK_RESTRICT cache,
255                              int toggle, int count) {
256     do {
257         unsigned fi = mirror_8bits(SkGradFixedToFixed(fx) >> 8);
258         SkASSERT(fi <= 0xFF);
259         fx += dx;
260         *dstC++ = cache[toggle + fi];
261         toggle = next_dither_toggle(toggle);
262     } while (--count != 0);
263 }
264
265 void shadeSpan_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx,
266         SkPMColor* SK_RESTRICT dstC,
267         const SkPMColor* SK_RESTRICT cache,
268         int toggle, int count) {
269     do {
270         unsigned fi = repeat_8bits(SkGradFixedToFixed(fx) >> 8);
271         SkASSERT(fi <= 0xFF);
272         fx += dx;
273         *dstC++ = cache[toggle + fi];
274         toggle = next_dither_toggle(toggle);
275     } while (--count != 0);
276 }
277
278 }
279
280 void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
281                                                         int count) {
282     SkASSERT(count > 0);
283     const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&>(fShader);
284
285 // Only use the Sk4f impl when known to be fast.
286 #if defined(SKNX_IS_FAST)
287     if (SkShader::kClamp_TileMode == linearGradient.fTileMode &&
288         kLinear_MatrixClass == fDstToIndexClass)
289     {
290         this->shade4_clamp(x, y, dstC, count);
291         return;
292     }
293 #endif
294
295     SkPoint             srcPt;
296     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
297     TileProc            proc = linearGradient.fTileProc;
298     const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
299     int                 toggle = init_dither_toggle(x, y);
300
301     if (fDstToIndexClass != kPerspective_MatrixClass) {
302         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
303                              SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
304         SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX);
305
306         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
307             SkFixed dxStorage[1];
308             (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, nullptr);
309             // todo: do we need a real/high-precision value for dx here?
310             dx = SkFixedToGradFixed(dxStorage[0]);
311         } else {
312             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
313             dx = SkScalarToGradFixed(fDstToIndex.getScaleX());
314         }
315
316         LinearShadeProc shadeProc = shadeSpan_linear_repeat;
317         if (0 == dx) {
318             shadeProc = shadeSpan_linear_vertical_lerp;
319         } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) {
320             shadeProc = shadeSpan_linear_clamp;
321         } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) {
322             shadeProc = shadeSpan_linear_mirror;
323         } else {
324             SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode);
325         }
326         (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
327     } else {
328         SkScalar    dstX = SkIntToScalar(x);
329         SkScalar    dstY = SkIntToScalar(y);
330         do {
331             dstProc(fDstToIndex, dstX, dstY, &srcPt);
332             unsigned fi = proc(SkScalarToFixed(srcPt.fX));
333             SkASSERT(fi <= 0xFFFF);
334             *dstC++ = cache[toggle + (fi >> kCache32Shift)];
335             toggle = next_dither_toggle(toggle);
336             dstX += SK_Scalar1;
337         } while (--count != 0);
338     }
339 }
340
341 SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {
342     if (info) {
343         commonAsAGradient(info);
344         info->fPoint[0] = fStart;
345         info->fPoint[1] = fEnd;
346     }
347     return kLinear_GradientType;
348 }
349
350 static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
351                             int count) {
352     if (reinterpret_cast<uintptr_t>(dst) & 2) {
353         *dst++ = value;
354         count -= 1;
355         SkTSwap(value, other);
356     }
357
358     sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
359
360     if (count & 1) {
361         dst[count - 1] = value;
362     }
363 }
364
365 #define NO_CHECK_ITER_16                \
366     do {                                \
367     unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift;  \
368     SkASSERT(fi < SkGradientShaderBase::kCache16Count);       \
369     fx += dx;                           \
370     *dstC++ = cache[toggle + fi];       \
371     toggle = next_dither_toggle16(toggle);            \
372     } while (0)
373
374 namespace {
375
376 typedef void (*LinearShade16Proc)(TileProc proc, SkGradFixed dx, SkGradFixed fx,
377                                   uint16_t* dstC, const uint16_t* cache,
378                                   int toggle, int count);
379
380 void shadeSpan16_linear_vertical(TileProc proc, SkGradFixed dx, SkGradFixed fx,
381                                  uint16_t* SK_RESTRICT dstC,
382                                  const uint16_t* SK_RESTRICT cache,
383                                  int toggle, int count) {
384     // we're a vertical gradient, so no change in a span
385     unsigned fi = proc(SkGradFixedToFixed(fx)) >> SkGradientShaderBase::kCache16Shift;
386     SkASSERT(fi < SkGradientShaderBase::kCache16Count);
387     dither_memset16(dstC, cache[toggle + fi],
388         cache[next_dither_toggle16(toggle) + fi], count);
389 }
390
391 void shadeSpan16_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
392                               uint16_t* SK_RESTRICT dstC,
393                               const uint16_t* SK_RESTRICT cache,
394                               int toggle, int count) {
395     SkClampRange range;
396     range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1);
397     range.validate(count);
398
399     if ((count = range.fCount0) > 0) {
400         dither_memset16(dstC,
401             cache[toggle + range.fV0],
402             cache[next_dither_toggle16(toggle) + range.fV0],
403             count);
404         dstC += count;
405     }
406     if ((count = range.fCount1) > 0) {
407         int unroll = count >> 3;
408         fx = range.fFx1;
409         for (int i = 0; i < unroll; i++) {
410             NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
411             NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
412             NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
413             NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
414         }
415         if ((count &= 7) > 0) {
416             do {
417                 NO_CHECK_ITER_16;
418             } while (--count != 0);
419         }
420     }
421     if ((count = range.fCount2) > 0) {
422         dither_memset16(dstC,
423             cache[toggle + range.fV1],
424             cache[next_dither_toggle16(toggle) + range.fV1],
425             count);
426     }
427 }
428
429 void shadeSpan16_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx,
430                                uint16_t* SK_RESTRICT dstC,
431                                const uint16_t* SK_RESTRICT cache,
432                                int toggle, int count) {
433     do {
434         unsigned fi = mirror_bits(SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift,
435                                         SkGradientShaderBase::kCache16Bits);
436         SkASSERT(fi < SkGradientShaderBase::kCache16Count);
437         fx += dx;
438         *dstC++ = cache[toggle + fi];
439         toggle = next_dither_toggle16(toggle);
440     } while (--count != 0);
441 }
442
443 void shadeSpan16_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx,
444                                uint16_t* SK_RESTRICT dstC,
445                                const uint16_t* SK_RESTRICT cache,
446                                int toggle, int count) {
447     do {
448         unsigned fi = repeat_bits(SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift,
449                                   SkGradientShaderBase::kCache16Bits);
450         SkASSERT(fi < SkGradientShaderBase::kCache16Count);
451         fx += dx;
452         *dstC++ = cache[toggle + fi];
453         toggle = next_dither_toggle16(toggle);
454     } while (--count != 0);
455 }
456 }
457
458 static bool fixed_nearly_zero(SkFixed x) {
459     return SkAbs32(x) < (SK_Fixed1 >> 12);
460 }
461
462 void SkLinearGradient::LinearGradientContext::shadeSpan16(int x, int y,
463                                                           uint16_t* SK_RESTRICT dstC, int count) {
464     SkASSERT(count > 0);
465
466     const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&>(fShader);
467
468     SkPoint             srcPt;
469     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
470     TileProc            proc = linearGradient.fTileProc;
471     const uint16_t* SK_RESTRICT cache = fCache->getCache16();
472     int                 toggle = init_dither_toggle16(x, y);
473
474     if (fDstToIndexClass != kPerspective_MatrixClass) {
475         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
476                              SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
477         SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX);
478
479         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
480             SkFixed dxStorage[1];
481             (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, nullptr);
482             // todo: do we need a real/high-precision value for dx here?
483             dx = SkFixedToGradFixed(dxStorage[0]);
484         } else {
485             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
486             dx = SkScalarToGradFixed(fDstToIndex.getScaleX());
487         }
488
489         LinearShade16Proc shadeProc = shadeSpan16_linear_repeat;
490         if (fixed_nearly_zero(SkGradFixedToFixed(dx))) {
491             shadeProc = shadeSpan16_linear_vertical;
492         } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) {
493             shadeProc = shadeSpan16_linear_clamp;
494         } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) {
495             shadeProc = shadeSpan16_linear_mirror;
496         } else {
497             SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode);
498         }
499         (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
500     } else {
501         SkScalar    dstX = SkIntToScalar(x);
502         SkScalar    dstY = SkIntToScalar(y);
503         do {
504             dstProc(fDstToIndex, dstX, dstY, &srcPt);
505             unsigned fi = proc(SkScalarToFixed(srcPt.fX));
506             SkASSERT(fi <= 0xFFFF);
507
508             int index = fi >> kCache16Shift;
509             *dstC++ = cache[toggle + index];
510             toggle = next_dither_toggle16(toggle);
511
512             dstX += SK_Scalar1;
513         } while (--count != 0);
514     }
515 }
516
517 #if SK_SUPPORT_GPU
518
519 #include "gl/builders/GrGLProgramBuilder.h"
520 #include "SkGr.h"
521
522 /////////////////////////////////////////////////////////////////////
523
524 class GrGLLinearGradient : public GrGLGradientEffect {
525 public:
526
527     GrGLLinearGradient(const GrProcessor&) {}
528
529     virtual ~GrGLLinearGradient() { }
530
531     virtual void emitCode(EmitArgs&) override;
532
533     static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
534         b->add32(GenBaseGradientKey(processor));
535     }
536
537 private:
538
539     typedef GrGLGradientEffect INHERITED;
540 };
541
542 /////////////////////////////////////////////////////////////////////
543
544 class GrLinearGradient : public GrGradientEffect {
545 public:
546
547     static GrFragmentProcessor* Create(GrContext* ctx,
548                                        const SkLinearGradient& shader,
549                                        const SkMatrix& matrix,
550                                        SkShader::TileMode tm) {
551         return new GrLinearGradient(ctx, shader, matrix, tm);
552     }
553
554     virtual ~GrLinearGradient() { }
555
556     const char* name() const override { return "Linear Gradient"; }
557
558 private:
559     GrLinearGradient(GrContext* ctx,
560                      const SkLinearGradient& shader,
561                      const SkMatrix& matrix,
562                      SkShader::TileMode tm)
563         : INHERITED(ctx, shader, matrix, tm) {
564         this->initClassID<GrLinearGradient>();
565     }
566
567     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
568         return new GrGLLinearGradient(*this);
569     }
570
571     virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
572                                        GrProcessorKeyBuilder* b) const override {
573         GrGLLinearGradient::GenKey(*this, caps, b);
574     }
575
576     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
577
578     typedef GrGradientEffect INHERITED;
579 };
580
581 /////////////////////////////////////////////////////////////////////
582
583 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrLinearGradient);
584
585 const GrFragmentProcessor* GrLinearGradient::TestCreate(GrProcessorTestData* d) {
586     SkPoint points[] = {{d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()},
587                         {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}};
588
589     SkColor colors[kMaxRandomGradientColors];
590     SkScalar stopsArray[kMaxRandomGradientColors];
591     SkScalar* stops = stopsArray;
592     SkShader::TileMode tm;
593     int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
594     SkAutoTUnref<SkShader> shader(SkGradientShader::CreateLinear(points,
595                                                                  colors, stops, colorCount,
596                                                                  tm));
597     const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
598         GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
599     GrAlwaysAssert(fp);
600     return fp;
601 }
602
603 /////////////////////////////////////////////////////////////////////
604
605 void GrGLLinearGradient::emitCode(EmitArgs& args) {
606     const GrLinearGradient& ge = args.fFp.cast<GrLinearGradient>();
607     this->emitUniforms(args.fBuilder, ge);
608     SkString t = args.fFragBuilder->ensureFSCoords2D(args.fCoords, 0);
609     t.append(".x");
610     this->emitColor(args.fBuilder,
611                     args.fFragBuilder,
612                     args.fGLSLCaps,
613                     ge, t.c_str(),
614                     args.fOutputColor,
615                     args.fInputColor,
616                     args.fSamplers);
617 }
618
619 /////////////////////////////////////////////////////////////////////
620
621 const GrFragmentProcessor* SkLinearGradient::asFragmentProcessor(
622                                                  GrContext* context,
623                                                  const SkMatrix& viewm,
624                                                  const SkMatrix* localMatrix,
625                                                  SkFilterQuality) const {
626     SkASSERT(context);
627
628     SkMatrix matrix;
629     if (!this->getLocalMatrix().invert(&matrix)) {
630         return nullptr;
631     }
632     if (localMatrix) {
633         SkMatrix inv;
634         if (!localMatrix->invert(&inv)) {
635             return nullptr;
636         }
637         matrix.postConcat(inv);
638     }
639     matrix.postConcat(fPtsToUnit);
640
641     SkAutoTUnref<const GrFragmentProcessor> inner(
642         GrLinearGradient::Create(context, *this, matrix, fTileMode));
643     return GrFragmentProcessor::MulOutputByInputAlpha(inner);
644 }
645
646
647 #endif
648
649 #ifndef SK_IGNORE_TO_STRING
650 void SkLinearGradient::toString(SkString* str) const {
651     str->append("SkLinearGradient (");
652
653     str->appendf("start: (%f, %f)", fStart.fX, fStart.fY);
654     str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY);
655
656     this->INHERITED::toString(str);
657
658     str->append(")");
659 }
660 #endif
661
662 ///////////////////////////////////////////////////////////////////////////////////////////////////
663
664 #include "SkNx.h"
665
666 static const SkLinearGradient::LinearGradientContext::Rec*
667 find_forward(const SkLinearGradient::LinearGradientContext::Rec rec[], float tiledX) {
668     SkASSERT(tiledX >= 0 && tiledX <= 1);
669
670     SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1);
671     SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1);
672     SkASSERT(rec[0].fPos <= rec[1].fPos);
673     rec += 1;
674     while (rec->fPos < tiledX) {
675         SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1);
676         SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1);
677         SkASSERT(rec[0].fPos <= rec[1].fPos);
678         rec += 1;
679     }
680     return rec - 1;
681 }
682
683 static const SkLinearGradient::LinearGradientContext::Rec*
684 find_backward(const SkLinearGradient::LinearGradientContext::Rec rec[], float tiledX) {
685     SkASSERT(tiledX >= 0 && tiledX <= 1);
686
687     SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1);
688     SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1);
689     SkASSERT(rec[0].fPos <= rec[1].fPos);
690     while (tiledX < rec->fPos) {
691         rec -= 1;
692         SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1);
693         SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1);
694         SkASSERT(rec[0].fPos <= rec[1].fPos);
695     }
696     return rec;
697 }
698
699 template <bool apply_alpha> SkPMColor trunc_from_255(const Sk4f& x) {
700     SkPMColor c;
701     x.toBytes((uint8_t*)&c);
702     if (apply_alpha) {
703         c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c),
704                               SkGetPackedG32(c), SkGetPackedB32(c));
705     }
706     return c;
707 }
708
709 template <bool apply_alpha> void fill(SkPMColor dst[], int count,
710                                       const Sk4f& c4, const Sk4f& c4other) {
711     sk_memset32_dither(dst, trunc_from_255<apply_alpha>(c4),
712                        trunc_from_255<apply_alpha>(c4other), count);
713 }
714
715 template <bool apply_alpha> void fill(SkPMColor dst[], int count, const Sk4f& c4) {
716     // Assumes that c4 does not need to be dithered.
717     sk_memset32(dst, trunc_from_255<apply_alpha>(c4), count);
718 }
719
720 /*
721  *  TODOs
722  *
723  *  - tilemodes
724  *  - interp before or after premul
725  *  - perspective
726  *  - optimizations
727  *      - use fixed (32bit or 16bit) instead of floats?
728  */
729
730 static Sk4f lerp_color(float fx, const SkLinearGradient::LinearGradientContext::Rec* rec) {
731     SkASSERT(fx >= rec[0].fPos);
732     SkASSERT(fx <= rec[1].fPos);
733
734     const float p0 = rec[0].fPos;
735     const Sk4f c0 = rec[0].fColor;
736     const Sk4f c1 = rec[1].fColor;
737     const Sk4f diffc = c1 - c0;
738     const float scale = rec[1].fPosScale;
739     const float t = (fx - p0) * scale;
740     return c0 + Sk4f(t) * diffc;
741 }
742
743 template <bool apply_alpha> void ramp(SkPMColor dstC[], int n, const Sk4f& c, const Sk4f& dc,
744                                       const Sk4f& dither0, const Sk4f& dither1) {
745     Sk4f dc2 = dc + dc;
746     Sk4f dc4 = dc2 + dc2;
747     Sk4f cd0 = c + dither0;
748     Sk4f cd1 = c + dc + dither1;
749     Sk4f cd2 = cd0 + dc2;
750     Sk4f cd3 = cd1 + dc2;
751     while (n >= 4) {
752         if (!apply_alpha) {
753             Sk4f::ToBytes((uint8_t*)dstC, cd0, cd1, cd2, cd3);
754             dstC += 4;
755         } else {
756             *dstC++ = trunc_from_255<apply_alpha>(cd0);
757             *dstC++ = trunc_from_255<apply_alpha>(cd1);
758             *dstC++ = trunc_from_255<apply_alpha>(cd2);
759             *dstC++ = trunc_from_255<apply_alpha>(cd3);
760         }
761         cd0 = cd0 + dc4;
762         cd1 = cd1 + dc4;
763         cd2 = cd2 + dc4;
764         cd3 = cd3 + dc4;
765         n -= 4;
766     }
767     if (n & 2) {
768         *dstC++ = trunc_from_255<apply_alpha>(cd0);
769         *dstC++ = trunc_from_255<apply_alpha>(cd1);
770         cd0 = cd0 + dc2;
771     }
772     if (n & 1) {
773         *dstC++ = trunc_from_255<apply_alpha>(cd0);
774     }
775 }
776
777 template <bool apply_alpha, bool dx_is_pos>
778 void SkLinearGradient::LinearGradientContext::shade4_dx_clamp(SkPMColor dstC[], int count,
779                                                               float fx, float dx, float invDx,
780                                                               const float dither[2]) {
781     Sk4f dither0(dither[0]);
782     Sk4f dither1(dither[1]);
783     const Rec* rec = fRecs.begin();
784
785     const Sk4f dx4 = Sk4f(dx);
786     SkDEBUGCODE(SkPMColor* endDstC = dstC + count;)
787
788     if (dx_is_pos) {
789         if (fx < 0) {
790             int n = SkTMin(SkFloatToIntFloor(-fx * invDx) + 1, count);
791             fill<apply_alpha>(dstC, n, rec[0].fColor);
792             count -= n;
793             dstC += n;
794             fx += n * dx;
795             SkASSERT(0 == count || fx >= 0);
796             if (n & 1) {
797                 SkTSwap(dither0, dither1);
798             }
799         }
800     } else { // dx < 0
801         if (fx > 1) {
802             int n = SkTMin(SkFloatToIntFloor((1 - fx) * invDx) + 1, count);
803             fill<apply_alpha>(dstC, n, rec[fRecs.count() - 1].fColor);
804             count -= n;
805             dstC += n;
806             fx += n * dx;
807             SkASSERT(0 == count || fx <= 1);
808             if (n & 1) {
809                 SkTSwap(dither0, dither1);
810             }
811         }
812     }
813     SkASSERT(count >= 0);
814
815     const Rec* r;
816     if (dx_is_pos) {
817         r = fRecs.begin();                      // start at the beginning
818     } else {
819         r = fRecs.begin() + fRecs.count() - 2;  // start at the end
820     }
821
822     while (count > 0) {
823         if (dx_is_pos) {
824             if (fx >= 1) {
825                 fill<apply_alpha>(dstC, count, rec[fRecs.count() - 1].fColor);
826                 return;
827             }
828         } else {    // dx < 0
829             if (fx <= 0) {
830                 fill<apply_alpha>(dstC, count, rec[0].fColor);
831                 return;
832             }
833         }
834
835         if (dx_is_pos) {
836             r = find_forward(r, fx);
837         } else {
838             r = find_backward(r, fx);
839         }
840         SkASSERT(r >= fRecs.begin() && r < fRecs.begin() + fRecs.count() - 1);
841
842         const float p0 = r[0].fPos;
843         const Sk4f c0 = r[0].fColor;
844         const float p1 = r[1].fPos;
845         const Sk4f diffc = Sk4f(r[1].fColor) - c0;
846         const float scale = r[1].fPosScale;
847         const float t = (fx - p0) * scale;
848         const Sk4f c = c0 + Sk4f(t) * diffc;
849         const Sk4f dc = diffc * dx4 * Sk4f(scale);
850
851         int n;
852         if (dx_is_pos) {
853             n = SkTMin((int)((p1 - fx) * invDx) + 1, count);
854         } else {
855             n = SkTMin((int)((p0 - fx) * invDx) + 1, count);
856         }
857
858         fx += n * dx;
859         count -= n;
860         SkASSERT(count >= 0);
861         if (dx_is_pos) {
862             SkASSERT(0 == count || fx >= p1);
863         } else {
864             SkASSERT(0 == count || fx <= p0);
865         }
866
867         ramp<apply_alpha>(dstC, n, c, dc, dither0, dither1);
868         dstC += n;
869         SkASSERT(dstC <= endDstC);
870
871         if (n & 1) {
872             SkTSwap(dither0, dither1);
873         }
874     }
875 }
876
877 void SkLinearGradient::LinearGradientContext::shade4_clamp(int x, int y, SkPMColor dstC[],
878                                                            int count) {
879     SkASSERT(count > 0);
880     SkASSERT(kLinear_MatrixClass == fDstToIndexClass);
881
882     SkPoint srcPt;
883     fDstToIndexProc(fDstToIndex, x + SK_ScalarHalf, y + SK_ScalarHalf, &srcPt);
884     float fx = srcPt.x();
885     const float dx = fDstToIndex.getScaleX();
886
887     // Default our dither bias values to 1/2, (rounding), which is no dithering
888     float dither0 = 0.5f;
889     float dither1 = 0.5f;
890     if (fDither) {
891         const float ditherCell[] = {
892             1/8.0f,   5/8.0f,
893             7/8.0f,   3/8.0f,
894         };
895         const int rowIndex = (y & 1) << 1;
896         dither0 = ditherCell[rowIndex];
897         dither1 = ditherCell[rowIndex + 1];
898         if (x & 1) {
899             SkTSwap(dither0, dither1);
900         }
901     }
902     const float dither[2] = { dither0, dither1 };
903     const float invDx = 1 / dx;
904
905     if (SkScalarNearlyZero(dx * count)) { // gradient is vertical
906         const float pinFx = SkTPin(fx, 0.0f, 1.0f);
907         Sk4f c = lerp_color(pinFx, find_forward(fRecs.begin(), pinFx));
908         if (fApplyAlphaAfterInterp) {
909             fill<true>(dstC, count, c + dither0, c + dither1);
910         } else {
911             fill<false>(dstC, count, c + dither0, c + dither1);
912         }
913         return;
914     }
915
916     if (dx > 0) {
917         if (fApplyAlphaAfterInterp) {
918             this->shade4_dx_clamp<true, true>(dstC, count, fx, dx, invDx, dither);
919         } else {
920             this->shade4_dx_clamp<false, true>(dstC, count, fx, dx, invDx, dither);
921         }
922     } else {
923         if (fApplyAlphaAfterInterp) {
924             this->shade4_dx_clamp<true, false>(dstC, count, fx, dx, invDx, dither);
925         } else {
926             this->shade4_dx_clamp<false, false>(dstC, count, fx, dx, invDx, dither);
927         }
928     }
929 }
930