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