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