Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / src / shaders / gradients / SkGradientShader.cpp
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 "include/core/SkColorSpace.h"
9 #include "include/core/SkMallocPixelRef.h"
10 #include "include/private/SkFloatBits.h"
11 #include "include/private/SkHalf.h"
12 #include "include/private/SkTPin.h"
13 #include "include/private/SkVx.h"
14 #include "src/core/SkColorSpacePriv.h"
15 #include "src/core/SkConvertPixels.h"
16 #include "src/core/SkMatrixProvider.h"
17 #include "src/core/SkReadBuffer.h"
18 #include "src/core/SkVM.h"
19 #include "src/core/SkWriteBuffer.h"
20 #include "src/shaders/gradients/Sk4fLinearGradient.h"
21 #include "src/shaders/gradients/SkGradientShaderPriv.h"
22 #include "src/shaders/gradients/SkLinearGradient.h"
23 #include "src/shaders/gradients/SkRadialGradient.h"
24 #include "src/shaders/gradients/SkSweepGradient.h"
25 #include "src/shaders/gradients/SkTwoPointConicalGradient.h"
26
27 #include <algorithm>
28
29 enum GradientSerializationFlags {
30     // Bits 29:31 used for various boolean flags
31     kHasPosition_GSF    = 0x80000000,
32     kHasLocalMatrix_GSF = 0x40000000,
33     kHasColorSpace_GSF  = 0x20000000,
34
35     // Bits 12:28 unused
36
37     // Bits 8:11 for fTileMode
38     kTileModeShift_GSF  = 8,
39     kTileModeMask_GSF   = 0xF,
40
41     // Bits 0:7 for fGradFlags (note that kForce4fContext_PrivateFlag is 0x80)
42     kGradFlagsShift_GSF = 0,
43     kGradFlagsMask_GSF  = 0xFF,
44 };
45
46 SkGradientShaderBase::Descriptor::Descriptor() {
47     sk_bzero(this, sizeof(*this));
48     fTileMode = SkTileMode::kClamp;
49 }
50 SkGradientShaderBase::Descriptor::~Descriptor() = default;
51
52 void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
53     uint32_t flags = 0;
54     if (fPos) {
55         flags |= kHasPosition_GSF;
56     }
57     if (fLocalMatrix) {
58         flags |= kHasLocalMatrix_GSF;
59     }
60     sk_sp<SkData> colorSpaceData = fColorSpace ? fColorSpace->serialize() : nullptr;
61     if (colorSpaceData) {
62         flags |= kHasColorSpace_GSF;
63     }
64     SkASSERT(static_cast<uint32_t>(fTileMode) <= kTileModeMask_GSF);
65     flags |= ((unsigned)fTileMode << kTileModeShift_GSF);
66     SkASSERT(fGradFlags <= kGradFlagsMask_GSF);
67     flags |= (fGradFlags << kGradFlagsShift_GSF);
68
69     buffer.writeUInt(flags);
70
71     buffer.writeColor4fArray(fColors, fCount);
72     if (colorSpaceData) {
73         buffer.writeDataAsByteArray(colorSpaceData.get());
74     }
75     if (fPos) {
76         buffer.writeScalarArray(fPos, fCount);
77     }
78     if (fLocalMatrix) {
79         buffer.writeMatrix(*fLocalMatrix);
80     }
81 }
82
83 template <int N, typename T, bool MEM_MOVE>
84 static bool validate_array(SkReadBuffer& buffer, size_t count, SkSTArray<N, T, MEM_MOVE>* array) {
85     if (!buffer.validateCanReadN<T>(count)) {
86         return false;
87     }
88
89     array->resize_back(count);
90     return true;
91 }
92
93 bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
94     // New gradient format. Includes floating point color, color space, densely packed flags
95     uint32_t flags = buffer.readUInt();
96
97     fTileMode = (SkTileMode)((flags >> kTileModeShift_GSF) & kTileModeMask_GSF);
98     fGradFlags = (flags >> kGradFlagsShift_GSF) & kGradFlagsMask_GSF;
99
100     fCount = buffer.getArrayCount();
101
102     if (!(validate_array(buffer, fCount, &fColorStorage) &&
103           buffer.readColor4fArray(fColorStorage.begin(), fCount))) {
104         return false;
105     }
106     fColors = fColorStorage.begin();
107
108     if (SkToBool(flags & kHasColorSpace_GSF)) {
109         sk_sp<SkData> data = buffer.readByteArrayAsData();
110         fColorSpace = data ? SkColorSpace::Deserialize(data->data(), data->size()) : nullptr;
111     } else {
112         fColorSpace = nullptr;
113     }
114     if (SkToBool(flags & kHasPosition_GSF)) {
115         if (!(validate_array(buffer, fCount, &fPosStorage) &&
116               buffer.readScalarArray(fPosStorage.begin(), fCount))) {
117             return false;
118         }
119         fPos = fPosStorage.begin();
120     } else {
121         fPos = nullptr;
122     }
123     if (SkToBool(flags & kHasLocalMatrix_GSF)) {
124         fLocalMatrix = &fLocalMatrixStorage;
125         buffer.readMatrix(&fLocalMatrixStorage);
126     } else {
127         fLocalMatrix = nullptr;
128     }
129     return buffer.isValid();
130 }
131
132 ////////////////////////////////////////////////////////////////////////////////////////////
133
134 SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit)
135     : INHERITED(desc.fLocalMatrix)
136     , fPtsToUnit(ptsToUnit)
137     , fColorSpace(desc.fColorSpace ? desc.fColorSpace : SkColorSpace::MakeSRGB())
138     , fColorsAreOpaque(true)
139 {
140     fPtsToUnit.getType();  // Precache so reads are threadsafe.
141     SkASSERT(desc.fCount > 1);
142
143     fGradFlags = static_cast<uint8_t>(desc.fGradFlags);
144
145     SkASSERT((unsigned)desc.fTileMode < kSkTileModeCount);
146     fTileMode = desc.fTileMode;
147
148     /*  Note: we let the caller skip the first and/or last position.
149         i.e. pos[0] = 0.3, pos[1] = 0.7
150         In these cases, we insert entries to ensure that the final data
151         will be bracketed by [0, 1].
152         i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
153
154         Thus colorCount (the caller's value, and fColorCount (our value) may
155         differ by up to 2. In the above example:
156             colorCount = 2
157             fColorCount = 4
158      */
159     fColorCount = desc.fCount;
160     // check if we need to add in start and/or end position/colors
161     bool needsFirst = false;
162     bool needsLast = false;
163     if (desc.fPos) {
164         needsFirst = desc.fPos[0] != 0;
165         needsLast = desc.fPos[desc.fCount - 1] != SK_Scalar1;
166         fColorCount += needsFirst + needsLast;
167     }
168
169     size_t storageSize = fColorCount * (sizeof(SkColor4f) + (desc.fPos ? sizeof(SkScalar) : 0));
170     fOrigColors4f      = reinterpret_cast<SkColor4f*>(fStorage.reset(storageSize));
171     fOrigPos           = desc.fPos ? reinterpret_cast<SkScalar*>(fOrigColors4f + fColorCount)
172                                    : nullptr;
173
174     // Now copy over the colors, adding the dummies as needed
175     SkColor4f* origColors = fOrigColors4f;
176     if (needsFirst) {
177         *origColors++ = desc.fColors[0];
178     }
179     for (int i = 0; i < desc.fCount; ++i) {
180         origColors[i] = desc.fColors[i];
181         fColorsAreOpaque = fColorsAreOpaque && (desc.fColors[i].fA == 1);
182     }
183     if (needsLast) {
184         origColors += desc.fCount;
185         *origColors = desc.fColors[desc.fCount - 1];
186     }
187
188     if (desc.fPos) {
189         SkScalar prev = 0;
190         SkScalar* origPosPtr = fOrigPos;
191         *origPosPtr++ = prev; // force the first pos to 0
192
193         int startIndex = needsFirst ? 0 : 1;
194         int count = desc.fCount + needsLast;
195
196         bool uniformStops = true;
197         const SkScalar uniformStep = desc.fPos[startIndex] - prev;
198         for (int i = startIndex; i < count; i++) {
199             // Pin the last value to 1.0, and make sure pos is monotonic.
200             auto curr = (i == desc.fCount) ? 1 : SkTPin(desc.fPos[i], prev, 1.0f);
201             uniformStops &= SkScalarNearlyEqual(uniformStep, curr - prev);
202
203             *origPosPtr++ = prev = curr;
204         }
205
206         // If the stops are uniform, treat them as implicit.
207         if (uniformStops) {
208             fOrigPos = nullptr;
209         }
210     }
211 }
212
213 SkGradientShaderBase::~SkGradientShaderBase() {}
214
215 void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
216     Descriptor desc;
217     desc.fColors = fOrigColors4f;
218     desc.fColorSpace = fColorSpace;
219     desc.fPos = fOrigPos;
220     desc.fCount = fColorCount;
221     desc.fTileMode = fTileMode;
222     desc.fGradFlags = fGradFlags;
223
224     const SkMatrix& m = this->getLocalMatrix();
225     desc.fLocalMatrix = m.isIdentity() ? nullptr : &m;
226     desc.flatten(buffer);
227 }
228
229 static void add_stop_color(SkRasterPipeline_GradientCtx* ctx, size_t stop, SkPMColor4f Fs, SkPMColor4f Bs) {
230     (ctx->fs[0])[stop] = Fs.fR;
231     (ctx->fs[1])[stop] = Fs.fG;
232     (ctx->fs[2])[stop] = Fs.fB;
233     (ctx->fs[3])[stop] = Fs.fA;
234
235     (ctx->bs[0])[stop] = Bs.fR;
236     (ctx->bs[1])[stop] = Bs.fG;
237     (ctx->bs[2])[stop] = Bs.fB;
238     (ctx->bs[3])[stop] = Bs.fA;
239 }
240
241 static void add_const_color(SkRasterPipeline_GradientCtx* ctx, size_t stop, SkPMColor4f color) {
242     add_stop_color(ctx, stop, { 0, 0, 0, 0 }, color);
243 }
244
245 // Calculate a factor F and a bias B so that color = F*t + B when t is in range of
246 // the stop. Assume that the distance between stops is 1/gapCount.
247 static void init_stop_evenly(
248     SkRasterPipeline_GradientCtx* ctx, float gapCount, size_t stop, SkPMColor4f c_l, SkPMColor4f c_r) {
249     // Clankium's GCC 4.9 targeting ARMv7 is barfing when we use Sk4f math here, so go scalar...
250     SkPMColor4f Fs = {
251         (c_r.fR - c_l.fR) * gapCount,
252         (c_r.fG - c_l.fG) * gapCount,
253         (c_r.fB - c_l.fB) * gapCount,
254         (c_r.fA - c_l.fA) * gapCount,
255     };
256     SkPMColor4f Bs = {
257         c_l.fR - Fs.fR*(stop/gapCount),
258         c_l.fG - Fs.fG*(stop/gapCount),
259         c_l.fB - Fs.fB*(stop/gapCount),
260         c_l.fA - Fs.fA*(stop/gapCount),
261     };
262     add_stop_color(ctx, stop, Fs, Bs);
263 }
264
265 // For each stop we calculate a bias B and a scale factor F, such that
266 // for any t between stops n and n+1, the color we want is B[n] + F[n]*t.
267 static void init_stop_pos(
268     SkRasterPipeline_GradientCtx* ctx, size_t stop, float t_l, float t_r, SkPMColor4f c_l, SkPMColor4f c_r) {
269     // See note about Clankium's old compiler in init_stop_evenly().
270     SkPMColor4f Fs = {
271         (c_r.fR - c_l.fR) / (t_r - t_l),
272         (c_r.fG - c_l.fG) / (t_r - t_l),
273         (c_r.fB - c_l.fB) / (t_r - t_l),
274         (c_r.fA - c_l.fA) / (t_r - t_l),
275     };
276     SkPMColor4f Bs = {
277         c_l.fR - Fs.fR*t_l,
278         c_l.fG - Fs.fG*t_l,
279         c_l.fB - Fs.fB*t_l,
280         c_l.fA - Fs.fA*t_l,
281     };
282     ctx->ts[stop] = t_l;
283     add_stop_color(ctx, stop, Fs, Bs);
284 }
285
286 bool SkGradientShaderBase::onAppendStages(const SkStageRec& rec) const {
287     SkRasterPipeline* p = rec.fPipeline;
288     SkArenaAlloc* alloc = rec.fAlloc;
289     SkRasterPipeline_DecalTileCtx* decal_ctx = nullptr;
290
291     SkMatrix matrix;
292     if (!this->computeTotalInverse(rec.fMatrixProvider.localToDevice(), rec.fLocalM, &matrix)) {
293         return false;
294     }
295     matrix.postConcat(fPtsToUnit);
296
297     SkRasterPipeline_<256> postPipeline;
298
299     p->append(SkRasterPipeline::seed_shader);
300     p->append_matrix(alloc, matrix);
301     this->appendGradientStages(alloc, p, &postPipeline);
302
303     switch(fTileMode) {
304         case SkTileMode::kMirror: p->append(SkRasterPipeline::mirror_x_1); break;
305         case SkTileMode::kRepeat: p->append(SkRasterPipeline::repeat_x_1); break;
306         case SkTileMode::kDecal:
307             decal_ctx = alloc->make<SkRasterPipeline_DecalTileCtx>();
308             decal_ctx->limit_x = SkBits2Float(SkFloat2Bits(1.0f) + 1);
309             // reuse mask + limit_x stage, or create a custom decal_1 that just stores the mask
310             p->append(SkRasterPipeline::decal_x, decal_ctx);
311             [[fallthrough]];
312
313         case SkTileMode::kClamp:
314             if (!fOrigPos) {
315                 // We clamp only when the stops are evenly spaced.
316                 // If not, there may be hard stops, and clamping ruins hard stops at 0 and/or 1.
317                 // In that case, we must make sure we're using the general "gradient" stage,
318                 // which is the only stage that will correctly handle unclamped t.
319                 p->append(SkRasterPipeline::clamp_x_1);
320             }
321             break;
322     }
323
324     const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag;
325
326     // Transform all of the colors to destination color space
327     SkColor4fXformer xformedColors(fOrigColors4f, fColorCount, fColorSpace.get(), rec.fDstCS);
328
329     auto prepareColor = [premulGrad, &xformedColors](int i) {
330         SkColor4f c = xformedColors.fColors[i];
331         return premulGrad ? c.premul()
332                           : SkPMColor4f{ c.fR, c.fG, c.fB, c.fA };
333     };
334
335     // The two-stop case with stops at 0 and 1.
336     if (fColorCount == 2 && fOrigPos == nullptr) {
337         const SkPMColor4f c_l = prepareColor(0),
338                           c_r = prepareColor(1);
339
340         // See F and B below.
341         auto ctx = alloc->make<SkRasterPipeline_EvenlySpaced2StopGradientCtx>();
342         (skvx::float4::Load(c_r.vec()) - skvx::float4::Load(c_l.vec())).store(ctx->f);
343         (                                skvx::float4::Load(c_l.vec())).store(ctx->b);
344         ctx->interpolatedInPremul = premulGrad;
345
346         p->append(SkRasterPipeline::evenly_spaced_2_stop_gradient, ctx);
347     } else {
348         auto* ctx = alloc->make<SkRasterPipeline_GradientCtx>();
349         ctx->interpolatedInPremul = premulGrad;
350
351         // Note: In order to handle clamps in search, the search assumes a stop conceptully placed
352         // at -inf. Therefore, the max number of stops is fColorCount+1.
353         for (int i = 0; i < 4; i++) {
354             // Allocate at least at for the AVX2 gather from a YMM register.
355             ctx->fs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
356             ctx->bs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
357         }
358
359         if (fOrigPos == nullptr) {
360             // Handle evenly distributed stops.
361
362             size_t stopCount = fColorCount;
363             float gapCount = stopCount - 1;
364
365             SkPMColor4f c_l = prepareColor(0);
366             for (size_t i = 0; i < stopCount - 1; i++) {
367                 SkPMColor4f c_r = prepareColor(i + 1);
368                 init_stop_evenly(ctx, gapCount, i, c_l, c_r);
369                 c_l = c_r;
370             }
371             add_const_color(ctx, stopCount - 1, c_l);
372
373             ctx->stopCount = stopCount;
374             p->append(SkRasterPipeline::evenly_spaced_gradient, ctx);
375         } else {
376             // Handle arbitrary stops.
377
378             ctx->ts = alloc->makeArray<float>(fColorCount+1);
379
380             // Remove the default stops inserted by SkGradientShaderBase::SkGradientShaderBase
381             // because they are naturally handled by the search method.
382             int firstStop;
383             int lastStop;
384             if (fColorCount > 2) {
385                 firstStop = fOrigColors4f[0] != fOrigColors4f[1] ? 0 : 1;
386                 lastStop = fOrigColors4f[fColorCount - 2] != fOrigColors4f[fColorCount - 1]
387                            ? fColorCount - 1 : fColorCount - 2;
388             } else {
389                 firstStop = 0;
390                 lastStop = 1;
391             }
392
393             size_t stopCount = 0;
394             float  t_l = fOrigPos[firstStop];
395             SkPMColor4f c_l = prepareColor(firstStop);
396             add_const_color(ctx, stopCount++, c_l);
397             // N.B. lastStop is the index of the last stop, not one after.
398             for (int i = firstStop; i < lastStop; i++) {
399                 float  t_r = fOrigPos[i + 1];
400                 SkPMColor4f c_r = prepareColor(i + 1);
401                 SkASSERT(t_l <= t_r);
402                 if (t_l < t_r) {
403                     init_stop_pos(ctx, stopCount, t_l, t_r, c_l, c_r);
404                     stopCount += 1;
405                 }
406                 t_l = t_r;
407                 c_l = c_r;
408             }
409
410             ctx->ts[stopCount] = t_l;
411             add_const_color(ctx, stopCount++, c_l);
412
413             ctx->stopCount = stopCount;
414             p->append(SkRasterPipeline::gradient, ctx);
415         }
416     }
417
418     if (decal_ctx) {
419         p->append(SkRasterPipeline::check_decal_mask, decal_ctx);
420     }
421
422     if (!premulGrad && !this->colorsAreOpaque()) {
423         p->append(SkRasterPipeline::premul);
424     }
425
426     p->extend(postPipeline);
427
428     return true;
429 }
430
431 skvm::Color SkGradientShaderBase::onProgram(skvm::Builder* p,
432                                             skvm::Coord device, skvm::Coord local,
433                                             skvm::Color /*paint*/,
434                                             const SkMatrixProvider& mats, const SkMatrix* localM,
435                                             const SkColorInfo& dstInfo,
436                                             skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
437     SkMatrix inv;
438     if (!this->computeTotalInverse(mats.localToDevice(), localM, &inv)) {
439         return {};
440     }
441     inv.postConcat(fPtsToUnit);
442     inv.normalizePerspective();
443
444     local = SkShaderBase::ApplyMatrix(p, inv, local, uniforms);
445
446     skvm::I32 mask = p->splat(~0);
447     skvm::F32 t = this->transformT(p,uniforms, local, &mask);
448
449     // Perhaps unexpectedly, clamping is handled naturally by our search, so we
450     // don't explicitly clamp t to [0,1].  That clamp would break hard stops
451     // right at 0 or 1 boundaries in kClamp mode.  (kRepeat and kMirror always
452     // produce values in [0,1].)
453     switch(fTileMode) {
454         case SkTileMode::kClamp:
455             break;
456
457         case SkTileMode::kDecal:
458             mask &= (t == clamp01(t));
459             break;
460
461         case SkTileMode::kRepeat:
462             t = fract(t);
463             break;
464
465         case SkTileMode::kMirror: {
466             // t = | (t-1) - 2*(floor( (t-1)*0.5 )) - 1 |
467             //       {-A-}      {--------B-------}
468             skvm::F32 A = t - 1.0f,
469                       B = floor(A * 0.5f);
470             t = abs(A - (B + B) - 1.0f);
471         } break;
472     }
473
474     // Transform our colors as we want them interpolated, in dst color space, possibly premul.
475     SkImageInfo common = SkImageInfo::Make(fColorCount,1, kRGBA_F32_SkColorType
476                                                         , kUnpremul_SkAlphaType),
477                 src    = common.makeColorSpace(fColorSpace),
478                 dst    = common.makeColorSpace(dstInfo.refColorSpace());
479     if (fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag) {
480         dst = dst.makeAlphaType(kPremul_SkAlphaType);
481     }
482
483     std::vector<float> rgba(4*fColorCount);  // TODO: SkSTArray?
484     SkAssertResult(SkConvertPixels(dst,   rgba.data(), dst.minRowBytes(),
485                                    src, fOrigColors4f, src.minRowBytes()));
486
487     // Transform our colors into a scale factor f and bias b such that for
488     // any t between stops i and i+1, the color we want is mad(t, f[i], b[i]).
489     using F4 = skvx::Vec<4,float>;
490     struct FB { F4 f,b; };
491     skvm::Color color;
492
493     auto uniformF = [&](float x) { return p->uniformF(uniforms->pushF(x)); };
494
495     if (fColorCount == 2) {
496         // 2-stop gradients have colors at 0 and 1, and so must be evenly spaced.
497         SkASSERT(fOrigPos == nullptr);
498
499         // With 2 stops, we upload the single FB as uniforms and interpolate directly with t.
500         F4 lo = F4::Load(rgba.data() + 0),
501            hi = F4::Load(rgba.data() + 4);
502         F4 F = hi - lo,
503            B = lo;
504
505         auto T = clamp01(t);
506         color = {
507             T * uniformF(F[0]) + uniformF(B[0]),
508             T * uniformF(F[1]) + uniformF(B[1]),
509             T * uniformF(F[2]) + uniformF(B[2]),
510             T * uniformF(F[3]) + uniformF(B[3]),
511         };
512     } else {
513         // To handle clamps in search we add a conceptual stop at t=-inf, so we
514         // may need up to fColorCount+1 FBs and fColorCount t stops between them:
515         //
516         //   FBs:         [color 0]  [color 0->1]  [color 1->2]  [color 2->3]  ...
517         //   stops:  (-inf)        t0            t1            t2  ...
518         //
519         // Both these arrays could end up shorter if any hard stops share the same t.
520         FB* fb = alloc->makeArrayDefault<FB>(fColorCount+1);
521         std::vector<float> stops;  // TODO: SkSTArray?
522         stops.reserve(fColorCount);
523
524         // Here's our conceptual stop at t=-inf covering all t<=0, clamping to our first color.
525         float  t_lo = this->getPos(0);
526         F4 color_lo = F4::Load(rgba.data());
527         fb[0] = { 0.0f, color_lo };
528         // N.B. No stops[] entry for this implicit -inf.
529
530         // Now the non-edge cases, calculating scale and bias between adjacent normal stops.
531         for (int i = 1; i < fColorCount; i++) {
532             float  t_hi = this->getPos(i);
533             F4 color_hi = F4::Load(rgba.data() + 4*i);
534
535             // If t_lo == t_hi, we're on a hard stop, and transition immediately to the next color.
536             SkASSERT(t_lo <= t_hi);
537             if (t_lo < t_hi) {
538                 F4 f = (color_hi - color_lo) / (t_hi - t_lo),
539                    b = color_lo - f*t_lo;
540                 stops.push_back(t_lo);
541                 fb[stops.size()] = {f,b};
542             }
543
544             t_lo = t_hi;
545             color_lo = color_hi;
546         }
547         // Anything >= our final t clamps to our final color.
548         stops.push_back(t_lo);
549         fb[stops.size()] = { 0.0f, color_lo };
550
551         // We'll gather FBs from that array we just created.
552         skvm::Uniform fbs = uniforms->pushPtr(fb);
553
554         // Find the two stops we need to interpolate.
555         skvm::I32 ix;
556         if (fOrigPos == nullptr) {
557             // Evenly spaced stops... we can calculate ix directly.
558             // Of note: we need to clamp t and skip over that conceptual -inf stop we made up.
559             ix = trunc(clamp01(t) * uniformF(stops.size() - 1) + 1.0f);
560         } else {
561             // Starting ix at 0 bakes in our conceptual first stop at -inf.
562             // TODO: good place to experiment with a loop in skvm.... stops.size() can be huge.
563             ix = p->splat(0);
564             for (float stop : stops) {
565                 // ix += (t >= stop) ? +1 : 0 ~~>
566                 // ix -= (t >= stop) ? -1 : 0
567                 ix -= (t >= uniformF(stop));
568             }
569             // TODO: we could skip any of the default stops GradientShaderBase's ctor added
570             // to ensure the full [0,1] span is covered.  This linear search doesn't need
571             // them for correctness, and it'd be up to two fewer stops to check.
572             // N.B. we do still need those stops for the fOrigPos == nullptr direct math path.
573         }
574
575         // A scale factor and bias for each lane, 8 total.
576         // TODO: simpler, faster, tidier to push 8 uniform pointers, one for each struct lane?
577         ix = shl(ix, 3);
578         skvm::F32 Fr = gatherF(fbs, ix + 0);
579         skvm::F32 Fg = gatherF(fbs, ix + 1);
580         skvm::F32 Fb = gatherF(fbs, ix + 2);
581         skvm::F32 Fa = gatherF(fbs, ix + 3);
582
583         skvm::F32 Br = gatherF(fbs, ix + 4);
584         skvm::F32 Bg = gatherF(fbs, ix + 5);
585         skvm::F32 Bb = gatherF(fbs, ix + 6);
586         skvm::F32 Ba = gatherF(fbs, ix + 7);
587
588         // This is what we've been building towards!
589         color = {
590             t * Fr + Br,
591             t * Fg + Bg,
592             t * Fb + Bb,
593             t * Fa + Ba,
594         };
595     }
596
597     // If we interpolated unpremul, premul now to match our output convention.
598     if (0 == (fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag)
599             && !fColorsAreOpaque) {
600         color = premul(color);
601     }
602
603     return {
604         pun_to_F32(mask & pun_to_I32(color.r)),
605         pun_to_F32(mask & pun_to_I32(color.g)),
606         pun_to_F32(mask & pun_to_I32(color.b)),
607         pun_to_F32(mask & pun_to_I32(color.a)),
608     };
609 }
610
611
612 bool SkGradientShaderBase::isOpaque() const {
613     return fColorsAreOpaque && (this->getTileMode() != SkTileMode::kDecal);
614 }
615
616 static unsigned rounded_divide(unsigned numer, unsigned denom) {
617     return (numer + (denom >> 1)) / denom;
618 }
619
620 bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const {
621     // we just compute an average color.
622     // possibly we could weight this based on the proportional width for each color
623     //   assuming they are not evenly distributed in the fPos array.
624     int r = 0;
625     int g = 0;
626     int b = 0;
627     const int n = fColorCount;
628     // TODO: use linear colors?
629     for (int i = 0; i < n; ++i) {
630         SkColor c = this->getLegacyColor(i);
631         r += SkColorGetR(c);
632         g += SkColorGetG(c);
633         b += SkColorGetB(c);
634     }
635     *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n));
636     return true;
637 }
638
639 SkColor4fXformer::SkColor4fXformer(const SkColor4f* colors, int colorCount,
640                                    SkColorSpace* src, SkColorSpace* dst) {
641     fColors = colors;
642
643     if (dst && !SkColorSpace::Equals(src, dst)) {
644         fStorage.reset(colorCount);
645
646         auto info = SkImageInfo::Make(colorCount,1, kRGBA_F32_SkColorType, kUnpremul_SkAlphaType);
647
648         auto dstInfo = info.makeColorSpace(sk_ref_sp(dst));
649         auto srcInfo = info.makeColorSpace(sk_ref_sp(src));
650         SkAssertResult(SkConvertPixels(dstInfo, fStorage.begin(), info.minRowBytes(),
651                                        srcInfo, fColors         , info.minRowBytes()));
652
653         fColors = fStorage.begin();
654     }
655 }
656
657 void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const {
658     if (info) {
659         if (info->fColorCount >= fColorCount) {
660             if (info->fColors) {
661                 for (int i = 0; i < fColorCount; ++i) {
662                     info->fColors[i] = this->getLegacyColor(i);
663                 }
664             }
665             if (info->fColorOffsets) {
666                 for (int i = 0; i < fColorCount; ++i) {
667                     info->fColorOffsets[i] = this->getPos(i);
668                 }
669             }
670         }
671         info->fColorCount = fColorCount;
672         info->fTileMode = fTileMode;
673         info->fGradientFlags = fGradFlags;
674     }
675 }
676
677 ///////////////////////////////////////////////////////////////////////////////
678 ///////////////////////////////////////////////////////////////////////////////
679
680 // Return true if these parameters are valid/legal/safe to construct a gradient
681 //
682 static bool valid_grad(const SkColor4f colors[], const SkScalar pos[], int count,
683                        SkTileMode tileMode) {
684     return nullptr != colors && count >= 1 && (unsigned)tileMode < kSkTileModeCount;
685 }
686
687 static void desc_init(SkGradientShaderBase::Descriptor* desc,
688                       const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
689                       const SkScalar pos[], int colorCount,
690                       SkTileMode mode, uint32_t flags, const SkMatrix* localMatrix) {
691     SkASSERT(colorCount > 1);
692
693     desc->fColors       = colors;
694     desc->fColorSpace   = std::move(colorSpace);
695     desc->fPos          = pos;
696     desc->fCount        = colorCount;
697     desc->fTileMode     = mode;
698     desc->fGradFlags    = flags;
699     desc->fLocalMatrix  = localMatrix;
700 }
701
702 static SkColor4f average_gradient_color(const SkColor4f colors[], const SkScalar pos[],
703                                         int colorCount) {
704     // The gradient is a piecewise linear interpolation between colors. For a given interval,
705     // the integral between the two endpoints is 0.5 * (ci + cj) * (pj - pi), which provides that
706     // intervals average color. The overall average color is thus the sum of each piece. The thing
707     // to keep in mind is that the provided gradient definition may implicitly use p=0 and p=1.
708     skvx::float4 blend(0.0f);
709     for (int i = 0; i < colorCount - 1; ++i) {
710         // Calculate the average color for the interval between pos(i) and pos(i+1)
711         auto c0 = skvx::float4::Load(&colors[i]);
712         auto c1 = skvx::float4::Load(&colors[i + 1]);
713
714         // when pos == null, there are colorCount uniformly distributed stops, going from 0 to 1,
715         // so pos[i + 1] - pos[i] = 1/(colorCount-1)
716         SkScalar w;
717         if (pos) {
718             // Match position fixing in SkGradientShader's constructor, clamping positions outside
719             // [0, 1] and forcing the sequence to be monotonic
720             SkScalar p0 = SkTPin(pos[i], 0.f, 1.f);
721             SkScalar p1 = SkTPin(pos[i + 1], p0, 1.f);
722             w = p1 - p0;
723
724             // And account for any implicit intervals at the start or end of the positions
725             if (i == 0) {
726                 if (p0 > 0.0f) {
727                     // The first color is fixed between p = 0 to pos[0], so 0.5*(ci + cj)*(pj - pi)
728                     // becomes 0.5*(c + c)*(pj - 0) = c * pj
729                     auto c = skvx::float4::Load(&colors[0]);
730                     blend += p0 * c;
731                 }
732             }
733             if (i == colorCount - 2) {
734                 if (p1 < 1.f) {
735                     // The last color is fixed between pos[n-1] to p = 1, so 0.5*(ci + cj)*(pj - pi)
736                     // becomes 0.5*(c + c)*(1 - pi) = c * (1 - pi)
737                     auto c = skvx::float4::Load(&colors[colorCount - 1]);
738                     blend += (1.f - p1) * c;
739                 }
740             }
741         } else {
742             w = 1.f / (colorCount - 1);
743         }
744
745         blend += 0.5f * w * (c1 + c0);
746     }
747
748     SkColor4f avg;
749     blend.store(&avg);
750     return avg;
751 }
752
753 // The default SkScalarNearlyZero threshold of .0024 is too big and causes regressions for svg
754 // gradients defined in the wild.
755 static constexpr SkScalar kDegenerateThreshold = SK_Scalar1 / (1 << 15);
756
757 // Except for special circumstances of clamped gradients, every gradient shape--when degenerate--
758 // can be mapped to the same fallbacks. The specific shape factories must account for special
759 // clamped conditions separately, this will always return the last color for clamped gradients.
760 static sk_sp<SkShader> make_degenerate_gradient(const SkColor4f colors[], const SkScalar pos[],
761                                                 int colorCount, sk_sp<SkColorSpace> colorSpace,
762                                                 SkTileMode mode) {
763     switch(mode) {
764         case SkTileMode::kDecal:
765             // normally this would reject the area outside of the interpolation region, so since
766             // inside region is empty when the radii are equal, the entire draw region is empty
767             return SkShaders::Empty();
768         case SkTileMode::kRepeat:
769         case SkTileMode::kMirror:
770             // repeat and mirror are treated the same: the border colors are never visible,
771             // but approximate the final color as infinite repetitions of the colors, so
772             // it can be represented as the average color of the gradient.
773             return SkShaders::Color(
774                     average_gradient_color(colors, pos, colorCount), std::move(colorSpace));
775         case SkTileMode::kClamp:
776             // Depending on how the gradient shape degenerates, there may be a more specialized
777             // fallback representation for the factories to use, but this is a reasonable default.
778             return SkShaders::Color(colors[colorCount - 1], std::move(colorSpace));
779     }
780     SkDEBUGFAIL("Should not be reached");
781     return nullptr;
782 }
783
784 // assumes colors is SkColor4f* and pos is SkScalar*
785 #define EXPAND_1_COLOR(count)                \
786      SkColor4f tmp[2];                       \
787      do {                                    \
788          if (1 == count) {                   \
789              tmp[0] = tmp[1] = colors[0];    \
790              colors = tmp;                   \
791              pos = nullptr;                  \
792              count = 2;                      \
793          }                                   \
794      } while (0)
795
796 struct ColorStopOptimizer {
797     ColorStopOptimizer(const SkColor4f* colors, const SkScalar* pos, int count, SkTileMode mode)
798         : fColors(colors)
799         , fPos(pos)
800         , fCount(count) {
801
802             if (!pos || count != 3) {
803                 return;
804             }
805
806             if (SkScalarNearlyEqual(pos[0], 0.0f) &&
807                 SkScalarNearlyEqual(pos[1], 0.0f) &&
808                 SkScalarNearlyEqual(pos[2], 1.0f)) {
809
810                 if (SkTileMode::kRepeat == mode || SkTileMode::kMirror == mode ||
811                     colors[0] == colors[1]) {
812
813                     // Ignore the leftmost color/pos.
814                     fColors += 1;
815                     fPos    += 1;
816                     fCount   = 2;
817                 }
818             } else if (SkScalarNearlyEqual(pos[0], 0.0f) &&
819                        SkScalarNearlyEqual(pos[1], 1.0f) &&
820                        SkScalarNearlyEqual(pos[2], 1.0f)) {
821
822                 if (SkTileMode::kRepeat == mode || SkTileMode::kMirror == mode ||
823                     colors[1] == colors[2]) {
824
825                     // Ignore the rightmost color/pos.
826                     fCount  = 2;
827                 }
828             }
829     }
830
831     const SkColor4f* fColors;
832     const SkScalar*  fPos;
833     int              fCount;
834 };
835
836 struct ColorConverter {
837     ColorConverter(const SkColor* colors, int count) {
838         const float ONE_OVER_255 = 1.f / 255;
839         for (int i = 0; i < count; ++i) {
840             fColors4f.push_back({
841                 SkColorGetR(colors[i]) * ONE_OVER_255,
842                 SkColorGetG(colors[i]) * ONE_OVER_255,
843                 SkColorGetB(colors[i]) * ONE_OVER_255,
844                 SkColorGetA(colors[i]) * ONE_OVER_255 });
845         }
846     }
847
848     SkSTArray<2, SkColor4f, true> fColors4f;
849 };
850
851 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
852                                              const SkColor colors[],
853                                              const SkScalar pos[], int colorCount,
854                                              SkTileMode mode,
855                                              uint32_t flags,
856                                              const SkMatrix* localMatrix) {
857     ColorConverter converter(colors, colorCount);
858     return MakeLinear(pts, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, flags,
859                       localMatrix);
860 }
861
862 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
863                                              const SkColor4f colors[],
864                                              sk_sp<SkColorSpace> colorSpace,
865                                              const SkScalar pos[], int count, SkTileMode mode) {
866     return MakeLinear(pts, colors, std::move(colorSpace), pos, count, mode, 0, nullptr);
867 }
868
869 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
870                                              const SkColor4f colors[],
871                                              sk_sp<SkColorSpace> colorSpace,
872                                              const SkScalar pos[], int colorCount,
873                                              SkTileMode mode,
874                                              uint32_t flags,
875                                              const SkMatrix* localMatrix) {
876     if (!pts || !SkScalarIsFinite((pts[1] - pts[0]).length())) {
877         return nullptr;
878     }
879     if (!valid_grad(colors, pos, colorCount, mode)) {
880         return nullptr;
881     }
882     if (1 == colorCount) {
883         return SkShaders::Color(colors[0], std::move(colorSpace));
884     }
885     if (localMatrix && !localMatrix->invert(nullptr)) {
886         return nullptr;
887     }
888
889     if (SkScalarNearlyZero((pts[1] - pts[0]).length(), kDegenerateThreshold)) {
890         // Degenerate gradient, the only tricky complication is when in clamp mode, the limit of
891         // the gradient approaches two half planes of solid color (first and last). However, they
892         // are divided by the line perpendicular to the start and end point, which becomes undefined
893         // once start and end are exactly the same, so just use the end color for a stable solution.
894         return make_degenerate_gradient(colors, pos, colorCount, std::move(colorSpace), mode);
895     }
896
897     ColorStopOptimizer opt(colors, pos, colorCount, mode);
898
899     SkGradientShaderBase::Descriptor desc;
900     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
901               localMatrix);
902     return sk_make_sp<SkLinearGradient>(pts, desc);
903 }
904
905 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
906                                              const SkColor colors[],
907                                              const SkScalar pos[], int colorCount,
908                                              SkTileMode mode,
909                                              uint32_t flags,
910                                              const SkMatrix* localMatrix) {
911     ColorConverter converter(colors, colorCount);
912     return MakeRadial(center, radius, converter.fColors4f.begin(), nullptr, pos, colorCount, mode,
913                       flags, localMatrix);
914 }
915
916 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
917                                              const SkColor4f colors[],
918                                              sk_sp<SkColorSpace> colorSpace,
919                                              const SkScalar pos[], int count, SkTileMode mode) {
920     return MakeRadial(center, radius, colors, std::move(colorSpace), pos, count, mode, 0, nullptr);
921 }
922
923 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
924                                              const SkColor4f colors[],
925                                              sk_sp<SkColorSpace> colorSpace,
926                                              const SkScalar pos[], int colorCount,
927                                              SkTileMode mode,
928                                              uint32_t flags,
929                                              const SkMatrix* localMatrix) {
930     if (radius < 0) {
931         return nullptr;
932     }
933     if (!valid_grad(colors, pos, colorCount, mode)) {
934         return nullptr;
935     }
936     if (1 == colorCount) {
937         return SkShaders::Color(colors[0], std::move(colorSpace));
938     }
939     if (localMatrix && !localMatrix->invert(nullptr)) {
940         return nullptr;
941     }
942
943     if (SkScalarNearlyZero(radius, kDegenerateThreshold)) {
944         // Degenerate gradient optimization, and no special logic needed for clamped radial gradient
945         return make_degenerate_gradient(colors, pos, colorCount, std::move(colorSpace), mode);
946     }
947
948     ColorStopOptimizer opt(colors, pos, colorCount, mode);
949
950     SkGradientShaderBase::Descriptor desc;
951     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
952               localMatrix);
953     return sk_make_sp<SkRadialGradient>(center, radius, desc);
954 }
955
956 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
957                                                       SkScalar startRadius,
958                                                       const SkPoint& end,
959                                                       SkScalar endRadius,
960                                                       const SkColor colors[],
961                                                       const SkScalar pos[],
962                                                       int colorCount,
963                                                       SkTileMode mode,
964                                                       uint32_t flags,
965                                                       const SkMatrix* localMatrix) {
966     ColorConverter converter(colors, colorCount);
967     return MakeTwoPointConical(start, startRadius, end, endRadius, converter.fColors4f.begin(),
968                                nullptr, pos, colorCount, mode, flags, localMatrix);
969 }
970
971 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
972                                                       SkScalar startRadius,
973                                                       const SkPoint& end,
974                                                       SkScalar endRadius,
975                                                       const SkColor4f colors[],
976                                                       sk_sp<SkColorSpace> colorSpace,
977                                                       const SkScalar pos[],
978                                                       int count, SkTileMode mode) {
979     return MakeTwoPointConical(start, startRadius, end, endRadius, colors,
980                                std::move(colorSpace), pos, count, mode, 0, nullptr);
981 }
982
983 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
984                                                       SkScalar startRadius,
985                                                       const SkPoint& end,
986                                                       SkScalar endRadius,
987                                                       const SkColor4f colors[],
988                                                       sk_sp<SkColorSpace> colorSpace,
989                                                       const SkScalar pos[],
990                                                       int colorCount,
991                                                       SkTileMode mode,
992                                                       uint32_t flags,
993                                                       const SkMatrix* localMatrix) {
994     if (startRadius < 0 || endRadius < 0) {
995         return nullptr;
996     }
997     if (!valid_grad(colors, pos, colorCount, mode)) {
998         return nullptr;
999     }
1000     if (SkScalarNearlyZero((start - end).length(), kDegenerateThreshold)) {
1001         // If the center positions are the same, then the gradient is the radial variant of a 2 pt
1002         // conical gradient, an actual radial gradient (startRadius == 0), or it is fully degenerate
1003         // (startRadius == endRadius).
1004         if (SkScalarNearlyEqual(startRadius, endRadius, kDegenerateThreshold)) {
1005             // Degenerate case, where the interpolation region area approaches zero. The proper
1006             // behavior depends on the tile mode, which is consistent with the default degenerate
1007             // gradient behavior, except when mode = clamp and the radii > 0.
1008             if (mode == SkTileMode::kClamp && endRadius > kDegenerateThreshold) {
1009                 // The interpolation region becomes an infinitely thin ring at the radius, so the
1010                 // final gradient will be the first color repeated from p=0 to 1, and then a hard
1011                 // stop switching to the last color at p=1.
1012                 static constexpr SkScalar circlePos[3] = {0, 1, 1};
1013                 SkColor4f reColors[3] = {colors[0], colors[0], colors[colorCount - 1]};
1014                 return MakeRadial(start, endRadius, reColors, std::move(colorSpace),
1015                                   circlePos, 3, mode, flags, localMatrix);
1016             } else {
1017                 // Otherwise use the default degenerate case
1018                 return make_degenerate_gradient(
1019                         colors, pos, colorCount, std::move(colorSpace), mode);
1020             }
1021         } else if (SkScalarNearlyZero(startRadius, kDegenerateThreshold)) {
1022             // We can treat this gradient as radial, which is faster. If we got here, we know
1023             // that endRadius is not equal to 0, so this produces a meaningful gradient
1024             return MakeRadial(start, endRadius, colors, std::move(colorSpace), pos, colorCount,
1025                               mode, flags, localMatrix);
1026         }
1027         // Else it's the 2pt conical radial variant with no degenerate radii, so fall through to the
1028         // regular 2pt constructor.
1029     }
1030
1031     if (localMatrix && !localMatrix->invert(nullptr)) {
1032         return nullptr;
1033     }
1034     EXPAND_1_COLOR(colorCount);
1035
1036     ColorStopOptimizer opt(colors, pos, colorCount, mode);
1037
1038     SkGradientShaderBase::Descriptor desc;
1039     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
1040               localMatrix);
1041     return SkTwoPointConicalGradient::Create(start, startRadius, end, endRadius, desc);
1042 }
1043
1044 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
1045                                             const SkColor colors[],
1046                                             const SkScalar pos[],
1047                                             int colorCount,
1048                                             SkTileMode mode,
1049                                             SkScalar startAngle,
1050                                             SkScalar endAngle,
1051                                             uint32_t flags,
1052                                             const SkMatrix* localMatrix) {
1053     ColorConverter converter(colors, colorCount);
1054     return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount,
1055                      mode, startAngle, endAngle, flags, localMatrix);
1056 }
1057
1058 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
1059                                             const SkColor4f colors[],
1060                                             sk_sp<SkColorSpace> colorSpace,
1061                                             const SkScalar pos[], int count,
1062                                             uint32_t flags, const SkMatrix* localMatrix) {
1063     return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count,
1064                      SkTileMode::kClamp, 0, 360, flags, localMatrix);
1065 }
1066 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
1067                                             const SkColor4f colors[],
1068                                             sk_sp<SkColorSpace> colorSpace,
1069                                             const SkScalar pos[], int count) {
1070     return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, 0, nullptr);
1071 }
1072
1073 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
1074                                             const SkColor4f colors[],
1075                                             sk_sp<SkColorSpace> colorSpace,
1076                                             const SkScalar pos[],
1077                                             int colorCount,
1078                                             SkTileMode mode,
1079                                             SkScalar startAngle,
1080                                             SkScalar endAngle,
1081                                             uint32_t flags,
1082                                             const SkMatrix* localMatrix) {
1083     if (!valid_grad(colors, pos, colorCount, mode)) {
1084         return nullptr;
1085     }
1086     if (1 == colorCount) {
1087         return SkShaders::Color(colors[0], std::move(colorSpace));
1088     }
1089     if (!SkScalarIsFinite(startAngle) || !SkScalarIsFinite(endAngle) || startAngle > endAngle) {
1090         return nullptr;
1091     }
1092     if (localMatrix && !localMatrix->invert(nullptr)) {
1093         return nullptr;
1094     }
1095
1096     if (SkScalarNearlyEqual(startAngle, endAngle, kDegenerateThreshold)) {
1097         // Degenerate gradient, which should follow default degenerate behavior unless it is
1098         // clamped and the angle is greater than 0.
1099         if (mode == SkTileMode::kClamp && endAngle > kDegenerateThreshold) {
1100             // In this case, the first color is repeated from 0 to the angle, then a hardstop
1101             // switches to the last color (all other colors are compressed to the infinitely thin
1102             // interpolation region).
1103             static constexpr SkScalar clampPos[3] = {0, 1, 1};
1104             SkColor4f reColors[3] = {colors[0], colors[0], colors[colorCount - 1]};
1105             return MakeSweep(cx, cy, reColors, std::move(colorSpace), clampPos, 3, mode, 0,
1106                              endAngle, flags, localMatrix);
1107         } else {
1108             return make_degenerate_gradient(colors, pos, colorCount, std::move(colorSpace), mode);
1109         }
1110     }
1111
1112     if (startAngle <= 0 && endAngle >= 360) {
1113         // If the t-range includes [0,1], then we can always use clamping (presumably faster).
1114         mode = SkTileMode::kClamp;
1115     }
1116
1117     ColorStopOptimizer opt(colors, pos, colorCount, mode);
1118
1119     SkGradientShaderBase::Descriptor desc;
1120     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
1121               localMatrix);
1122
1123     const SkScalar t0 = startAngle / 360,
1124                    t1 =   endAngle / 360;
1125
1126     return sk_make_sp<SkSweepGradient>(SkPoint::Make(cx, cy), t0, t1, desc);
1127 }
1128
1129 void SkGradientShader::RegisterFlattenables() {
1130     SK_REGISTER_FLATTENABLE(SkLinearGradient);
1131     SK_REGISTER_FLATTENABLE(SkRadialGradient);
1132     SK_REGISTER_FLATTENABLE(SkSweepGradient);
1133     SK_REGISTER_FLATTENABLE(SkTwoPointConicalGradient);
1134 }