blob: a1674cb9e375a2e3035b0b237a44bd9eadcd9758 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* libs/graphics/effects/SkGradientShader.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkGradientShader.h"
19#include "SkColorPriv.h"
20#include "SkUnitMapper.h"
21#include "SkUtils.h"
22
23/*
24 ToDo
25
26 - not sure we still need the full Rec struct, now that we're using a cache
27 - detect const-alpha (but not opaque) in getFlags()
28*/
29
30/* dither seems to look better, but not stuningly yet, and it slows us down a little
31 so its not on by default yet.
32*/
33#define TEST_GRADIENT_DITHER
34
35///////////////////////////////////////////////////////////////////////////
36
37typedef SkFixed (*TileProc)(SkFixed);
38
39static SkFixed clamp_tileproc(SkFixed x)
40{
41 return SkClampMax(x, 0xFFFF);
42}
43
44static SkFixed repeat_tileproc(SkFixed x)
45{
46 return x & 0xFFFF;
47}
48
49static inline SkFixed mirror_tileproc(SkFixed x)
50{
51 int s = x << 15 >> 31;
52 return (x ^ s) & 0xFFFF;
53}
54
55static const TileProc gTileProcs[] = {
56 clamp_tileproc,
57 repeat_tileproc,
58 mirror_tileproc
59};
60
61//////////////////////////////////////////////////////////////////////////////
62
63static inline int repeat_6bits(int x)
64{
65 return x & 63;
66}
67
68static inline int mirror_6bits(int x)
69{
70#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
71 if (x & 64)
72 x = ~x;
73 return x & 63;
74#else
75 int s = x << 25 >> 31;
76 return (x ^ s) & 63;
77#endif
78}
79
80static inline int repeat_8bits(int x)
81{
82 return x & 0xFF;
83}
84
85static inline int mirror_8bits(int x)
86{
87#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
88 if (x & 256)
89 x = ~x;
90 return x & 255;
91#else
92 int s = x << 23 >> 31;
93 return (x ^ s) & 0xFF;
94#endif
95}
96
97//////////////////////////////////////////////////////////////////////////////
98
99class Gradient_Shader : public SkShader {
100public:
101 Gradient_Shader(const SkColor colors[], const SkScalar pos[],
102 int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper);
103 virtual ~Gradient_Shader();
104
105 // overrides
106 virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&);
107 virtual uint32_t getFlags() { return fFlags; }
108
109protected:
110 Gradient_Shader(SkFlattenableReadBuffer& );
111 SkUnitMapper* fMapper;
112 SkMatrix fPtsToUnit; // set by subclass
113 SkMatrix fDstToIndex;
114 SkMatrix::MapXYProc fDstToIndexProc;
115 SkPMColor* fARGB32;
116 TileMode fTileMode;
117 TileProc fTileProc;
118 uint16_t fColorCount;
119 uint8_t fDstToIndexClass;
120 uint8_t fFlags;
121
122 struct Rec {
123 SkFixed fPos; // 0...1
124 uint32_t fScale; // (1 << 24) / range
125 };
126 Rec* fRecs;
127
128 enum {
129 kCache16Bits = 6, // seems like enough for visual accuracy
130 kCache16Count = 1 << kCache16Bits,
131 kCache32Bits = 8, // pretty much should always be 8
132 kCache32Count = 1 << kCache32Bits
133 };
134 virtual void flatten(SkFlattenableWriteBuffer& );
135 const uint16_t* getCache16();
136 const SkPMColor* getCache32();
137
138private:
139 enum {
140 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
141
142 kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec))
143 };
144 SkColor fStorage[(kStorageSize + 3) >> 2];
145 SkColor* fOrigColors;
146
147 uint16_t* fCache16; // working ptr. If this is NULL, we need to recompute the cache values
148 SkPMColor* fCache32; // working ptr. If this is NULL, we need to recompute the cache values
149
150 uint16_t* fCache16Storage; // storage for fCache16, allocated on demand
151 SkPMColor* fCache32Storage; // storage for fCache32, allocated on demand
152 unsigned fCacheAlpha; // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
153
154 typedef SkShader INHERITED;
155};
156
157static inline unsigned scalarToU16(SkScalar x)
158{
159 SkASSERT(x >= 0 && x <= SK_Scalar1);
160
161#ifdef SK_SCALAR_IS_FLOAT
162 return (unsigned)(x * 0xFFFF);
163#else
164 return x - (x >> 16); // probably should be x - (x > 0x7FFF) but that is slower
165#endif
166}
167
168Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[], int colorCount,
169 SkShader::TileMode mode, SkUnitMapper* mapper)
170{
171 SkASSERT(colorCount > 1);
172
173 fCacheAlpha = 256; // init to a value that paint.getAlpha() can't return
174
175 fMapper = mapper;
176 mapper->safeRef();
177
178 fCache16 = fCache16Storage = NULL;
179 fCache32 = fCache32Storage = NULL;
180
181 fColorCount = SkToU16(colorCount);
182 if (colorCount > kColorStorageCount)
183 fOrigColors = (SkColor*)sk_malloc_throw((sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec)) * colorCount);
184 else
185 fOrigColors = fStorage;
186 memcpy(fOrigColors, colors, colorCount * sizeof(SkColor));
187 // our premul colors point to the 2nd half of the array
188 // these are assigned each time in setContext
189 fARGB32 = fOrigColors + colorCount;
190
191 SkASSERT((unsigned)mode < SkShader::kTileModeCount);
192 SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
193 fTileMode = mode;
194 fTileProc = gTileProcs[mode];
195
196 fRecs = (Rec*)(fARGB32 + colorCount);
197 if (colorCount > 2)
198 {
199 Rec* recs = fRecs;
200
201 recs[0].fPos = 0;
202 // recs[0].fScale = 0; // unused;
203 if (pos)
204 {
205 /* We need to convert the user's array of relative positions into
206 fixed-point positions and scale factors. We need these results
207 to be strictly monotonic (no two values equal or out of order).
208 Hence this complex loop that just jams a zero for the scale
209 value if it sees a segment out of order, and it assures that
210 we start at 0 and end at 1.0
211 */
212 SkFixed prev = 0;
213 for (int i = 1; i < colorCount; i++)
214 {
215 // force the last value to be 1.0
216 SkFixed curr;
217 if (i == colorCount - 1)
218 curr = SK_Fixed1;
219 else
220 {
221 curr = SkScalarToFixed(pos[i]);
222 // pin curr withing range
223 if (curr < 0)
224 curr = 0;
225 else if (curr > SK_Fixed1)
226 curr = SK_Fixed1;
227 }
228 recs[i].fPos = curr;
229 if (curr > prev)
230 recs[i].fScale = (1 << 24) / (curr - prev);
231 else
232 recs[i].fScale = 0; // ignore this segment
233 // get ready for the next value
234 prev = curr;
235 }
236 }
237 else // assume even distribution
238 {
239 SkFixed dp = SK_Fixed1 / (colorCount - 1);
240 SkFixed p = dp;
241 SkFixed scale = (colorCount - 1) << 8; // (1 << 24) / dp
242 for (int i = 1; i < colorCount; i++)
243 {
244 recs[i].fPos = p;
245 recs[i].fScale = scale;
246 p += dp;
247 }
248 }
249 }
250}
251
252Gradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) :
253 INHERITED(buffer)
254{
255 fCacheAlpha = 256;
256
257 fMapper = static_cast<SkUnitMapper*>(buffer.readFlattenable());
258
259 fCache16 = fCache16Storage = NULL;
260 fCache32 = fCache32Storage = NULL;
261
262 int colorCount = fColorCount = buffer.readU16();
263 if (colorCount > kColorStorageCount)
264 fOrigColors = (SkColor*)sk_malloc_throw((sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec)) * colorCount);
265 else
266 fOrigColors = fStorage;
267 buffer.read(fOrigColors, colorCount * sizeof(SkColor));
268 fARGB32 = fOrigColors + colorCount;
269
270 fTileMode = (TileMode)buffer.readU8();
271 fTileProc = gTileProcs[fTileMode];
272 fRecs = (Rec*)(fARGB32 + colorCount);
273 if (colorCount > 2) {
274 Rec* recs = fRecs;
275 recs[0].fPos = 0;
276 for (int i = 1; i < colorCount; i++) {
277 recs[i].fPos = buffer.readS32();
278 recs[i].fScale = buffer.readU32();
279 }
280 }
281 buffer.read(&fPtsToUnit, sizeof(SkMatrix));
282}
283
284Gradient_Shader::~Gradient_Shader()
285{
286 if (fCache16Storage)
287 sk_free(fCache16Storage);
288 if (fCache32Storage)
289 sk_free(fCache32Storage);
290 if (fOrigColors != fStorage)
291 sk_free(fOrigColors);
292 fMapper->safeUnref();
293}
294
295void Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer)
296{
297 this->INHERITED::flatten(buffer);
298 buffer.writeFlattenable(fMapper);
299 buffer.write16(fColorCount);
300 buffer.writeMul4(fOrigColors, fColorCount * sizeof(SkColor));
301 buffer.write8(fTileMode);
302 if (fColorCount > 2) {
303 Rec* recs = fRecs;
304 for (int i = 1; i < fColorCount; i++) {
305 buffer.write32(recs[i].fPos);
306 buffer.write32(recs[i].fScale);
307 }
308 }
309 buffer.writeMul4(&fPtsToUnit, sizeof(SkMatrix));
310}
311
312bool Gradient_Shader::setContext(const SkBitmap& device,
313 const SkPaint& paint,
314 const SkMatrix& matrix)
315{
316 if (!this->INHERITED::setContext(device, paint, matrix))
317 return false;
318
319 const SkMatrix& inverse = this->getTotalInverse();
320
321 if (!fDstToIndex.setConcat(fPtsToUnit, inverse)) {
322 return false;
323 }
324
325 fDstToIndexProc = fDstToIndex.getMapXYProc();
326 fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex);
327
328 // now convert our colors in to PMColors
329 unsigned paintAlpha = this->getPaintAlpha();
330 unsigned colorAlpha = 0xFF;
331
332 for (unsigned i = 0; i < fColorCount; i++) {
333 SkColor src = fOrigColors[i];
334 unsigned sa = SkColorGetA(src);
335 colorAlpha &= sa;
336
337 // now modulate it by the paint for our resulting ARGB32 array
338 sa = SkMulDiv255Round(sa, paintAlpha);
339 fARGB32[i] = SkPreMultiplyARGB(sa, SkColorGetR(src), SkColorGetG(src),
340 SkColorGetB(src));
341 }
342
343 fFlags = this->INHERITED::getFlags();
344 if ((colorAlpha & paintAlpha) == 0xFF) {
345 fFlags |= kOpaqueAlpha_Flag;
346 }
347 // we can do span16 as long as our individual colors are opaque,
348 // regardless of the paint's alpha
349 if (0xFF == colorAlpha) {
350 fFlags |= kHasSpan16_Flag;
351 }
352
353 // if the new alpha differs from the previous time we were called, inval our cache
354 // this will trigger the cache to be rebuilt.
355 // we don't care about the first time, since the cache ptrs will already be NULL
356 if (fCacheAlpha != paintAlpha) {
357 fCache16 = NULL; // inval the cache
358 fCache32 = NULL; // inval the cache
359 fCacheAlpha = paintAlpha; // record the new alpha
360 }
361 return true;
362}
363
364static inline int blend8(int a, int b, int scale)
365{
366 SkASSERT(a == SkToU8(a));
367 SkASSERT(b == SkToU8(b));
368 SkASSERT(scale >= 0 && scale <= 256);
369
370 return a + ((b - a) * scale >> 8);
371}
372
373static inline uint32_t dot8_blend_packed32(uint32_t s0, uint32_t s1, int blend)
374{
375#if 0
376 int a = blend8(SkGetPackedA32(s0), SkGetPackedA32(s1), blend);
377 int r = blend8(SkGetPackedR32(s0), SkGetPackedR32(s1), blend);
378 int g = blend8(SkGetPackedG32(s0), SkGetPackedG32(s1), blend);
379 int b = blend8(SkGetPackedB32(s0), SkGetPackedB32(s1), blend);
380
381 return SkPackARGB32(a, r, g, b);
382#else
383 int otherBlend = 256 - blend;
384
385#if 0
386 U32 t0 = (((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF;
387 U32 t1 = (((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00;
388 SkASSERT((t0 & t1) == 0);
389 return t0 | t1;
390#else
391 return ((((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF) |
392 ((((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00);
393#endif
394
395#endif
396}
397
398#define Fixed_To_Dot8(x) (((x) + 0x80) >> 8)
399
400/** We take the original colors, not our premultiplied PMColors, since we can build a 16bit table
401 as long as the original colors are opaque, even if the paint specifies a non-opaque alpha.
402*/
403static void build_16bit_cache(uint16_t cache[], SkColor c0, SkColor c1, int count)
404{
405 SkASSERT(count > 1);
406 SkASSERT(SkColorGetA(c0) == 0xFF);
407 SkASSERT(SkColorGetA(c1) == 0xFF);
408
409 SkFixed r = SkColorGetR(c0);
410 SkFixed g = SkColorGetG(c0);
411 SkFixed b = SkColorGetB(c0);
412
413 SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
414 SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
415 SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
416
417 r = SkIntToFixed(r) + 0x8000;
418 g = SkIntToFixed(g) + 0x8000;
419 b = SkIntToFixed(b) + 0x8000;
420
421 do {
422 unsigned rr = r >> 16;
423 unsigned gg = g >> 16;
424 unsigned bb = b >> 16;
425 cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
426 cache[64] = SkDitherPack888ToRGB16(rr, gg, bb);
427 cache += 1;
428 r += dr;
429 g += dg;
430 b += db;
431 } while (--count != 0);
432}
433
434static void build_32bit_cache(SkPMColor cache[], SkPMColor c0, SkPMColor c1, int count)
435{
436 SkASSERT(count > 1);
437
438 SkFixed a = SkGetPackedA32(c0);
439 SkFixed r = SkGetPackedR32(c0);
440 SkFixed g = SkGetPackedG32(c0);
441 SkFixed b = SkGetPackedB32(c0);
442
443 SkFixed da = SkIntToFixed(SkGetPackedA32(c1) - a) / (count - 1);
444 SkFixed dr = SkIntToFixed(SkGetPackedR32(c1) - r) / (count - 1);
445 SkFixed dg = SkIntToFixed(SkGetPackedG32(c1) - g) / (count - 1);
446 SkFixed db = SkIntToFixed(SkGetPackedB32(c1) - b) / (count - 1);
447
448 a = SkIntToFixed(a) + 0x8000;
449 r = SkIntToFixed(r) + 0x8000;
450 g = SkIntToFixed(g) + 0x8000;
451 b = SkIntToFixed(b) + 0x8000;
452
453 do {
454 *cache++ = SkPackARGB32(a >> 16, r >> 16, g >> 16, b >> 16);
455 a += da;
456 r += dr;
457 g += dg;
458 b += db;
459 } while (--count != 0);
460}
461
462static inline int SkFixedToFFFF(SkFixed x)
463{
464 SkASSERT((unsigned)x <= SK_Fixed1);
465 return x - (x >> 16);
466}
467
468static inline U16CPU dot6to16(unsigned x)
469{
470 SkASSERT(x < 64);
471 return (x << 10) | (x << 4) | (x >> 2);
472}
473
474const uint16_t* Gradient_Shader::getCache16()
475{
476 if (fCache16 == NULL)
477 {
478 if (fCache16Storage == NULL) // set the storage and our working ptr
479#ifdef TEST_GRADIENT_DITHER
480 fCache16Storage = (uint16_t*)sk_malloc_throw(sizeof(uint16_t) * kCache16Count * 2);
481#else
482 fCache16Storage = (uint16_t*)sk_malloc_throw(sizeof(uint16_t) * kCache16Count);
483#endif
484 fCache16 = fCache16Storage;
485 if (fColorCount == 2)
486 build_16bit_cache(fCache16, fOrigColors[0], fOrigColors[1], kCache16Count);
487 else
488 {
489 Rec* rec = fRecs;
490 int prevIndex = 0;
491 for (unsigned i = 1; i < fColorCount; i++)
492 {
493 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache16Bits);
494 SkASSERT(nextIndex < kCache16Count);
495
496 if (nextIndex > prevIndex)
497 build_16bit_cache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1);
498 prevIndex = nextIndex;
499 }
500 SkASSERT(prevIndex == kCache16Count - 1);
501 }
502
503 if (fMapper)
504 {
505#ifdef TEST_GRADIENT_DITHER
506 fCache16Storage = (uint16_t*)sk_malloc_throw(sizeof(uint16_t) * kCache16Count * 2);
507#else
508 fCache16Storage = (uint16_t*)sk_malloc_throw(sizeof(uint16_t) * kCache16Count);
509#endif
510 uint16_t* linear = fCache16; // just computed linear data
511 uint16_t* mapped = fCache16Storage; // storage for mapped data
512 SkUnitMapper* map = fMapper;
513 for (int i = 0; i < 64; i++)
514 {
515 int index = map->mapUnit16(dot6to16(i)) >> 10;
516 mapped[i] = linear[index];
517#ifdef TEST_GRADIENT_DITHER
518 mapped[i + 64] = linear[index + 64];
519#endif
520 }
521 sk_free(fCache16);
522 fCache16 = fCache16Storage;
523 }
524 }
525 return fCache16;
526}
527
528const SkPMColor* Gradient_Shader::getCache32()
529{
530 if (fCache32 == NULL)
531 {
532 if (fCache32Storage == NULL) // set the storage and our working ptr
533 fCache32Storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * kCache32Count);
534
535 fCache32 = fCache32Storage;
536 if (fColorCount == 2)
537 build_32bit_cache(fCache32, fARGB32[0], fARGB32[1], kCache32Count);
538 else
539 {
540 Rec* rec = fRecs;
541 int prevIndex = 0;
542 for (unsigned i = 1; i < fColorCount; i++)
543 {
544 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache32Bits);
545 SkASSERT(nextIndex < kCache32Count);
546
547 if (nextIndex > prevIndex)
548 build_32bit_cache(fCache32 + prevIndex, fARGB32[i-1], fARGB32[i], nextIndex - prevIndex + 1);
549 prevIndex = nextIndex;
550 }
551 SkASSERT(prevIndex == kCache32Count - 1);
552 }
553
554 if (fMapper)
555 {
556 fCache32Storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * kCache32Count);
557 SkPMColor* linear = fCache32; // just computed linear data
558 SkPMColor* mapped = fCache32Storage; // storage for mapped data
559 SkUnitMapper* map = fMapper;
560 for (int i = 0; i < 256; i++)
561 mapped[i] = linear[map->mapUnit16((i << 8) | i) >> 8];
562 sk_free(fCache32);
563 fCache32 = fCache32Storage;
564 }
565 }
566 return fCache32;
567}
568
569///////////////////////////////////////////////////////////////////////////
570
571static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix)
572{
573 SkVector vec = pts[1] - pts[0];
574 SkScalar mag = vec.length();
575 SkScalar inv = mag ? SkScalarInvert(mag) : 0;
576
577 vec.scale(inv);
578 matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
579 matrix->postTranslate(-pts[0].fX, -pts[0].fY);
580 matrix->postScale(inv, inv);
581}
582
583///////////////////////////////////////////////////////////////////////////////
584
585class Linear_Gradient : public Gradient_Shader {
586public:
587 Linear_Gradient(const SkPoint pts[2],
588 const SkColor colors[], const SkScalar pos[], int colorCount,
589 SkShader::TileMode mode, SkUnitMapper* mapper)
590 : Gradient_Shader(colors, pos, colorCount, mode, mapper)
591 {
592 pts_to_unit_matrix(pts, &fPtsToUnit);
593 }
594 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
595 virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
596 virtual bool asABitmap(SkBitmap*, SkMatrix*, TileMode*);
597
598 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
599 return SkNEW_ARGS(Linear_Gradient, (buffer));
600 }
601
602protected:
603 Linear_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {};
604 virtual Factory getFactory() { return CreateProc; }
605
606private:
607 typedef Gradient_Shader INHERITED;
608};
609
610// Return true if fx, fx+dx, fx+2*dx, ... is always in range
611static bool no_need_for_clamp(int fx, int dx, int count)
612{
613 SkASSERT(count > 0);
614 return (unsigned)((fx | (fx + (count - 1) * dx)) >> 8) <= 0xFF;
615}
616
617void Linear_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count)
618{
619 SkASSERT(count > 0);
620
621 SkPoint srcPt;
622 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
623 TileProc proc = fTileProc;
624 const SkPMColor* cache = this->getCache32();
625
626 if (fDstToIndexClass != kPerspective_MatrixClass)
627 {
628 dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
629 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
630
631 if (fDstToIndexClass == kFixedStepInX_MatrixClass)
632 {
633 SkFixed dxStorage[1];
634 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
635 dx = dxStorage[0];
636 }
637 else
638 {
639 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
640 dx = SkScalarToFixed(fDstToIndex.getScaleX());
641 }
642
643 if (SkFixedNearlyZero(dx)) // we're a vertical gradient, so no change in a span
644 {
645 unsigned fi = proc(fx);
646 SkASSERT(fi <= 0xFFFF);
647 sk_memset32(dstC, cache[fi >> (16 - kCache32Bits)], count);
648 }
649 else if (proc == clamp_tileproc)
650 {
651#if 0
652 if (no_need_for_clamp(fx, dx, count))
653 {
654 unsigned fi;
655 while ((count -= 4) >= 0)
656 {
657 fi = fx >> 8; SkASSERT(fi <= 0xFF); fx += dx; *dstC++ = cache[fi];
658 fi = fx >> 8; SkASSERT(fi <= 0xFF); fx += dx; *dstC++ = cache[fi];
659 fi = fx >> 8; SkASSERT(fi <= 0xFF); fx += dx; *dstC++ = cache[fi];
660 fi = fx >> 8; SkASSERT(fi <= 0xFF); fx += dx; *dstC++ = cache[fi];
661 }
662 SkASSERT(count <= -1 && count >= -4);
663 count += 4;
664 while (--count >= 0)
665 {
666 fi = fx >> 8;
667 SkASSERT(fi <= 0xFF);
668 fx += dx;
669 *dstC++ = cache[fi];
670 }
671 }
672 else
673#endif
674 do {
675 unsigned fi = SkClampMax(fx >> 8, 0xFF);
676 SkASSERT(fi <= 0xFF);
677 fx += dx;
678 *dstC++ = cache[fi];
679 } while (--count != 0);
680 }
681 else if (proc == mirror_tileproc)
682 {
683 do {
684 unsigned fi = mirror_8bits(fx >> 8);
685 SkASSERT(fi <= 0xFF);
686 fx += dx;
687 *dstC++ = cache[fi];
688 } while (--count != 0);
689 }
690 else
691 {
692 SkASSERT(proc == repeat_tileproc);
693 do {
694 unsigned fi = repeat_8bits(fx >> 8);
695 SkASSERT(fi <= 0xFF);
696 fx += dx;
697 *dstC++ = cache[fi];
698 } while (--count != 0);
699 }
700 }
701 else
702 {
703 SkScalar dstX = SkIntToScalar(x);
704 SkScalar dstY = SkIntToScalar(y);
705 do {
706 dstProc(fDstToIndex, dstX, dstY, &srcPt);
707 unsigned fi = proc(SkScalarToFixed(srcPt.fX));
708 SkASSERT(fi <= 0xFFFF);
709 *dstC++ = cache[fi >> (16 - kCache32Bits)];
710 dstX += SK_Scalar1;
711 } while (--count != 0);
712 }
713}
714
715bool Linear_Gradient::asABitmap(SkBitmap* bitmap, SkMatrix* matrix,
716 TileMode xy[]) {
717 if (bitmap) {
718 bitmap->setConfig(SkBitmap::kARGB_8888_Config, kCache32Count, 1);
719 bitmap->allocPixels(); // share with shader???
720 memcpy(bitmap->getPixels(), this->getCache32(), kCache32Count * 4);
721 }
722 if (matrix) {
723 matrix->setScale(SkIntToScalar(kCache32Count), SK_Scalar1);
724 matrix->preConcat(fPtsToUnit);
725 }
726 if (xy) {
727 xy[0] = fTileMode;
728 xy[1] = kClamp_TileMode;
729 }
730 return true;
731}
732
733#ifdef TEST_GRADIENT_DITHER
734static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other, int count)
735{
736 if ((unsigned)dst & 2)
737 {
738 *dst++ = value;
739 count -= 1;
740 SkTSwap(value, other);
741 }
742
743 sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
744
745 if (count & 1)
746 dst[count - 1] = value;
747}
748#endif
749
750void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count)
751{
752 SkASSERT(count > 0);
753
754 SkPoint srcPt;
755 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
756 TileProc proc = fTileProc;
757 const uint16_t* cache = this->getCache16();
758#ifdef TEST_GRADIENT_DITHER
759 int toggle = ((x ^ y) & 1) << kCache16Bits;
760#endif
761
762 if (fDstToIndexClass != kPerspective_MatrixClass)
763 {
764 dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
765 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
766
767 if (fDstToIndexClass == kFixedStepInX_MatrixClass)
768 {
769 SkFixed dxStorage[1];
770 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
771 dx = dxStorage[0];
772 }
773 else
774 {
775 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
776 dx = SkScalarToFixed(fDstToIndex.getScaleX());
777 }
778
779 if (SkFixedNearlyZero(dx)) // we're a vertical gradient, so no change in a span
780 {
781 unsigned fi = proc(fx) >> 10;
782 SkASSERT(fi <= 63);
783#ifdef TEST_GRADIENT_DITHER
784 dither_memset16(dstC, cache[toggle + fi], cache[(toggle ^ (1 << kCache16Bits)) + fi], count);
785#else
786 sk_memset16(dstC, cache[fi], count);
787#endif
788 }
789 else if (proc == clamp_tileproc)
790 {
791 do {
792 unsigned fi = SkClampMax(fx >> 10, 63);
793 SkASSERT(fi <= 63);
794 fx += dx;
795#ifdef TEST_GRADIENT_DITHER
796 *dstC++ = cache[toggle + fi];
797 toggle ^= (1 << kCache16Bits);
798#else
799 *dstC++ = cache[fi];
800#endif
801 } while (--count != 0);
802 }
803 else if (proc == mirror_tileproc)
804 {
805 do {
806 unsigned fi = mirror_6bits(fx >> 10);
807 SkASSERT(fi <= 0x3F);
808 fx += dx;
809#ifdef TEST_GRADIENT_DITHER
810 *dstC++ = cache[toggle + fi];
811 toggle ^= (1 << kCache16Bits);
812#else
813 *dstC++ = cache[fi];
814#endif
815 } while (--count != 0);
816 }
817 else
818 {
819 SkASSERT(proc == repeat_tileproc);
820 do {
821 unsigned fi = repeat_6bits(fx >> 10);
822 SkASSERT(fi <= 0x3F);
823 fx += dx;
824#ifdef TEST_GRADIENT_DITHER
825 *dstC++ = cache[toggle + fi];
826 toggle ^= (1 << kCache16Bits);
827#else
828 *dstC++ = cache[fi];
829#endif
830 } while (--count != 0);
831 }
832 }
833 else
834 {
835 SkScalar dstX = SkIntToScalar(x);
836 SkScalar dstY = SkIntToScalar(y);
837 do {
838 dstProc(fDstToIndex, dstX, dstY, &srcPt);
839 unsigned fi = proc(SkScalarToFixed(srcPt.fX));
840 SkASSERT(fi <= 0xFFFF);
841
842 int index = fi >> (16 - kCache16Bits);
843#ifdef TEST_GRADIENT_DITHER
844 *dstC++ = cache[toggle + index];
845 toggle ^= (1 << kCache16Bits);
846#else
847 *dstC++ = cache[index];
848#endif
849
850 dstX += SK_Scalar1;
851 } while (--count != 0);
852 }
853}
854
855///////////////////////////////////////////////////////////////////////////////
856
857#define kSQRT_TABLE_BITS 11
858#define kSQRT_TABLE_SIZE (1 << kSQRT_TABLE_BITS)
859
860#include "SkRadialGradient_Table.h"
861
862#if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG)
863
864#include <stdio.h>
865
866void SkRadialGradient_BuildTable()
867{
868 // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table
869
870 FILE* file = ::fopen("SkRadialGradient_Table.h", "w");
871 SkASSERT(file);
872 ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n");
873
874 for (int i = 0; i < kSQRT_TABLE_SIZE; i++)
875 {
876 if ((i & 15) == 0)
877 ::fprintf(file, "\t");
878
879 uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8);
880
881 ::fprintf(file, "0x%02X", value);
882 if (i < kSQRT_TABLE_SIZE-1)
883 ::fprintf(file, ", ");
884 if ((i & 15) == 15)
885 ::fprintf(file, "\n");
886 }
887 ::fprintf(file, "};\n");
888 ::fclose(file);
889}
890
891#endif
892
893
894static void rad_to_unit_matrix(const SkPoint& center, SkScalar radius, SkMatrix* matrix)
895{
896 SkScalar inv = SkScalarInvert(radius);
897
898 matrix->setTranslate(-center.fX, -center.fY);
899 matrix->postScale(inv, inv);
900}
901
902class Radial_Gradient : public Gradient_Shader {
903public:
904 Radial_Gradient(const SkPoint& center, SkScalar radius,
905 const SkColor colors[], const SkScalar pos[], int colorCount,
906 SkShader::TileMode mode, SkUnitMapper* mapper)
907 : Gradient_Shader(colors, pos, colorCount, mode, mapper)
908 {
909 // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
910 SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
911
912 rad_to_unit_matrix(center, radius, &fPtsToUnit);
913 }
914 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
915 {
916 SkASSERT(count > 0);
917
918 SkPoint srcPt;
919 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
920 TileProc proc = fTileProc;
921 const SkPMColor* cache = this->getCache32();
922
923 if (fDstToIndexClass != kPerspective_MatrixClass)
924 {
925 dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
926 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
927 SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
928
929 if (fDstToIndexClass == kFixedStepInX_MatrixClass)
930 {
931 SkFixed storage[2];
932 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &storage[0], &storage[1]);
933 dx = storage[0];
934 dy = storage[1];
935 }
936 else
937 {
938 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
939 dx = SkScalarToFixed(fDstToIndex.getScaleX());
940 dy = SkScalarToFixed(fDstToIndex.getSkewY());
941 }
942
943 if (proc == clamp_tileproc)
944 {
945 const uint8_t* sqrt_table = gSqrt8Table;
946 fx >>= 1;
947 dx >>= 1;
948 fy >>= 1;
949 dy >>= 1;
950 do {
951 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
952 unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
953 fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
954 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
955 *dstC++ = cache[sqrt_table[fi] >> (8 - kCache32Bits)];
956 fx += dx;
957 fy += dy;
958 } while (--count != 0);
959 }
960 else if (proc == mirror_tileproc)
961 {
962 do {
963 SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
964 unsigned fi = mirror_tileproc(dist);
965 SkASSERT(fi <= 0xFFFF);
966 *dstC++ = cache[fi >> (16 - kCache32Bits)];
967 fx += dx;
968 fy += dy;
969 } while (--count != 0);
970 }
971 else
972 {
973 SkASSERT(proc == repeat_tileproc);
974 do {
975 SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
976 unsigned fi = repeat_tileproc(dist);
977 SkASSERT(fi <= 0xFFFF);
978 *dstC++ = cache[fi >> (16 - kCache32Bits)];
979 fx += dx;
980 fy += dy;
981 } while (--count != 0);
982 }
983 }
984 else // perspective case
985 {
986 SkScalar dstX = SkIntToScalar(x);
987 SkScalar dstY = SkIntToScalar(y);
988 do {
989 dstProc(fDstToIndex, dstX, dstY, &srcPt);
990 unsigned fi = proc(SkScalarToFixed(srcPt.length()));
991 SkASSERT(fi <= 0xFFFF);
992 *dstC++ = cache[fi >> (16 - kCache32Bits)];
993 dstX += SK_Scalar1;
994 } while (--count != 0);
995 }
996 }
997 virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count)
998 {
999 SkASSERT(count > 0);
1000
1001 SkPoint srcPt;
1002 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1003 TileProc proc = fTileProc;
1004 const uint16_t* cache = this->getCache16();
1005#ifdef TEST_GRADIENT_DITHER
1006 int toggle = ((x ^ y) & 1) << kCache16Bits;
1007#endif
1008
1009 if (fDstToIndexClass != kPerspective_MatrixClass)
1010 {
1011 dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
1012 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1013 SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
1014
1015 if (fDstToIndexClass == kFixedStepInX_MatrixClass)
1016 {
1017 SkFixed storage[2];
1018 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &storage[0], &storage[1]);
1019 dx = storage[0];
1020 dy = storage[1];
1021 }
1022 else
1023 {
1024 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1025 dx = SkScalarToFixed(fDstToIndex.getScaleX());
1026 dy = SkScalarToFixed(fDstToIndex.getSkewY());
1027 }
1028
1029 if (proc == clamp_tileproc)
1030 {
1031 const uint8_t* sqrt_table = gSqrt8Table;
1032
1033 /* knock these down so we can pin against +- 0x7FFF, which is an immediate load,
1034 rather than 0xFFFF which is slower. This is a compromise, since it reduces our
1035 precision, but that appears to be visually OK. If we decide this is OK for
1036 all of our cases, we could (it seems) put this scale-down into fDstToIndex,
1037 to avoid having to do these extra shifts each time.
1038 */
1039 fx >>= 1;
1040 dx >>= 1;
1041 fy >>= 1;
1042 dy >>= 1;
1043 if (dy == 0) // might perform this check for the other modes, but the win will be a smaller % of the total
1044 {
1045 fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1046 fy *= fy;
1047 do {
1048 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1049 unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS);
1050 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1051 fx += dx;
1052#ifdef TEST_GRADIENT_DITHER
1053 *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
1054 toggle ^= (1 << kCache16Bits);
1055#else
1056 *dstC++ = cache[sqrt_table[fi] >> (8 - kCache16Bits)];
1057#endif
1058 } while (--count != 0);
1059 }
1060 else
1061 {
1062 do {
1063 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1064 unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1065 fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
1066 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1067 fx += dx;
1068 fy += dy;
1069#ifdef TEST_GRADIENT_DITHER
1070 *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
1071 toggle ^= (1 << kCache16Bits);
1072#else
1073 *dstC++ = cache[sqrt_table[fi] >> (8 - kCache16Bits)];
1074#endif
1075 } while (--count != 0);
1076 }
1077 }
1078 else if (proc == mirror_tileproc)
1079 {
1080 do {
1081 SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
1082 unsigned fi = mirror_tileproc(dist);
1083 SkASSERT(fi <= 0xFFFF);
1084 fx += dx;
1085 fy += dy;
1086#ifdef TEST_GRADIENT_DITHER
1087 *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
1088 toggle ^= (1 << kCache16Bits);
1089#else
1090 *dstC++ = cache[fi >> (16 - kCache16Bits)];
1091#endif
1092 } while (--count != 0);
1093 }
1094 else
1095 {
1096 SkASSERT(proc == repeat_tileproc);
1097 do {
1098 SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
1099 unsigned fi = repeat_tileproc(dist);
1100 SkASSERT(fi <= 0xFFFF);
1101 fx += dx;
1102 fy += dy;
1103#ifdef TEST_GRADIENT_DITHER
1104 *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
1105 toggle ^= (1 << kCache16Bits);
1106#else
1107 *dstC++ = cache[fi >> (16 - kCache16Bits)];
1108#endif
1109 } while (--count != 0);
1110 }
1111 }
1112 else // perspective case
1113 {
1114 SkScalar dstX = SkIntToScalar(x);
1115 SkScalar dstY = SkIntToScalar(y);
1116 do {
1117 dstProc(fDstToIndex, dstX, dstY, &srcPt);
1118 unsigned fi = proc(SkScalarToFixed(srcPt.length()));
1119 SkASSERT(fi <= 0xFFFF);
1120
1121 int index = fi >> (16 - kCache16Bits);
1122#ifdef TEST_GRADIENT_DITHER
1123 *dstC++ = cache[toggle + index];
1124 toggle ^= (1 << kCache16Bits);
1125#else
1126 *dstC++ = cache[index];
1127#endif
1128
1129 dstX += SK_Scalar1;
1130 } while (--count != 0);
1131 }
1132 }
1133
1134 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
1135 return SkNEW_ARGS(Radial_Gradient, (buffer));
1136 }
1137
1138protected:
1139 Radial_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {};
1140 virtual Factory getFactory() { return CreateProc; }
1141
1142private:
1143 typedef Gradient_Shader INHERITED;
1144};
1145
1146///////////////////////////////////////////////////////////////////////////////
1147
1148class Sweep_Gradient : public Gradient_Shader {
1149public:
1150 Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
1151 const SkScalar pos[], int count, SkUnitMapper* mapper)
1152 : Gradient_Shader(colors, pos, count, SkShader::kClamp_TileMode, mapper)
1153 {
1154 fPtsToUnit.setTranslate(-cx, -cy);
1155 }
1156 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
1157 virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
1158
1159 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
1160 return SkNEW_ARGS(Sweep_Gradient, (buffer));
1161 }
1162
1163protected:
1164 Sweep_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {}
1165
1166 virtual Factory getFactory() { return CreateProc; }
1167
1168private:
1169 typedef Gradient_Shader INHERITED;
1170};
1171
1172#ifdef COMPUTE_SWEEP_TABLE
1173#define PI 3.14159265
1174static bool gSweepTableReady;
1175static uint8_t gSweepTable[65];
1176
1177/* Our table stores precomputed values for atan: [0...1] -> [0..PI/4]
1178 We scale the results to [0..32]
1179*/
1180static const uint8_t* build_sweep_table()
1181{
1182 if (!gSweepTableReady)
1183 {
1184 const int N = 65;
1185 const double DENOM = N - 1;
1186
1187 for (int i = 0; i < N; i++)
1188 {
1189 double arg = i / DENOM;
1190 double v = atan(arg);
1191 int iv = (int)round(v * DENOM * 2 / PI);
1192// printf("[%d] atan(%g) = %g %d\n", i, arg, v, iv);
1193 printf("%d, ", iv);
1194 gSweepTable[i] = iv;
1195 }
1196 gSweepTableReady = true;
1197 }
1198 return gSweepTable;
1199}
1200#else
1201static const uint8_t gSweepTable[] = {
1202 0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9,
1203 10, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18,
1204 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26,
1205 26, 27, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32,
1206 32
1207};
1208static const uint8_t* build_sweep_table() { return gSweepTable; }
1209#endif
1210
1211// divide numer/denom, with a bias of 6bits. Assumes numer <= denom
1212// and denom != 0. Since our table is 6bits big (+1), this is a nice fit.
1213// Same as (but faster than) SkFixedDiv(numer, denom) >> 10
1214
1215//unsigned div_64(int numer, int denom);
1216static unsigned div_64(int numer, int denom)
1217{
1218 SkASSERT(numer <= denom);
1219 SkASSERT(numer > 0);
1220 SkASSERT(denom > 0);
1221
1222 int nbits = SkCLZ(numer);
1223 int dbits = SkCLZ(denom);
1224 int bits = 6 - nbits + dbits;
1225 SkASSERT(bits <= 6);
1226
1227 if (bits < 0) // detect underflow
1228 return 0;
1229
1230 denom <<= dbits - 1;
1231 numer <<= nbits - 1;
1232
1233 unsigned result = 0;
1234
1235 // do the first one
1236 if ((numer -= denom) >= 0)
1237 result = 1;
1238 else
1239 numer += denom;
1240
1241 // Now fall into our switch statement if there are more bits to compute
1242 if (bits > 0)
1243 {
1244 // make room for the rest of the answer bits
1245 result <<= bits;
1246 switch (bits) {
1247 case 6:
1248 if ((numer = (numer << 1) - denom) >= 0)
1249 result |= 32;
1250 else
1251 numer += denom;
1252 case 5:
1253 if ((numer = (numer << 1) - denom) >= 0)
1254 result |= 16;
1255 else
1256 numer += denom;
1257 case 4:
1258 if ((numer = (numer << 1) - denom) >= 0)
1259 result |= 8;
1260 else
1261 numer += denom;
1262 case 3:
1263 if ((numer = (numer << 1) - denom) >= 0)
1264 result |= 4;
1265 else
1266 numer += denom;
1267 case 2:
1268 if ((numer = (numer << 1) - denom) >= 0)
1269 result |= 2;
1270 else
1271 numer += denom;
1272 case 1:
1273 default: // not strictly need, but makes GCC make better ARM code
1274 if ((numer = (numer << 1) - denom) >= 0)
1275 result |= 1;
1276 else
1277 numer += denom;
1278 }
1279 }
1280 return result;
1281}
1282
1283// Given x,y in the first quadrant, return 0..63 for the angle [0..90]
1284static unsigned atan_0_90(SkFixed y, SkFixed x)
1285{
1286#ifdef SK_DEBUG
1287 {
1288 static bool gOnce;
1289 if (!gOnce)
1290 {
1291 gOnce = true;
1292 SkASSERT(div_64(55, 55) == 64);
1293 SkASSERT(div_64(128, 256) == 32);
1294 SkASSERT(div_64(2326528, 4685824) == 31);
1295 SkASSERT(div_64(753664, 5210112) == 9);
1296 SkASSERT(div_64(229376, 4882432) == 3);
1297 SkASSERT(div_64(2, 64) == 2);
1298 SkASSERT(div_64(1, 64) == 1);
1299 // test that we handle underflow correctly
1300 SkASSERT(div_64(12345, 0x54321234) == 0);
1301 }
1302 }
1303#endif
1304
1305 SkASSERT(y > 0 && x > 0);
1306 const uint8_t* table = build_sweep_table();
1307
1308 unsigned result;
1309 bool swap = (x < y);
1310 if (swap)
1311 {
1312 // first part of the atan(v) = PI/2 - atan(1/v) identity
1313 // since our div_64 and table want v <= 1, where v = y/x
1314 SkTSwap<SkFixed>(x, y);
1315 }
1316
1317 result = div_64(y, x);
1318
1319#ifdef SK_DEBUG
1320 {
1321 unsigned result2 = SkDivBits(y, x, 6);
1322 SkASSERT(result2 == result ||
1323 (result == 1 && result2 == 0));
1324 }
1325#endif
1326
1327 SkASSERT(result < SK_ARRAY_COUNT(gSweepTable));
1328 result = table[result];
1329
1330 if (swap)
1331 {
1332 // complete the atan(v) = PI/2 - atan(1/v) identity
1333 result = 64 - result;
1334 // pin to 63
1335 result -= result >> 6;
1336 }
1337
1338 SkASSERT(result <= 63);
1339 return result;
1340}
1341
1342// returns angle in a circle [0..2PI) -> [0..255]
1343static unsigned SkATan2_255(SkFixed y, SkFixed x)
1344{
1345 if (x == 0)
1346 {
1347 if (y == 0)
1348 return 0;
1349 return y < 0 ? 192 : 64;
1350 }
1351 if (y == 0)
1352 return x < 0 ? 128 : 0;
1353
1354 /* Find the right quadrant for x,y
1355 Since atan_0_90 only handles the first quadrant, we rotate x,y
1356 appropriately before calling it, and then add the right amount
1357 to account for the real quadrant.
1358 quadrant 0 : add 0 | x > 0 && y > 0
1359 quadrant 1 : add 64 (90 degrees) | x < 0 && y > 0
1360 quadrant 2 : add 128 (180 degrees) | x < 0 && y < 0
1361 quadrant 3 : add 192 (270 degrees) | x > 0 && y < 0
1362
1363 map x<0 to (1 << 6)
1364 map y<0 to (3 << 6)
1365 add = map_x ^ map_y
1366 */
1367 int xsign = x >> 31;
1368 int ysign = y >> 31;
1369 int add = ((-xsign) ^ (ysign & 3)) << 6;
1370
1371#ifdef SK_DEBUG
1372 if (0 == add)
1373 SkASSERT(x > 0 && y > 0);
1374 else if (64 == add)
1375 SkASSERT(x < 0 && y > 0);
1376 else if (128 == add)
1377 SkASSERT(x < 0 && y < 0);
1378 else if (192 == add)
1379 SkASSERT(x > 0 && y < 0);
1380 else
1381 SkASSERT(!"bad value for add");
1382#endif
1383
1384 /* This ^ trick makes x, y positive, and the swap<> handles quadrants
1385 where we need to rotate x,y by 90 or -90
1386 */
1387 x = (x ^ xsign) - xsign;
1388 y = (y ^ ysign) - ysign;
1389 if (add & 64) // quads 1 or 3 need to swap x,y
1390 SkTSwap<SkFixed>(x, y);
1391
1392 unsigned result = add + atan_0_90(y, x);
1393 SkASSERT(result < 256);
1394 return result;
1395}
1396
1397void Sweep_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count)
1398{
1399 SkMatrix::MapXYProc proc = fDstToIndexProc;
1400 const SkMatrix& matrix = fDstToIndex;
1401 const SkPMColor* cache = this->getCache32();
1402 SkPoint srcPt;
1403
1404 if (fDstToIndexClass != kPerspective_MatrixClass)
1405 {
1406 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
1407 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1408 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1409 SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
1410
1411 if (fDstToIndexClass == kFixedStepInX_MatrixClass)
1412 {
1413 SkFixed storage[2];
1414 (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
1415 &storage[0], &storage[1]);
1416 dx = storage[0];
1417 dy = storage[1];
1418 }
1419 else
1420 {
1421 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1422 dx = SkScalarToFixed(matrix.getScaleX());
1423 dy = SkScalarToFixed(matrix.getSkewY());
1424 }
1425
1426 for (; count > 0; --count)
1427 {
1428 *dstC++ = cache[SkATan2_255(fy, fx)];
1429 fx += dx;
1430 fy += dy;
1431 }
1432 }
1433 else // perspective case
1434 {
1435 for (int stop = x + count; x < stop; x++)
1436 {
1437 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
1438 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1439
1440 int index = SkATan2_255(SkScalarToFixed(srcPt.fY),
1441 SkScalarToFixed(srcPt.fX));
1442 *dstC++ = cache[index];
1443 }
1444 }
1445}
1446
1447void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count)
1448{
1449 SkMatrix::MapXYProc proc = fDstToIndexProc;
1450 const SkMatrix& matrix = fDstToIndex;
1451 const uint16_t* cache = this->getCache16();
1452 int toggle = ((x ^ y) & 1) << kCache16Bits;
1453 SkPoint srcPt;
1454
1455 if (fDstToIndexClass != kPerspective_MatrixClass)
1456 {
1457 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
1458 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1459 SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1460 SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
1461
1462 if (fDstToIndexClass == kFixedStepInX_MatrixClass)
1463 {
1464 SkFixed storage[2];
1465 (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
1466 &storage[0], &storage[1]);
1467 dx = storage[0];
1468 dy = storage[1];
1469 }
1470 else
1471 {
1472 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1473 dx = SkScalarToFixed(matrix.getScaleX());
1474 dy = SkScalarToFixed(matrix.getSkewY());
1475 }
1476
1477 for (; count > 0; --count)
1478 {
1479 int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
1480 *dstC++ = cache[toggle + index];
1481 toggle ^= (1 << kCache16Bits);
1482 fx += dx;
1483 fy += dy;
1484 }
1485 }
1486 else // perspective case
1487 {
1488 for (int stop = x + count; x < stop; x++)
1489 {
1490 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
1491 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1492
1493 int index = SkATan2_255(SkScalarToFixed(srcPt.fY),
1494 SkScalarToFixed(srcPt.fX));
1495 index >>= (8 - kCache16Bits);
1496 *dstC++ = cache[toggle + index];
1497 toggle ^= (1 << kCache16Bits);
1498 }
1499 }
1500}
1501
1502///////////////////////////////////////////////////////////////////////////
1503///////////////////////////////////////////////////////////////////////////
1504
1505// assumes colors is SkColor* and pos is SkScalar*
1506#define EXPAND_1_COLOR(count) \
1507 SkColor tmp[2]; \
1508 do { \
1509 if (1 == count) { \
1510 tmp[0] = tmp[1] = colors[0]; \
1511 colors = tmp; \
1512 pos = NULL; \
1513 count = 2; \
1514 } \
1515 } while (0)
1516
1517SkShader* SkGradientShader::CreateLinear( const SkPoint pts[2],
1518 const SkColor colors[], const SkScalar pos[], int colorCount,
1519 SkShader::TileMode mode, SkUnitMapper* mapper)
1520{
1521 if (NULL == pts || NULL == colors || colorCount < 1) {
1522 return NULL;
1523 }
1524 EXPAND_1_COLOR(colorCount);
1525
1526 return SkNEW_ARGS(Linear_Gradient, (pts, colors, pos, colorCount, mode, mapper));
1527}
1528
1529SkShader* SkGradientShader::CreateRadial( const SkPoint& center, SkScalar radius,
1530 const SkColor colors[], const SkScalar pos[], int colorCount,
1531 SkShader::TileMode mode, SkUnitMapper* mapper)
1532{
1533 if (radius <= 0 || NULL == colors || colorCount < 1) {
1534 return NULL;
1535 }
1536 EXPAND_1_COLOR(colorCount);
1537
1538 return SkNEW_ARGS(Radial_Gradient, (center, radius, colors, pos, colorCount, mode, mapper));
1539}
1540
1541SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
1542 const SkColor colors[],
1543 const SkScalar pos[],
1544 int count, SkUnitMapper* mapper)
1545{
1546 if (NULL == colors || count < 1) {
1547 return NULL;
1548 }
1549 EXPAND_1_COLOR(count);
1550
1551 return SkNEW_ARGS(Sweep_Gradient, (cx, cy, colors, pos, count, mapper));
1552}
1553
1554static SkFlattenable::Registrar gLinearGradientReg("Linear_Gradient",
1555 Linear_Gradient::CreateProc);
1556
1557static SkFlattenable::Registrar gRadialGradientReg("Radial_Gradient",
1558 Radial_Gradient::CreateProc);
1559
1560static SkFlattenable::Registrar gSweepGradientReg("Sweep_Gradient",
1561 Sweep_Gradient::CreateProc);
1562