1
2 /*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10 #include "SkGradientShader.h"
11 #include "SkClampRange.h"
12 #include "SkColorPriv.h"
13 #include "SkMallocPixelRef.h"
14 #include "SkUnitMapper.h"
15 #include "SkUtils.h"
16 #include "SkTemplates.h"
17 #include "SkBitmapCache.h"
18
19 #ifndef SK_DISABLE_DITHER_32BIT_GRADIENT
20 #define USE_DITHER_32BIT_GRADIENT
21 #endif
22
sk_memset32_dither(uint32_t dst[],uint32_t v0,uint32_t v1,int count)23 static void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
24 int count) {
25 if (count > 0) {
26 if (v0 == v1) {
27 sk_memset32(dst, v0, count);
28 } else {
29 int pairs = count >> 1;
30 for (int i = 0; i < pairs; i++) {
31 *dst++ = v0;
32 *dst++ = v1;
33 }
34 if (count & 1) {
35 *dst = v0;
36 }
37 }
38 }
39 }
40
41 ///////////////////////////////////////////////////////////////////////////////
42 // Can't use a two-argument function with side effects like this in a
43 // constructor's initializer's argument list because the order of
44 // evaluations in that context is undefined (and backwards on linux/gcc).
unflatten_point(SkReader32 & buffer)45 static SkPoint unflatten_point(SkReader32& buffer) {
46 SkPoint retval;
47 retval.fX = buffer.readScalar();
48 retval.fY = buffer.readScalar();
49 return retval;
50 }
51
52 // Clamp
53
clamp_tileproc(SkFixed x)54 static SkFixed clamp_tileproc(SkFixed x) {
55 return SkClampMax(x, 0xFFFF);
56 }
57
58 // Repeat
59
repeat_tileproc(SkFixed x)60 static SkFixed repeat_tileproc(SkFixed x) {
61 return x & 0xFFFF;
62 }
63
repeat_bits(int x,const int bits)64 static inline int repeat_bits(int x, const int bits) {
65 return x & ((1 << bits) - 1);
66 }
67
repeat_8bits(int x)68 static inline int repeat_8bits(int x) {
69 return x & 0xFF;
70 }
71
72 // Mirror
73
74 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
75 // See http://code.google.com/p/skia/issues/detail?id=472
76 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
77 #pragma optimize("", off)
78 #endif
79
mirror_tileproc(SkFixed x)80 static inline SkFixed mirror_tileproc(SkFixed x) {
81 int s = x << 15 >> 31;
82 return (x ^ s) & 0xFFFF;
83 }
84
mirror_bits(int x,const int bits)85 static inline int mirror_bits(int x, const int bits) {
86 #ifdef SK_CPU_HAS_CONDITIONAL_INSTR
87 if (x & (1 << bits))
88 x = ~x;
89 return x & ((1 << bits) - 1);
90 #else
91 int s = x << (31 - bits) >> 31;
92 return (x ^ s) & ((1 << bits) - 1);
93 #endif
94 }
95
mirror_8bits(int x)96 static inline int mirror_8bits(int x) {
97 #ifdef SK_CPU_HAS_CONDITIONAL_INSTR
98 if (x & 256) {
99 x = ~x;
100 }
101 return x & 255;
102 #else
103 int s = x << 23 >> 31;
104 return (x ^ s) & 0xFF;
105 #endif
106 }
107
108 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
109 #pragma optimize("", on)
110 #endif
111
112 ///////////////////////////////////////////////////////////////////////////////
113
114 typedef SkFixed (*TileProc)(SkFixed);
115
116 static const TileProc gTileProcs[] = {
117 clamp_tileproc,
118 repeat_tileproc,
119 mirror_tileproc
120 };
121
122 ///////////////////////////////////////////////////////////////////////////////
123 ///////////////////////////////////////////////////////////////////////////////
124
125 class Gradient_Shader : public SkShader {
126 public:
127 Gradient_Shader(const SkColor colors[], const SkScalar pos[],
128 int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper);
129 virtual ~Gradient_Shader();
130
131 // overrides
132 virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
getFlags()133 virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
134 virtual bool isOpaque() const SK_OVERRIDE;
135
136 enum {
137 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
138 /// it, use a larger cache.
139 kCache16Bits = 8,
140 kGradient16Length = (1 << kCache16Bits),
141 /// Each cache gets 1 extra entry at the end so we don't have to
142 /// test for end-of-cache in lerps. This is also the value used
143 /// to stride *writes* into the dither cache; it must not be zero.
144 /// Total space for a cache is 2x kCache16Count entries: one
145 /// regular cache, one for dithering.
146 kCache16Count = kGradient16Length + 1,
147 kCache16Shift = 16 - kCache16Bits,
148 kSqrt16Shift = 8 - kCache16Bits,
149
150 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
151 /// it, use a larger cache.
152 kCache32Bits = 8,
153 kGradient32Length = (1 << kCache32Bits),
154 /// Each cache gets 1 extra entry at the end so we don't have to
155 /// test for end-of-cache in lerps. This is also the value used
156 /// to stride *writes* into the dither cache; it must not be zero.
157 /// Total space for a cache is 2x kCache32Count entries: one
158 /// regular cache, one for dithering.
159 kCache32Count = kGradient32Length + 1,
160 kCache32Shift = 16 - kCache32Bits,
161 kSqrt32Shift = 8 - kCache32Bits,
162
163 /// This value is used to *read* the dither cache; it may be 0
164 /// if dithering is disabled.
165 #ifdef USE_DITHER_32BIT_GRADIENT
166 kDitherStride32 = kCache32Count,
167 #else
168 kDitherStride32 = 0,
169 #endif
170 kDitherStride16 = kCache16Count,
171 kLerpRemainderMask32 = (1 << (16 - kCache32Bits)) - 1
172 };
173
174
175 protected:
176 Gradient_Shader(SkFlattenableReadBuffer& );
177 SkUnitMapper* fMapper;
178 SkMatrix fPtsToUnit; // set by subclass
179 SkMatrix fDstToIndex;
180 SkMatrix::MapXYProc fDstToIndexProc;
181 TileMode fTileMode;
182 TileProc fTileProc;
183 int fColorCount;
184 uint8_t fDstToIndexClass;
185 uint8_t fFlags;
186
187 struct Rec {
188 SkFixed fPos; // 0...1
189 uint32_t fScale; // (1 << 24) / range
190 };
191 Rec* fRecs;
192
193 virtual void flatten(SkFlattenableWriteBuffer& );
194 const uint16_t* getCache16() const;
195 const SkPMColor* getCache32() const;
196
197 void commonAsABitmap(SkBitmap*) const;
198 void commonAsAGradient(GradientInfo*) const;
199
200 private:
201 enum {
202 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
203
204 kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
205 };
206 SkColor fStorage[(kStorageSize + 3) >> 2];
207 SkColor* fOrigColors; // original colors, before modulation by paint in setContext
208 bool fColorsAreOpaque;
209
210 mutable uint16_t* fCache16; // working ptr. If this is NULL, we need to recompute the cache values
211 mutable SkPMColor* fCache32; // working ptr. If this is NULL, we need to recompute the cache values
212
213 mutable uint16_t* fCache16Storage; // storage for fCache16, allocated on demand
214 mutable SkMallocPixelRef* fCache32PixelRef;
215 mutable unsigned fCacheAlpha; // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
216
217 static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
218 static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
219 U8CPU alpha);
220 void setCacheAlpha(U8CPU alpha) const;
221 void initCommon();
222
223 typedef SkShader INHERITED;
224 };
225
scalarToU16(SkScalar x)226 static inline unsigned scalarToU16(SkScalar x) {
227 SkASSERT(x >= 0 && x <= SK_Scalar1);
228
229 #ifdef SK_SCALAR_IS_FLOAT
230 return (unsigned)(x * 0xFFFF);
231 #else
232 return x - (x >> 16); // probably should be x - (x > 0x7FFF) but that is slower
233 #endif
234 }
235
Gradient_Shader(const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)236 Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[],
237 int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper) {
238 SkASSERT(colorCount > 1);
239
240 fCacheAlpha = 256; // init to a value that paint.getAlpha() can't return
241
242 fMapper = mapper;
243 SkSafeRef(mapper);
244
245 SkASSERT((unsigned)mode < SkShader::kTileModeCount);
246 SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
247 fTileMode = mode;
248 fTileProc = gTileProcs[mode];
249
250 fCache16 = fCache16Storage = NULL;
251 fCache32 = NULL;
252 fCache32PixelRef = NULL;
253
254 /* Note: we let the caller skip the first and/or last position.
255 i.e. pos[0] = 0.3, pos[1] = 0.7
256 In these cases, we insert dummy entries to ensure that the final data
257 will be bracketed by [0, 1].
258 i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
259
260 Thus colorCount (the caller's value, and fColorCount (our value) may
261 differ by up to 2. In the above example:
262 colorCount = 2
263 fColorCount = 4
264 */
265 fColorCount = colorCount;
266 // check if we need to add in dummy start and/or end position/colors
267 bool dummyFirst = false;
268 bool dummyLast = false;
269 if (pos) {
270 dummyFirst = pos[0] != 0;
271 dummyLast = pos[colorCount - 1] != SK_Scalar1;
272 fColorCount += dummyFirst + dummyLast;
273 }
274
275 if (fColorCount > kColorStorageCount) {
276 size_t size = sizeof(SkColor) + sizeof(Rec);
277 fOrigColors = reinterpret_cast<SkColor*>(
278 sk_malloc_throw(size * fColorCount));
279 }
280 else {
281 fOrigColors = fStorage;
282 }
283
284 // Now copy over the colors, adding the dummies as needed
285 {
286 SkColor* origColors = fOrigColors;
287 if (dummyFirst) {
288 *origColors++ = colors[0];
289 }
290 memcpy(origColors, colors, colorCount * sizeof(SkColor));
291 if (dummyLast) {
292 origColors += colorCount;
293 *origColors = colors[colorCount - 1];
294 }
295 }
296
297 fRecs = (Rec*)(fOrigColors + fColorCount);
298 if (fColorCount > 2) {
299 Rec* recs = fRecs;
300 recs->fPos = 0;
301 // recs->fScale = 0; // unused;
302 recs += 1;
303 if (pos) {
304 /* We need to convert the user's array of relative positions into
305 fixed-point positions and scale factors. We need these results
306 to be strictly monotonic (no two values equal or out of order).
307 Hence this complex loop that just jams a zero for the scale
308 value if it sees a segment out of order, and it assures that
309 we start at 0 and end at 1.0
310 */
311 SkFixed prev = 0;
312 int startIndex = dummyFirst ? 0 : 1;
313 int count = colorCount + dummyLast;
314 for (int i = startIndex; i < count; i++) {
315 // force the last value to be 1.0
316 SkFixed curr;
317 if (i == colorCount) { // we're really at the dummyLast
318 curr = SK_Fixed1;
319 } else {
320 curr = SkScalarToFixed(pos[i]);
321 }
322 // pin curr withing range
323 if (curr < 0) {
324 curr = 0;
325 } else if (curr > SK_Fixed1) {
326 curr = SK_Fixed1;
327 }
328 recs->fPos = curr;
329 if (curr > prev) {
330 recs->fScale = (1 << 24) / (curr - prev);
331 } else {
332 recs->fScale = 0; // ignore this segment
333 }
334 // get ready for the next value
335 prev = curr;
336 recs += 1;
337 }
338 } else { // assume even distribution
339 SkFixed dp = SK_Fixed1 / (colorCount - 1);
340 SkFixed p = dp;
341 SkFixed scale = (colorCount - 1) << 8; // (1 << 24) / dp
342 for (int i = 1; i < colorCount; i++) {
343 recs->fPos = p;
344 recs->fScale = scale;
345 recs += 1;
346 p += dp;
347 }
348 }
349 }
350 this->initCommon();
351 }
352
Gradient_Shader(SkFlattenableReadBuffer & buffer)353 Gradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) :
354 INHERITED(buffer) {
355 fCacheAlpha = 256;
356
357 fMapper = static_cast<SkUnitMapper*>(buffer.readFlattenable());
358
359 fCache16 = fCache16Storage = NULL;
360 fCache32 = NULL;
361 fCache32PixelRef = NULL;
362
363 int colorCount = fColorCount = buffer.readU32();
364 if (colorCount > kColorStorageCount) {
365 size_t size = sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec);
366 fOrigColors = (SkColor*)sk_malloc_throw(size * colorCount);
367 } else {
368 fOrigColors = fStorage;
369 }
370 buffer.read(fOrigColors, colorCount * sizeof(SkColor));
371
372 fTileMode = (TileMode)buffer.readU8();
373 fTileProc = gTileProcs[fTileMode];
374 fRecs = (Rec*)(fOrigColors + colorCount);
375 if (colorCount > 2) {
376 Rec* recs = fRecs;
377 recs[0].fPos = 0;
378 for (int i = 1; i < colorCount; i++) {
379 recs[i].fPos = buffer.readS32();
380 recs[i].fScale = buffer.readU32();
381 }
382 }
383 SkReadMatrix(&buffer, &fPtsToUnit);
384 this->initCommon();
385 }
386
~Gradient_Shader()387 Gradient_Shader::~Gradient_Shader() {
388 if (fCache16Storage) {
389 sk_free(fCache16Storage);
390 }
391 SkSafeUnref(fCache32PixelRef);
392 if (fOrigColors != fStorage) {
393 sk_free(fOrigColors);
394 }
395 SkSafeUnref(fMapper);
396 }
397
initCommon()398 void Gradient_Shader::initCommon() {
399 fFlags = 0;
400 unsigned colorAlpha = 0xFF;
401 for (int i = 0; i < fColorCount; i++) {
402 colorAlpha &= SkColorGetA(fOrigColors[i]);
403 }
404 fColorsAreOpaque = colorAlpha == 0xFF;
405 }
406
flatten(SkFlattenableWriteBuffer & buffer)407 void Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer) {
408 this->INHERITED::flatten(buffer);
409 buffer.writeFlattenable(fMapper);
410 buffer.write32(fColorCount);
411 buffer.writeMul4(fOrigColors, fColorCount * sizeof(SkColor));
412 buffer.write8(fTileMode);
413 if (fColorCount > 2) {
414 Rec* recs = fRecs;
415 for (int i = 1; i < fColorCount; i++) {
416 buffer.write32(recs[i].fPos);
417 buffer.write32(recs[i].fScale);
418 }
419 }
420 SkWriteMatrix(&buffer, fPtsToUnit);
421 }
422
isOpaque() const423 bool Gradient_Shader::isOpaque() const {
424 return fColorsAreOpaque;
425 }
426
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)427 bool Gradient_Shader::setContext(const SkBitmap& device,
428 const SkPaint& paint,
429 const SkMatrix& matrix) {
430 if (!this->INHERITED::setContext(device, paint, matrix)) {
431 return false;
432 }
433
434 const SkMatrix& inverse = this->getTotalInverse();
435
436 if (!fDstToIndex.setConcat(fPtsToUnit, inverse)) {
437 return false;
438 }
439
440 fDstToIndexProc = fDstToIndex.getMapXYProc();
441 fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex);
442
443 // now convert our colors in to PMColors
444 unsigned paintAlpha = this->getPaintAlpha();
445
446 fFlags = this->INHERITED::getFlags();
447 if (fColorsAreOpaque && paintAlpha == 0xFF) {
448 fFlags |= kOpaqueAlpha_Flag;
449 }
450 // we can do span16 as long as our individual colors are opaque,
451 // regardless of the paint's alpha
452 if (fColorsAreOpaque) {
453 fFlags |= kHasSpan16_Flag;
454 }
455
456 this->setCacheAlpha(paintAlpha);
457 return true;
458 }
459
setCacheAlpha(U8CPU alpha) const460 void Gradient_Shader::setCacheAlpha(U8CPU alpha) const {
461 // if the new alpha differs from the previous time we were called, inval our cache
462 // this will trigger the cache to be rebuilt.
463 // we don't care about the first time, since the cache ptrs will already be NULL
464 if (fCacheAlpha != alpha) {
465 fCache16 = NULL; // inval the cache
466 fCache32 = NULL; // inval the cache
467 fCacheAlpha = alpha; // record the new alpha
468 // inform our subclasses
469 if (fCache32PixelRef) {
470 fCache32PixelRef->notifyPixelsChanged();
471 }
472 }
473 }
474
blend8(int a,int b,int scale)475 static inline int blend8(int a, int b, int scale) {
476 SkASSERT(a == SkToU8(a));
477 SkASSERT(b == SkToU8(b));
478 SkASSERT(scale >= 0 && scale <= 256);
479 return a + ((b - a) * scale >> 8);
480 }
481
dot8_blend_packed32(uint32_t s0,uint32_t s1,int blend)482 static inline uint32_t dot8_blend_packed32(uint32_t s0, uint32_t s1,
483 int blend) {
484 #if 0
485 int a = blend8(SkGetPackedA32(s0), SkGetPackedA32(s1), blend);
486 int r = blend8(SkGetPackedR32(s0), SkGetPackedR32(s1), blend);
487 int g = blend8(SkGetPackedG32(s0), SkGetPackedG32(s1), blend);
488 int b = blend8(SkGetPackedB32(s0), SkGetPackedB32(s1), blend);
489
490 return SkPackARGB32(a, r, g, b);
491 #else
492 int otherBlend = 256 - blend;
493
494 #if 0
495 U32 t0 = (((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF;
496 U32 t1 = (((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00;
497 SkASSERT((t0 & t1) == 0);
498 return t0 | t1;
499 #else
500 return ((((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF) |
501 ((((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00);
502 #endif
503
504 #endif
505 }
506
507 #define Fixed_To_Dot8(x) (((x) + 0x80) >> 8)
508
509 /** We take the original colors, not our premultiplied PMColors, since we can
510 build a 16bit table as long as the original colors are opaque, even if the
511 paint specifies a non-opaque alpha.
512 */
Build16bitCache(uint16_t cache[],SkColor c0,SkColor c1,int count)513 void Gradient_Shader::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1,
514 int count) {
515 SkASSERT(count > 1);
516 SkASSERT(SkColorGetA(c0) == 0xFF);
517 SkASSERT(SkColorGetA(c1) == 0xFF);
518
519 SkFixed r = SkColorGetR(c0);
520 SkFixed g = SkColorGetG(c0);
521 SkFixed b = SkColorGetB(c0);
522
523 SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
524 SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
525 SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
526
527 r = SkIntToFixed(r) + 0x8000;
528 g = SkIntToFixed(g) + 0x8000;
529 b = SkIntToFixed(b) + 0x8000;
530
531 do {
532 unsigned rr = r >> 16;
533 unsigned gg = g >> 16;
534 unsigned bb = b >> 16;
535 cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
536 cache[kCache16Count] = SkDitherPack888ToRGB16(rr, gg, bb);
537 cache += 1;
538 r += dr;
539 g += dg;
540 b += db;
541 } while (--count != 0);
542 }
543
544 /*
545 * 2x2 dither a fixed-point color component (8.16) down to 8, matching the
546 * semantics of how we 2x2 dither 32->16
547 */
dither_fixed_to_8(SkFixed n)548 static inline U8CPU dither_fixed_to_8(SkFixed n) {
549 n >>= 8;
550 return ((n << 1) - ((n >> 8 << 8) | (n >> 8))) >> 8;
551 }
552
553 /*
554 * For dithering with premultiply, we want to ceiling the alpha component,
555 * to ensure that it is always >= any color component.
556 */
dither_ceil_fixed_to_8(SkFixed n)557 static inline U8CPU dither_ceil_fixed_to_8(SkFixed n) {
558 n >>= 8;
559 return ((n << 1) - (n | (n >> 8))) >> 8;
560 }
561
Build32bitCache(SkPMColor cache[],SkColor c0,SkColor c1,int count,U8CPU paintAlpha)562 void Gradient_Shader::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
563 int count, U8CPU paintAlpha) {
564 SkASSERT(count > 1);
565
566 // need to apply paintAlpha to our two endpoints
567 SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
568 SkFixed da;
569 {
570 int tmp = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
571 da = SkIntToFixed(tmp - a) / (count - 1);
572 }
573
574 SkFixed r = SkColorGetR(c0);
575 SkFixed g = SkColorGetG(c0);
576 SkFixed b = SkColorGetB(c0);
577 SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
578 SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
579 SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
580
581 a = SkIntToFixed(a) + 0x8000;
582 r = SkIntToFixed(r) + 0x8000;
583 g = SkIntToFixed(g) + 0x8000;
584 b = SkIntToFixed(b) + 0x8000;
585
586 do {
587 cache[0] = SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16);
588 cache[kCache32Count] =
589 SkPremultiplyARGBInline(dither_ceil_fixed_to_8(a),
590 dither_fixed_to_8(r),
591 dither_fixed_to_8(g),
592 dither_fixed_to_8(b));
593 cache += 1;
594 a += da;
595 r += dr;
596 g += dg;
597 b += db;
598 } while (--count != 0);
599 }
600
SkFixedToFFFF(SkFixed x)601 static inline int SkFixedToFFFF(SkFixed x) {
602 SkASSERT((unsigned)x <= SK_Fixed1);
603 return x - (x >> 16);
604 }
605
bitsTo16(unsigned x,const unsigned bits)606 static inline U16CPU bitsTo16(unsigned x, const unsigned bits) {
607 SkASSERT(x < (1U << bits));
608 if (6 == bits) {
609 return (x << 10) | (x << 4) | (x >> 2);
610 }
611 if (8 == bits) {
612 return (x << 8) | x;
613 }
614 sk_throw();
615 return 0;
616 }
617
618 /** We duplicate the last value in each half of the cache so that
619 interpolation doesn't have to special-case being at the last point.
620 */
complete_16bit_cache(uint16_t * cache,int stride)621 static void complete_16bit_cache(uint16_t* cache, int stride) {
622 cache[stride - 1] = cache[stride - 2];
623 cache[2 * stride - 1] = cache[2 * stride - 2];
624 }
625
getCache16() const626 const uint16_t* Gradient_Shader::getCache16() const {
627 if (fCache16 == NULL) {
628 // double the count for dither entries
629 const int entryCount = kCache16Count * 2;
630 const size_t allocSize = sizeof(uint16_t) * entryCount;
631
632 if (fCache16Storage == NULL) { // set the storage and our working ptr
633 fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
634 }
635 fCache16 = fCache16Storage;
636 if (fColorCount == 2) {
637 Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1],
638 kGradient16Length);
639 } else {
640 Rec* rec = fRecs;
641 int prevIndex = 0;
642 for (int i = 1; i < fColorCount; i++) {
643 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
644 SkASSERT(nextIndex < kCache16Count);
645
646 if (nextIndex > prevIndex)
647 Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1);
648 prevIndex = nextIndex;
649 }
650 // one extra space left over at the end for complete_16bit_cache()
651 SkASSERT(prevIndex == kGradient16Length - 1);
652 }
653
654 if (fMapper) {
655 fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
656 uint16_t* linear = fCache16; // just computed linear data
657 uint16_t* mapped = fCache16Storage; // storage for mapped data
658 SkUnitMapper* map = fMapper;
659 for (int i = 0; i < kGradient16Length; i++) {
660 int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift;
661 mapped[i] = linear[index];
662 mapped[i + kCache16Count] = linear[index + kCache16Count];
663 }
664 sk_free(fCache16);
665 fCache16 = fCache16Storage;
666 }
667 complete_16bit_cache(fCache16, kCache16Count);
668 }
669 return fCache16;
670 }
671
672 /** We duplicate the last value in each half of the cache so that
673 interpolation doesn't have to special-case being at the last point.
674 */
complete_32bit_cache(SkPMColor * cache,int stride)675 static void complete_32bit_cache(SkPMColor* cache, int stride) {
676 cache[stride - 1] = cache[stride - 2];
677 cache[2 * stride - 1] = cache[2 * stride - 2];
678 }
679
getCache32() const680 const SkPMColor* Gradient_Shader::getCache32() const {
681 if (fCache32 == NULL) {
682 // double the count for dither entries
683 const int entryCount = kCache32Count * 2;
684 const size_t allocSize = sizeof(SkPMColor) * entryCount;
685
686 if (NULL == fCache32PixelRef) {
687 fCache32PixelRef = SkNEW_ARGS(SkMallocPixelRef,
688 (NULL, allocSize, NULL));
689 }
690 fCache32 = (SkPMColor*)fCache32PixelRef->getAddr();
691 if (fColorCount == 2) {
692 Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
693 kGradient32Length, fCacheAlpha);
694 } else {
695 Rec* rec = fRecs;
696 int prevIndex = 0;
697 for (int i = 1; i < fColorCount; i++) {
698 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
699 SkASSERT(nextIndex < kGradient32Length);
700
701 if (nextIndex > prevIndex)
702 Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1],
703 fOrigColors[i],
704 nextIndex - prevIndex + 1, fCacheAlpha);
705 prevIndex = nextIndex;
706 }
707 SkASSERT(prevIndex == kGradient32Length - 1);
708 }
709
710 if (fMapper) {
711 SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef,
712 (NULL, allocSize, NULL));
713 SkPMColor* linear = fCache32; // just computed linear data
714 SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data
715 SkUnitMapper* map = fMapper;
716 for (int i = 0; i < kGradient32Length; i++) {
717 int index = map->mapUnit16((i << 8) | i) >> 8;
718 mapped[i] = linear[index];
719 mapped[i + kCache32Count] = linear[index + kCache32Count];
720 }
721 fCache32PixelRef->unref();
722 fCache32PixelRef = newPR;
723 fCache32 = (SkPMColor*)newPR->getAddr();
724 }
725 complete_32bit_cache(fCache32, kCache32Count);
726 }
727 return fCache32;
728 }
729
730 /*
731 * Because our caller might rebuild the same (logically the same) gradient
732 * over and over, we'd like to return exactly the same "bitmap" if possible,
733 * allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
734 * To do that, we maintain a private cache of built-bitmaps, based on our
735 * colors and positions. Note: we don't try to flatten the fMapper, so if one
736 * is present, we skip the cache for now.
737 */
commonAsABitmap(SkBitmap * bitmap) const738 void Gradient_Shader::commonAsABitmap(SkBitmap* bitmap) const {
739 // our caller assumes no external alpha, so we ensure that our cache is
740 // built with 0xFF
741 this->setCacheAlpha(0xFF);
742
743 // don't have a way to put the mapper into our cache-key yet
744 if (fMapper) {
745 // force our cahce32pixelref to be built
746 (void)this->getCache32();
747 bitmap->setConfig(SkBitmap::kARGB_8888_Config, kGradient32Length, 1);
748 bitmap->setPixelRef(fCache32PixelRef);
749 return;
750 }
751
752 // build our key: [numColors + colors[] + {positions[]} ]
753 int count = 1 + fColorCount;
754 if (fColorCount > 2) {
755 count += fColorCount - 1; // fRecs[].fPos
756 }
757
758 SkAutoSTMalloc<16, int32_t> storage(count);
759 int32_t* buffer = storage.get();
760
761 *buffer++ = fColorCount;
762 memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor));
763 buffer += fColorCount;
764 if (fColorCount > 2) {
765 for (int i = 1; i < fColorCount; i++) {
766 *buffer++ = fRecs[i].fPos;
767 }
768 }
769 SkASSERT(buffer - storage.get() == count);
770
771 ///////////////////////////////////
772
773 SK_DECLARE_STATIC_MUTEX(gMutex);
774 static SkBitmapCache* gCache;
775 // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp
776 static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
777 SkAutoMutexAcquire ama(gMutex);
778
779 if (NULL == gCache) {
780 gCache = new SkBitmapCache(MAX_NUM_CACHED_GRADIENT_BITMAPS);
781 }
782 size_t size = count * sizeof(int32_t);
783
784 if (!gCache->find(storage.get(), size, bitmap)) {
785 // force our cahce32pixelref to be built
786 (void)this->getCache32();
787 // Only expose the linear section of the cache; don't let the caller
788 // know about the padding at the end to make interpolation faster.
789 bitmap->setConfig(SkBitmap::kARGB_8888_Config, kGradient32Length, 1);
790 bitmap->setPixelRef(fCache32PixelRef);
791
792 gCache->add(storage.get(), size, *bitmap);
793 }
794 }
795
commonAsAGradient(GradientInfo * info) const796 void Gradient_Shader::commonAsAGradient(GradientInfo* info) const {
797 if (info) {
798 if (info->fColorCount >= fColorCount) {
799 if (info->fColors) {
800 memcpy(info->fColors, fOrigColors,
801 fColorCount * sizeof(SkColor));
802 }
803 if (info->fColorOffsets) {
804 if (fColorCount == 2) {
805 info->fColorOffsets[0] = 0;
806 info->fColorOffsets[1] = SK_Scalar1;
807 } else if (fColorCount > 2) {
808 for (int i = 0; i < fColorCount; i++)
809 info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos);
810 }
811 }
812 }
813 info->fColorCount = fColorCount;
814 info->fTileMode = fTileMode;
815 }
816 }
817
818 ///////////////////////////////////////////////////////////////////////////////
819
pts_to_unit_matrix(const SkPoint pts[2],SkMatrix * matrix)820 static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
821 SkVector vec = pts[1] - pts[0];
822 SkScalar mag = vec.length();
823 SkScalar inv = mag ? SkScalarInvert(mag) : 0;
824
825 vec.scale(inv);
826 matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
827 matrix->postTranslate(-pts[0].fX, -pts[0].fY);
828 matrix->postScale(inv, inv);
829 }
830
831 ///////////////////////////////////////////////////////////////////////////////
832
833 class Linear_Gradient : public Gradient_Shader {
834 public:
Linear_Gradient(const SkPoint pts[2],const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)835 Linear_Gradient(const SkPoint pts[2],
836 const SkColor colors[], const SkScalar pos[], int colorCount,
837 SkShader::TileMode mode, SkUnitMapper* mapper)
838 : Gradient_Shader(colors, pos, colorCount, mode, mapper),
839 fStart(pts[0]),
840 fEnd(pts[1])
841 {
842 pts_to_unit_matrix(pts, &fPtsToUnit);
843 }
844
845 virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
846 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
847 virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
848 virtual BitmapType asABitmap(SkBitmap*, SkMatrix*, TileMode*,
849 SkScalar* twoPointRadialParams) const SK_OVERRIDE;
850 virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE;
851
CreateProc(SkFlattenableReadBuffer & buffer)852 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
853 return SkNEW_ARGS(Linear_Gradient, (buffer));
854 }
855
flatten(SkFlattenableWriteBuffer & buffer)856 virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
857 this->INHERITED::flatten(buffer);
858 buffer.writeScalar(fStart.fX);
859 buffer.writeScalar(fStart.fY);
860 buffer.writeScalar(fEnd.fX);
861 buffer.writeScalar(fEnd.fY);
862 }
863
864 SK_DECLARE_FLATTENABLE_REGISTRAR()
865
866 protected:
Linear_Gradient(SkFlattenableReadBuffer & buffer)867 Linear_Gradient(SkFlattenableReadBuffer& buffer)
868 : Gradient_Shader(buffer),
869 fStart(unflatten_point(buffer)),
870 fEnd(unflatten_point(buffer)) {
871 }
getFactory()872 virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
873
874 private:
875 typedef Gradient_Shader INHERITED;
876 const SkPoint fStart;
877 const SkPoint fEnd;
878 };
879
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)880 bool Linear_Gradient::setContext(const SkBitmap& device, const SkPaint& paint,
881 const SkMatrix& matrix) {
882 if (!this->INHERITED::setContext(device, paint, matrix)) {
883 return false;
884 }
885
886 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
887 if ((fDstToIndex.getType() & ~mask) == 0) {
888 fFlags |= SkShader::kConstInY32_Flag;
889 if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
890 // only claim this if we do have a 16bit mode (i.e. none of our
891 // colors have alpha), and if we are not dithering (which obviously
892 // is not const in Y).
893 fFlags |= SkShader::kConstInY16_Flag;
894 }
895 }
896 return true;
897 }
898
899 #define NO_CHECK_ITER \
900 do { \
901 unsigned fi = fx >> Gradient_Shader::kCache32Shift; \
902 SkASSERT(fi <= 0xFF); \
903 fx += dx; \
904 *dstC++ = cache[toggle + fi]; \
905 toggle ^= Gradient_Shader::kDitherStride32; \
906 } while (0)
907
908 namespace {
909
910 typedef void (*LinearShadeProc)(TileProc proc, SkFixed dx, SkFixed fx,
911 SkPMColor* dstC, const SkPMColor* cache,
912 int toggle, int count);
913
914 // This function is deprecated, and will be replaced by
915 // shadeSpan_linear_vertical_lerp() once Chrome has been weaned off of it.
shadeSpan_linear_vertical(TileProc proc,SkFixed dx,SkFixed fx,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int toggle,int count)916 void shadeSpan_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
917 SkPMColor* SK_RESTRICT dstC,
918 const SkPMColor* SK_RESTRICT cache,
919 int toggle, int count) {
920 // We're a vertical gradient, so no change in a span.
921 // If colors change sharply across the gradient, dithering is
922 // insufficient (it subsamples the color space) and we need to lerp.
923 unsigned fullIndex = proc(fx);
924 unsigned fi = fullIndex >> (16 - Gradient_Shader::kCache32Bits);
925 sk_memset32_dither(dstC,
926 cache[toggle + fi],
927 cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi],
928 count);
929 }
930
931 // Linear interpolation (lerp) is unnecessary if there are no sharp
932 // discontinuities in the gradient - which must be true if there are
933 // only 2 colors - but it's cheap.
shadeSpan_linear_vertical_lerp(TileProc proc,SkFixed dx,SkFixed fx,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int toggle,int count)934 void shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx,
935 SkPMColor* SK_RESTRICT dstC,
936 const SkPMColor* SK_RESTRICT cache,
937 int toggle, int count) {
938 // We're a vertical gradient, so no change in a span.
939 // If colors change sharply across the gradient, dithering is
940 // insufficient (it subsamples the color space) and we need to lerp.
941 unsigned fullIndex = proc(fx);
942 unsigned fi = fullIndex >> (16 - Gradient_Shader::kCache32Bits);
943 unsigned remainder = fullIndex & Gradient_Shader::kLerpRemainderMask32;
944 SkPMColor lerp =
945 SkFastFourByteInterp(
946 cache[toggle + fi + 1],
947 cache[toggle + fi], remainder);
948 SkPMColor dlerp =
949 SkFastFourByteInterp(
950 cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi + 1],
951 cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi], remainder);
952 sk_memset32_dither(dstC, lerp, dlerp, count);
953 }
954
shadeSpan_linear_clamp(TileProc proc,SkFixed dx,SkFixed fx,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int toggle,int count)955 void shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
956 SkPMColor* SK_RESTRICT dstC,
957 const SkPMColor* SK_RESTRICT cache,
958 int toggle, int count) {
959 SkClampRange range;
960 range.init(fx, dx, count, 0, Gradient_Shader::kGradient32Length);
961
962 if ((count = range.fCount0) > 0) {
963 sk_memset32_dither(dstC,
964 cache[toggle + range.fV0],
965 cache[(toggle ^ Gradient_Shader::kDitherStride32) + range.fV0],
966 count);
967 dstC += count;
968 }
969 if ((count = range.fCount1) > 0) {
970 int unroll = count >> 3;
971 fx = range.fFx1;
972 for (int i = 0; i < unroll; i++) {
973 NO_CHECK_ITER; NO_CHECK_ITER;
974 NO_CHECK_ITER; NO_CHECK_ITER;
975 NO_CHECK_ITER; NO_CHECK_ITER;
976 NO_CHECK_ITER; NO_CHECK_ITER;
977 }
978 if ((count &= 7) > 0) {
979 do {
980 NO_CHECK_ITER;
981 } while (--count != 0);
982 }
983 }
984 if ((count = range.fCount2) > 0) {
985 sk_memset32_dither(dstC,
986 cache[toggle + range.fV1],
987 cache[(toggle ^ Gradient_Shader::kDitherStride32) + range.fV1],
988 count);
989 }
990 }
991
shadeSpan_linear_mirror(TileProc proc,SkFixed dx,SkFixed fx,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int toggle,int count)992 void shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
993 SkPMColor* SK_RESTRICT dstC,
994 const SkPMColor* SK_RESTRICT cache,
995 int toggle, int count) {
996 do {
997 unsigned fi = mirror_8bits(fx >> 8);
998 SkASSERT(fi <= 0xFF);
999 fx += dx;
1000 *dstC++ = cache[toggle + fi];
1001 toggle ^= Gradient_Shader::kDitherStride32;
1002 } while (--count != 0);
1003 }
1004
shadeSpan_linear_repeat(TileProc proc,SkFixed dx,SkFixed fx,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int toggle,int count)1005 void shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
1006 SkPMColor* SK_RESTRICT dstC,
1007 const SkPMColor* SK_RESTRICT cache,
1008 int toggle, int count) {
1009 do {
1010 unsigned fi = repeat_8bits(fx >> 8);
1011 SkASSERT(fi <= 0xFF);
1012 fx += dx;
1013 *dstC++ = cache[toggle + fi];
1014 toggle ^= Gradient_Shader::kDitherStride32;
1015 } while (--count != 0);
1016 }
1017
1018 }
1019
shadeSpan(int x,int y,SkPMColor * SK_RESTRICT dstC,int count)1020 void Linear_Gradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
1021 int count) {
1022 SkASSERT(count > 0);
1023
1024 SkPoint srcPt;
1025 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1026 TileProc proc = fTileProc;
1027 const SkPMColor* SK_RESTRICT cache = this->getCache32();
1028 #ifdef USE_DITHER_32BIT_GRADIENT
1029 int toggle = ((x ^ y) & 1) * kDitherStride32;
1030 #else
1031 int toggle = 0;
1032 #endif
1033
1034 if (fDstToIndexClass != kPerspective_MatrixClass) {
1035 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
1036 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1037 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1038
1039 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1040 SkFixed dxStorage[1];
1041 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
1042 dx = dxStorage[0];
1043 } else {
1044 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1045 dx = SkScalarToFixed(fDstToIndex.getScaleX());
1046 }
1047
1048 LinearShadeProc shadeProc = shadeSpan_linear_repeat;
1049 // We really should check the endpoint colors, but short of that change
1050 // we reduce the tolerance of SkFixedNearlyZero to be more restrictive.
1051 if (SkFixedNearlyZero(dx, (SK_Fixed1 >> 14))) {
1052 #ifdef SK_SIMPLE_TWOCOLOR_VERTICAL_GRADIENTS
1053 if (fColorCount > 2) {
1054 shadeProc = shadeSpan_linear_vertical_lerp;
1055 } else {
1056 shadeProc = shadeSpan_linear_vertical;
1057 }
1058 #else
1059 shadeProc = shadeSpan_linear_vertical_lerp;
1060 #endif
1061 } else if (proc == clamp_tileproc) {
1062 shadeProc = shadeSpan_linear_clamp;
1063 } else if (proc == mirror_tileproc) {
1064 shadeProc = shadeSpan_linear_mirror;
1065 } else {
1066 SkASSERT(proc == repeat_tileproc);
1067 }
1068 (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
1069 } else {
1070 SkScalar dstX = SkIntToScalar(x);
1071 SkScalar dstY = SkIntToScalar(y);
1072 do {
1073 dstProc(fDstToIndex, dstX, dstY, &srcPt);
1074 unsigned fi = proc(SkScalarToFixed(srcPt.fX));
1075 SkASSERT(fi <= 0xFFFF);
1076 *dstC++ = cache[toggle + (fi >> kCache32Shift)];
1077 toggle ^= Gradient_Shader::kDitherStride32;
1078 dstX += SK_Scalar1;
1079 } while (--count != 0);
1080 }
1081 }
1082
asABitmap(SkBitmap * bitmap,SkMatrix * matrix,TileMode xy[],SkScalar * twoPointRadialParams) const1083 SkShader::BitmapType Linear_Gradient::asABitmap(SkBitmap* bitmap,
1084 SkMatrix* matrix,
1085 TileMode xy[],
1086 SkScalar* twoPointRadialParams) const {
1087 if (bitmap) {
1088 this->commonAsABitmap(bitmap);
1089 }
1090 if (matrix) {
1091 matrix->setScale(SkIntToScalar(kGradient32Length), SK_Scalar1);
1092 matrix->preConcat(fPtsToUnit);
1093 }
1094 if (xy) {
1095 xy[0] = fTileMode;
1096 xy[1] = kClamp_TileMode;
1097 }
1098 return kDefault_BitmapType;
1099 }
1100
asAGradient(GradientInfo * info) const1101 SkShader::GradientType Linear_Gradient::asAGradient(GradientInfo* info) const {
1102 if (info) {
1103 commonAsAGradient(info);
1104 info->fPoint[0] = fStart;
1105 info->fPoint[1] = fEnd;
1106 }
1107 return kLinear_GradientType;
1108 }
1109
dither_memset16(uint16_t dst[],uint16_t value,uint16_t other,int count)1110 static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
1111 int count) {
1112 if (reinterpret_cast<uintptr_t>(dst) & 2) {
1113 *dst++ = value;
1114 count -= 1;
1115 SkTSwap(value, other);
1116 }
1117
1118 sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
1119
1120 if (count & 1) {
1121 dst[count - 1] = value;
1122 }
1123 }
1124
1125 #define NO_CHECK_ITER_16 \
1126 do { \
1127 unsigned fi = fx >> Gradient_Shader::kCache16Shift; \
1128 SkASSERT(fi < Gradient_Shader::kCache16Count); \
1129 fx += dx; \
1130 *dstC++ = cache[toggle + fi]; \
1131 toggle ^= Gradient_Shader::kDitherStride16; \
1132 } while (0)
1133
1134 namespace {
1135
1136 typedef void (*LinearShade16Proc)(TileProc proc, SkFixed dx, SkFixed fx,
1137 uint16_t* dstC, const uint16_t* cache,
1138 int toggle, int count);
1139
shadeSpan16_linear_vertical(TileProc proc,SkFixed dx,SkFixed fx,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1140 void shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
1141 uint16_t* SK_RESTRICT dstC,
1142 const uint16_t* SK_RESTRICT cache,
1143 int toggle, int count) {
1144 // we're a vertical gradient, so no change in a span
1145 unsigned fi = proc(fx) >> Gradient_Shader::kCache16Shift;
1146 SkASSERT(fi < Gradient_Shader::kCache16Count);
1147 dither_memset16(dstC, cache[toggle + fi],
1148 cache[(toggle ^ Gradient_Shader::kDitherStride16) + fi], count);
1149
1150 }
1151
shadeSpan16_linear_clamp(TileProc proc,SkFixed dx,SkFixed fx,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1152 void shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
1153 uint16_t* SK_RESTRICT dstC,
1154 const uint16_t* SK_RESTRICT cache,
1155 int toggle, int count) {
1156 SkClampRange range;
1157 range.init(fx, dx, count, 0, Gradient_Shader::kGradient16Length);
1158
1159 if ((count = range.fCount0) > 0) {
1160 dither_memset16(dstC,
1161 cache[toggle + range.fV0],
1162 cache[(toggle ^ Gradient_Shader::kDitherStride16) + range.fV0],
1163 count);
1164 dstC += count;
1165 }
1166 if ((count = range.fCount1) > 0) {
1167 int unroll = count >> 3;
1168 fx = range.fFx1;
1169 for (int i = 0; i < unroll; i++) {
1170 NO_CHECK_ITER_16; NO_CHECK_ITER_16;
1171 NO_CHECK_ITER_16; NO_CHECK_ITER_16;
1172 NO_CHECK_ITER_16; NO_CHECK_ITER_16;
1173 NO_CHECK_ITER_16; NO_CHECK_ITER_16;
1174 }
1175 if ((count &= 7) > 0) {
1176 do {
1177 NO_CHECK_ITER_16;
1178 } while (--count != 0);
1179 }
1180 }
1181 if ((count = range.fCount2) > 0) {
1182 dither_memset16(dstC,
1183 cache[toggle + range.fV1],
1184 cache[(toggle ^ Gradient_Shader::kDitherStride16) + range.fV1],
1185 count);
1186 }
1187 }
1188
shadeSpan16_linear_mirror(TileProc proc,SkFixed dx,SkFixed fx,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1189 void shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
1190 uint16_t* SK_RESTRICT dstC,
1191 const uint16_t* SK_RESTRICT cache,
1192 int toggle, int count) {
1193 do {
1194 unsigned fi = mirror_bits(fx >> Gradient_Shader::kCache16Shift,
1195 Gradient_Shader::kCache16Bits);
1196 SkASSERT(fi < Gradient_Shader::kCache16Count);
1197 fx += dx;
1198 *dstC++ = cache[toggle + fi];
1199 toggle ^= Gradient_Shader::kDitherStride16;
1200 } while (--count != 0);
1201 }
1202
shadeSpan16_linear_repeat(TileProc proc,SkFixed dx,SkFixed fx,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1203 void shadeSpan16_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
1204 uint16_t* SK_RESTRICT dstC,
1205 const uint16_t* SK_RESTRICT cache,
1206 int toggle, int count) {
1207 SkASSERT(proc == repeat_tileproc);
1208 do {
1209 unsigned fi = repeat_bits(fx >> Gradient_Shader::kCache16Shift,
1210 Gradient_Shader::kCache16Bits);
1211 SkASSERT(fi < Gradient_Shader::kCache16Count);
1212 fx += dx;
1213 *dstC++ = cache[toggle + fi];
1214 toggle ^= Gradient_Shader::kDitherStride16;
1215 } while (--count != 0);
1216 }
1217 }
1218
shadeSpan16(int x,int y,uint16_t * SK_RESTRICT dstC,int count)1219 void Linear_Gradient::shadeSpan16(int x, int y,
1220 uint16_t* SK_RESTRICT dstC, int count) {
1221 SkASSERT(count > 0);
1222
1223 SkPoint srcPt;
1224 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1225 TileProc proc = fTileProc;
1226 const uint16_t* SK_RESTRICT cache = this->getCache16();
1227 int toggle = ((x ^ y) & 1) * kDitherStride16;
1228
1229 if (fDstToIndexClass != kPerspective_MatrixClass) {
1230 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
1231 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1232 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1233
1234 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1235 SkFixed dxStorage[1];
1236 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
1237 dx = dxStorage[0];
1238 } else {
1239 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1240 dx = SkScalarToFixed(fDstToIndex.getScaleX());
1241 }
1242
1243 LinearShade16Proc shadeProc = shadeSpan16_linear_repeat;
1244 if (SkFixedNearlyZero(dx)) {
1245 shadeProc = shadeSpan16_linear_vertical;
1246 } else if (proc == clamp_tileproc) {
1247 shadeProc = shadeSpan16_linear_clamp;
1248 } else if (proc == mirror_tileproc) {
1249 shadeProc = shadeSpan16_linear_mirror;
1250 } else {
1251 SkASSERT(proc == repeat_tileproc);
1252 }
1253 (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
1254 } else {
1255 SkScalar dstX = SkIntToScalar(x);
1256 SkScalar dstY = SkIntToScalar(y);
1257 do {
1258 dstProc(fDstToIndex, dstX, dstY, &srcPt);
1259 unsigned fi = proc(SkScalarToFixed(srcPt.fX));
1260 SkASSERT(fi <= 0xFFFF);
1261
1262 int index = fi >> kCache16Shift;
1263 *dstC++ = cache[toggle + index];
1264 toggle ^= Gradient_Shader::kDitherStride16;
1265
1266 dstX += SK_Scalar1;
1267 } while (--count != 0);
1268 }
1269 }
1270
1271 ///////////////////////////////////////////////////////////////////////////////
1272
1273 #define kSQRT_TABLE_BITS 11
1274 #define kSQRT_TABLE_SIZE (1 << kSQRT_TABLE_BITS)
1275
1276 #include "SkRadialGradient_Table.h"
1277
1278 #if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG)
1279
1280 #include <stdio.h>
1281
SkRadialGradient_BuildTable()1282 void SkRadialGradient_BuildTable() {
1283 // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table
1284
1285 FILE* file = ::fopen("SkRadialGradient_Table.h", "w");
1286 SkASSERT(file);
1287 ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n");
1288
1289 for (int i = 0; i < kSQRT_TABLE_SIZE; i++) {
1290 if ((i & 15) == 0) {
1291 ::fprintf(file, "\t");
1292 }
1293
1294 uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8);
1295
1296 ::fprintf(file, "0x%02X", value);
1297 if (i < kSQRT_TABLE_SIZE-1) {
1298 ::fprintf(file, ", ");
1299 }
1300 if ((i & 15) == 15) {
1301 ::fprintf(file, "\n");
1302 }
1303 }
1304 ::fprintf(file, "};\n");
1305 ::fclose(file);
1306 }
1307
1308 #endif
1309
1310
rad_to_unit_matrix(const SkPoint & center,SkScalar radius,SkMatrix * matrix)1311 static void rad_to_unit_matrix(const SkPoint& center, SkScalar radius,
1312 SkMatrix* matrix) {
1313 SkScalar inv = SkScalarInvert(radius);
1314
1315 matrix->setTranslate(-center.fX, -center.fY);
1316 matrix->postScale(inv, inv);
1317 }
1318
1319
1320 namespace {
1321
1322 typedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx,
1323 SkScalar sfy, SkScalar sdy,
1324 uint16_t* dstC, const uint16_t* cache,
1325 int toggle, int count);
1326
shadeSpan16_radial_clamp(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1327 void shadeSpan16_radial_clamp(SkScalar sfx, SkScalar sdx,
1328 SkScalar sfy, SkScalar sdy,
1329 uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
1330 int toggle, int count) {
1331 const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
1332
1333 /* knock these down so we can pin against +- 0x7FFF, which is an
1334 immediate load, rather than 0xFFFF which is slower. This is a
1335 compromise, since it reduces our precision, but that appears
1336 to be visually OK. If we decide this is OK for all of our cases,
1337 we could (it seems) put this scale-down into fDstToIndex,
1338 to avoid having to do these extra shifts each time.
1339 */
1340 SkFixed fx = SkScalarToFixed(sfx) >> 1;
1341 SkFixed dx = SkScalarToFixed(sdx) >> 1;
1342 SkFixed fy = SkScalarToFixed(sfy) >> 1;
1343 SkFixed dy = SkScalarToFixed(sdy) >> 1;
1344 // might perform this check for the other modes,
1345 // but the win will be a smaller % of the total
1346 if (dy == 0) {
1347 fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1348 fy *= fy;
1349 do {
1350 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1351 unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS);
1352 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1353 fx += dx;
1354 *dstC++ = cache[toggle +
1355 (sqrt_table[fi] >> Gradient_Shader::kSqrt16Shift)];
1356 toggle ^= Gradient_Shader::kDitherStride16;
1357 } while (--count != 0);
1358 } else {
1359 do {
1360 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1361 unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1362 fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
1363 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1364 fx += dx;
1365 fy += dy;
1366 *dstC++ = cache[toggle +
1367 (sqrt_table[fi] >> Gradient_Shader::kSqrt16Shift)];
1368 toggle ^= Gradient_Shader::kDitherStride16;
1369 } while (--count != 0);
1370 }
1371 }
1372
shadeSpan16_radial_mirror(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1373 void shadeSpan16_radial_mirror(SkScalar sfx, SkScalar sdx,
1374 SkScalar sfy, SkScalar sdy,
1375 uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
1376 int toggle, int count) {
1377 do {
1378 #ifdef SK_SCALAR_IS_FLOAT
1379 float fdist = sk_float_sqrt(sfx*sfx + sfy*sfy);
1380 SkFixed dist = SkFloatToFixed(fdist);
1381 #else
1382 SkFixed magnitudeSquared = SkFixedSquare(sfx) +
1383 SkFixedSquare(sfy);
1384 if (magnitudeSquared < 0) // Overflow.
1385 magnitudeSquared = SK_FixedMax;
1386 SkFixed dist = SkFixedSqrt(magnitudeSquared);
1387 #endif
1388 unsigned fi = mirror_tileproc(dist);
1389 SkASSERT(fi <= 0xFFFF);
1390 *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache16Shift)];
1391 toggle ^= Gradient_Shader::kDitherStride16;
1392 sfx += sdx;
1393 sfy += sdy;
1394 } while (--count != 0);
1395 }
1396
shadeSpan16_radial_repeat(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1397 void shadeSpan16_radial_repeat(SkScalar sfx, SkScalar sdx,
1398 SkScalar sfy, SkScalar sdy,
1399 uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
1400 int toggle, int count) {
1401 SkFixed fx = SkScalarToFixed(sfx);
1402 SkFixed dx = SkScalarToFixed(sdx);
1403 SkFixed fy = SkScalarToFixed(sfy);
1404 SkFixed dy = SkScalarToFixed(sdy);
1405 do {
1406 SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
1407 unsigned fi = repeat_tileproc(dist);
1408 SkASSERT(fi <= 0xFFFF);
1409 fx += dx;
1410 fy += dy;
1411 *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache16Shift)];
1412 toggle ^= Gradient_Shader::kDitherStride16;
1413 } while (--count != 0);
1414 }
1415
1416 }
1417
1418 class Radial_Gradient : public Gradient_Shader {
1419 public:
Radial_Gradient(const SkPoint & center,SkScalar radius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)1420 Radial_Gradient(const SkPoint& center, SkScalar radius,
1421 const SkColor colors[], const SkScalar pos[], int colorCount,
1422 SkShader::TileMode mode, SkUnitMapper* mapper)
1423 : Gradient_Shader(colors, pos, colorCount, mode, mapper),
1424 fCenter(center),
1425 fRadius(radius)
1426 {
1427 // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
1428 SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
1429
1430 rad_to_unit_matrix(center, radius, &fPtsToUnit);
1431 }
1432
1433 virtual void shadeSpan(int x, int y, SkPMColor* dstC, int count)
1434 SK_OVERRIDE;
shadeSpan16(int x,int y,uint16_t * SK_RESTRICT dstC,int count)1435 virtual void shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
1436 int count) SK_OVERRIDE {
1437 SkASSERT(count > 0);
1438
1439 SkPoint srcPt;
1440 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1441 TileProc proc = fTileProc;
1442 const uint16_t* SK_RESTRICT cache = this->getCache16();
1443 int toggle = ((x ^ y) & 1) * kDitherStride16;
1444
1445 if (fDstToIndexClass != kPerspective_MatrixClass) {
1446 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
1447 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1448
1449 SkScalar sdx = fDstToIndex.getScaleX();
1450 SkScalar sdy = fDstToIndex.getSkewY();
1451
1452 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1453 SkFixed storage[2];
1454 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
1455 &storage[0], &storage[1]);
1456 sdx = SkFixedToScalar(storage[0]);
1457 sdy = SkFixedToScalar(storage[1]);
1458 } else {
1459 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1460 }
1461
1462 RadialShade16Proc shadeProc = shadeSpan16_radial_repeat;
1463 if (proc == clamp_tileproc) {
1464 shadeProc = shadeSpan16_radial_clamp;
1465 } else if (proc == mirror_tileproc) {
1466 shadeProc = shadeSpan16_radial_mirror;
1467 } else {
1468 SkASSERT(proc == repeat_tileproc);
1469 }
1470 (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC,
1471 cache, toggle, count);
1472 } else { // perspective case
1473 SkScalar dstX = SkIntToScalar(x);
1474 SkScalar dstY = SkIntToScalar(y);
1475 do {
1476 dstProc(fDstToIndex, dstX, dstY, &srcPt);
1477 unsigned fi = proc(SkScalarToFixed(srcPt.length()));
1478 SkASSERT(fi <= 0xFFFF);
1479
1480 int index = fi >> (16 - kCache16Bits);
1481 *dstC++ = cache[toggle + index];
1482 toggle ^= kDitherStride16;
1483
1484 dstX += SK_Scalar1;
1485 } while (--count != 0);
1486 }
1487 }
1488
asABitmap(SkBitmap * bitmap,SkMatrix * matrix,TileMode * xy,SkScalar * twoPointRadialParams) const1489 virtual BitmapType asABitmap(SkBitmap* bitmap,
1490 SkMatrix* matrix,
1491 TileMode* xy,
1492 SkScalar* twoPointRadialParams)
1493 const SK_OVERRIDE {
1494 if (bitmap) {
1495 this->commonAsABitmap(bitmap);
1496 }
1497 if (matrix) {
1498 matrix->setScale(SkIntToScalar(kGradient32Length),
1499 SkIntToScalar(kGradient32Length));
1500 matrix->preConcat(fPtsToUnit);
1501 }
1502 if (xy) {
1503 xy[0] = fTileMode;
1504 xy[1] = kClamp_TileMode;
1505 }
1506 return kRadial_BitmapType;
1507 }
asAGradient(GradientInfo * info) const1508 virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
1509 if (info) {
1510 commonAsAGradient(info);
1511 info->fPoint[0] = fCenter;
1512 info->fRadius[0] = fRadius;
1513 }
1514 return kRadial_GradientType;
1515 }
1516
CreateProc(SkFlattenableReadBuffer & buffer)1517 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
1518 return SkNEW_ARGS(Radial_Gradient, (buffer));
1519 }
1520
flatten(SkFlattenableWriteBuffer & buffer)1521 virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
1522 this->INHERITED::flatten(buffer);
1523 buffer.writeScalar(fCenter.fX);
1524 buffer.writeScalar(fCenter.fY);
1525 buffer.writeScalar(fRadius);
1526 }
1527
1528 protected:
Radial_Gradient(SkFlattenableReadBuffer & buffer)1529 Radial_Gradient(SkFlattenableReadBuffer& buffer)
1530 : Gradient_Shader(buffer),
1531 fCenter(unflatten_point(buffer)),
1532 fRadius(buffer.readScalar()) {
1533 }
getFactory()1534 virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
1535
1536 private:
1537 typedef Gradient_Shader INHERITED;
1538 const SkPoint fCenter;
1539 const SkScalar fRadius;
1540 };
1541
1542 namespace {
1543
radial_completely_pinned(int fx,int dx,int fy,int dy)1544 inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) {
1545 // fast, overly-conservative test: checks unit square instead
1546 // of unit circle
1547 bool xClamped = (fx >= SK_FixedHalf && dx >= 0) ||
1548 (fx <= -SK_FixedHalf && dx <= 0);
1549 bool yClamped = (fy >= SK_FixedHalf && dy >= 0) ||
1550 (fy <= -SK_FixedHalf && dy <= 0);
1551
1552 return xClamped || yClamped;
1553 }
1554
1555 // Return true if (fx * fy) is always inside the unit circle
1556 // SkPin32 is expensive, but so are all the SkFixedMul in this test,
1557 // so it shouldn't be run if count is small.
no_need_for_radial_pin(int fx,int dx,int fy,int dy,int count)1558 inline bool no_need_for_radial_pin(int fx, int dx,
1559 int fy, int dy, int count) {
1560 SkASSERT(count > 0);
1561 if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
1562 return false;
1563 }
1564 if (fx*fx + fy*fy > 0x7FFF*0x7FFF) {
1565 return false;
1566 }
1567 fx += (count - 1) * dx;
1568 fy += (count - 1) * dy;
1569 if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
1570 return false;
1571 }
1572 return fx*fx + fy*fy <= 0x7FFF*0x7FFF;
1573 }
1574
1575 #define UNPINNED_RADIAL_STEP \
1576 fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \
1577 *dstC++ = cache[toggle + \
1578 (sqrt_table[fi] >> Gradient_Shader::kSqrt32Shift)]; \
1579 toggle ^= Gradient_Shader::kDitherStride32; \
1580 fx += dx; \
1581 fy += dy;
1582
1583 typedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx,
1584 SkScalar sfy, SkScalar sdy,
1585 SkPMColor* dstC, const SkPMColor* cache,
1586 int count, int toggle);
1587
1588 // On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT
shadeSpan_radial_clamp(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count,int toggle)1589 void shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx,
1590 SkScalar sfy, SkScalar sdy,
1591 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1592 int count, int toggle) {
1593 // Floating point seems to be slower than fixed point,
1594 // even when we have float hardware.
1595 const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
1596 SkFixed fx = SkScalarToFixed(sfx) >> 1;
1597 SkFixed dx = SkScalarToFixed(sdx) >> 1;
1598 SkFixed fy = SkScalarToFixed(sfy) >> 1;
1599 SkFixed dy = SkScalarToFixed(sdy) >> 1;
1600 if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) {
1601 unsigned fi = Gradient_Shader::kGradient32Length;
1602 sk_memset32_dither(dstC,
1603 cache[toggle + fi],
1604 cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi],
1605 count);
1606 } else if ((count > 4) &&
1607 no_need_for_radial_pin(fx, dx, fy, dy, count)) {
1608 unsigned fi;
1609 // 4x unroll appears to be no faster than 2x unroll on Linux
1610 while (count > 1) {
1611 UNPINNED_RADIAL_STEP;
1612 UNPINNED_RADIAL_STEP;
1613 count -= 2;
1614 }
1615 if (count) {
1616 UNPINNED_RADIAL_STEP;
1617 }
1618 }
1619 else {
1620 // Specializing for dy == 0 gains us 25% on Skia benchmarks
1621 if (dy == 0) {
1622 unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1623 yy *= yy;
1624 do {
1625 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1626 unsigned fi = (xx * xx + yy) >> (14 + 16 - kSQRT_TABLE_BITS);
1627 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1628 *dstC++ = cache[toggle + (sqrt_table[fi] >>
1629 Gradient_Shader::kSqrt32Shift)];
1630 toggle ^= Gradient_Shader::kDitherStride32;
1631 fx += dx;
1632 } while (--count != 0);
1633 } else {
1634 do {
1635 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1636 unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1637 fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
1638 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1639 *dstC++ = cache[toggle + (sqrt_table[fi] >>
1640 Gradient_Shader::kSqrt32Shift)];
1641 toggle ^= Gradient_Shader::kDitherStride32;
1642 fx += dx;
1643 fy += dy;
1644 } while (--count != 0);
1645 }
1646 }
1647 }
1648
1649 // Unrolling this loop doesn't seem to help (when float); we're stalling to
1650 // get the results of the sqrt (?), and don't have enough extra registers to
1651 // have many in flight.
shadeSpan_radial_mirror(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count,int toggle)1652 void shadeSpan_radial_mirror(SkScalar sfx, SkScalar sdx,
1653 SkScalar sfy, SkScalar sdy,
1654 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1655 int count, int toggle) {
1656 do {
1657 #ifdef SK_SCALAR_IS_FLOAT
1658 float fdist = sk_float_sqrt(sfx*sfx + sfy*sfy);
1659 SkFixed dist = SkFloatToFixed(fdist);
1660 #else
1661 SkFixed magnitudeSquared = SkFixedSquare(sfx) +
1662 SkFixedSquare(sfy);
1663 if (magnitudeSquared < 0) // Overflow.
1664 magnitudeSquared = SK_FixedMax;
1665 SkFixed dist = SkFixedSqrt(magnitudeSquared);
1666 #endif
1667 unsigned fi = mirror_tileproc(dist);
1668 SkASSERT(fi <= 0xFFFF);
1669 *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache32Shift)];
1670 toggle ^= Gradient_Shader::kDitherStride32;
1671 sfx += sdx;
1672 sfy += sdy;
1673 } while (--count != 0);
1674 }
1675
shadeSpan_radial_repeat(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count,int toggle)1676 void shadeSpan_radial_repeat(SkScalar sfx, SkScalar sdx,
1677 SkScalar sfy, SkScalar sdy,
1678 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1679 int count, int toggle) {
1680 SkFixed fx = SkScalarToFixed(sfx);
1681 SkFixed dx = SkScalarToFixed(sdx);
1682 SkFixed fy = SkScalarToFixed(sfy);
1683 SkFixed dy = SkScalarToFixed(sdy);
1684 do {
1685 SkFixed magnitudeSquared = SkFixedSquare(fx) +
1686 SkFixedSquare(fy);
1687 if (magnitudeSquared < 0) // Overflow.
1688 magnitudeSquared = SK_FixedMax;
1689 SkFixed dist = SkFixedSqrt(magnitudeSquared);
1690 unsigned fi = repeat_tileproc(dist);
1691 SkASSERT(fi <= 0xFFFF);
1692 *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache32Shift)];
1693 toggle ^= Gradient_Shader::kDitherStride32;
1694 fx += dx;
1695 fy += dy;
1696 } while (--count != 0);
1697 }
1698 }
1699
shadeSpan(int x,int y,SkPMColor * SK_RESTRICT dstC,int count)1700 void Radial_Gradient::shadeSpan(int x, int y,
1701 SkPMColor* SK_RESTRICT dstC, int count) {
1702 SkASSERT(count > 0);
1703
1704 SkPoint srcPt;
1705 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1706 TileProc proc = fTileProc;
1707 const SkPMColor* SK_RESTRICT cache = this->getCache32();
1708 #ifdef USE_DITHER_32BIT_GRADIENT
1709 int toggle = ((x ^ y) & 1) * Gradient_Shader::kDitherStride32;
1710 #else
1711 int toggle = 0;
1712 #endif
1713
1714 if (fDstToIndexClass != kPerspective_MatrixClass) {
1715 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
1716 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1717 SkScalar sdx = fDstToIndex.getScaleX();
1718 SkScalar sdy = fDstToIndex.getSkewY();
1719
1720 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1721 SkFixed storage[2];
1722 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
1723 &storage[0], &storage[1]);
1724 sdx = SkFixedToScalar(storage[0]);
1725 sdy = SkFixedToScalar(storage[1]);
1726 } else {
1727 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1728 }
1729
1730 RadialShadeProc shadeProc = shadeSpan_radial_repeat;
1731 if (proc == clamp_tileproc) {
1732 shadeProc = shadeSpan_radial_clamp;
1733 } else if (proc == mirror_tileproc) {
1734 shadeProc = shadeSpan_radial_mirror;
1735 } else {
1736 SkASSERT(proc == repeat_tileproc);
1737 }
1738 (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle);
1739 } else { // perspective case
1740 SkScalar dstX = SkIntToScalar(x);
1741 SkScalar dstY = SkIntToScalar(y);
1742 do {
1743 dstProc(fDstToIndex, dstX, dstY, &srcPt);
1744 unsigned fi = proc(SkScalarToFixed(srcPt.length()));
1745 SkASSERT(fi <= 0xFFFF);
1746 *dstC++ = cache[fi >> Gradient_Shader::kCache32Shift];
1747 dstX += SK_Scalar1;
1748 } while (--count != 0);
1749 }
1750 }
1751
1752 /* Two-point radial gradients are specified by two circles, each with a center
1753 point and radius. The gradient can be considered to be a series of
1754 concentric circles, with the color interpolated from the start circle
1755 (at t=0) to the end circle (at t=1).
1756
1757 For each point (x, y) in the span, we want to find the
1758 interpolated circle that intersects that point. The center
1759 of the desired circle (Cx, Cy) falls at some distance t
1760 along the line segment between the start point (Sx, Sy) and
1761 end point (Ex, Ey):
1762
1763 Cx = (1 - t) * Sx + t * Ex (0 <= t <= 1)
1764 Cy = (1 - t) * Sy + t * Ey
1765
1766 The radius of the desired circle (r) is also a linear interpolation t
1767 between the start and end radii (Sr and Er):
1768
1769 r = (1 - t) * Sr + t * Er
1770
1771 But
1772
1773 (x - Cx)^2 + (y - Cy)^2 = r^2
1774
1775 so
1776
1777 (x - ((1 - t) * Sx + t * Ex))^2
1778 + (y - ((1 - t) * Sy + t * Ey))^2
1779 = ((1 - t) * Sr + t * Er)^2
1780
1781 Solving for t yields
1782
1783 [(Sx - Ex)^2 + (Sy - Ey)^2 - (Er - Sr)^2)] * t^2
1784 + [2 * (Sx - Ex)(x - Sx) + 2 * (Sy - Ey)(y - Sy) - 2 * (Er - Sr) * Sr] * t
1785 + [(x - Sx)^2 + (y - Sy)^2 - Sr^2] = 0
1786
1787 To simplify, let Dx = Sx - Ex, Dy = Sy - Ey, Dr = Er - Sr, dx = x - Sx, dy = y - Sy
1788
1789 [Dx^2 + Dy^2 - Dr^2)] * t^2
1790 + 2 * [Dx * dx + Dy * dy - Dr * Sr] * t
1791 + [dx^2 + dy^2 - Sr^2] = 0
1792
1793 A quadratic in t. The two roots of the quadratic reflect the two
1794 possible circles on which the point may fall. Solving for t yields
1795 the gradient value to use.
1796
1797 If a<0, the start circle is entirely contained in the
1798 end circle, and one of the roots will be <0 or >1 (off the line
1799 segment). If a>0, the start circle falls at least partially
1800 outside the end circle (or vice versa), and the gradient
1801 defines a "tube" where a point may be on one circle (on the
1802 inside of the tube) or the other (outside of the tube). We choose
1803 one arbitrarily.
1804
1805 In order to keep the math to within the limits of fixed point,
1806 we divide the entire quadratic by Dr^2, and replace
1807 (x - Sx)/Dr with x' and (y - Sy)/Dr with y', giving
1808
1809 [Dx^2 / Dr^2 + Dy^2 / Dr^2 - 1)] * t^2
1810 + 2 * [x' * Dx / Dr + y' * Dy / Dr - Sr / Dr] * t
1811 + [x'^2 + y'^2 - Sr^2/Dr^2] = 0
1812
1813 (x' and y' are computed by appending the subtract and scale to the
1814 fDstToIndex matrix in the constructor).
1815
1816 Since the 'A' component of the quadratic is independent of x' and y', it
1817 is precomputed in the constructor. Since the 'B' component is linear in
1818 x' and y', if x and y are linear in the span, 'B' can be computed
1819 incrementally with a simple delta (db below). If it is not (e.g.,
1820 a perspective projection), it must be computed in the loop.
1821
1822 */
1823
1824 namespace {
1825
two_point_radial(SkScalar b,SkScalar fx,SkScalar fy,SkScalar sr2d2,SkScalar foura,SkScalar oneOverTwoA,bool posRoot)1826 inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
1827 SkScalar sr2d2, SkScalar foura,
1828 SkScalar oneOverTwoA, bool posRoot) {
1829 SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2;
1830 if (0 == foura) {
1831 return SkScalarToFixed(SkScalarDiv(-c, b));
1832 }
1833
1834 SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c);
1835 if (discrim < 0) {
1836 discrim = -discrim;
1837 }
1838 SkScalar rootDiscrim = SkScalarSqrt(discrim);
1839 SkScalar result;
1840 if (posRoot) {
1841 result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
1842 } else {
1843 result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
1844 }
1845 return SkScalarToFixed(result);
1846 }
1847
1848 typedef void (* TwoPointRadialShadeProc)(SkScalar fx, SkScalar dx,
1849 SkScalar fy, SkScalar dy,
1850 SkScalar b, SkScalar db,
1851 SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
1852 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1853 int count);
1854
shadeSpan_twopoint_clamp(SkScalar fx,SkScalar dx,SkScalar fy,SkScalar dy,SkScalar b,SkScalar db,SkScalar fSr2D2,SkScalar foura,SkScalar fOneOverTwoA,bool posRoot,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count)1855 void shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx,
1856 SkScalar fy, SkScalar dy,
1857 SkScalar b, SkScalar db,
1858 SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
1859 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1860 int count) {
1861 for (; count > 0; --count) {
1862 SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
1863 fOneOverTwoA, posRoot);
1864 SkFixed index = SkClampMax(t, 0xFFFF);
1865 SkASSERT(index <= 0xFFFF);
1866 *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
1867 fx += dx;
1868 fy += dy;
1869 b += db;
1870 }
1871 }
shadeSpan_twopoint_mirror(SkScalar fx,SkScalar dx,SkScalar fy,SkScalar dy,SkScalar b,SkScalar db,SkScalar fSr2D2,SkScalar foura,SkScalar fOneOverTwoA,bool posRoot,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count)1872 void shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx,
1873 SkScalar fy, SkScalar dy,
1874 SkScalar b, SkScalar db,
1875 SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
1876 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1877 int count) {
1878 for (; count > 0; --count) {
1879 SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
1880 fOneOverTwoA, posRoot);
1881 SkFixed index = mirror_tileproc(t);
1882 SkASSERT(index <= 0xFFFF);
1883 *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
1884 fx += dx;
1885 fy += dy;
1886 b += db;
1887 }
1888 }
1889
shadeSpan_twopoint_repeat(SkScalar fx,SkScalar dx,SkScalar fy,SkScalar dy,SkScalar b,SkScalar db,SkScalar fSr2D2,SkScalar foura,SkScalar fOneOverTwoA,bool posRoot,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count)1890 void shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx,
1891 SkScalar fy, SkScalar dy,
1892 SkScalar b, SkScalar db,
1893 SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
1894 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1895 int count) {
1896 for (; count > 0; --count) {
1897 SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
1898 fOneOverTwoA, posRoot);
1899 SkFixed index = repeat_tileproc(t);
1900 SkASSERT(index <= 0xFFFF);
1901 *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
1902 fx += dx;
1903 fy += dy;
1904 b += db;
1905 }
1906 }
1907
1908
1909
1910 }
1911
1912 class Two_Point_Radial_Gradient : public Gradient_Shader {
1913 public:
Two_Point_Radial_Gradient(const SkPoint & start,SkScalar startRadius,const SkPoint & end,SkScalar endRadius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)1914 Two_Point_Radial_Gradient(const SkPoint& start, SkScalar startRadius,
1915 const SkPoint& end, SkScalar endRadius,
1916 const SkColor colors[], const SkScalar pos[],
1917 int colorCount, SkShader::TileMode mode,
1918 SkUnitMapper* mapper)
1919 : Gradient_Shader(colors, pos, colorCount, mode, mapper),
1920 fCenter1(start),
1921 fCenter2(end),
1922 fRadius1(startRadius),
1923 fRadius2(endRadius) {
1924 init();
1925 }
1926
asABitmap(SkBitmap * bitmap,SkMatrix * matrix,TileMode * xy,SkScalar * twoPointRadialParams) const1927 virtual BitmapType asABitmap(SkBitmap* bitmap,
1928 SkMatrix* matrix,
1929 TileMode* xy,
1930 SkScalar* twoPointRadialParams) const {
1931 if (bitmap) {
1932 this->commonAsABitmap(bitmap);
1933 }
1934 SkScalar diffL = 0; // just to avoid gcc warning
1935 if (matrix || twoPointRadialParams) {
1936 diffL = SkScalarSqrt(SkScalarSquare(fDiff.fX) +
1937 SkScalarSquare(fDiff.fY));
1938 }
1939 if (matrix) {
1940 if (diffL) {
1941 SkScalar invDiffL = SkScalarInvert(diffL);
1942 matrix->setSinCos(-SkScalarMul(invDiffL, fDiff.fY),
1943 SkScalarMul(invDiffL, fDiff.fX));
1944 } else {
1945 matrix->reset();
1946 }
1947 matrix->preConcat(fPtsToUnit);
1948 }
1949 if (xy) {
1950 xy[0] = fTileMode;
1951 xy[1] = kClamp_TileMode;
1952 }
1953 if (NULL != twoPointRadialParams) {
1954 twoPointRadialParams[0] = diffL;
1955 twoPointRadialParams[1] = fStartRadius;
1956 twoPointRadialParams[2] = fDiffRadius;
1957 }
1958 return kTwoPointRadial_BitmapType;
1959 }
1960
asAGradient(GradientInfo * info) const1961 virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
1962 if (info) {
1963 commonAsAGradient(info);
1964 info->fPoint[0] = fCenter1;
1965 info->fPoint[1] = fCenter2;
1966 info->fRadius[0] = fRadius1;
1967 info->fRadius[1] = fRadius2;
1968 }
1969 return kRadial2_GradientType;
1970 }
1971
shadeSpan(int x,int y,SkPMColor * SK_RESTRICT dstC,int count)1972 virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
1973 int count) SK_OVERRIDE {
1974 SkASSERT(count > 0);
1975
1976 // Zero difference between radii: fill with transparent black.
1977 if (fDiffRadius == 0) {
1978 sk_bzero(dstC, count * sizeof(*dstC));
1979 return;
1980 }
1981 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1982 TileProc proc = fTileProc;
1983 const SkPMColor* SK_RESTRICT cache = this->getCache32();
1984
1985 SkScalar foura = fA * 4;
1986 bool posRoot = fDiffRadius < 0;
1987 if (fDstToIndexClass != kPerspective_MatrixClass) {
1988 SkPoint srcPt;
1989 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
1990 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1991 SkScalar dx, fx = srcPt.fX;
1992 SkScalar dy, fy = srcPt.fY;
1993
1994 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1995 SkFixed fixedX, fixedY;
1996 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
1997 dx = SkFixedToScalar(fixedX);
1998 dy = SkFixedToScalar(fixedY);
1999 } else {
2000 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
2001 dx = fDstToIndex.getScaleX();
2002 dy = fDstToIndex.getSkewY();
2003 }
2004 SkScalar b = (SkScalarMul(fDiff.fX, fx) +
2005 SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
2006 SkScalar db = (SkScalarMul(fDiff.fX, dx) +
2007 SkScalarMul(fDiff.fY, dy)) * 2;
2008
2009 TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
2010 if (proc == clamp_tileproc) {
2011 shadeProc = shadeSpan_twopoint_clamp;
2012 } else if (proc == mirror_tileproc) {
2013 shadeProc = shadeSpan_twopoint_mirror;
2014 } else {
2015 SkASSERT(proc == repeat_tileproc);
2016 }
2017 (*shadeProc)(fx, dx, fy, dy, b, db,
2018 fSr2D2, foura, fOneOverTwoA, posRoot,
2019 dstC, cache, count);
2020 } else { // perspective case
2021 SkScalar dstX = SkIntToScalar(x);
2022 SkScalar dstY = SkIntToScalar(y);
2023 for (; count > 0; --count) {
2024 SkPoint srcPt;
2025 dstProc(fDstToIndex, dstX, dstY, &srcPt);
2026 SkScalar fx = srcPt.fX;
2027 SkScalar fy = srcPt.fY;
2028 SkScalar b = (SkScalarMul(fDiff.fX, fx) +
2029 SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
2030 SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
2031 fOneOverTwoA, posRoot);
2032 SkFixed index = proc(t);
2033 SkASSERT(index <= 0xFFFF);
2034 *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
2035 dstX += SK_Scalar1;
2036 }
2037 }
2038 }
2039
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)2040 virtual bool setContext(const SkBitmap& device,
2041 const SkPaint& paint,
2042 const SkMatrix& matrix) SK_OVERRIDE {
2043 if (!this->INHERITED::setContext(device, paint, matrix)) {
2044 return false;
2045 }
2046
2047 // we don't have a span16 proc
2048 fFlags &= ~kHasSpan16_Flag;
2049 return true;
2050 }
2051
CreateProc(SkFlattenableReadBuffer & buffer)2052 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
2053 return SkNEW_ARGS(Two_Point_Radial_Gradient, (buffer));
2054 }
2055
flatten(SkFlattenableWriteBuffer & buffer)2056 virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
2057 this->INHERITED::flatten(buffer);
2058 buffer.writeScalar(fCenter1.fX);
2059 buffer.writeScalar(fCenter1.fY);
2060 buffer.writeScalar(fCenter2.fX);
2061 buffer.writeScalar(fCenter2.fY);
2062 buffer.writeScalar(fRadius1);
2063 buffer.writeScalar(fRadius2);
2064 }
2065
2066 protected:
Two_Point_Radial_Gradient(SkFlattenableReadBuffer & buffer)2067 Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer)
2068 : Gradient_Shader(buffer),
2069 fCenter1(unflatten_point(buffer)),
2070 fCenter2(unflatten_point(buffer)),
2071 fRadius1(buffer.readScalar()),
2072 fRadius2(buffer.readScalar()) {
2073 init();
2074 };
getFactory()2075 virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
2076
2077 private:
2078 typedef Gradient_Shader INHERITED;
2079 const SkPoint fCenter1;
2080 const SkPoint fCenter2;
2081 const SkScalar fRadius1;
2082 const SkScalar fRadius2;
2083 SkPoint fDiff;
2084 SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
2085
init()2086 void init() {
2087 fDiff = fCenter1 - fCenter2;
2088 fDiffRadius = fRadius2 - fRadius1;
2089 SkScalar inv = SkScalarInvert(fDiffRadius);
2090 fDiff.fX = SkScalarMul(fDiff.fX, inv);
2091 fDiff.fY = SkScalarMul(fDiff.fY, inv);
2092 fStartRadius = SkScalarMul(fRadius1, inv);
2093 fSr2D2 = SkScalarSquare(fStartRadius);
2094 fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
2095 fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
2096
2097 fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
2098 fPtsToUnit.postScale(inv, inv);
2099 }
2100 };
2101
2102 ///////////////////////////////////////////////////////////////////////////////
2103
2104 class Sweep_Gradient : public Gradient_Shader {
2105 public:
Sweep_Gradient(SkScalar cx,SkScalar cy,const SkColor colors[],const SkScalar pos[],int count,SkUnitMapper * mapper)2106 Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
2107 const SkScalar pos[], int count, SkUnitMapper* mapper)
2108 : Gradient_Shader(colors, pos, count, SkShader::kClamp_TileMode, mapper),
2109 fCenter(SkPoint::Make(cx, cy))
2110 {
2111 fPtsToUnit.setTranslate(-cx, -cy);
2112 }
2113 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
2114 virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
2115
asABitmap(SkBitmap * bitmap,SkMatrix * matrix,TileMode * xy,SkScalar * twoPointRadialParams) const2116 virtual BitmapType asABitmap(SkBitmap* bitmap,
2117 SkMatrix* matrix,
2118 TileMode* xy,
2119 SkScalar* twoPointRadialParams) const SK_OVERRIDE {
2120 if (bitmap) {
2121 this->commonAsABitmap(bitmap);
2122 }
2123 if (matrix) {
2124 *matrix = fPtsToUnit;
2125 }
2126 if (xy) {
2127 xy[0] = fTileMode;
2128 xy[1] = kClamp_TileMode;
2129 }
2130 return kSweep_BitmapType;
2131 }
2132
asAGradient(GradientInfo * info) const2133 virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
2134 if (info) {
2135 commonAsAGradient(info);
2136 info->fPoint[0] = fCenter;
2137 }
2138 return kSweep_GradientType;
2139 }
2140
CreateProc(SkFlattenableReadBuffer & buffer)2141 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
2142 return SkNEW_ARGS(Sweep_Gradient, (buffer));
2143 }
2144
flatten(SkFlattenableWriteBuffer & buffer)2145 virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
2146 this->INHERITED::flatten(buffer);
2147 buffer.writeScalar(fCenter.fX);
2148 buffer.writeScalar(fCenter.fY);
2149 }
2150
2151 protected:
Sweep_Gradient(SkFlattenableReadBuffer & buffer)2152 Sweep_Gradient(SkFlattenableReadBuffer& buffer)
2153 : Gradient_Shader(buffer),
2154 fCenter(unflatten_point(buffer)) {
2155 }
2156
getFactory()2157 virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
2158
2159 private:
2160 typedef Gradient_Shader INHERITED;
2161 const SkPoint fCenter;
2162 };
2163
2164 #ifdef COMPUTE_SWEEP_TABLE
2165 #define PI 3.14159265
2166 static bool gSweepTableReady;
2167 static uint8_t gSweepTable[65];
2168
2169 /* Our table stores precomputed values for atan: [0...1] -> [0..PI/4]
2170 We scale the results to [0..32]
2171 */
build_sweep_table()2172 static const uint8_t* build_sweep_table() {
2173 if (!gSweepTableReady) {
2174 const int N = 65;
2175 const double DENOM = N - 1;
2176
2177 for (int i = 0; i < N; i++)
2178 {
2179 double arg = i / DENOM;
2180 double v = atan(arg);
2181 int iv = (int)round(v * DENOM * 2 / PI);
2182 // printf("[%d] atan(%g) = %g %d\n", i, arg, v, iv);
2183 printf("%d, ", iv);
2184 gSweepTable[i] = iv;
2185 }
2186 gSweepTableReady = true;
2187 }
2188 return gSweepTable;
2189 }
2190 #else
2191 static const uint8_t gSweepTable[] = {
2192 0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9,
2193 10, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18,
2194 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26,
2195 26, 27, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32,
2196 32
2197 };
build_sweep_table()2198 static const uint8_t* build_sweep_table() { return gSweepTable; }
2199 #endif
2200
2201 // divide numer/denom, with a bias of 6bits. Assumes numer <= denom
2202 // and denom != 0. Since our table is 6bits big (+1), this is a nice fit.
2203 // Same as (but faster than) SkFixedDiv(numer, denom) >> 10
2204
2205 //unsigned div_64(int numer, int denom);
div_64(int numer,int denom)2206 static unsigned div_64(int numer, int denom) {
2207 SkASSERT(numer <= denom);
2208 SkASSERT(numer > 0);
2209 SkASSERT(denom > 0);
2210
2211 int nbits = SkCLZ(numer);
2212 int dbits = SkCLZ(denom);
2213 int bits = 6 - nbits + dbits;
2214 SkASSERT(bits <= 6);
2215
2216 if (bits < 0) { // detect underflow
2217 return 0;
2218 }
2219
2220 denom <<= dbits - 1;
2221 numer <<= nbits - 1;
2222
2223 unsigned result = 0;
2224
2225 // do the first one
2226 if ((numer -= denom) >= 0) {
2227 result = 1;
2228 } else {
2229 numer += denom;
2230 }
2231
2232 // Now fall into our switch statement if there are more bits to compute
2233 if (bits > 0) {
2234 // make room for the rest of the answer bits
2235 result <<= bits;
2236 switch (bits) {
2237 case 6:
2238 if ((numer = (numer << 1) - denom) >= 0)
2239 result |= 32;
2240 else
2241 numer += denom;
2242 case 5:
2243 if ((numer = (numer << 1) - denom) >= 0)
2244 result |= 16;
2245 else
2246 numer += denom;
2247 case 4:
2248 if ((numer = (numer << 1) - denom) >= 0)
2249 result |= 8;
2250 else
2251 numer += denom;
2252 case 3:
2253 if ((numer = (numer << 1) - denom) >= 0)
2254 result |= 4;
2255 else
2256 numer += denom;
2257 case 2:
2258 if ((numer = (numer << 1) - denom) >= 0)
2259 result |= 2;
2260 else
2261 numer += denom;
2262 case 1:
2263 default: // not strictly need, but makes GCC make better ARM code
2264 if ((numer = (numer << 1) - denom) >= 0)
2265 result |= 1;
2266 else
2267 numer += denom;
2268 }
2269 }
2270 return result;
2271 }
2272
2273 // Given x,y in the first quadrant, return 0..63 for the angle [0..90]
atan_0_90(SkFixed y,SkFixed x)2274 static unsigned atan_0_90(SkFixed y, SkFixed x) {
2275 #ifdef SK_DEBUG
2276 {
2277 static bool gOnce;
2278 if (!gOnce) {
2279 gOnce = true;
2280 SkASSERT(div_64(55, 55) == 64);
2281 SkASSERT(div_64(128, 256) == 32);
2282 SkASSERT(div_64(2326528, 4685824) == 31);
2283 SkASSERT(div_64(753664, 5210112) == 9);
2284 SkASSERT(div_64(229376, 4882432) == 3);
2285 SkASSERT(div_64(2, 64) == 2);
2286 SkASSERT(div_64(1, 64) == 1);
2287 // test that we handle underflow correctly
2288 SkASSERT(div_64(12345, 0x54321234) == 0);
2289 }
2290 }
2291 #endif
2292
2293 SkASSERT(y > 0 && x > 0);
2294 const uint8_t* table = build_sweep_table();
2295
2296 unsigned result;
2297 bool swap = (x < y);
2298 if (swap) {
2299 // first part of the atan(v) = PI/2 - atan(1/v) identity
2300 // since our div_64 and table want v <= 1, where v = y/x
2301 SkTSwap<SkFixed>(x, y);
2302 }
2303
2304 result = div_64(y, x);
2305
2306 #ifdef SK_DEBUG
2307 {
2308 unsigned result2 = SkDivBits(y, x, 6);
2309 SkASSERT(result2 == result ||
2310 (result == 1 && result2 == 0));
2311 }
2312 #endif
2313
2314 SkASSERT(result < SK_ARRAY_COUNT(gSweepTable));
2315 result = table[result];
2316
2317 if (swap) {
2318 // complete the atan(v) = PI/2 - atan(1/v) identity
2319 result = 64 - result;
2320 // pin to 63
2321 result -= result >> 6;
2322 }
2323
2324 SkASSERT(result <= 63);
2325 return result;
2326 }
2327
2328 // returns angle in a circle [0..2PI) -> [0..255]
2329 #ifdef SK_SCALAR_IS_FLOAT
SkATan2_255(float y,float x)2330 static unsigned SkATan2_255(float y, float x) {
2331 // static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
2332 static const float g255Over2PI = 40.584510488433314f;
2333
2334 float result = sk_float_atan2(y, x);
2335 if (result < 0) {
2336 result += 2 * SK_ScalarPI;
2337 }
2338 SkASSERT(result >= 0);
2339 // since our value is always >= 0, we can cast to int, which is faster than
2340 // calling floorf()
2341 int ir = (int)(result * g255Over2PI);
2342 SkASSERT(ir >= 0 && ir <= 255);
2343 return ir;
2344 }
2345 #else
SkATan2_255(SkFixed y,SkFixed x)2346 static unsigned SkATan2_255(SkFixed y, SkFixed x) {
2347 if (x == 0) {
2348 if (y == 0) {
2349 return 0;
2350 }
2351 return y < 0 ? 192 : 64;
2352 }
2353 if (y == 0) {
2354 return x < 0 ? 128 : 0;
2355 }
2356
2357 /* Find the right quadrant for x,y
2358 Since atan_0_90 only handles the first quadrant, we rotate x,y
2359 appropriately before calling it, and then add the right amount
2360 to account for the real quadrant.
2361 quadrant 0 : add 0 | x > 0 && y > 0
2362 quadrant 1 : add 64 (90 degrees) | x < 0 && y > 0
2363 quadrant 2 : add 128 (180 degrees) | x < 0 && y < 0
2364 quadrant 3 : add 192 (270 degrees) | x > 0 && y < 0
2365
2366 map x<0 to (1 << 6)
2367 map y<0 to (3 << 6)
2368 add = map_x ^ map_y
2369 */
2370 int xsign = x >> 31;
2371 int ysign = y >> 31;
2372 int add = ((-xsign) ^ (ysign & 3)) << 6;
2373
2374 #ifdef SK_DEBUG
2375 if (0 == add)
2376 SkASSERT(x > 0 && y > 0);
2377 else if (64 == add)
2378 SkASSERT(x < 0 && y > 0);
2379 else if (128 == add)
2380 SkASSERT(x < 0 && y < 0);
2381 else if (192 == add)
2382 SkASSERT(x > 0 && y < 0);
2383 else
2384 SkDEBUGFAIL("bad value for add");
2385 #endif
2386
2387 /* This ^ trick makes x, y positive, and the swap<> handles quadrants
2388 where we need to rotate x,y by 90 or -90
2389 */
2390 x = (x ^ xsign) - xsign;
2391 y = (y ^ ysign) - ysign;
2392 if (add & 64) { // quads 1 or 3 need to swap x,y
2393 SkTSwap<SkFixed>(x, y);
2394 }
2395
2396 unsigned result = add + atan_0_90(y, x);
2397 SkASSERT(result < 256);
2398 return result;
2399 }
2400 #endif
2401
shadeSpan(int x,int y,SkPMColor * SK_RESTRICT dstC,int count)2402 void Sweep_Gradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
2403 int count) {
2404 SkMatrix::MapXYProc proc = fDstToIndexProc;
2405 const SkMatrix& matrix = fDstToIndex;
2406 const SkPMColor* SK_RESTRICT cache = this->getCache32();
2407 SkPoint srcPt;
2408
2409 if (fDstToIndexClass != kPerspective_MatrixClass) {
2410 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
2411 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
2412 SkScalar dx, fx = srcPt.fX;
2413 SkScalar dy, fy = srcPt.fY;
2414
2415 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
2416 SkFixed storage[2];
2417 (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
2418 &storage[0], &storage[1]);
2419 dx = SkFixedToScalar(storage[0]);
2420 dy = SkFixedToScalar(storage[1]);
2421 } else {
2422 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
2423 dx = matrix.getScaleX();
2424 dy = matrix.getSkewY();
2425 }
2426
2427 for (; count > 0; --count) {
2428 *dstC++ = cache[SkATan2_255(fy, fx)];
2429 fx += dx;
2430 fy += dy;
2431 }
2432 } else { // perspective case
2433 for (int stop = x + count; x < stop; x++) {
2434 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
2435 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
2436 *dstC++ = cache[SkATan2_255(srcPt.fY, srcPt.fX)];
2437 }
2438 }
2439 }
2440
shadeSpan16(int x,int y,uint16_t * SK_RESTRICT dstC,int count)2441 void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
2442 int count) {
2443 SkMatrix::MapXYProc proc = fDstToIndexProc;
2444 const SkMatrix& matrix = fDstToIndex;
2445 const uint16_t* SK_RESTRICT cache = this->getCache16();
2446 int toggle = ((x ^ y) & 1) * kDitherStride16;
2447 SkPoint srcPt;
2448
2449 if (fDstToIndexClass != kPerspective_MatrixClass) {
2450 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
2451 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
2452 SkScalar dx, fx = srcPt.fX;
2453 SkScalar dy, fy = srcPt.fY;
2454
2455 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
2456 SkFixed storage[2];
2457 (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
2458 &storage[0], &storage[1]);
2459 dx = SkFixedToScalar(storage[0]);
2460 dy = SkFixedToScalar(storage[1]);
2461 } else {
2462 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
2463 dx = matrix.getScaleX();
2464 dy = matrix.getSkewY();
2465 }
2466
2467 for (; count > 0; --count) {
2468 int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
2469 *dstC++ = cache[toggle + index];
2470 toggle ^= kDitherStride16;
2471 fx += dx;
2472 fy += dy;
2473 }
2474 } else { // perspective case
2475 for (int stop = x + count; x < stop; x++) {
2476 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
2477 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
2478
2479 int index = SkATan2_255(srcPt.fY, srcPt.fX);
2480 index >>= (8 - kCache16Bits);
2481 *dstC++ = cache[toggle + index];
2482 toggle ^= kDitherStride16;
2483 }
2484 }
2485 }
2486
2487 ///////////////////////////////////////////////////////////////////////////////
2488 ///////////////////////////////////////////////////////////////////////////////
2489
2490 // assumes colors is SkColor* and pos is SkScalar*
2491 #define EXPAND_1_COLOR(count) \
2492 SkColor tmp[2]; \
2493 do { \
2494 if (1 == count) { \
2495 tmp[0] = tmp[1] = colors[0]; \
2496 colors = tmp; \
2497 pos = NULL; \
2498 count = 2; \
2499 } \
2500 } while (0)
2501
CreateLinear(const SkPoint pts[2],const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)2502 SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2],
2503 const SkColor colors[],
2504 const SkScalar pos[], int colorCount,
2505 SkShader::TileMode mode,
2506 SkUnitMapper* mapper) {
2507 if (NULL == pts || NULL == colors || colorCount < 1) {
2508 return NULL;
2509 }
2510 EXPAND_1_COLOR(colorCount);
2511
2512 return SkNEW_ARGS(Linear_Gradient,
2513 (pts, colors, pos, colorCount, mode, mapper));
2514 }
2515
CreateRadial(const SkPoint & center,SkScalar radius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)2516 SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius,
2517 const SkColor colors[],
2518 const SkScalar pos[], int colorCount,
2519 SkShader::TileMode mode,
2520 SkUnitMapper* mapper) {
2521 if (radius <= 0 || NULL == colors || colorCount < 1) {
2522 return NULL;
2523 }
2524 EXPAND_1_COLOR(colorCount);
2525
2526 return SkNEW_ARGS(Radial_Gradient,
2527 (center, radius, colors, pos, colorCount, mode, mapper));
2528 }
2529
CreateTwoPointRadial(const SkPoint & start,SkScalar startRadius,const SkPoint & end,SkScalar endRadius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)2530 SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start,
2531 SkScalar startRadius,
2532 const SkPoint& end,
2533 SkScalar endRadius,
2534 const SkColor colors[],
2535 const SkScalar pos[],
2536 int colorCount,
2537 SkShader::TileMode mode,
2538 SkUnitMapper* mapper) {
2539 if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
2540 return NULL;
2541 }
2542 EXPAND_1_COLOR(colorCount);
2543
2544 return SkNEW_ARGS(Two_Point_Radial_Gradient,
2545 (start, startRadius, end, endRadius, colors, pos,
2546 colorCount, mode, mapper));
2547 }
2548
CreateSweep(SkScalar cx,SkScalar cy,const SkColor colors[],const SkScalar pos[],int count,SkUnitMapper * mapper)2549 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
2550 const SkColor colors[],
2551 const SkScalar pos[],
2552 int count, SkUnitMapper* mapper) {
2553 if (NULL == colors || count < 1) {
2554 return NULL;
2555 }
2556 EXPAND_1_COLOR(count);
2557
2558 return SkNEW_ARGS(Sweep_Gradient, (cx, cy, colors, pos, count, mapper));
2559 }
2560
2561 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
2562 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Linear_Gradient)
2563 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Radial_Gradient)
2564
2565 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Sweep_Gradient)
2566
2567 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Two_Point_Radial_Gradient)
2568 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
2569