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