blob: 9ceaba1b43739e8ff66b13c168278a1231c61c4d [file] [log] [blame]
rileya@google.com589708b2012-07-26 20:04:23 +00001/*
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
Herb Derby4de13042017-05-15 10:49:39 -04008#include <algorithm>
fmalitabc590c02016-02-22 09:12:33 -08009#include "Sk4fLinearGradient.h"
Mike Kleine28a6b52018-07-25 13:05:17 -040010#include "SkColorSpacePriv.h"
Florin Malita39d71de2017-10-31 11:33:49 -040011#include "SkColorSpaceXformer.h"
Cary Clark4dc5a452018-05-21 11:56:57 -040012#include "SkFlattenablePriv.h"
Florin Malitacad3b8c2017-10-28 21:42:50 -040013#include "SkFloatBits.h"
rileya@google.com589708b2012-07-26 20:04:23 +000014#include "SkGradientShaderPriv.h"
brianosmand4546092016-09-22 12:31:58 -070015#include "SkHalf.h"
rileya@google.com589708b2012-07-26 20:04:23 +000016#include "SkLinearGradient.h"
Mike Reed6b3155c2017-04-03 14:41:44 -040017#include "SkMallocPixelRef.h"
rileya@google.com589708b2012-07-26 20:04:23 +000018#include "SkRadialGradient.h"
Florin Malitad4e9ec82017-10-25 18:00:26 -040019#include "SkReadBuffer.h"
Mike Klein02ab8cc2017-05-04 22:41:05 +000020#include "SkSweepGradient.h"
Mike Kleina3771842017-05-04 19:38:48 -040021#include "SkTwoPointConicalGradient.h"
Florin Malitad4e9ec82017-10-25 18:00:26 -040022#include "SkWriteBuffer.h"
Herb Derby4de13042017-05-15 10:49:39 -040023#include "../../jumper/SkJumper.h"
Brian Osman6667fb12018-07-03 16:44:02 -040024#include "../../third_party/skcms/skcms.h"
rileya@google.com589708b2012-07-26 20:04:23 +000025
brianosmane25d71c2016-09-28 11:27:28 -070026enum GradientSerializationFlags {
27 // Bits 29:31 used for various boolean flags
28 kHasPosition_GSF = 0x80000000,
29 kHasLocalMatrix_GSF = 0x40000000,
30 kHasColorSpace_GSF = 0x20000000,
31
32 // Bits 12:28 unused
33
34 // Bits 8:11 for fTileMode
35 kTileModeShift_GSF = 8,
36 kTileModeMask_GSF = 0xF,
37
38 // Bits 0:7 for fGradFlags (note that kForce4fContext_PrivateFlag is 0x80)
39 kGradFlagsShift_GSF = 0,
40 kGradFlagsMask_GSF = 0xFF,
41};
42
reed9fa60da2014-08-21 07:59:51 -070043void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
brianosmane25d71c2016-09-28 11:27:28 -070044 uint32_t flags = 0;
reed9fa60da2014-08-21 07:59:51 -070045 if (fPos) {
brianosmane25d71c2016-09-28 11:27:28 -070046 flags |= kHasPosition_GSF;
reed9fa60da2014-08-21 07:59:51 -070047 }
reed9fa60da2014-08-21 07:59:51 -070048 if (fLocalMatrix) {
brianosmane25d71c2016-09-28 11:27:28 -070049 flags |= kHasLocalMatrix_GSF;
50 }
51 sk_sp<SkData> colorSpaceData = fColorSpace ? fColorSpace->serialize() : nullptr;
52 if (colorSpaceData) {
53 flags |= kHasColorSpace_GSF;
54 }
55 SkASSERT(static_cast<uint32_t>(fTileMode) <= kTileModeMask_GSF);
56 flags |= (fTileMode << kTileModeShift_GSF);
57 SkASSERT(fGradFlags <= kGradFlagsMask_GSF);
58 flags |= (fGradFlags << kGradFlagsShift_GSF);
59
60 buffer.writeUInt(flags);
61
62 buffer.writeColor4fArray(fColors, fCount);
63 if (colorSpaceData) {
64 buffer.writeDataAsByteArray(colorSpaceData.get());
65 }
66 if (fPos) {
67 buffer.writeScalarArray(fPos, fCount);
68 }
69 if (fLocalMatrix) {
reed9fa60da2014-08-21 07:59:51 -070070 buffer.writeMatrix(*fLocalMatrix);
reed9fa60da2014-08-21 07:59:51 -070071 }
72}
73
Florin Malitaf77db112018-05-10 09:52:27 -040074template <int N, typename T, bool MEM_MOVE>
75static bool validate_array(SkReadBuffer& buffer, size_t count, SkSTArray<N, T, MEM_MOVE>* array) {
Kevin Lubickdaebae92018-05-17 11:29:10 -040076 if (!buffer.validateCanReadN<T>(count)) {
Florin Malitaf77db112018-05-10 09:52:27 -040077 return false;
78 }
79
80 array->resize_back(count);
81 return true;
82}
83
reed9fa60da2014-08-21 07:59:51 -070084bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
Mike Reed70bc94f2017-06-08 12:45:52 -040085 // New gradient format. Includes floating point color, color space, densely packed flags
86 uint32_t flags = buffer.readUInt();
reed9fa60da2014-08-21 07:59:51 -070087
Mike Reed70bc94f2017-06-08 12:45:52 -040088 fTileMode = (SkShader::TileMode)((flags >> kTileModeShift_GSF) & kTileModeMask_GSF);
89 fGradFlags = (flags >> kGradFlagsShift_GSF) & kGradFlagsMask_GSF;
reed9fa60da2014-08-21 07:59:51 -070090
Mike Reed70bc94f2017-06-08 12:45:52 -040091 fCount = buffer.getArrayCount();
Florin Malitaf77db112018-05-10 09:52:27 -040092
93 if (!(validate_array(buffer, fCount, &fColorStorage) &&
94 buffer.readColor4fArray(fColorStorage.begin(), fCount))) {
Mike Reed70bc94f2017-06-08 12:45:52 -040095 return false;
96 }
Florin Malitaf77db112018-05-10 09:52:27 -040097 fColors = fColorStorage.begin();
98
Mike Reed70bc94f2017-06-08 12:45:52 -040099 if (SkToBool(flags & kHasColorSpace_GSF)) {
100 sk_sp<SkData> data = buffer.readByteArrayAsData();
Florin Malitac2ea3272018-05-10 09:41:38 -0400101 fColorSpace = data ? SkColorSpace::Deserialize(data->data(), data->size()) : nullptr;
Mike Reed70bc94f2017-06-08 12:45:52 -0400102 } else {
brianosmane25d71c2016-09-28 11:27:28 -0700103 fColorSpace = nullptr;
Mike Reed70bc94f2017-06-08 12:45:52 -0400104 }
105 if (SkToBool(flags & kHasPosition_GSF)) {
Florin Malitaf77db112018-05-10 09:52:27 -0400106 if (!(validate_array(buffer, fCount, &fPosStorage) &&
107 buffer.readScalarArray(fPosStorage.begin(), fCount))) {
Mike Reed70bc94f2017-06-08 12:45:52 -0400108 return false;
brianosmane25d71c2016-09-28 11:27:28 -0700109 }
Florin Malitaf77db112018-05-10 09:52:27 -0400110 fPos = fPosStorage.begin();
reed9fa60da2014-08-21 07:59:51 -0700111 } else {
Mike Reed70bc94f2017-06-08 12:45:52 -0400112 fPos = nullptr;
113 }
114 if (SkToBool(flags & kHasLocalMatrix_GSF)) {
115 fLocalMatrix = &fLocalMatrixStorage;
116 buffer.readMatrix(&fLocalMatrixStorage);
117 } else {
118 fLocalMatrix = nullptr;
reed9fa60da2014-08-21 07:59:51 -0700119 }
120 return buffer.isValid();
121}
122
123////////////////////////////////////////////////////////////////////////////////////////////
124
mtkleincc695fe2014-12-10 10:29:19 -0800125SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit)
reedaddf2ed2014-08-11 08:28:24 -0700126 : INHERITED(desc.fLocalMatrix)
mtkleincc695fe2014-12-10 10:29:19 -0800127 , fPtsToUnit(ptsToUnit)
Brian Osman6667fb12018-07-03 16:44:02 -0400128 , fColorSpace(desc.fColorSpace ? desc.fColorSpace : SkColorSpace::MakeSRGB())
Florin Malita39d71de2017-10-31 11:33:49 -0400129 , fColorsAreOpaque(true)
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000130{
mtkleincc695fe2014-12-10 10:29:19 -0800131 fPtsToUnit.getType(); // Precache so reads are threadsafe.
reed@google.com437d6eb2013-05-23 19:03:05 +0000132 SkASSERT(desc.fCount > 1);
rileya@google.com589708b2012-07-26 20:04:23 +0000133
fmalita6d7e4e82016-09-20 06:55:16 -0700134 fGradFlags = static_cast<uint8_t>(desc.fGradFlags);
rileya@google.com589708b2012-07-26 20:04:23 +0000135
reed@google.com437d6eb2013-05-23 19:03:05 +0000136 SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount);
reed@google.com437d6eb2013-05-23 19:03:05 +0000137 fTileMode = desc.fTileMode;
rileya@google.com589708b2012-07-26 20:04:23 +0000138
rileya@google.com589708b2012-07-26 20:04:23 +0000139 /* Note: we let the caller skip the first and/or last position.
140 i.e. pos[0] = 0.3, pos[1] = 0.7
141 In these cases, we insert dummy entries to ensure that the final data
142 will be bracketed by [0, 1].
143 i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
144
145 Thus colorCount (the caller's value, and fColorCount (our value) may
146 differ by up to 2. In the above example:
147 colorCount = 2
148 fColorCount = 4
149 */
reed@google.com437d6eb2013-05-23 19:03:05 +0000150 fColorCount = desc.fCount;
rileya@google.com589708b2012-07-26 20:04:23 +0000151 // check if we need to add in dummy start and/or end position/colors
152 bool dummyFirst = false;
153 bool dummyLast = false;
reed@google.com437d6eb2013-05-23 19:03:05 +0000154 if (desc.fPos) {
155 dummyFirst = desc.fPos[0] != 0;
156 dummyLast = desc.fPos[desc.fCount - 1] != SK_Scalar1;
rileya@google.com589708b2012-07-26 20:04:23 +0000157 fColorCount += dummyFirst + dummyLast;
158 }
159
Mike Reed62ce2ca2018-02-19 14:20:15 -0500160 size_t storageSize = fColorCount * (sizeof(SkColor4f) + (desc.fPos ? sizeof(SkScalar) : 0));
Florin Malita89ab2402017-11-01 10:14:57 -0400161 fOrigColors4f = reinterpret_cast<SkColor4f*>(fStorage.reset(storageSize));
Mike Reed62ce2ca2018-02-19 14:20:15 -0500162 fOrigPos = desc.fPos ? reinterpret_cast<SkScalar*>(fOrigColors4f + fColorCount)
163 : nullptr;
rileya@google.com589708b2012-07-26 20:04:23 +0000164
brianosmane25d71c2016-09-28 11:27:28 -0700165 // Now copy over the colors, adding the dummies as needed
166 SkColor4f* origColors = fOrigColors4f;
167 if (dummyFirst) {
168 *origColors++ = desc.fColors[0];
169 }
Florin Malita39d71de2017-10-31 11:33:49 -0400170 for (int i = 0; i < desc.fCount; ++i) {
Mike Reed62ce2ca2018-02-19 14:20:15 -0500171 origColors[i] = desc.fColors[i];
Florin Malita39d71de2017-10-31 11:33:49 -0400172 fColorsAreOpaque = fColorsAreOpaque && (desc.fColors[i].fA == 1);
173 }
brianosmane25d71c2016-09-28 11:27:28 -0700174 if (dummyLast) {
Mike Reed62ce2ca2018-02-19 14:20:15 -0500175 origColors += desc.fCount;
176 *origColors = desc.fColors[desc.fCount - 1];
brianosmane25d71c2016-09-28 11:27:28 -0700177 }
brianosmanb9c51372016-09-15 11:09:45 -0700178
Florin Malita89ab2402017-11-01 10:14:57 -0400179 if (desc.fPos) {
Florin Malita64bb78e2017-11-03 12:54:07 -0400180 SkScalar prev = 0;
Mike Reed62ce2ca2018-02-19 14:20:15 -0500181 SkScalar* origPosPtr = fOrigPos;
Florin Malita64bb78e2017-11-03 12:54:07 -0400182 *origPosPtr++ = prev; // force the first pos to 0
reed9fa60da2014-08-21 07:59:51 -0700183
Florin Malita89ab2402017-11-01 10:14:57 -0400184 int startIndex = dummyFirst ? 0 : 1;
185 int count = desc.fCount + dummyLast;
Florin Malita64bb78e2017-11-03 12:54:07 -0400186
187 bool uniformStops = true;
188 const SkScalar uniformStep = desc.fPos[startIndex] - prev;
Florin Malita89ab2402017-11-01 10:14:57 -0400189 for (int i = startIndex; i < count; i++) {
Florin Malita3e20d022017-11-03 12:11:38 -0400190 // Pin the last value to 1.0, and make sure pos is monotonic.
Florin Malita64bb78e2017-11-03 12:54:07 -0400191 auto curr = (i == desc.fCount) ? 1 : SkScalarPin(desc.fPos[i], prev, 1);
192 uniformStops &= SkScalarNearlyEqual(uniformStep, curr - prev);
193
194 *origPosPtr++ = prev = curr;
reed9fa60da2014-08-21 07:59:51 -0700195 }
Florin Malita64bb78e2017-11-03 12:54:07 -0400196
Florin Malita64bb78e2017-11-03 12:54:07 -0400197 // If the stops are uniform, treat them as implicit.
Mike Reed62ce2ca2018-02-19 14:20:15 -0500198 if (uniformStops) {
Florin Malita64bb78e2017-11-03 12:54:07 -0400199 fOrigPos = nullptr;
200 }
rileya@google.com589708b2012-07-26 20:04:23 +0000201 }
rileya@google.com589708b2012-07-26 20:04:23 +0000202}
203
Florin Malita89ab2402017-11-01 10:14:57 -0400204SkGradientShaderBase::~SkGradientShaderBase() {}
rileya@google.com589708b2012-07-26 20:04:23 +0000205
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000206void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
reed9fa60da2014-08-21 07:59:51 -0700207 Descriptor desc;
brianosmane25d71c2016-09-28 11:27:28 -0700208 desc.fColors = fOrigColors4f;
brianosmanb9c51372016-09-15 11:09:45 -0700209 desc.fColorSpace = fColorSpace;
reed9fa60da2014-08-21 07:59:51 -0700210 desc.fPos = fOrigPos;
211 desc.fCount = fColorCount;
212 desc.fTileMode = fTileMode;
213 desc.fGradFlags = fGradFlags;
214
215 const SkMatrix& m = this->getLocalMatrix();
halcanary96fcdcc2015-08-27 07:41:13 -0700216 desc.fLocalMatrix = m.isIdentity() ? nullptr : &m;
reed9fa60da2014-08-21 07:59:51 -0700217 desc.flatten(buffer);
rileya@google.com589708b2012-07-26 20:04:23 +0000218}
219
Brian Osman781e3502018-10-03 15:42:47 -0400220static void add_stop_color(SkJumper_GradientCtx* ctx, size_t stop, SkPMColor4f Fs, SkPMColor4f Bs) {
221 (ctx->fs[0])[stop] = Fs.fR;
222 (ctx->fs[1])[stop] = Fs.fG;
223 (ctx->fs[2])[stop] = Fs.fB;
224 (ctx->fs[3])[stop] = Fs.fA;
225 (ctx->bs[0])[stop] = Bs.fR;
226 (ctx->bs[1])[stop] = Bs.fG;
227 (ctx->bs[2])[stop] = Bs.fB;
228 (ctx->bs[3])[stop] = Bs.fA;
Mike Kleinf945cbb2017-05-17 09:30:58 -0400229}
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400230
Brian Osman781e3502018-10-03 15:42:47 -0400231static void add_const_color(SkJumper_GradientCtx* ctx, size_t stop, SkPMColor4f color) {
232 add_stop_color(ctx, stop, { 0, 0, 0, 0 }, color);
Mike Kleinf945cbb2017-05-17 09:30:58 -0400233}
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400234
235// Calculate a factor F and a bias B so that color = F*t + B when t is in range of
236// the stop. Assume that the distance between stops is 1/gapCount.
237static void init_stop_evenly(
Brian Osman781e3502018-10-03 15:42:47 -0400238 SkJumper_GradientCtx* ctx, float gapCount, size_t stop, SkPMColor4f c_l, SkPMColor4f c_r) {
Mike Klein68768172017-05-17 09:54:36 -0400239 // Clankium's GCC 4.9 targeting ARMv7 is barfing when we use Sk4f math here, so go scalar...
Brian Osman781e3502018-10-03 15:42:47 -0400240 SkPMColor4f Fs = {
241 (c_r.fR - c_l.fR) * gapCount,
242 (c_r.fG - c_l.fG) * gapCount,
243 (c_r.fB - c_l.fB) * gapCount,
244 (c_r.fA - c_l.fA) * gapCount,
245 };
246 SkPMColor4f Bs = {
247 c_l.fR - Fs.fR*(stop/gapCount),
248 c_l.fG - Fs.fG*(stop/gapCount),
249 c_l.fB - Fs.fB*(stop/gapCount),
250 c_l.fA - Fs.fA*(stop/gapCount),
251 };
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400252 add_stop_color(ctx, stop, Fs, Bs);
Mike Kleinf945cbb2017-05-17 09:30:58 -0400253}
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400254
255// For each stop we calculate a bias B and a scale factor F, such that
256// for any t between stops n and n+1, the color we want is B[n] + F[n]*t.
257static void init_stop_pos(
Brian Osman781e3502018-10-03 15:42:47 -0400258 SkJumper_GradientCtx* ctx, size_t stop, float t_l, float t_r, SkPMColor4f c_l, SkPMColor4f c_r) {
Mike Klein68768172017-05-17 09:54:36 -0400259 // See note about Clankium's old compiler in init_stop_evenly().
Brian Osman781e3502018-10-03 15:42:47 -0400260 SkPMColor4f Fs = {
261 (c_r.fR - c_l.fR) / (t_r - t_l),
262 (c_r.fG - c_l.fG) / (t_r - t_l),
263 (c_r.fB - c_l.fB) / (t_r - t_l),
264 (c_r.fA - c_l.fA) / (t_r - t_l),
265 };
266 SkPMColor4f Bs = {
267 c_l.fR - Fs.fR*t_l,
268 c_l.fG - Fs.fG*t_l,
269 c_l.fB - Fs.fB*t_l,
270 c_l.fA - Fs.fA*t_l,
271 };
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400272 ctx->ts[stop] = t_l;
273 add_stop_color(ctx, stop, Fs, Bs);
Mike Kleinf945cbb2017-05-17 09:30:58 -0400274}
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400275
Mike Reed1d8c42e2017-08-29 14:58:19 -0400276bool SkGradientShaderBase::onAppendStages(const StageRec& rec) const {
277 SkRasterPipeline* p = rec.fPipeline;
278 SkArenaAlloc* alloc = rec.fAlloc;
Mike Reed62ce2ca2018-02-19 14:20:15 -0500279 SkJumper_DecalTileCtx* decal_ctx = nullptr;
Mike Reed1d8c42e2017-08-29 14:58:19 -0400280
Mike Kleina3771842017-05-04 19:38:48 -0400281 SkMatrix matrix;
Mike Reed1d8c42e2017-08-29 14:58:19 -0400282 if (!this->computeTotalInverse(rec.fCTM, rec.fLocalM, &matrix)) {
Mike Kleina3771842017-05-04 19:38:48 -0400283 return false;
284 }
Florin Malita50b20842017-07-29 19:08:28 -0400285 matrix.postConcat(fPtsToUnit);
Mike Kleina3771842017-05-04 19:38:48 -0400286
Florin Malita2e409002017-06-28 14:46:54 -0400287 SkRasterPipeline_<256> postPipeline;
Mike Kleina3771842017-05-04 19:38:48 -0400288
Mike Kleine8de0242018-03-10 12:37:11 -0500289 p->append(SkRasterPipeline::seed_shader);
Mike Reed6b59bf42017-07-03 21:26:44 -0400290 p->append_matrix(alloc, matrix);
Florin Malita50b20842017-07-29 19:08:28 -0400291 this->appendGradientStages(alloc, p, &postPipeline);
Mike Kleine7598532017-05-11 11:29:29 -0400292
Mike Reed62ce2ca2018-02-19 14:20:15 -0500293 switch(fTileMode) {
Mike Klein9f85d682017-05-23 07:52:01 -0400294 case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x_1); break;
295 case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x_1); break;
Mike Reeddfc0e912018-02-16 12:40:18 -0500296 case kDecal_TileMode:
Mike Reed62ce2ca2018-02-19 14:20:15 -0500297 decal_ctx = alloc->make<SkJumper_DecalTileCtx>();
298 decal_ctx->limit_x = SkBits2Float(SkFloat2Bits(1.0f) + 1);
299 // reuse mask + limit_x stage, or create a custom decal_1 that just stores the mask
300 p->append(SkRasterPipeline::decal_x, decal_ctx);
301 // fall-through to clamp
Mike Kleine7598532017-05-11 11:29:29 -0400302 case kClamp_TileMode:
303 if (!fOrigPos) {
304 // We clamp only when the stops are evenly spaced.
305 // If not, there may be hard stops, and clamping ruins hard stops at 0 and/or 1.
Mike Klein5c7960b2017-05-11 10:59:22 -0400306 // In that case, we must make sure we're using the general "gradient" stage,
Mike Kleine7598532017-05-11 11:29:29 -0400307 // which is the only stage that will correctly handle unclamped t.
Mike Klein9f85d682017-05-23 07:52:01 -0400308 p->append(SkRasterPipeline::clamp_x_1);
Mike Kleine7598532017-05-11 11:29:29 -0400309 }
Mike Reed62ce2ca2018-02-19 14:20:15 -0500310 break;
Mike Kleine7598532017-05-11 11:29:29 -0400311 }
Mike Kleina3771842017-05-04 19:38:48 -0400312
313 const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag;
Brian Osman6667fb12018-07-03 16:44:02 -0400314
315 // Transform all of the colors to destination color space
316 SkColor4fXformer xformedColors(fOrigColors4f, fColorCount, fColorSpace.get(), rec.fDstCS);
317
318 auto prepareColor = [premulGrad, &xformedColors](int i) {
319 SkColor4f c = xformedColors.fColors[i];
Brian Osman781e3502018-10-03 15:42:47 -0400320 return premulGrad ? c.premul()
321 : SkPMColor4f{ c.fR, c.fG, c.fB, c.fA };
Mike Kleina3771842017-05-04 19:38:48 -0400322 };
323
324 // The two-stop case with stops at 0 and 1.
325 if (fColorCount == 2 && fOrigPos == nullptr) {
Brian Osman781e3502018-10-03 15:42:47 -0400326 const SkPMColor4f c_l = prepareColor(0),
327 c_r = prepareColor(1);
Mike Kleina3771842017-05-04 19:38:48 -0400328
329 // See F and B below.
Mike Klein24de6482018-09-07 12:05:29 -0400330 auto ctx = alloc->make<SkJumper_EvenlySpaced2StopGradientCtx>();
Brian Osman781e3502018-10-03 15:42:47 -0400331 (Sk4f::Load(c_r.vec()) - Sk4f::Load(c_l.vec())).store(ctx->f);
332 ( Sk4f::Load(c_l.vec())).store(ctx->b);
Mike Klein24de6482018-09-07 12:05:29 -0400333 ctx->interpolatedInPremul = premulGrad;
Mike Kleina3771842017-05-04 19:38:48 -0400334
Mike Klein24de6482018-09-07 12:05:29 -0400335 p->append(SkRasterPipeline::evenly_spaced_2_stop_gradient, ctx);
Mike Kleina3771842017-05-04 19:38:48 -0400336 } else {
Herb Derby4de13042017-05-15 10:49:39 -0400337 auto* ctx = alloc->make<SkJumper_GradientCtx>();
Mike Klein24de6482018-09-07 12:05:29 -0400338 ctx->interpolatedInPremul = premulGrad;
Herb Derby4de13042017-05-15 10:49:39 -0400339
340 // Note: In order to handle clamps in search, the search assumes a stop conceptully placed
341 // at -inf. Therefore, the max number of stops is fColorCount+1.
342 for (int i = 0; i < 4; i++) {
343 // Allocate at least at for the AVX2 gather from a YMM register.
344 ctx->fs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
345 ctx->bs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
346 }
347
Mike Kleina3771842017-05-04 19:38:48 -0400348 if (fOrigPos == nullptr) {
349 // Handle evenly distributed stops.
350
Herb Derby4de13042017-05-15 10:49:39 -0400351 size_t stopCount = fColorCount;
352 float gapCount = stopCount - 1;
Mike Kleina3771842017-05-04 19:38:48 -0400353
Brian Osman781e3502018-10-03 15:42:47 -0400354 SkPMColor4f c_l = prepareColor(0);
Herb Derby4de13042017-05-15 10:49:39 -0400355 for (size_t i = 0; i < stopCount - 1; i++) {
Brian Osman781e3502018-10-03 15:42:47 -0400356 SkPMColor4f c_r = prepareColor(i + 1);
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400357 init_stop_evenly(ctx, gapCount, i, c_l, c_r);
Mike Kleina3771842017-05-04 19:38:48 -0400358 c_l = c_r;
359 }
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400360 add_const_color(ctx, stopCount - 1, c_l);
Mike Kleina3771842017-05-04 19:38:48 -0400361
Herb Derby4de13042017-05-15 10:49:39 -0400362 ctx->stopCount = stopCount;
363 p->append(SkRasterPipeline::evenly_spaced_gradient, ctx);
Mike Kleina3771842017-05-04 19:38:48 -0400364 } else {
365 // Handle arbitrary stops.
366
Herb Derby4de13042017-05-15 10:49:39 -0400367 ctx->ts = alloc->makeArray<float>(fColorCount+1);
368
Mike Kleina3771842017-05-04 19:38:48 -0400369 // Remove the dummy stops inserted by SkGradientShaderBase::SkGradientShaderBase
370 // because they are naturally handled by the search method.
371 int firstStop;
372 int lastStop;
373 if (fColorCount > 2) {
374 firstStop = fOrigColors4f[0] != fOrigColors4f[1] ? 0 : 1;
375 lastStop = fOrigColors4f[fColorCount - 2] != fOrigColors4f[fColorCount - 1]
376 ? fColorCount - 1 : fColorCount - 2;
377 } else {
378 firstStop = 0;
379 lastStop = 1;
380 }
Mike Kleina3771842017-05-04 19:38:48 -0400381
Mike Kleina3771842017-05-04 19:38:48 -0400382 size_t stopCount = 0;
383 float t_l = fOrigPos[firstStop];
Brian Osman781e3502018-10-03 15:42:47 -0400384 SkPMColor4f c_l = prepareColor(firstStop);
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400385 add_const_color(ctx, stopCount++, c_l);
Mike Kleina3771842017-05-04 19:38:48 -0400386 // N.B. lastStop is the index of the last stop, not one after.
387 for (int i = firstStop; i < lastStop; i++) {
388 float t_r = fOrigPos[i + 1];
Brian Osman781e3502018-10-03 15:42:47 -0400389 SkPMColor4f c_r = prepareColor(i + 1);
Florin Malita3e20d022017-11-03 12:11:38 -0400390 SkASSERT(t_l <= t_r);
Mike Kleina3771842017-05-04 19:38:48 -0400391 if (t_l < t_r) {
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400392 init_stop_pos(ctx, stopCount, t_l, t_r, c_l, c_r);
Mike Kleina3771842017-05-04 19:38:48 -0400393 stopCount += 1;
394 }
395 t_l = t_r;
396 c_l = c_r;
397 }
398
Herb Derby4de13042017-05-15 10:49:39 -0400399 ctx->ts[stopCount] = t_l;
Herb Derbyeb99bfd2017-05-16 10:51:26 -0400400 add_const_color(ctx, stopCount++, c_l);
Mike Kleina3771842017-05-04 19:38:48 -0400401
Herb Derby4de13042017-05-15 10:49:39 -0400402 ctx->stopCount = stopCount;
403 p->append(SkRasterPipeline::gradient, ctx);
Mike Kleina3771842017-05-04 19:38:48 -0400404 }
Mike Kleina3771842017-05-04 19:38:48 -0400405 }
406
Mike Reed62ce2ca2018-02-19 14:20:15 -0500407 if (decal_ctx) {
408 p->append(SkRasterPipeline::check_decal_mask, decal_ctx);
409 }
410
Mike Kleina3771842017-05-04 19:38:48 -0400411 if (!premulGrad && !this->colorsAreOpaque()) {
Mike Kleine7598532017-05-11 11:29:29 -0400412 p->append(SkRasterPipeline::premul);
Mike Kleina3771842017-05-04 19:38:48 -0400413 }
414
Florin Malita2e409002017-06-28 14:46:54 -0400415 p->extend(postPipeline);
416
Mike Kleina3771842017-05-04 19:38:48 -0400417 return true;
418}
419
420
rileya@google.com589708b2012-07-26 20:04:23 +0000421bool SkGradientShaderBase::isOpaque() const {
Mike Reed62ce2ca2018-02-19 14:20:15 -0500422 return fColorsAreOpaque && (this->getTileMode() != SkShader::kDecal_TileMode);
423}
424
reed8367b8c2014-08-22 08:30:20 -0700425static unsigned rounded_divide(unsigned numer, unsigned denom) {
426 return (numer + (denom >> 1)) / denom;
427}
428
429bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const {
430 // we just compute an average color.
431 // possibly we could weight this based on the proportional width for each color
432 // assuming they are not evenly distributed in the fPos array.
433 int r = 0;
434 int g = 0;
435 int b = 0;
436 const int n = fColorCount;
Florin Malita39d71de2017-10-31 11:33:49 -0400437 // TODO: use linear colors?
reed8367b8c2014-08-22 08:30:20 -0700438 for (int i = 0; i < n; ++i) {
Florin Malita39d71de2017-10-31 11:33:49 -0400439 SkColor c = this->getLegacyColor(i);
reed8367b8c2014-08-22 08:30:20 -0700440 r += SkColorGetR(c);
441 g += SkColorGetG(c);
442 b += SkColorGetB(c);
443 }
444 *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n));
445 return true;
446}
447
Florin Malita39d71de2017-10-31 11:33:49 -0400448SkGradientShaderBase::AutoXformColors::AutoXformColors(const SkGradientShaderBase& grad,
449 SkColorSpaceXformer* xformer)
450 : fColors(grad.fColorCount) {
451 // TODO: stay in 4f to preserve precision?
452
453 SkAutoSTMalloc<8, SkColor> origColors(grad.fColorCount);
454 for (int i = 0; i < grad.fColorCount; ++i) {
455 origColors[i] = grad.getLegacyColor(i);
456 }
457
458 xformer->apply(fColors.get(), origColors.get(), grad.fColorCount);
459}
460
Brian Osman6667fb12018-07-03 16:44:02 -0400461SkColor4fXformer::SkColor4fXformer(const SkColor4f* colors, int colorCount,
462 SkColorSpace* src, SkColorSpace* dst) {
463 // Transform all of the colors to destination color space
464 fColors = colors;
Brian Osmanccd39952018-07-06 16:16:43 -0400465
Mike Kleine28a6b52018-07-25 13:05:17 -0400466 // Treat null destinations as sRGB.
Brian Osman6667fb12018-07-03 16:44:02 -0400467 if (!dst) {
Mike Kleine28a6b52018-07-25 13:05:17 -0400468 dst = sk_srgb_singleton();
Brian Osman6667fb12018-07-03 16:44:02 -0400469 }
470
Mike Kleine28a6b52018-07-25 13:05:17 -0400471 // Treat null sources as sRGB.
Brian Osman6667fb12018-07-03 16:44:02 -0400472 if (!src) {
Mike Kleine28a6b52018-07-25 13:05:17 -0400473 src = sk_srgb_singleton();
Brian Osman6667fb12018-07-03 16:44:02 -0400474 }
475
476 if (!SkColorSpace::Equals(src, dst)) {
477 skcms_ICCProfile srcProfile, dstProfile;
478 src->toProfile(&srcProfile);
479 dst->toProfile(&dstProfile);
480 fStorage.reset(colorCount);
481 const skcms_PixelFormat rgba_f32 = skcms_PixelFormat_RGBA_ffff;
482 const skcms_AlphaFormat unpremul = skcms_AlphaFormat_Unpremul;
483 SkAssertResult(skcms_Transform(colors, rgba_f32, unpremul, &srcProfile,
484 fStorage.begin(), rgba_f32, unpremul, &dstProfile,
485 colorCount));
486 fColors = fStorage.begin();
487 }
488}
489
Florin Malita5f379a82017-10-18 16:22:35 -0400490void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const {
rileya@google.com589708b2012-07-26 20:04:23 +0000491 if (info) {
492 if (info->fColorCount >= fColorCount) {
493 if (info->fColors) {
Florin Malita39d71de2017-10-31 11:33:49 -0400494 for (int i = 0; i < fColorCount; ++i) {
495 info->fColors[i] = this->getLegacyColor(i);
496 }
rileya@google.com589708b2012-07-26 20:04:23 +0000497 }
498 if (info->fColorOffsets) {
Florin Malitaed6ae562017-10-28 11:06:48 -0400499 for (int i = 0; i < fColorCount; ++i) {
500 info->fColorOffsets[i] = this->getPos(i);
rileya@google.com589708b2012-07-26 20:04:23 +0000501 }
502 }
503 }
504 info->fColorCount = fColorCount;
505 info->fTileMode = fTileMode;
reed@google.com3d3a8602013-05-24 14:58:44 +0000506 info->fGradientFlags = fGradFlags;
rileya@google.com589708b2012-07-26 20:04:23 +0000507 }
508}
509
510///////////////////////////////////////////////////////////////////////////////
511///////////////////////////////////////////////////////////////////////////////
512
reed1b747302015-01-06 07:13:19 -0800513// Return true if these parameters are valid/legal/safe to construct a gradient
514//
brianosmane25d71c2016-09-28 11:27:28 -0700515static bool valid_grad(const SkColor4f colors[], const SkScalar pos[], int count,
516 unsigned tileMode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700517 return nullptr != colors && count >= 1 && tileMode < (unsigned)SkShader::kTileModeCount;
reed1b747302015-01-06 07:13:19 -0800518}
519
reed@google.com437d6eb2013-05-23 19:03:05 +0000520static void desc_init(SkGradientShaderBase::Descriptor* desc,
brianosmane25d71c2016-09-28 11:27:28 -0700521 const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
522 const SkScalar pos[], int colorCount,
reedaddf2ed2014-08-11 08:28:24 -0700523 SkShader::TileMode mode, uint32_t flags, const SkMatrix* localMatrix) {
fmalita748d6202016-05-11 11:39:58 -0700524 SkASSERT(colorCount > 1);
525
commit-bot@chromium.org6c5aea22014-04-22 16:25:15 +0000526 desc->fColors = colors;
brianosmane25d71c2016-09-28 11:27:28 -0700527 desc->fColorSpace = std::move(colorSpace);
commit-bot@chromium.org6c5aea22014-04-22 16:25:15 +0000528 desc->fPos = pos;
529 desc->fCount = colorCount;
530 desc->fTileMode = mode;
commit-bot@chromium.org6c5aea22014-04-22 16:25:15 +0000531 desc->fGradFlags = flags;
reedaddf2ed2014-08-11 08:28:24 -0700532 desc->fLocalMatrix = localMatrix;
reed@google.com437d6eb2013-05-23 19:03:05 +0000533}
534
brianosmane25d71c2016-09-28 11:27:28 -0700535// assumes colors is SkColor4f* and pos is SkScalar*
fmenozzie9fd0f82016-08-19 07:50:57 -0700536#define EXPAND_1_COLOR(count) \
brianosmane25d71c2016-09-28 11:27:28 -0700537 SkColor4f tmp[2]; \
fmenozzie9fd0f82016-08-19 07:50:57 -0700538 do { \
539 if (1 == count) { \
540 tmp[0] = tmp[1] = colors[0]; \
541 colors = tmp; \
542 pos = nullptr; \
543 count = 2; \
544 } \
545 } while (0)
546
fmenozzi68d952c2016-08-19 08:56:56 -0700547struct ColorStopOptimizer {
brianosmane25d71c2016-09-28 11:27:28 -0700548 ColorStopOptimizer(const SkColor4f* colors, const SkScalar* pos,
fmenozzi68d952c2016-08-19 08:56:56 -0700549 int count, SkShader::TileMode mode)
550 : fColors(colors)
551 , fPos(pos)
552 , fCount(count) {
553
554 if (!pos || count != 3) {
555 return;
556 }
557
558 if (SkScalarNearlyEqual(pos[0], 0.0f) &&
559 SkScalarNearlyEqual(pos[1], 0.0f) &&
560 SkScalarNearlyEqual(pos[2], 1.0f)) {
561
562 if (SkShader::kRepeat_TileMode == mode ||
563 SkShader::kMirror_TileMode == mode ||
564 colors[0] == colors[1]) {
565
fmalita582a6562016-08-22 06:28:57 -0700566 // Ignore the leftmost color/pos.
567 fColors += 1;
568 fPos += 1;
569 fCount = 2;
fmenozzi68d952c2016-08-19 08:56:56 -0700570 }
571 } else if (SkScalarNearlyEqual(pos[0], 0.0f) &&
572 SkScalarNearlyEqual(pos[1], 1.0f) &&
573 SkScalarNearlyEqual(pos[2], 1.0f)) {
574
575 if (SkShader::kRepeat_TileMode == mode ||
576 SkShader::kMirror_TileMode == mode ||
577 colors[1] == colors[2]) {
578
fmalita582a6562016-08-22 06:28:57 -0700579 // Ignore the rightmost color/pos.
fmenozzi68d952c2016-08-19 08:56:56 -0700580 fCount = 2;
581 }
582 }
583 }
584
brianosmane25d71c2016-09-28 11:27:28 -0700585 const SkColor4f* fColors;
586 const SkScalar* fPos;
587 int fCount;
588};
589
590struct ColorConverter {
591 ColorConverter(const SkColor* colors, int count) {
Brian Osman6667fb12018-07-03 16:44:02 -0400592 const float ONE_OVER_255 = 1.f / 255;
brianosmane25d71c2016-09-28 11:27:28 -0700593 for (int i = 0; i < count; ++i) {
Brian Osman6667fb12018-07-03 16:44:02 -0400594 fColors4f.push_back({
595 SkColorGetR(colors[i]) * ONE_OVER_255,
596 SkColorGetG(colors[i]) * ONE_OVER_255,
597 SkColorGetB(colors[i]) * ONE_OVER_255,
598 SkColorGetA(colors[i]) * ONE_OVER_255 });
brianosmane25d71c2016-09-28 11:27:28 -0700599 }
600 }
601
602 SkSTArray<2, SkColor4f, true> fColors4f;
fmenozzi68d952c2016-08-19 08:56:56 -0700603};
604
reed8a21c9f2016-03-08 18:50:00 -0800605sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
fmenozzi68d952c2016-08-19 08:56:56 -0700606 const SkColor colors[],
607 const SkScalar pos[], int colorCount,
608 SkShader::TileMode mode,
609 uint32_t flags,
610 const SkMatrix* localMatrix) {
brianosmane25d71c2016-09-28 11:27:28 -0700611 ColorConverter converter(colors, colorCount);
612 return MakeLinear(pts, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, flags,
613 localMatrix);
614}
615
616sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
617 const SkColor4f colors[],
618 sk_sp<SkColorSpace> colorSpace,
619 const SkScalar pos[], int colorCount,
620 SkShader::TileMode mode,
621 uint32_t flags,
622 const SkMatrix* localMatrix) {
fmalitac5231042016-08-10 05:45:50 -0700623 if (!pts || !SkScalarIsFinite((pts[1] - pts[0]).length())) {
halcanary96fcdcc2015-08-27 07:41:13 -0700624 return nullptr;
reed1b747302015-01-06 07:13:19 -0800625 }
626 if (!valid_grad(colors, pos, colorCount, mode)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700627 return nullptr;
rileya@google.com589708b2012-07-26 20:04:23 +0000628 }
fmenozzie9fd0f82016-08-19 07:50:57 -0700629 if (1 == colorCount) {
brianosmane25d71c2016-09-28 11:27:28 -0700630 return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
fmenozzie9fd0f82016-08-19 07:50:57 -0700631 }
Florin Malita8d3ffad2017-02-03 18:21:17 +0000632 if (localMatrix && !localMatrix->invert(nullptr)) {
633 return nullptr;
634 }
rileya@google.com589708b2012-07-26 20:04:23 +0000635
fmenozzi68d952c2016-08-19 08:56:56 -0700636 ColorStopOptimizer opt(colors, pos, colorCount, mode);
637
reed@google.com437d6eb2013-05-23 19:03:05 +0000638 SkGradientShaderBase::Descriptor desc;
brianosmane25d71c2016-09-28 11:27:28 -0700639 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
640 localMatrix);
reed8a21c9f2016-03-08 18:50:00 -0800641 return sk_make_sp<SkLinearGradient>(pts, desc);
rileya@google.com589708b2012-07-26 20:04:23 +0000642}
643
reed8a21c9f2016-03-08 18:50:00 -0800644sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
brianosmane25d71c2016-09-28 11:27:28 -0700645 const SkColor colors[],
646 const SkScalar pos[], int colorCount,
647 SkShader::TileMode mode,
648 uint32_t flags,
649 const SkMatrix* localMatrix) {
650 ColorConverter converter(colors, colorCount);
651 return MakeRadial(center, radius, converter.fColors4f.begin(), nullptr, pos, colorCount, mode,
652 flags, localMatrix);
653}
654
655sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
656 const SkColor4f colors[],
657 sk_sp<SkColorSpace> colorSpace,
658 const SkScalar pos[], int colorCount,
659 SkShader::TileMode mode,
660 uint32_t flags,
661 const SkMatrix* localMatrix) {
reed1b747302015-01-06 07:13:19 -0800662 if (radius <= 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700663 return nullptr;
reed1b747302015-01-06 07:13:19 -0800664 }
665 if (!valid_grad(colors, pos, colorCount, mode)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700666 return nullptr;
rileya@google.com589708b2012-07-26 20:04:23 +0000667 }
fmenozzie9fd0f82016-08-19 07:50:57 -0700668 if (1 == colorCount) {
brianosmane25d71c2016-09-28 11:27:28 -0700669 return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
fmenozzie9fd0f82016-08-19 07:50:57 -0700670 }
Florin Malita8d3ffad2017-02-03 18:21:17 +0000671 if (localMatrix && !localMatrix->invert(nullptr)) {
672 return nullptr;
673 }
rileya@google.com589708b2012-07-26 20:04:23 +0000674
fmenozzi68d952c2016-08-19 08:56:56 -0700675 ColorStopOptimizer opt(colors, pos, colorCount, mode);
676
reed@google.com437d6eb2013-05-23 19:03:05 +0000677 SkGradientShaderBase::Descriptor desc;
brianosmane25d71c2016-09-28 11:27:28 -0700678 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
679 localMatrix);
reed8a21c9f2016-03-08 18:50:00 -0800680 return sk_make_sp<SkRadialGradient>(center, radius, desc);
rileya@google.com589708b2012-07-26 20:04:23 +0000681}
682
reed8a21c9f2016-03-08 18:50:00 -0800683sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
brianosmane25d71c2016-09-28 11:27:28 -0700684 SkScalar startRadius,
685 const SkPoint& end,
686 SkScalar endRadius,
687 const SkColor colors[],
688 const SkScalar pos[],
689 int colorCount,
690 SkShader::TileMode mode,
691 uint32_t flags,
692 const SkMatrix* localMatrix) {
693 ColorConverter converter(colors, colorCount);
694 return MakeTwoPointConical(start, startRadius, end, endRadius, converter.fColors4f.begin(),
695 nullptr, pos, colorCount, mode, flags, localMatrix);
696}
697
698sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
699 SkScalar startRadius,
700 const SkPoint& end,
701 SkScalar endRadius,
702 const SkColor4f colors[],
703 sk_sp<SkColorSpace> colorSpace,
704 const SkScalar pos[],
705 int colorCount,
706 SkShader::TileMode mode,
707 uint32_t flags,
708 const SkMatrix* localMatrix) {
reed1b747302015-01-06 07:13:19 -0800709 if (startRadius < 0 || endRadius < 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700710 return nullptr;
reed1b747302015-01-06 07:13:19 -0800711 }
Florin Malita327290f2017-07-07 09:23:16 -0400712 if (SkScalarNearlyZero((start - end).length()) && SkScalarNearlyZero(startRadius)) {
713 // We can treat this gradient as radial, which is faster.
714 return MakeRadial(start, endRadius, colors, std::move(colorSpace), pos, colorCount,
715 mode, flags, localMatrix);
716 }
reed1b747302015-01-06 07:13:19 -0800717 if (!valid_grad(colors, pos, colorCount, mode)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700718 return nullptr;
rileya@google.com589708b2012-07-26 20:04:23 +0000719 }
fmalita5edf82e2016-03-03 06:41:54 -0800720 if (startRadius == endRadius) {
721 if (start == end || startRadius == 0) {
reed8a21c9f2016-03-08 18:50:00 -0800722 return SkShader::MakeEmptyShader();
fmalita5edf82e2016-03-03 06:41:54 -0800723 }
rileya@google.com589708b2012-07-26 20:04:23 +0000724 }
Florin Malita8d3ffad2017-02-03 18:21:17 +0000725 if (localMatrix && !localMatrix->invert(nullptr)) {
726 return nullptr;
727 }
reed6b7a6c72016-08-18 16:13:50 -0700728 EXPAND_1_COLOR(colorCount);
rileya@google.com589708b2012-07-26 20:04:23 +0000729
fmenozzi68d952c2016-08-19 08:56:56 -0700730 ColorStopOptimizer opt(colors, pos, colorCount, mode);
731
reed@google.com437d6eb2013-05-23 19:03:05 +0000732 SkGradientShaderBase::Descriptor desc;
Florin Malita5f379a82017-10-18 16:22:35 -0400733 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
734 localMatrix);
735 return SkTwoPointConicalGradient::Create(start, startRadius, end, endRadius, desc);
rileya@google.com589708b2012-07-26 20:04:23 +0000736}
737
reed8a21c9f2016-03-08 18:50:00 -0800738sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
brianosmane25d71c2016-09-28 11:27:28 -0700739 const SkColor colors[],
740 const SkScalar pos[],
741 int colorCount,
Florin Malita5a9a9812017-08-01 16:38:08 -0400742 SkShader::TileMode mode,
743 SkScalar startAngle,
744 SkScalar endAngle,
brianosmane25d71c2016-09-28 11:27:28 -0700745 uint32_t flags,
746 const SkMatrix* localMatrix) {
747 ColorConverter converter(colors, colorCount);
Florin Malita5a9a9812017-08-01 16:38:08 -0400748 return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount,
749 mode, startAngle, endAngle, flags, localMatrix);
brianosmane25d71c2016-09-28 11:27:28 -0700750}
751
752sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
753 const SkColor4f colors[],
754 sk_sp<SkColorSpace> colorSpace,
755 const SkScalar pos[],
756 int colorCount,
Florin Malita5a9a9812017-08-01 16:38:08 -0400757 SkShader::TileMode mode,
758 SkScalar startAngle,
759 SkScalar endAngle,
brianosmane25d71c2016-09-28 11:27:28 -0700760 uint32_t flags,
761 const SkMatrix* localMatrix) {
Florin Malita5a9a9812017-08-01 16:38:08 -0400762 if (!valid_grad(colors, pos, colorCount, mode)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700763 return nullptr;
rileya@google.com589708b2012-07-26 20:04:23 +0000764 }
fmenozzie9fd0f82016-08-19 07:50:57 -0700765 if (1 == colorCount) {
brianosmane25d71c2016-09-28 11:27:28 -0700766 return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
fmenozzie9fd0f82016-08-19 07:50:57 -0700767 }
Robert Phillipsb456e2f2018-07-09 15:06:32 -0400768 if (!SkScalarIsFinite(startAngle) || !SkScalarIsFinite(endAngle) || startAngle >= endAngle) {
Florin Malita5a9a9812017-08-01 16:38:08 -0400769 return nullptr;
770 }
Florin Malita8d3ffad2017-02-03 18:21:17 +0000771 if (localMatrix && !localMatrix->invert(nullptr)) {
772 return nullptr;
773 }
rileya@google.com589708b2012-07-26 20:04:23 +0000774
Florin Malita5a9a9812017-08-01 16:38:08 -0400775 if (startAngle <= 0 && endAngle >= 360) {
776 // If the t-range includes [0,1], then we can always use clamping (presumably faster).
777 mode = SkShader::kClamp_TileMode;
778 }
fmenozzi68d952c2016-08-19 08:56:56 -0700779
780 ColorStopOptimizer opt(colors, pos, colorCount, mode);
781
reed@google.com437d6eb2013-05-23 19:03:05 +0000782 SkGradientShaderBase::Descriptor desc;
brianosmane25d71c2016-09-28 11:27:28 -0700783 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
784 localMatrix);
Florin Malita5a9a9812017-08-01 16:38:08 -0400785
786 const SkScalar t0 = startAngle / 360,
787 t1 = endAngle / 360;
788
789 return sk_make_sp<SkSweepGradient>(SkPoint::Make(cx, cy), t0, t1, desc);
rileya@google.com589708b2012-07-26 20:04:23 +0000790}
791
792SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
793 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)
794 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient)
795 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient)
rileya@google.com589708b2012-07-26 20:04:23 +0000796 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient)
797SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END