• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
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 <algorithm>
9 #include "Sk4fLinearGradient.h"
10 #include "SkColorSpace_XYZ.h"
11 #include "SkGradientShaderPriv.h"
12 #include "SkHalf.h"
13 #include "SkLinearGradient.h"
14 #include "SkMallocPixelRef.h"
15 #include "SkRadialGradient.h"
16 #include "SkSweepGradient.h"
17 #include "SkTwoPointConicalGradient.h"
18 #include "../../jumper/SkJumper.h"
19 
20 
21 enum GradientSerializationFlags {
22     // Bits 29:31 used for various boolean flags
23     kHasPosition_GSF    = 0x80000000,
24     kHasLocalMatrix_GSF = 0x40000000,
25     kHasColorSpace_GSF  = 0x20000000,
26 
27     // Bits 12:28 unused
28 
29     // Bits 8:11 for fTileMode
30     kTileModeShift_GSF  = 8,
31     kTileModeMask_GSF   = 0xF,
32 
33     // Bits 0:7 for fGradFlags (note that kForce4fContext_PrivateFlag is 0x80)
34     kGradFlagsShift_GSF = 0,
35     kGradFlagsMask_GSF  = 0xFF,
36 };
37 
flatten(SkWriteBuffer & buffer) const38 void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
39     uint32_t flags = 0;
40     if (fPos) {
41         flags |= kHasPosition_GSF;
42     }
43     if (fLocalMatrix) {
44         flags |= kHasLocalMatrix_GSF;
45     }
46     sk_sp<SkData> colorSpaceData = fColorSpace ? fColorSpace->serialize() : nullptr;
47     if (colorSpaceData) {
48         flags |= kHasColorSpace_GSF;
49     }
50     SkASSERT(static_cast<uint32_t>(fTileMode) <= kTileModeMask_GSF);
51     flags |= (fTileMode << kTileModeShift_GSF);
52     SkASSERT(fGradFlags <= kGradFlagsMask_GSF);
53     flags |= (fGradFlags << kGradFlagsShift_GSF);
54 
55     buffer.writeUInt(flags);
56 
57     buffer.writeColor4fArray(fColors, fCount);
58     if (colorSpaceData) {
59         buffer.writeDataAsByteArray(colorSpaceData.get());
60     }
61     if (fPos) {
62         buffer.writeScalarArray(fPos, fCount);
63     }
64     if (fLocalMatrix) {
65         buffer.writeMatrix(*fLocalMatrix);
66     }
67 }
68 
unflatten(SkReadBuffer & buffer)69 bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
70     // New gradient format. Includes floating point color, color space, densely packed flags
71     uint32_t flags = buffer.readUInt();
72 
73     fTileMode = (SkShader::TileMode)((flags >> kTileModeShift_GSF) & kTileModeMask_GSF);
74     fGradFlags = (flags >> kGradFlagsShift_GSF) & kGradFlagsMask_GSF;
75 
76     fCount = buffer.getArrayCount();
77     if (fCount > kStorageCount) {
78         size_t allocSize = (sizeof(SkColor4f) + sizeof(SkScalar)) * fCount;
79         fDynamicStorage.reset(allocSize);
80         fColors = (SkColor4f*)fDynamicStorage.get();
81         fPos = (SkScalar*)(fColors + fCount);
82     } else {
83         fColors = fColorStorage;
84         fPos = fPosStorage;
85     }
86     if (!buffer.readColor4fArray(mutableColors(), fCount)) {
87         return false;
88     }
89     if (SkToBool(flags & kHasColorSpace_GSF)) {
90         sk_sp<SkData> data = buffer.readByteArrayAsData();
91         fColorSpace = SkColorSpace::Deserialize(data->data(), data->size());
92     } else {
93         fColorSpace = nullptr;
94     }
95     if (SkToBool(flags & kHasPosition_GSF)) {
96         if (!buffer.readScalarArray(mutablePos(), fCount)) {
97             return false;
98         }
99     } else {
100         fPos = nullptr;
101     }
102     if (SkToBool(flags & kHasLocalMatrix_GSF)) {
103         fLocalMatrix = &fLocalMatrixStorage;
104         buffer.readMatrix(&fLocalMatrixStorage);
105     } else {
106         fLocalMatrix = nullptr;
107     }
108     return buffer.isValid();
109 }
110 
111 ////////////////////////////////////////////////////////////////////////////////////////////
112 
SkGradientShaderBase(const Descriptor & desc,const SkMatrix & ptsToUnit)113 SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit)
114     : INHERITED(desc.fLocalMatrix)
115     , fPtsToUnit(ptsToUnit)
116 {
117     fPtsToUnit.getType();  // Precache so reads are threadsafe.
118     SkASSERT(desc.fCount > 1);
119 
120     fGradFlags = static_cast<uint8_t>(desc.fGradFlags);
121 
122     SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount);
123     SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
124     fTileMode = desc.fTileMode;
125     fTileProc = gTileProcs[desc.fTileMode];
126 
127     /*  Note: we let the caller skip the first and/or last position.
128         i.e. pos[0] = 0.3, pos[1] = 0.7
129         In these cases, we insert dummy entries to ensure that the final data
130         will be bracketed by [0, 1].
131         i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
132 
133         Thus colorCount (the caller's value, and fColorCount (our value) may
134         differ by up to 2. In the above example:
135             colorCount = 2
136             fColorCount = 4
137      */
138     fColorCount = desc.fCount;
139     // check if we need to add in dummy start and/or end position/colors
140     bool dummyFirst = false;
141     bool dummyLast = false;
142     if (desc.fPos) {
143         dummyFirst = desc.fPos[0] != 0;
144         dummyLast = desc.fPos[desc.fCount - 1] != SK_Scalar1;
145         fColorCount += dummyFirst + dummyLast;
146     }
147 
148     if (fColorCount > kColorStorageCount) {
149         size_t size = sizeof(SkColor) + sizeof(SkColor4f) + sizeof(Rec);
150         if (desc.fPos) {
151             size += sizeof(SkScalar);
152         }
153         fOrigColors = reinterpret_cast<SkColor*>(sk_malloc_throw(size * fColorCount));
154     }
155     else {
156         fOrigColors = fStorage;
157     }
158 
159     fOrigColors4f = (SkColor4f*)(fOrigColors + fColorCount);
160 
161     // Now copy over the colors, adding the dummies as needed
162     SkColor4f* origColors = fOrigColors4f;
163     if (dummyFirst) {
164         *origColors++ = desc.fColors[0];
165     }
166     memcpy(origColors, desc.fColors, desc.fCount * sizeof(SkColor4f));
167     if (dummyLast) {
168         origColors += desc.fCount;
169         *origColors = desc.fColors[desc.fCount - 1];
170     }
171 
172     // Convert our SkColor4f colors to SkColor as well. Note that this is incorrect if the
173     // source colors are not in sRGB gamut. We would need to do a gamut transformation, but
174     // SkColorSpaceXform can't do that (yet). GrColorSpaceXform can, but we may not have GPU
175     // support compiled in here. For the common case (sRGB colors), this does the right thing.
176     for (int i = 0; i < fColorCount; ++i) {
177         fOrigColors[i] = fOrigColors4f[i].toSkColor();
178     }
179 
180     if (!desc.fColorSpace) {
181         // This happens if we were constructed from SkColors, so our colors are really sRGB
182         fColorSpace = SkColorSpace::MakeSRGBLinear();
183     } else {
184         // The color space refers to the float colors, so it must be linear gamma
185         SkASSERT(desc.fColorSpace->gammaIsLinear());
186         fColorSpace = desc.fColorSpace;
187     }
188 
189     if (desc.fPos && fColorCount) {
190         fOrigPos = (SkScalar*)(fOrigColors4f + fColorCount);
191         fRecs = (Rec*)(fOrigPos + fColorCount);
192     } else {
193         fOrigPos = nullptr;
194         fRecs = (Rec*)(fOrigColors4f + fColorCount);
195     }
196 
197     if (fColorCount > 2) {
198         Rec* recs = fRecs;
199         recs->fPos = 0;
200         //  recs->fScale = 0; // unused;
201         recs += 1;
202         if (desc.fPos) {
203             SkScalar* origPosPtr = fOrigPos;
204             *origPosPtr++ = 0;
205 
206             /*  We need to convert the user's array of relative positions into
207                 fixed-point positions and scale factors. We need these results
208                 to be strictly monotonic (no two values equal or out of order).
209                 Hence this complex loop that just jams a zero for the scale
210                 value if it sees a segment out of order, and it assures that
211                 we start at 0 and end at 1.0
212             */
213             SkScalar prev = 0;
214             int startIndex = dummyFirst ? 0 : 1;
215             int count = desc.fCount + dummyLast;
216             for (int i = startIndex; i < count; i++) {
217                 // force the last value to be 1.0
218                 SkScalar curr;
219                 if (i == desc.fCount) {  // we're really at the dummyLast
220                     curr = 1;
221                 } else {
222                     curr = SkScalarPin(desc.fPos[i], 0, 1);
223                 }
224                 *origPosPtr++ = curr;
225 
226                 recs->fPos = SkScalarToFixed(curr);
227                 SkFixed diff = SkScalarToFixed(curr - prev);
228                 if (diff > 0) {
229                     recs->fScale = (1 << 24) / diff;
230                 } else {
231                     recs->fScale = 0; // ignore this segment
232                 }
233                 // get ready for the next value
234                 prev = curr;
235                 recs += 1;
236             }
237         } else {    // assume even distribution
238             fOrigPos = nullptr;
239 
240             SkFixed dp = SK_Fixed1 / (desc.fCount - 1);
241             SkFixed p = dp;
242             SkFixed scale = (desc.fCount - 1) << 8;  // (1 << 24) / dp
243             for (int i = 1; i < desc.fCount - 1; i++) {
244                 recs->fPos   = p;
245                 recs->fScale = scale;
246                 recs += 1;
247                 p += dp;
248             }
249             recs->fPos = SK_Fixed1;
250             recs->fScale = scale;
251         }
252     } else if (desc.fPos) {
253         SkASSERT(2 == fColorCount);
254         fOrigPos[0] = SkScalarPin(desc.fPos[0], 0, 1);
255         fOrigPos[1] = SkScalarPin(desc.fPos[1], fOrigPos[0], 1);
256         if (0 == fOrigPos[0] && 1 == fOrigPos[1]) {
257             fOrigPos = nullptr;
258         }
259     }
260     this->initCommon();
261 }
262 
~SkGradientShaderBase()263 SkGradientShaderBase::~SkGradientShaderBase() {
264     if (fOrigColors != fStorage) {
265         sk_free(fOrigColors);
266     }
267 }
268 
initCommon()269 void SkGradientShaderBase::initCommon() {
270     unsigned colorAlpha = 0xFF;
271     for (int i = 0; i < fColorCount; i++) {
272         colorAlpha &= SkColorGetA(fOrigColors[i]);
273     }
274     fColorsAreOpaque = colorAlpha == 0xFF;
275 }
276 
flatten(SkWriteBuffer & buffer) const277 void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
278     Descriptor desc;
279     desc.fColors = fOrigColors4f;
280     desc.fColorSpace = fColorSpace;
281     desc.fPos = fOrigPos;
282     desc.fCount = fColorCount;
283     desc.fTileMode = fTileMode;
284     desc.fGradFlags = fGradFlags;
285 
286     const SkMatrix& m = this->getLocalMatrix();
287     desc.fLocalMatrix = m.isIdentity() ? nullptr : &m;
288     desc.flatten(buffer);
289 }
290 
FlipGradientColors(SkColor * colorDst,Rec * recDst,SkColor * colorSrc,Rec * recSrc,int count)291 void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst,
292                                               SkColor* colorSrc, Rec* recSrc,
293                                               int count) {
294     SkAutoSTArray<8, SkColor> colorsTemp(count);
295     for (int i = 0; i < count; ++i) {
296         int offset = count - i - 1;
297         colorsTemp[i] = colorSrc[offset];
298     }
299     if (count > 2) {
300         SkAutoSTArray<8, Rec> recsTemp(count);
301         for (int i = 0; i < count; ++i) {
302             int offset = count - i - 1;
303             recsTemp[i].fPos = SK_Fixed1 - recSrc[offset].fPos;
304             recsTemp[i].fScale = recSrc[offset].fScale;
305         }
306         memcpy(recDst, recsTemp.get(), count * sizeof(Rec));
307     }
308     memcpy(colorDst, colorsTemp.get(), count * sizeof(SkColor));
309 }
310 
add_stop_color(SkJumper_GradientCtx * ctx,size_t stop,SkPM4f Fs,SkPM4f Bs)311 static void add_stop_color(SkJumper_GradientCtx* ctx, size_t stop, SkPM4f Fs, SkPM4f Bs) {
312     (ctx->fs[0])[stop] = Fs.r();
313     (ctx->fs[1])[stop] = Fs.g();
314     (ctx->fs[2])[stop] = Fs.b();
315     (ctx->fs[3])[stop] = Fs.a();
316     (ctx->bs[0])[stop] = Bs.r();
317     (ctx->bs[1])[stop] = Bs.g();
318     (ctx->bs[2])[stop] = Bs.b();
319     (ctx->bs[3])[stop] = Bs.a();
320 }
321 
add_const_color(SkJumper_GradientCtx * ctx,size_t stop,SkPM4f color)322 static void add_const_color(SkJumper_GradientCtx* ctx, size_t stop, SkPM4f color) {
323     add_stop_color(ctx, stop, SkPM4f::FromPremulRGBA(0,0,0,0), color);
324 }
325 
326 // Calculate a factor F and a bias B so that color = F*t + B when t is in range of
327 // the stop. Assume that the distance between stops is 1/gapCount.
init_stop_evenly(SkJumper_GradientCtx * ctx,float gapCount,size_t stop,SkPM4f c_l,SkPM4f c_r)328 static void init_stop_evenly(
329     SkJumper_GradientCtx* ctx, float gapCount, size_t stop, SkPM4f c_l, SkPM4f c_r) {
330     // Clankium's GCC 4.9 targeting ARMv7 is barfing when we use Sk4f math here, so go scalar...
331     SkPM4f Fs = {{
332         (c_r.r() - c_l.r()) * gapCount,
333         (c_r.g() - c_l.g()) * gapCount,
334         (c_r.b() - c_l.b()) * gapCount,
335         (c_r.a() - c_l.a()) * gapCount,
336     }};
337     SkPM4f Bs = {{
338         c_l.r() - Fs.r()*(stop/gapCount),
339         c_l.g() - Fs.g()*(stop/gapCount),
340         c_l.b() - Fs.b()*(stop/gapCount),
341         c_l.a() - Fs.a()*(stop/gapCount),
342     }};
343     add_stop_color(ctx, stop, Fs, Bs);
344 }
345 
346 // For each stop we calculate a bias B and a scale factor F, such that
347 // for any t between stops n and n+1, the color we want is B[n] + F[n]*t.
init_stop_pos(SkJumper_GradientCtx * ctx,size_t stop,float t_l,float t_r,SkPM4f c_l,SkPM4f c_r)348 static void init_stop_pos(
349     SkJumper_GradientCtx* ctx, size_t stop, float t_l, float t_r, SkPM4f c_l, SkPM4f c_r) {
350     // See note about Clankium's old compiler in init_stop_evenly().
351     SkPM4f Fs = {{
352         (c_r.r() - c_l.r()) / (t_r - t_l),
353         (c_r.g() - c_l.g()) / (t_r - t_l),
354         (c_r.b() - c_l.b()) / (t_r - t_l),
355         (c_r.a() - c_l.a()) / (t_r - t_l),
356     }};
357     SkPM4f Bs = {{
358         c_l.r() - Fs.r()*t_l,
359         c_l.g() - Fs.g()*t_l,
360         c_l.b() - Fs.b()*t_l,
361         c_l.a() - Fs.a()*t_l,
362     }};
363     ctx->ts[stop] = t_l;
364     add_stop_color(ctx, stop, Fs, Bs);
365 }
366 
onAppendStages(SkRasterPipeline * p,SkColorSpace * dstCS,SkArenaAlloc * alloc,const SkMatrix & ctm,const SkPaint & paint,const SkMatrix * localM) const367 bool SkGradientShaderBase::onAppendStages(SkRasterPipeline* p,
368                                           SkColorSpace* dstCS,
369                                           SkArenaAlloc* alloc,
370                                           const SkMatrix& ctm,
371                                           const SkPaint& paint,
372                                           const SkMatrix* localM) const {
373     SkMatrix matrix;
374     if (!this->computeTotalInverse(ctm, localM, &matrix)) {
375         return false;
376     }
377 
378     SkRasterPipeline_<256> tPipeline;
379     SkRasterPipeline_<256> postPipeline;
380     if (!this->adjustMatrixAndAppendStages(alloc, &matrix, &tPipeline, &postPipeline)) {
381         return false;
382     }
383 
384     p->append(SkRasterPipeline::seed_shader);
385     p->append_matrix(alloc, matrix);
386     p->extend(tPipeline);
387 
388     switch(fTileMode) {
389         case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x_1); break;
390         case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x_1); break;
391         case kClamp_TileMode:
392             if (!fOrigPos) {
393                 // We clamp only when the stops are evenly spaced.
394                 // If not, there may be hard stops, and clamping ruins hard stops at 0 and/or 1.
395                 // In that case, we must make sure we're using the general "gradient" stage,
396                 // which is the only stage that will correctly handle unclamped t.
397                 p->append(SkRasterPipeline::clamp_x_1);
398             }
399     }
400 
401     const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag;
402     auto prepareColor = [premulGrad, dstCS, this](int i) {
403         SkColor4f c = this->getXformedColor(i, dstCS);
404         return premulGrad ? c.premul()
405                           : SkPM4f::From4f(Sk4f::Load(&c));
406     };
407 
408     // The two-stop case with stops at 0 and 1.
409     if (fColorCount == 2 && fOrigPos == nullptr) {
410         const SkPM4f c_l = prepareColor(0),
411             c_r = prepareColor(1);
412 
413         // See F and B below.
414         auto* f_and_b = alloc->makeArrayDefault<SkPM4f>(2);
415         f_and_b[0] = SkPM4f::From4f(c_r.to4f() - c_l.to4f());
416         f_and_b[1] = c_l;
417 
418         p->append(SkRasterPipeline::evenly_spaced_2_stop_gradient, f_and_b);
419     } else {
420         auto* ctx = alloc->make<SkJumper_GradientCtx>();
421 
422         // Note: In order to handle clamps in search, the search assumes a stop conceptully placed
423         // at -inf. Therefore, the max number of stops is fColorCount+1.
424         for (int i = 0; i < 4; i++) {
425             // Allocate at least at for the AVX2 gather from a YMM register.
426             ctx->fs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
427             ctx->bs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
428         }
429 
430         if (fOrigPos == nullptr) {
431             // Handle evenly distributed stops.
432 
433             size_t stopCount = fColorCount;
434             float gapCount = stopCount - 1;
435 
436             SkPM4f c_l = prepareColor(0);
437             for (size_t i = 0; i < stopCount - 1; i++) {
438                 SkPM4f c_r = prepareColor(i + 1);
439                 init_stop_evenly(ctx, gapCount, i, c_l, c_r);
440                 c_l = c_r;
441             }
442             add_const_color(ctx, stopCount - 1, c_l);
443 
444             ctx->stopCount = stopCount;
445             p->append(SkRasterPipeline::evenly_spaced_gradient, ctx);
446         } else {
447             // Handle arbitrary stops.
448 
449             ctx->ts = alloc->makeArray<float>(fColorCount+1);
450 
451             // Remove the dummy stops inserted by SkGradientShaderBase::SkGradientShaderBase
452             // because they are naturally handled by the search method.
453             int firstStop;
454             int lastStop;
455             if (fColorCount > 2) {
456                 firstStop = fOrigColors4f[0] != fOrigColors4f[1] ? 0 : 1;
457                 lastStop = fOrigColors4f[fColorCount - 2] != fOrigColors4f[fColorCount - 1]
458                            ? fColorCount - 1 : fColorCount - 2;
459             } else {
460                 firstStop = 0;
461                 lastStop = 1;
462             }
463 
464             size_t stopCount = 0;
465             float  t_l = fOrigPos[firstStop];
466             SkPM4f c_l = prepareColor(firstStop);
467             add_const_color(ctx, stopCount++, c_l);
468             // N.B. lastStop is the index of the last stop, not one after.
469             for (int i = firstStop; i < lastStop; i++) {
470                 float  t_r = fOrigPos[i + 1];
471                 SkPM4f c_r = prepareColor(i + 1);
472                 if (t_l < t_r) {
473                     init_stop_pos(ctx, stopCount, t_l, t_r, c_l, c_r);
474                     stopCount += 1;
475                 }
476                 t_l = t_r;
477                 c_l = c_r;
478             }
479 
480             ctx->ts[stopCount] = t_l;
481             add_const_color(ctx, stopCount++, c_l);
482 
483             ctx->stopCount = stopCount;
484             p->append(SkRasterPipeline::gradient, ctx);
485         }
486     }
487 
488     if (!premulGrad && !this->colorsAreOpaque()) {
489         p->append(SkRasterPipeline::premul);
490     }
491 
492     p->extend(postPipeline);
493 
494     return true;
495 }
496 
497 
isOpaque() const498 bool SkGradientShaderBase::isOpaque() const {
499     return fColorsAreOpaque;
500 }
501 
rounded_divide(unsigned numer,unsigned denom)502 static unsigned rounded_divide(unsigned numer, unsigned denom) {
503     return (numer + (denom >> 1)) / denom;
504 }
505 
onAsLuminanceColor(SkColor * lum) const506 bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const {
507     // we just compute an average color.
508     // possibly we could weight this based on the proportional width for each color
509     //   assuming they are not evenly distributed in the fPos array.
510     int r = 0;
511     int g = 0;
512     int b = 0;
513     const int n = fColorCount;
514     for (int i = 0; i < n; ++i) {
515         SkColor c = fOrigColors[i];
516         r += SkColorGetR(c);
517         g += SkColorGetG(c);
518         b += SkColorGetB(c);
519     }
520     *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n));
521     return true;
522 }
523 
GradientShaderBaseContext(const SkGradientShaderBase & shader,const ContextRec & rec)524 SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext(
525         const SkGradientShaderBase& shader, const ContextRec& rec)
526     : INHERITED(shader, rec)
527 #ifdef SK_SUPPORT_LEGACY_GRADIENT_DITHERING
528     , fDither(true)
529 #else
530     , fDither(rec.fPaint->isDither())
531 #endif
532     , fCache(shader.refCache(getPaintAlpha(), fDither))
533 {
534     const SkMatrix& inverse = this->getTotalInverse();
535 
536     fDstToIndex.setConcat(shader.fPtsToUnit, inverse);
537     SkASSERT(!fDstToIndex.hasPerspective());
538 
539     fDstToIndexProc = fDstToIndex.getMapXYProc();
540 
541     // now convert our colors in to PMColors
542     unsigned paintAlpha = this->getPaintAlpha();
543 
544     fFlags = this->INHERITED::getFlags();
545     if (shader.fColorsAreOpaque && paintAlpha == 0xFF) {
546         fFlags |= kOpaqueAlpha_Flag;
547     }
548 }
549 
isValid() const550 bool SkGradientShaderBase::GradientShaderBaseContext::isValid() const {
551     return fDstToIndex.isFinite();
552 }
553 
GradientShaderCache(U8CPU alpha,bool dither,const SkGradientShaderBase & shader)554 SkGradientShaderBase::GradientShaderCache::GradientShaderCache(
555         U8CPU alpha, bool dither, const SkGradientShaderBase& shader)
556     : fCacheAlpha(alpha)
557     , fCacheDither(dither)
558     , fShader(shader)
559 {
560     // Only initialize the cache in getCache32.
561     fCache32 = nullptr;
562 }
563 
~GradientShaderCache()564 SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() {}
565 
566 /*
567  *  r,g,b used to be SkFixed, but on gcc (4.2.1 mac and 4.6.3 goobuntu) in
568  *  release builds, we saw a compiler error where the 0xFF parameter in
569  *  SkPackARGB32() was being totally ignored whenever it was called with
570  *  a non-zero add (e.g. 0x8000).
571  *
572  *  We found two work-arounds:
573  *      1. change r,g,b to unsigned (or just one of them)
574  *      2. change SkPackARGB32 to + its (a << SK_A32_SHIFT) value instead
575  *         of using |
576  *
577  *  We chose #1 just because it was more localized.
578  *  See http://code.google.com/p/skia/issues/detail?id=1113
579  *
580  *  The type SkUFixed encapsulate this need for unsigned, but logically Fixed.
581  */
582 typedef uint32_t SkUFixed;
583 
Build32bitCache(SkPMColor cache[],SkColor c0,SkColor c1,int count,U8CPU paintAlpha,uint32_t gradFlags,bool dither)584 void SkGradientShaderBase::GradientShaderCache::Build32bitCache(
585         SkPMColor cache[], SkColor c0, SkColor c1,
586         int count, U8CPU paintAlpha, uint32_t gradFlags, bool dither) {
587     SkASSERT(count > 1);
588 
589     // need to apply paintAlpha to our two endpoints
590     uint32_t a0 = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
591     uint32_t a1 = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
592 
593 
594     const bool interpInPremul = SkToBool(gradFlags &
595                            SkGradientShader::kInterpolateColorsInPremul_Flag);
596 
597     uint32_t r0 = SkColorGetR(c0);
598     uint32_t g0 = SkColorGetG(c0);
599     uint32_t b0 = SkColorGetB(c0);
600 
601     uint32_t r1 = SkColorGetR(c1);
602     uint32_t g1 = SkColorGetG(c1);
603     uint32_t b1 = SkColorGetB(c1);
604 
605     if (interpInPremul) {
606         r0 = SkMulDiv255Round(r0, a0);
607         g0 = SkMulDiv255Round(g0, a0);
608         b0 = SkMulDiv255Round(b0, a0);
609 
610         r1 = SkMulDiv255Round(r1, a1);
611         g1 = SkMulDiv255Round(g1, a1);
612         b1 = SkMulDiv255Round(b1, a1);
613     }
614 
615     SkFixed da = SkIntToFixed(a1 - a0) / (count - 1);
616     SkFixed dr = SkIntToFixed(r1 - r0) / (count - 1);
617     SkFixed dg = SkIntToFixed(g1 - g0) / (count - 1);
618     SkFixed db = SkIntToFixed(b1 - b0) / (count - 1);
619 
620     /*  We pre-add 1/8 to avoid having to add this to our [0] value each time
621         in the loop. Without this, the bias for each would be
622             0x2000  0xA000  0xE000  0x6000
623         With this trick, we can add 0 for the first (no-op) and just adjust the
624         others.
625      */
626     const SkUFixed bias0 = dither ? 0x2000 : 0x8000;
627     const SkUFixed bias1 = dither ? 0x8000 : 0;
628     const SkUFixed bias2 = dither ? 0xC000 : 0;
629     const SkUFixed bias3 = dither ? 0x4000 : 0;
630 
631     SkUFixed a = SkIntToFixed(a0) + bias0;
632     SkUFixed r = SkIntToFixed(r0) + bias0;
633     SkUFixed g = SkIntToFixed(g0) + bias0;
634     SkUFixed b = SkIntToFixed(b0) + bias0;
635 
636     /*
637      *  Our dither-cell (spatially) is
638      *      0 2
639      *      3 1
640      *  Where
641      *      [0] -> [-1/8 ... 1/8 ) values near 0
642      *      [1] -> [ 1/8 ... 3/8 ) values near 1/4
643      *      [2] -> [ 3/8 ... 5/8 ) values near 1/2
644      *      [3] -> [ 5/8 ... 7/8 ) values near 3/4
645      */
646 
647     if (0xFF == a0 && 0 == da) {
648         do {
649             cache[kCache32Count*0] = SkPackARGB32(0xFF, (r + 0    ) >> 16,
650                                                         (g + 0    ) >> 16,
651                                                         (b + 0    ) >> 16);
652             cache[kCache32Count*1] = SkPackARGB32(0xFF, (r + bias1) >> 16,
653                                                         (g + bias1) >> 16,
654                                                         (b + bias1) >> 16);
655             cache[kCache32Count*2] = SkPackARGB32(0xFF, (r + bias2) >> 16,
656                                                         (g + bias2) >> 16,
657                                                         (b + bias2) >> 16);
658             cache[kCache32Count*3] = SkPackARGB32(0xFF, (r + bias3) >> 16,
659                                                         (g + bias3) >> 16,
660                                                         (b + bias3) >> 16);
661             cache += 1;
662             r += dr;
663             g += dg;
664             b += db;
665         } while (--count != 0);
666     } else if (interpInPremul) {
667         do {
668             cache[kCache32Count*0] = SkPackARGB32((a + 0    ) >> 16,
669                                                   (r + 0    ) >> 16,
670                                                   (g + 0    ) >> 16,
671                                                   (b + 0    ) >> 16);
672             cache[kCache32Count*1] = SkPackARGB32((a + bias1) >> 16,
673                                                   (r + bias1) >> 16,
674                                                   (g + bias1) >> 16,
675                                                   (b + bias1) >> 16);
676             cache[kCache32Count*2] = SkPackARGB32((a + bias2) >> 16,
677                                                   (r + bias2) >> 16,
678                                                   (g + bias2) >> 16,
679                                                   (b + bias2) >> 16);
680             cache[kCache32Count*3] = SkPackARGB32((a + bias3) >> 16,
681                                                   (r + bias3) >> 16,
682                                                   (g + bias3) >> 16,
683                                                   (b + bias3) >> 16);
684             cache += 1;
685             a += da;
686             r += dr;
687             g += dg;
688             b += db;
689         } while (--count != 0);
690     } else {    // interpolate in unpreml space
691         do {
692             cache[kCache32Count*0] = SkPremultiplyARGBInline((a + 0     ) >> 16,
693                                                              (r + 0     ) >> 16,
694                                                              (g + 0     ) >> 16,
695                                                              (b + 0     ) >> 16);
696             cache[kCache32Count*1] = SkPremultiplyARGBInline((a + bias1) >> 16,
697                                                              (r + bias1) >> 16,
698                                                              (g + bias1) >> 16,
699                                                              (b + bias1) >> 16);
700             cache[kCache32Count*2] = SkPremultiplyARGBInline((a + bias2) >> 16,
701                                                              (r + bias2) >> 16,
702                                                              (g + bias2) >> 16,
703                                                              (b + bias2) >> 16);
704             cache[kCache32Count*3] = SkPremultiplyARGBInline((a + bias3) >> 16,
705                                                              (r + bias3) >> 16,
706                                                              (g + bias3) >> 16,
707                                                              (b + bias3) >> 16);
708             cache += 1;
709             a += da;
710             r += dr;
711             g += dg;
712             b += db;
713         } while (--count != 0);
714     }
715 }
716 
SkFixedToFFFF(SkFixed x)717 static inline int SkFixedToFFFF(SkFixed x) {
718     SkASSERT((unsigned)x <= SK_Fixed1);
719     return x - (x >> 16);
720 }
721 
getCache32()722 const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() {
723     fCache32InitOnce(SkGradientShaderBase::GradientShaderCache::initCache32, this);
724     SkASSERT(fCache32);
725     return fCache32;
726 }
727 
initCache32(GradientShaderCache * cache)728 void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache* cache) {
729     const int kNumberOfDitherRows = 4;
730     const SkImageInfo info = SkImageInfo::MakeN32Premul(kCache32Count, kNumberOfDitherRows);
731 
732     SkASSERT(nullptr == cache->fCache32PixelRef);
733     cache->fCache32PixelRef = SkMallocPixelRef::MakeAllocate(info, 0);
734     cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->pixels();
735     if (cache->fShader.fColorCount == 2) {
736         Build32bitCache(cache->fCache32, cache->fShader.fOrigColors[0],
737                         cache->fShader.fOrigColors[1], kCache32Count, cache->fCacheAlpha,
738                         cache->fShader.fGradFlags, cache->fCacheDither);
739     } else {
740         Rec* rec = cache->fShader.fRecs;
741         int prevIndex = 0;
742         for (int i = 1; i < cache->fShader.fColorCount; i++) {
743             int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
744             SkASSERT(nextIndex < kCache32Count);
745 
746             if (nextIndex > prevIndex)
747                 Build32bitCache(cache->fCache32 + prevIndex, cache->fShader.fOrigColors[i-1],
748                                 cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1,
749                                 cache->fCacheAlpha, cache->fShader.fGradFlags, cache->fCacheDither);
750             prevIndex = nextIndex;
751         }
752     }
753 }
754 
initLinearBitmap(SkBitmap * bitmap) const755 void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap) const {
756     const bool interpInPremul = SkToBool(fGradFlags &
757                                          SkGradientShader::kInterpolateColorsInPremul_Flag);
758     SkHalf* pixelsF16 = reinterpret_cast<SkHalf*>(bitmap->getPixels());
759     uint32_t* pixelsS32 = reinterpret_cast<uint32_t*>(bitmap->getPixels());
760 
761     typedef std::function<void(const Sk4f&, int)> pixelWriteFn_t;
762 
763     pixelWriteFn_t writeF16Pixel = [&](const Sk4f& x, int index) {
764         Sk4h c = SkFloatToHalf_finite_ftz(x);
765         pixelsF16[4*index+0] = c[0];
766         pixelsF16[4*index+1] = c[1];
767         pixelsF16[4*index+2] = c[2];
768         pixelsF16[4*index+3] = c[3];
769     };
770     pixelWriteFn_t writeS32Pixel = [&](const Sk4f& c, int index) {
771         pixelsS32[index] = Sk4f_toS32(c);
772     };
773 
774     pixelWriteFn_t writeSizedPixel =
775         (kRGBA_F16_SkColorType == bitmap->colorType()) ? writeF16Pixel : writeS32Pixel;
776     pixelWriteFn_t writeUnpremulPixel = [&](const Sk4f& c, int index) {
777         writeSizedPixel(c * Sk4f(c[3], c[3], c[3], 1.0f), index);
778     };
779 
780     pixelWriteFn_t writePixel = interpInPremul ? writeSizedPixel : writeUnpremulPixel;
781 
782     int prevIndex = 0;
783     for (int i = 1; i < fColorCount; i++) {
784         int nextIndex = (fColorCount == 2) ? (kCache32Count - 1)
785             : SkFixedToFFFF(fRecs[i].fPos) >> kCache32Shift;
786         SkASSERT(nextIndex < kCache32Count);
787 
788         if (nextIndex > prevIndex) {
789             Sk4f c0 = Sk4f::Load(fOrigColors4f[i - 1].vec());
790             Sk4f c1 = Sk4f::Load(fOrigColors4f[i].vec());
791             if (interpInPremul) {
792                 c0 = c0 * Sk4f(c0[3], c0[3], c0[3], 1.0f);
793                 c1 = c1 * Sk4f(c1[3], c1[3], c1[3], 1.0f);
794             }
795 
796             Sk4f step = Sk4f(1.0f / static_cast<float>(nextIndex - prevIndex));
797             Sk4f delta = (c1 - c0) * step;
798 
799             for (int curIndex = prevIndex; curIndex <= nextIndex; ++curIndex) {
800                 writePixel(c0, curIndex);
801                 c0 += delta;
802             }
803         }
804         prevIndex = nextIndex;
805     }
806     SkASSERT(prevIndex == kCache32Count - 1);
807 }
808 
809 /*
810  *  The gradient holds a cache for the most recent value of alpha. Successive
811  *  callers with the same alpha value will share the same cache.
812  */
refCache(U8CPU alpha,bool dither) const813 sk_sp<SkGradientShaderBase::GradientShaderCache> SkGradientShaderBase::refCache(U8CPU alpha,
814                                                                           bool dither) const {
815     SkAutoMutexAcquire ama(fCacheMutex);
816     if (!fCache || fCache->getAlpha() != alpha || fCache->getDither() != dither) {
817         fCache.reset(new GradientShaderCache(alpha, dither, *this));
818     }
819     // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
820     // Otherwise, the pointer may have been overwritten on a different thread before the object's
821     // ref count was incremented.
822     return fCache;
823 }
824 
getXformedColor(size_t i,SkColorSpace * dstCS) const825 SkColor4f SkGradientShaderBase::getXformedColor(size_t i, SkColorSpace* dstCS) const {
826     return dstCS ? to_colorspace(fOrigColors4f[i], fColorSpace.get(), dstCS)
827                  : SkColor4f_from_SkColor(fOrigColors[i], nullptr);
828 }
829 
830 SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex);
831 /*
832  *  Because our caller might rebuild the same (logically the same) gradient
833  *  over and over, we'd like to return exactly the same "bitmap" if possible,
834  *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
835  *  To do that, we maintain a private cache of built-bitmaps, based on our
836  *  colors and positions. Note: we don't try to flatten the fMapper, so if one
837  *  is present, we skip the cache for now.
838  */
getGradientTableBitmap(SkBitmap * bitmap,GradientBitmapType bitmapType) const839 void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap,
840                                                   GradientBitmapType bitmapType) const {
841     // our caller assumes no external alpha, so we ensure that our cache is built with 0xFF
842     sk_sp<GradientShaderCache> cache(this->refCache(0xFF, true));
843 
844     // build our key: [numColors + colors[] + {positions[]} + flags + colorType ]
845     int count = 1 + fColorCount + 1 + 1;
846     if (fColorCount > 2) {
847         count += fColorCount - 1;    // fRecs[].fPos
848     }
849 
850     SkAutoSTMalloc<16, int32_t> storage(count);
851     int32_t* buffer = storage.get();
852 
853     *buffer++ = fColorCount;
854     memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor));
855     buffer += fColorCount;
856     if (fColorCount > 2) {
857         for (int i = 1; i < fColorCount; i++) {
858             *buffer++ = fRecs[i].fPos;
859         }
860     }
861     *buffer++ = fGradFlags;
862     *buffer++ = static_cast<int32_t>(bitmapType);
863     SkASSERT(buffer - storage.get() == count);
864 
865     ///////////////////////////////////
866 
867     static SkGradientBitmapCache* gCache;
868     // each cache cost 1K or 2K of RAM, since each bitmap will be 1x256 at either 32bpp or 64bpp
869     static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
870     SkAutoMutexAcquire ama(gGradientCacheMutex);
871 
872     if (nullptr == gCache) {
873         gCache = new SkGradientBitmapCache(MAX_NUM_CACHED_GRADIENT_BITMAPS);
874     }
875     size_t size = count * sizeof(int32_t);
876 
877     if (!gCache->find(storage.get(), size, bitmap)) {
878         if (GradientBitmapType::kLegacy == bitmapType) {
879             // force our cache32pixelref to be built
880             (void)cache->getCache32();
881             bitmap->setInfo(SkImageInfo::MakeN32Premul(kCache32Count, 1));
882             bitmap->setPixelRef(sk_ref_sp(cache->getCache32PixelRef()), 0, 0);
883         } else {
884             // For these cases we use the bitmap cache, but not the GradientShaderCache. So just
885             // allocate and populate the bitmap's data directly.
886 
887             SkImageInfo info;
888             switch (bitmapType) {
889                 case GradientBitmapType::kSRGB:
890                     info = SkImageInfo::Make(kCache32Count, 1, kRGBA_8888_SkColorType,
891                                              kPremul_SkAlphaType,
892                                              SkColorSpace::MakeSRGB());
893                     break;
894                 case GradientBitmapType::kHalfFloat:
895                     info = SkImageInfo::Make(
896                         kCache32Count, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType,
897                         SkColorSpace::MakeSRGBLinear());
898                     break;
899                 default:
900                     SkFAIL("Unexpected bitmap type");
901                     return;
902             }
903             bitmap->allocPixels(info);
904             this->initLinearBitmap(bitmap);
905         }
906         gCache->add(storage.get(), size, *bitmap);
907     }
908 }
909 
commonAsAGradient(GradientInfo * info,bool flipGrad) const910 void SkGradientShaderBase::commonAsAGradient(GradientInfo* info, bool flipGrad) const {
911     if (info) {
912         if (info->fColorCount >= fColorCount) {
913             SkColor* colorLoc;
914             Rec*     recLoc;
915             SkAutoSTArray<8, SkColor> colorStorage;
916             SkAutoSTArray<8, Rec> recStorage;
917             if (flipGrad && (info->fColors || info->fColorOffsets)) {
918                 colorStorage.reset(fColorCount);
919                 recStorage.reset(fColorCount);
920                 colorLoc = colorStorage.get();
921                 recLoc = recStorage.get();
922                 FlipGradientColors(colorLoc, recLoc, fOrigColors, fRecs, fColorCount);
923             } else {
924                 colorLoc = fOrigColors;
925                 recLoc = fRecs;
926             }
927             if (info->fColors) {
928                 memcpy(info->fColors, colorLoc, fColorCount * sizeof(SkColor));
929             }
930             if (info->fColorOffsets) {
931                 if (fColorCount == 2) {
932                     info->fColorOffsets[0] = 0;
933                     info->fColorOffsets[1] = SK_Scalar1;
934                 } else if (fColorCount > 2) {
935                     for (int i = 0; i < fColorCount; ++i) {
936                         info->fColorOffsets[i] = SkFixedToScalar(recLoc[i].fPos);
937                     }
938                 }
939             }
940         }
941         info->fColorCount = fColorCount;
942         info->fTileMode = fTileMode;
943         info->fGradientFlags = fGradFlags;
944     }
945 }
946 
947 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const948 void SkGradientShaderBase::toString(SkString* str) const {
949 
950     str->appendf("%d colors: ", fColorCount);
951 
952     for (int i = 0; i < fColorCount; ++i) {
953         str->appendHex(fOrigColors[i], 8);
954         if (i < fColorCount-1) {
955             str->append(", ");
956         }
957     }
958 
959     if (fColorCount > 2) {
960         str->append(" points: (");
961         for (int i = 0; i < fColorCount; ++i) {
962             str->appendScalar(SkFixedToScalar(fRecs[i].fPos));
963             if (i < fColorCount-1) {
964                 str->append(", ");
965             }
966         }
967         str->append(")");
968     }
969 
970     static const char* gTileModeName[SkShader::kTileModeCount] = {
971         "clamp", "repeat", "mirror"
972     };
973 
974     str->append(" ");
975     str->append(gTileModeName[fTileMode]);
976 
977     this->INHERITED::toString(str);
978 }
979 #endif
980 
981 ///////////////////////////////////////////////////////////////////////////////
982 ///////////////////////////////////////////////////////////////////////////////
983 
984 // Return true if these parameters are valid/legal/safe to construct a gradient
985 //
valid_grad(const SkColor4f colors[],const SkScalar pos[],int count,unsigned tileMode)986 static bool valid_grad(const SkColor4f colors[], const SkScalar pos[], int count,
987                        unsigned tileMode) {
988     return nullptr != colors && count >= 1 && tileMode < (unsigned)SkShader::kTileModeCount;
989 }
990 
desc_init(SkGradientShaderBase::Descriptor * desc,const SkColor4f colors[],sk_sp<SkColorSpace> colorSpace,const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)991 static void desc_init(SkGradientShaderBase::Descriptor* desc,
992                       const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
993                       const SkScalar pos[], int colorCount,
994                       SkShader::TileMode mode, uint32_t flags, const SkMatrix* localMatrix) {
995     SkASSERT(colorCount > 1);
996 
997     desc->fColors       = colors;
998     desc->fColorSpace   = std::move(colorSpace);
999     desc->fPos          = pos;
1000     desc->fCount        = colorCount;
1001     desc->fTileMode     = mode;
1002     desc->fGradFlags    = flags;
1003     desc->fLocalMatrix  = localMatrix;
1004 }
1005 
1006 // assumes colors is SkColor4f* and pos is SkScalar*
1007 #define EXPAND_1_COLOR(count)                \
1008      SkColor4f tmp[2];                       \
1009      do {                                    \
1010          if (1 == count) {                   \
1011              tmp[0] = tmp[1] = colors[0];    \
1012              colors = tmp;                   \
1013              pos = nullptr;                  \
1014              count = 2;                      \
1015          }                                   \
1016      } while (0)
1017 
1018 struct ColorStopOptimizer {
ColorStopOptimizerColorStopOptimizer1019     ColorStopOptimizer(const SkColor4f* colors, const SkScalar* pos,
1020                        int count, SkShader::TileMode mode)
1021         : fColors(colors)
1022         , fPos(pos)
1023         , fCount(count) {
1024 
1025             if (!pos || count != 3) {
1026                 return;
1027             }
1028 
1029             if (SkScalarNearlyEqual(pos[0], 0.0f) &&
1030                 SkScalarNearlyEqual(pos[1], 0.0f) &&
1031                 SkScalarNearlyEqual(pos[2], 1.0f)) {
1032 
1033                 if (SkShader::kRepeat_TileMode == mode ||
1034                     SkShader::kMirror_TileMode == mode ||
1035                     colors[0] == colors[1]) {
1036 
1037                     // Ignore the leftmost color/pos.
1038                     fColors += 1;
1039                     fPos    += 1;
1040                     fCount   = 2;
1041                 }
1042             } else if (SkScalarNearlyEqual(pos[0], 0.0f) &&
1043                        SkScalarNearlyEqual(pos[1], 1.0f) &&
1044                        SkScalarNearlyEqual(pos[2], 1.0f)) {
1045 
1046                 if (SkShader::kRepeat_TileMode == mode ||
1047                     SkShader::kMirror_TileMode == mode ||
1048                     colors[1] == colors[2]) {
1049 
1050                     // Ignore the rightmost color/pos.
1051                     fCount  = 2;
1052                 }
1053             }
1054     }
1055 
1056     const SkColor4f* fColors;
1057     const SkScalar*  fPos;
1058     int              fCount;
1059 };
1060 
1061 struct ColorConverter {
ColorConverterColorConverter1062     ColorConverter(const SkColor* colors, int count) {
1063         for (int i = 0; i < count; ++i) {
1064             fColors4f.push_back(SkColor4f::FromColor(colors[i]));
1065         }
1066     }
1067 
1068     SkSTArray<2, SkColor4f, true> fColors4f;
1069 };
1070 
MakeLinear(const SkPoint pts[2],const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)1071 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
1072                                              const SkColor colors[],
1073                                              const SkScalar pos[], int colorCount,
1074                                              SkShader::TileMode mode,
1075                                              uint32_t flags,
1076                                              const SkMatrix* localMatrix) {
1077     ColorConverter converter(colors, colorCount);
1078     return MakeLinear(pts, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, flags,
1079                       localMatrix);
1080 }
1081 
MakeLinear(const SkPoint pts[2],const SkColor4f colors[],sk_sp<SkColorSpace> colorSpace,const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)1082 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
1083                                              const SkColor4f colors[],
1084                                              sk_sp<SkColorSpace> colorSpace,
1085                                              const SkScalar pos[], int colorCount,
1086                                              SkShader::TileMode mode,
1087                                              uint32_t flags,
1088                                              const SkMatrix* localMatrix) {
1089     if (!pts || !SkScalarIsFinite((pts[1] - pts[0]).length())) {
1090         return nullptr;
1091     }
1092     if (!valid_grad(colors, pos, colorCount, mode)) {
1093         return nullptr;
1094     }
1095     if (1 == colorCount) {
1096         return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
1097     }
1098     if (localMatrix && !localMatrix->invert(nullptr)) {
1099         return nullptr;
1100     }
1101 
1102     ColorStopOptimizer opt(colors, pos, colorCount, mode);
1103 
1104     SkGradientShaderBase::Descriptor desc;
1105     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
1106               localMatrix);
1107     return sk_make_sp<SkLinearGradient>(pts, desc);
1108 }
1109 
MakeRadial(const SkPoint & center,SkScalar radius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)1110 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
1111                                              const SkColor colors[],
1112                                              const SkScalar pos[], int colorCount,
1113                                              SkShader::TileMode mode,
1114                                              uint32_t flags,
1115                                              const SkMatrix* localMatrix) {
1116     ColorConverter converter(colors, colorCount);
1117     return MakeRadial(center, radius, converter.fColors4f.begin(), nullptr, pos, colorCount, mode,
1118                       flags, localMatrix);
1119 }
1120 
MakeRadial(const SkPoint & center,SkScalar radius,const SkColor4f colors[],sk_sp<SkColorSpace> colorSpace,const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)1121 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
1122                                              const SkColor4f colors[],
1123                                              sk_sp<SkColorSpace> colorSpace,
1124                                              const SkScalar pos[], int colorCount,
1125                                              SkShader::TileMode mode,
1126                                              uint32_t flags,
1127                                              const SkMatrix* localMatrix) {
1128     if (radius <= 0) {
1129         return nullptr;
1130     }
1131     if (!valid_grad(colors, pos, colorCount, mode)) {
1132         return nullptr;
1133     }
1134     if (1 == colorCount) {
1135         return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
1136     }
1137     if (localMatrix && !localMatrix->invert(nullptr)) {
1138         return nullptr;
1139     }
1140 
1141     ColorStopOptimizer opt(colors, pos, colorCount, mode);
1142 
1143     SkGradientShaderBase::Descriptor desc;
1144     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
1145               localMatrix);
1146     return sk_make_sp<SkRadialGradient>(center, radius, desc);
1147 }
1148 
MakeTwoPointConical(const SkPoint & start,SkScalar startRadius,const SkPoint & end,SkScalar endRadius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)1149 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
1150                                                       SkScalar startRadius,
1151                                                       const SkPoint& end,
1152                                                       SkScalar endRadius,
1153                                                       const SkColor colors[],
1154                                                       const SkScalar pos[],
1155                                                       int colorCount,
1156                                                       SkShader::TileMode mode,
1157                                                       uint32_t flags,
1158                                                       const SkMatrix* localMatrix) {
1159     ColorConverter converter(colors, colorCount);
1160     return MakeTwoPointConical(start, startRadius, end, endRadius, converter.fColors4f.begin(),
1161                                nullptr, pos, colorCount, mode, flags, localMatrix);
1162 }
1163 
MakeTwoPointConical(const SkPoint & start,SkScalar startRadius,const SkPoint & end,SkScalar endRadius,const SkColor4f colors[],sk_sp<SkColorSpace> colorSpace,const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)1164 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
1165                                                       SkScalar startRadius,
1166                                                       const SkPoint& end,
1167                                                       SkScalar endRadius,
1168                                                       const SkColor4f colors[],
1169                                                       sk_sp<SkColorSpace> colorSpace,
1170                                                       const SkScalar pos[],
1171                                                       int colorCount,
1172                                                       SkShader::TileMode mode,
1173                                                       uint32_t flags,
1174                                                       const SkMatrix* localMatrix) {
1175     if (startRadius < 0 || endRadius < 0) {
1176         return nullptr;
1177     }
1178     if (SkScalarNearlyZero((start - end).length()) && SkScalarNearlyZero(startRadius)) {
1179         // We can treat this gradient as radial, which is faster.
1180         return MakeRadial(start, endRadius, colors, std::move(colorSpace), pos, colorCount,
1181                           mode, flags, localMatrix);
1182     }
1183     if (!valid_grad(colors, pos, colorCount, mode)) {
1184         return nullptr;
1185     }
1186     if (startRadius == endRadius) {
1187         if (start == end || startRadius == 0) {
1188             return SkShader::MakeEmptyShader();
1189         }
1190     }
1191     if (localMatrix && !localMatrix->invert(nullptr)) {
1192         return nullptr;
1193     }
1194     EXPAND_1_COLOR(colorCount);
1195 
1196     ColorStopOptimizer opt(colors, pos, colorCount, mode);
1197 
1198     bool flipGradient = startRadius > endRadius;
1199 
1200     SkGradientShaderBase::Descriptor desc;
1201 
1202     if (!flipGradient) {
1203         desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
1204                   localMatrix);
1205         return sk_make_sp<SkTwoPointConicalGradient>(start, startRadius, end, endRadius,
1206                                                      flipGradient, desc);
1207     } else {
1208         SkAutoSTArray<8, SkColor4f> colorsNew(opt.fCount);
1209         SkAutoSTArray<8, SkScalar> posNew(opt.fCount);
1210         for (int i = 0; i < opt.fCount; ++i) {
1211             colorsNew[i] = opt.fColors[opt.fCount - i - 1];
1212         }
1213 
1214         if (pos) {
1215             for (int i = 0; i < opt.fCount; ++i) {
1216                 posNew[i] = 1 - opt.fPos[opt.fCount - i - 1];
1217             }
1218             desc_init(&desc, colorsNew.get(), std::move(colorSpace), posNew.get(), opt.fCount, mode,
1219                       flags, localMatrix);
1220         } else {
1221             desc_init(&desc, colorsNew.get(), std::move(colorSpace), nullptr, opt.fCount, mode,
1222                       flags, localMatrix);
1223         }
1224 
1225         return sk_make_sp<SkTwoPointConicalGradient>(end, endRadius, start, startRadius,
1226                                                      flipGradient, desc);
1227     }
1228 }
1229 
MakeSweep(SkScalar cx,SkScalar cy,const SkColor colors[],const SkScalar pos[],int colorCount,uint32_t flags,const SkMatrix * localMatrix)1230 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
1231                                             const SkColor colors[],
1232                                             const SkScalar pos[],
1233                                             int colorCount,
1234                                             uint32_t flags,
1235                                             const SkMatrix* localMatrix) {
1236     ColorConverter converter(colors, colorCount);
1237     return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount, flags,
1238                      localMatrix);
1239 }
1240 
MakeSweep(SkScalar cx,SkScalar cy,const SkColor4f colors[],sk_sp<SkColorSpace> colorSpace,const SkScalar pos[],int colorCount,uint32_t flags,const SkMatrix * localMatrix)1241 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
1242                                             const SkColor4f colors[],
1243                                             sk_sp<SkColorSpace> colorSpace,
1244                                             const SkScalar pos[],
1245                                             int colorCount,
1246                                             uint32_t flags,
1247                                             const SkMatrix* localMatrix) {
1248     if (!valid_grad(colors, pos, colorCount, SkShader::kClamp_TileMode)) {
1249         return nullptr;
1250     }
1251     if (1 == colorCount) {
1252         return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
1253     }
1254     if (localMatrix && !localMatrix->invert(nullptr)) {
1255         return nullptr;
1256     }
1257 
1258     auto mode = SkShader::kClamp_TileMode;
1259 
1260     ColorStopOptimizer opt(colors, pos, colorCount, mode);
1261 
1262     SkGradientShaderBase::Descriptor desc;
1263     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
1264               localMatrix);
1265     return sk_make_sp<SkSweepGradient>(cx, cy, desc);
1266 }
1267 
1268 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)1269     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)
1270     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient)
1271     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient)
1272     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient)
1273 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
1274 
1275 ///////////////////////////////////////////////////////////////////////////////
1276 
1277 #if SK_SUPPORT_GPU
1278 
1279 #include "GrContext.h"
1280 #include "GrShaderCaps.h"
1281 #include "GrTextureStripAtlas.h"
1282 #include "gl/GrGLContext.h"
1283 #include "glsl/GrGLSLColorSpaceXformHelper.h"
1284 #include "glsl/GrGLSLFragmentShaderBuilder.h"
1285 #include "glsl/GrGLSLProgramDataManager.h"
1286 #include "glsl/GrGLSLUniformHandler.h"
1287 #include "SkGr.h"
1288 
1289 static inline bool close_to_one_half(const SkFixed& val) {
1290     return SkScalarNearlyEqual(SkFixedToScalar(val), SK_ScalarHalf);
1291 }
1292 
color_type_to_color_count(GrGradientEffect::ColorType colorType)1293 static inline int color_type_to_color_count(GrGradientEffect::ColorType colorType) {
1294     switch (colorType) {
1295 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
1296         case GrGradientEffect::kSingleHardStop_ColorType:
1297             return 4;
1298         case GrGradientEffect::kHardStopLeftEdged_ColorType:
1299         case GrGradientEffect::kHardStopRightEdged_ColorType:
1300             return 3;
1301 #endif
1302         case GrGradientEffect::kTwo_ColorType:
1303             return 2;
1304         case GrGradientEffect::kThree_ColorType:
1305             return 3;
1306         case GrGradientEffect::kTexture_ColorType:
1307             return 0;
1308     }
1309 
1310     SkDEBUGFAIL("Unhandled ColorType in color_type_to_color_count()");
1311     return -1;
1312 }
1313 
determineColorType(const SkGradientShaderBase & shader)1314 GrGradientEffect::ColorType GrGradientEffect::determineColorType(
1315         const SkGradientShaderBase& shader) {
1316 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
1317     if (shader.fOrigPos) {
1318         if (4 == shader.fColorCount) {
1319             if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
1320                 SkScalarNearlyEqual(shader.fOrigPos[1], shader.fOrigPos[2]) &&
1321                 SkScalarNearlyEqual(shader.fOrigPos[3], 1.0f)) {
1322 
1323                 return kSingleHardStop_ColorType;
1324             }
1325         } else if (3 == shader.fColorCount) {
1326             if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
1327                 SkScalarNearlyEqual(shader.fOrigPos[1], 0.0f) &&
1328                 SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) {
1329 
1330                 return kHardStopLeftEdged_ColorType;
1331             } else if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
1332                        SkScalarNearlyEqual(shader.fOrigPos[1], 1.0f) &&
1333                        SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) {
1334 
1335                 return kHardStopRightEdged_ColorType;
1336             }
1337         }
1338     }
1339 #endif
1340 
1341     if (SkShader::kClamp_TileMode == shader.getTileMode()) {
1342         if (2 == shader.fColorCount) {
1343             return kTwo_ColorType;
1344         } else if (3 == shader.fColorCount &&
1345                    close_to_one_half(shader.getRecs()[1].fPos)) {
1346             return kThree_ColorType;
1347         }
1348     }
1349 
1350     return kTexture_ColorType;
1351 }
1352 
emitUniforms(GrGLSLUniformHandler * uniformHandler,const GrGradientEffect & ge)1353 void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniformHandler,
1354                                                    const GrGradientEffect& ge) {
1355     if (int colorCount = color_type_to_color_count(ge.getColorType())) {
1356         fColorsUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag,
1357                                                      kVec4f_GrSLType,
1358                                                      kDefault_GrSLPrecision,
1359                                                      "Colors",
1360                                                      colorCount);
1361         if (ge.fColorType == kSingleHardStop_ColorType) {
1362             fHardStopT = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
1363                                                     kDefault_GrSLPrecision, "HardStopT");
1364         }
1365     } else {
1366         fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
1367                                              kFloat_GrSLType, kDefault_GrSLPrecision,
1368                                              "GradientYCoordFS");
1369     }
1370 }
1371 
set_after_interp_color_uni_array(const GrGLSLProgramDataManager & pdman,const GrGLSLProgramDataManager::UniformHandle uni,const SkTDArray<SkColor4f> & colors,const GrColorSpaceXform * colorSpaceXform)1372 static inline void set_after_interp_color_uni_array(
1373                                                   const GrGLSLProgramDataManager& pdman,
1374                                                   const GrGLSLProgramDataManager::UniformHandle uni,
1375                                                   const SkTDArray<SkColor4f>& colors,
1376                                                   const GrColorSpaceXform* colorSpaceXform) {
1377     int count = colors.count();
1378     if (colorSpaceXform) {
1379         constexpr int kSmallCount = 10;
1380         SkAutoSTArray<4 * kSmallCount, float> vals(4 * count);
1381 
1382         for (int i = 0; i < count; i++) {
1383             colorSpaceXform->srcToDst().mapScalars(colors[i].vec(), &vals[4 * i]);
1384         }
1385 
1386         pdman.set4fv(uni, count, vals.get());
1387     } else {
1388         pdman.set4fv(uni, count, (float*)&colors[0]);
1389     }
1390 }
1391 
set_before_interp_color_uni_array(const GrGLSLProgramDataManager & pdman,const GrGLSLProgramDataManager::UniformHandle uni,const SkTDArray<SkColor4f> & colors,const GrColorSpaceXform * colorSpaceXform)1392 static inline void set_before_interp_color_uni_array(
1393                                                   const GrGLSLProgramDataManager& pdman,
1394                                                   const GrGLSLProgramDataManager::UniformHandle uni,
1395                                                   const SkTDArray<SkColor4f>& colors,
1396                                                   const GrColorSpaceXform* colorSpaceXform) {
1397     int count = colors.count();
1398     constexpr int kSmallCount = 10;
1399     SkAutoSTArray<4 * kSmallCount, float> vals(4 * count);
1400 
1401     for (int i = 0; i < count; i++) {
1402         float a = colors[i].fA;
1403         vals[4 * i + 0] = colors[i].fR * a;
1404         vals[4 * i + 1] = colors[i].fG * a;
1405         vals[4 * i + 2] = colors[i].fB * a;
1406         vals[4 * i + 3] = a;
1407     }
1408 
1409     if (colorSpaceXform) {
1410         for (int i = 0; i < count; i++) {
1411             colorSpaceXform->srcToDst().mapScalars(&vals[4 * i]);
1412         }
1413     }
1414 
1415     pdman.set4fv(uni, count, vals.get());
1416 }
1417 
set_after_interp_color_uni_array(const GrGLSLProgramDataManager & pdman,const GrGLSLProgramDataManager::UniformHandle uni,const SkTDArray<SkColor> & colors)1418 static inline void set_after_interp_color_uni_array(const GrGLSLProgramDataManager& pdman,
1419                                        const GrGLSLProgramDataManager::UniformHandle uni,
1420                                        const SkTDArray<SkColor>& colors) {
1421     int count = colors.count();
1422     constexpr int kSmallCount = 10;
1423 
1424     SkAutoSTArray<4*kSmallCount, float> vals(4*count);
1425 
1426     for (int i = 0; i < colors.count(); i++) {
1427         // RGBA
1428         vals[4*i + 0] = SkColorGetR(colors[i]) / 255.f;
1429         vals[4*i + 1] = SkColorGetG(colors[i]) / 255.f;
1430         vals[4*i + 2] = SkColorGetB(colors[i]) / 255.f;
1431         vals[4*i + 3] = SkColorGetA(colors[i]) / 255.f;
1432     }
1433 
1434     pdman.set4fv(uni, colors.count(), vals.get());
1435 }
1436 
set_before_interp_color_uni_array(const GrGLSLProgramDataManager & pdman,const GrGLSLProgramDataManager::UniformHandle uni,const SkTDArray<SkColor> & colors)1437 static inline void set_before_interp_color_uni_array(const GrGLSLProgramDataManager& pdman,
1438                                               const GrGLSLProgramDataManager::UniformHandle uni,
1439                                               const SkTDArray<SkColor>& colors) {
1440     int count = colors.count();
1441     constexpr int kSmallCount = 10;
1442 
1443     SkAutoSTArray<4*kSmallCount, float> vals(4*count);
1444 
1445     for (int i = 0; i < count; i++) {
1446         float a = SkColorGetA(colors[i]) / 255.f;
1447         float aDiv255 = a / 255.f;
1448 
1449         // RGBA
1450         vals[4*i + 0] = SkColorGetR(colors[i]) * aDiv255;
1451         vals[4*i + 1] = SkColorGetG(colors[i]) * aDiv255;
1452         vals[4*i + 2] = SkColorGetB(colors[i]) * aDiv255;
1453         vals[4*i + 3] = a;
1454     }
1455 
1456     pdman.set4fv(uni, count, vals.get());
1457 }
1458 
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & processor)1459 void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman,
1460                                                 const GrFragmentProcessor& processor) {
1461     const GrGradientEffect& e = processor.cast<GrGradientEffect>();
1462 
1463     switch (e.getColorType()) {
1464 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
1465         case GrGradientEffect::kSingleHardStop_ColorType:
1466             pdman.set1f(fHardStopT, e.fPositions[1]);
1467             // fall through
1468         case GrGradientEffect::kHardStopLeftEdged_ColorType:
1469         case GrGradientEffect::kHardStopRightEdged_ColorType:
1470 #endif
1471         case GrGradientEffect::kTwo_ColorType:
1472         case GrGradientEffect::kThree_ColorType: {
1473             if (e.fColors4f.count() > 0) {
1474                 // Gamma-correct / color-space aware
1475                 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
1476                     set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors4f,
1477                                                       e.fColorSpaceXform.get());
1478                 } else {
1479                     set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors4f,
1480                                                      e.fColorSpaceXform.get());
1481                 }
1482             } else {
1483                 // Legacy mode. Would be nice if we had converted the 8-bit colors to float earlier
1484                 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
1485                     set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors);
1486                 } else {
1487                     set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors);
1488                 }
1489             }
1490 
1491             break;
1492         }
1493 
1494         case GrGradientEffect::kTexture_ColorType: {
1495             SkScalar yCoord = e.getYCoord();
1496             if (yCoord != fCachedYCoord) {
1497                 pdman.set1f(fFSYUni, yCoord);
1498                 fCachedYCoord = yCoord;
1499             }
1500             if (SkToBool(e.fColorSpaceXform)) {
1501                 fColorSpaceHelper.setData(pdman, e.fColorSpaceXform.get());
1502             }
1503             break;
1504         }
1505     }
1506 }
1507 
GenBaseGradientKey(const GrProcessor & processor)1508 uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor& processor) {
1509     const GrGradientEffect& e = processor.cast<GrGradientEffect>();
1510 
1511     uint32_t key = 0;
1512 
1513     if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
1514         key |= kPremulBeforeInterpKey;
1515     }
1516 
1517     if (GrGradientEffect::kTwo_ColorType == e.getColorType()) {
1518         key |= kTwoColorKey;
1519     } else if (GrGradientEffect::kThree_ColorType == e.getColorType()) {
1520         key |= kThreeColorKey;
1521     }
1522 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
1523     else if (GrGradientEffect::kSingleHardStop_ColorType == e.getColorType()) {
1524         key |= kHardStopCenteredKey;
1525     } else if (GrGradientEffect::kHardStopLeftEdged_ColorType == e.getColorType()) {
1526         key |= kHardStopZeroZeroOneKey;
1527     } else if (GrGradientEffect::kHardStopRightEdged_ColorType == e.getColorType()) {
1528         key |= kHardStopZeroOneOneKey;
1529     }
1530 
1531     if (SkShader::TileMode::kClamp_TileMode == e.fTileMode) {
1532         key |= kClampTileMode;
1533     } else if (SkShader::TileMode::kRepeat_TileMode == e.fTileMode) {
1534         key |= kRepeatTileMode;
1535     } else {
1536         key |= kMirrorTileMode;
1537     }
1538 #endif
1539 
1540     key |= GrColorSpaceXform::XformKey(e.fColorSpaceXform.get()) << kReservedBits;
1541 
1542     return key;
1543 }
1544 
emitColor(GrGLSLFPFragmentBuilder * fragBuilder,GrGLSLUniformHandler * uniformHandler,const GrShaderCaps * shaderCaps,const GrGradientEffect & ge,const char * gradientTValue,const char * outputColor,const char * inputColor,const TextureSamplers & texSamplers)1545 void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
1546                                                 GrGLSLUniformHandler* uniformHandler,
1547                                                 const GrShaderCaps* shaderCaps,
1548                                                 const GrGradientEffect& ge,
1549                                                 const char* gradientTValue,
1550                                                 const char* outputColor,
1551                                                 const char* inputColor,
1552                                                 const TextureSamplers& texSamplers) {
1553     switch (ge.getColorType()) {
1554 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
1555         case kSingleHardStop_ColorType: {
1556             const char* t      = gradientTValue;
1557             const char* colors = uniformHandler->getUniformCStr(fColorsUni);
1558             const char* stopT = uniformHandler->getUniformCStr(fHardStopT);
1559 
1560             fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
1561 
1562             // Account for tile mode
1563             if (SkShader::kRepeat_TileMode == ge.fTileMode) {
1564                 fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
1565             } else if (SkShader::kMirror_TileMode == ge.fTileMode) {
1566                 fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
1567                 fragBuilder->codeAppendf("    if (mod(floor(%s), 2.0) == 0.0) {", t);
1568                 fragBuilder->codeAppendf("        clamp_t = fract(%s);", t);
1569                 fragBuilder->codeAppendf("    } else {");
1570                 fragBuilder->codeAppendf("        clamp_t = 1.0 - fract(%s);", t);
1571                 fragBuilder->codeAppendf("    }");
1572                 fragBuilder->codeAppendf("}");
1573             }
1574 
1575             // Calculate color
1576             fragBuilder->codeAppend ("vec4 start, end;");
1577             fragBuilder->codeAppend ("float relative_t;");
1578             fragBuilder->codeAppendf("if (clamp_t < %s) {", stopT);
1579             fragBuilder->codeAppendf("    start = %s[0];", colors);
1580             fragBuilder->codeAppendf("    end   = %s[1];", colors);
1581             fragBuilder->codeAppendf("    relative_t = clamp_t / %s;", stopT);
1582             fragBuilder->codeAppend ("} else {");
1583             fragBuilder->codeAppendf("    start = %s[2];", colors);
1584             fragBuilder->codeAppendf("    end   = %s[3];", colors);
1585             fragBuilder->codeAppendf("    relative_t = (clamp_t - %s) / (1 - %s);", stopT, stopT);
1586             fragBuilder->codeAppend ("}");
1587             fragBuilder->codeAppend ("vec4 colorTemp = mix(start, end, relative_t);");
1588 
1589             if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
1590                 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
1591             }
1592             if (ge.fColorSpaceXform) {
1593                 fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);");
1594             }
1595             fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
1596 
1597             break;
1598         }
1599 
1600         case kHardStopLeftEdged_ColorType: {
1601             const char* t      = gradientTValue;
1602             const char* colors = uniformHandler->getUniformCStr(fColorsUni);
1603 
1604             fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
1605 
1606             // Account for tile mode
1607             if (SkShader::kRepeat_TileMode == ge.fTileMode) {
1608                 fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
1609             } else if (SkShader::kMirror_TileMode == ge.fTileMode) {
1610                 fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
1611                 fragBuilder->codeAppendf("    if (mod(floor(%s), 2.0) == 0.0) {", t);
1612                 fragBuilder->codeAppendf("        clamp_t = fract(%s);", t);
1613                 fragBuilder->codeAppendf("    } else {");
1614                 fragBuilder->codeAppendf("        clamp_t = 1.0 - fract(%s);", t);
1615                 fragBuilder->codeAppendf("    }");
1616                 fragBuilder->codeAppendf("}");
1617             }
1618 
1619             fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[1], %s[2], clamp_t);", colors,
1620                                      colors);
1621             if (SkShader::kClamp_TileMode == ge.fTileMode) {
1622                 fragBuilder->codeAppendf("if (%s < 0.0) {", t);
1623                 fragBuilder->codeAppendf("    colorTemp = %s[0];", colors);
1624                 fragBuilder->codeAppendf("}");
1625             }
1626 
1627             if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
1628                 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
1629             }
1630             if (ge.fColorSpaceXform) {
1631                 fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);");
1632             }
1633             fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
1634 
1635             break;
1636         }
1637 
1638         case kHardStopRightEdged_ColorType: {
1639             const char* t      = gradientTValue;
1640             const char* colors = uniformHandler->getUniformCStr(fColorsUni);
1641 
1642             fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
1643 
1644             // Account for tile mode
1645             if (SkShader::kRepeat_TileMode == ge.fTileMode) {
1646                 fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
1647             } else if (SkShader::kMirror_TileMode == ge.fTileMode) {
1648                 fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
1649                 fragBuilder->codeAppendf("    if (mod(floor(%s), 2.0) == 0.0) {", t);
1650                 fragBuilder->codeAppendf("        clamp_t = fract(%s);", t);
1651                 fragBuilder->codeAppendf("    } else {");
1652                 fragBuilder->codeAppendf("        clamp_t = 1.0 - fract(%s);", t);
1653                 fragBuilder->codeAppendf("    }");
1654                 fragBuilder->codeAppendf("}");
1655             }
1656 
1657             fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp_t);", colors,
1658                                      colors);
1659             if (SkShader::kClamp_TileMode == ge.fTileMode) {
1660                 fragBuilder->codeAppendf("if (%s > 1.0) {", t);
1661                 fragBuilder->codeAppendf("    colorTemp = %s[2];", colors);
1662                 fragBuilder->codeAppendf("}");
1663             }
1664 
1665             if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
1666                 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
1667             }
1668             if (ge.fColorSpaceXform) {
1669                 fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);");
1670             }
1671             fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
1672 
1673             break;
1674         }
1675 #endif
1676 
1677         case kTwo_ColorType: {
1678             const char* t      = gradientTValue;
1679             const char* colors = uniformHandler->getUniformCStr(fColorsUni);
1680 
1681             fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp(%s, 0.0, 1.0));",
1682                                      colors, colors, t);
1683 
1684             // We could skip this step if both colors are known to be opaque. Two
1685             // considerations:
1686             // The gradient SkShader reporting opaque is more restrictive than necessary in the two
1687             // pt case. Make sure the key reflects this optimization (and note that it can use the
1688             // same shader as thekBeforeIterp case). This same optimization applies to the 3 color
1689             // case below.
1690             if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
1691                 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
1692             }
1693             if (ge.fColorSpaceXform) {
1694                 fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);");
1695             }
1696 
1697             fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
1698 
1699             break;
1700         }
1701 
1702         case kThree_ColorType: {
1703             const char* t      = gradientTValue;
1704             const char* colors = uniformHandler->getUniformCStr(fColorsUni);
1705 
1706             fragBuilder->codeAppendf("float oneMinus2t = 1.0 - (2.0 * %s);", t);
1707             fragBuilder->codeAppendf("vec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s[0];",
1708                                      colors);
1709             if (!shaderCaps->canUseMinAndAbsTogether()) {
1710                 // The Tegra3 compiler will sometimes never return if we have
1711                 // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
1712                 fragBuilder->codeAppendf("float minAbs = abs(oneMinus2t);");
1713                 fragBuilder->codeAppendf("minAbs = minAbs > 1.0 ? 1.0 : minAbs;");
1714                 fragBuilder->codeAppendf("colorTemp += (1.0 - minAbs) * %s[1];", colors);
1715             } else {
1716                 fragBuilder->codeAppendf("colorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s[1];",
1717                                          colors);
1718             }
1719             fragBuilder->codeAppendf("colorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s[2];", colors);
1720 
1721             if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
1722                 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
1723             }
1724             if (ge.fColorSpaceXform) {
1725                 fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);");
1726             }
1727 
1728             fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
1729 
1730             break;
1731         }
1732 
1733         case kTexture_ColorType: {
1734             fColorSpaceHelper.emitCode(uniformHandler, ge.fColorSpaceXform.get());
1735 
1736             const char* fsyuni = uniformHandler->getUniformCStr(fFSYUni);
1737 
1738             fragBuilder->codeAppendf("vec2 coord = vec2(%s, %s);", gradientTValue, fsyuni);
1739             fragBuilder->codeAppendf("%s = ", outputColor);
1740             fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord",
1741                                                         kVec2f_GrSLType, &fColorSpaceHelper);
1742             fragBuilder->codeAppend(";");
1743 
1744             break;
1745         }
1746     }
1747 }
1748 
1749 /////////////////////////////////////////////////////////////////////
1750 
OptFlags(bool isOpaque)1751 inline GrFragmentProcessor::OptimizationFlags GrGradientEffect::OptFlags(bool isOpaque) {
1752     return isOpaque
1753                    ? kPreservesOpaqueInput_OptimizationFlag |
1754                              kCompatibleWithCoverageAsAlpha_OptimizationFlag
1755                    : kCompatibleWithCoverageAsAlpha_OptimizationFlag;
1756 }
1757 
GrGradientEffect(const CreateArgs & args,bool isOpaque)1758 GrGradientEffect::GrGradientEffect(const CreateArgs& args, bool isOpaque)
1759         : INHERITED(OptFlags(isOpaque)) {
1760     const SkGradientShaderBase& shader(*args.fShader);
1761 
1762     fIsOpaque = shader.isOpaque();
1763 
1764     fColorType = this->determineColorType(shader);
1765     fColorSpaceXform = std::move(args.fColorSpaceXform);
1766 
1767     if (kTexture_ColorType != fColorType) {
1768         SkASSERT(shader.fOrigColors && shader.fOrigColors4f);
1769         if (args.fGammaCorrect) {
1770             fColors4f = SkTDArray<SkColor4f>(shader.fOrigColors4f, shader.fColorCount);
1771         } else {
1772             fColors = SkTDArray<SkColor>(shader.fOrigColors, shader.fColorCount);
1773         }
1774 
1775 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
1776         if (shader.fOrigPos) {
1777             fPositions = SkTDArray<SkScalar>(shader.fOrigPos, shader.fColorCount);
1778         }
1779 #endif
1780     }
1781 
1782 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
1783     fTileMode = args.fTileMode;
1784 #endif
1785 
1786     switch (fColorType) {
1787         // The two and three color specializations do not currently support tiling.
1788         case kTwo_ColorType:
1789         case kThree_ColorType:
1790 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
1791         case kHardStopLeftEdged_ColorType:
1792         case kHardStopRightEdged_ColorType:
1793         case kSingleHardStop_ColorType:
1794 #endif
1795             fRow = -1;
1796 
1797             if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) {
1798                 fPremulType = kBeforeInterp_PremulType;
1799             } else {
1800                 fPremulType = kAfterInterp_PremulType;
1801             }
1802 
1803             fCoordTransform.reset(*args.fMatrix);
1804 
1805             break;
1806         case kTexture_ColorType:
1807             // doesn't matter how this is set, just be consistent because it is part of the
1808             // effect key.
1809             fPremulType = kBeforeInterp_PremulType;
1810 
1811             SkGradientShaderBase::GradientBitmapType bitmapType =
1812                 SkGradientShaderBase::GradientBitmapType::kLegacy;
1813             if (args.fGammaCorrect) {
1814                 // Try to use F16 if we can
1815                 if (args.fContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) {
1816                     bitmapType = SkGradientShaderBase::GradientBitmapType::kHalfFloat;
1817                 } else if (args.fContext->caps()->isConfigTexturable(kSRGBA_8888_GrPixelConfig)) {
1818                     bitmapType = SkGradientShaderBase::GradientBitmapType::kSRGB;
1819                 } else {
1820                     // This can happen, but only if someone explicitly creates an unsupported
1821                     // (eg sRGB) surface. Just fall back to legacy behavior.
1822                 }
1823             }
1824 
1825             SkBitmap bitmap;
1826             shader.getGradientTableBitmap(&bitmap, bitmapType);
1827             SkASSERT(1 == bitmap.height() && SkIsPow2(bitmap.width()));
1828 
1829 
1830             GrTextureStripAtlas::Desc desc;
1831             desc.fWidth  = bitmap.width();
1832             desc.fHeight = 32;
1833             desc.fRowHeight = bitmap.height();
1834             desc.fContext = args.fContext;
1835             desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *args.fContext->caps());
1836             fAtlas = GrTextureStripAtlas::GetAtlas(desc);
1837             SkASSERT(fAtlas);
1838 
1839             // We always filter the gradient table. Each table is one row of a texture, always
1840             // y-clamp.
1841             GrSamplerParams params;
1842             params.setFilterMode(GrSamplerParams::kBilerp_FilterMode);
1843             params.setTileModeX(args.fTileMode);
1844 
1845             fRow = fAtlas->lockRow(bitmap);
1846             if (-1 != fRow) {
1847                 fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight();
1848                 // This is 1/2 places where auto-normalization is disabled
1849                 fCoordTransform.reset(*args.fMatrix, fAtlas->asTextureProxyRef().get(), false);
1850                 fTextureSampler.reset(fAtlas->asTextureProxyRef(), params);
1851             } else {
1852                 // In this instance we know the params are:
1853                 //   clampY, bilerp
1854                 // and the proxy is:
1855                 //   exact fit, power of two in both dimensions
1856                 // Only the x-tileMode is unknown. However, given all the other knowns we know
1857                 // that GrMakeCachedBitmapProxy is sufficient (i.e., it won't need to be
1858                 // extracted to a subset or mipmapped).
1859                 sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(
1860                                                                 args.fContext->resourceProvider(),
1861                                                                 bitmap);
1862                 if (!proxy) {
1863                     SkDebugf("Gradient won't draw. Could not create texture.");
1864                     return;
1865                 }
1866                 // This is 2/2 places where auto-normalization is disabled
1867                 fCoordTransform.reset(*args.fMatrix, proxy.get(), false);
1868                 fTextureSampler.reset(std::move(proxy), params);
1869                 fYCoord = SK_ScalarHalf;
1870             }
1871 
1872             this->addTextureSampler(&fTextureSampler);
1873 
1874             break;
1875     }
1876 
1877     this->addCoordTransform(&fCoordTransform);
1878 }
1879 
~GrGradientEffect()1880 GrGradientEffect::~GrGradientEffect() {
1881     if (this->useAtlas()) {
1882         fAtlas->unlockRow(fRow);
1883     }
1884 }
1885 
onIsEqual(const GrFragmentProcessor & processor) const1886 bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
1887     const GrGradientEffect& ge = processor.cast<GrGradientEffect>();
1888 
1889     if (this->fColorType != ge.getColorType()) {
1890         return false;
1891     }
1892     SkASSERT(this->useAtlas() == ge.useAtlas());
1893     if (kTexture_ColorType == fColorType) {
1894         if (fYCoord != ge.getYCoord()) {
1895             return false;
1896         }
1897     } else {
1898         if (kSingleHardStop_ColorType == fColorType) {
1899             if (!SkScalarNearlyEqual(ge.fPositions[1], fPositions[1])) {
1900                 return false;
1901             }
1902         }
1903         if (this->getPremulType() != ge.getPremulType() ||
1904             this->fColors.count() != ge.fColors.count() ||
1905             this->fColors4f.count() != ge.fColors4f.count()) {
1906             return false;
1907         }
1908 
1909         for (int i = 0; i < this->fColors.count(); i++) {
1910             if (*this->getColors(i) != *ge.getColors(i)) {
1911                 return false;
1912             }
1913         }
1914         for (int i = 0; i < this->fColors4f.count(); i++) {
1915             if (*this->getColors4f(i) != *ge.getColors4f(i)) {
1916                 return false;
1917             }
1918         }
1919     }
1920     return GrColorSpaceXform::Equals(this->fColorSpaceXform.get(), ge.fColorSpaceXform.get());
1921 }
1922 
1923 #if GR_TEST_UTILS
RandomGradientParams(SkRandom * random)1924 GrGradientEffect::RandomGradientParams::RandomGradientParams(SkRandom* random) {
1925     // Set color count to min of 2 so that we don't trigger the const color optimization and make
1926     // a non-gradient processor.
1927     fColorCount = random->nextRangeU(2, kMaxRandomGradientColors);
1928     fUseColors4f = random->nextBool();
1929 
1930     // if one color, omit stops, otherwise randomly decide whether or not to
1931     if (fColorCount == 1 || (fColorCount >= 2 && random->nextBool())) {
1932         fStops = nullptr;
1933     } else {
1934         fStops = fStopStorage;
1935     }
1936 
1937     // if using SkColor4f, attach a random (possibly null) color space (with linear gamma)
1938     if (fUseColors4f) {
1939         fColorSpace = GrTest::TestColorSpace(random);
1940         if (fColorSpace) {
1941             SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(fColorSpace)->type());
1942             fColorSpace = static_cast<SkColorSpace_XYZ*>(fColorSpace.get())->makeLinearGamma();
1943         }
1944     }
1945 
1946     SkScalar stop = 0.f;
1947     for (int i = 0; i < fColorCount; ++i) {
1948         if (fUseColors4f) {
1949             fColors4f[i].fR = random->nextUScalar1();
1950             fColors4f[i].fG = random->nextUScalar1();
1951             fColors4f[i].fB = random->nextUScalar1();
1952             fColors4f[i].fA = random->nextUScalar1();
1953         } else {
1954             fColors[i] = random->nextU();
1955         }
1956         if (fStops) {
1957             fStops[i] = stop;
1958             stop = i < fColorCount - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f;
1959         }
1960     }
1961     fTileMode = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount));
1962 }
1963 #endif
1964 
1965 #endif
1966