1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #include "SkGradientShaderPriv.h" 10 #include "SkLinearGradient.h" 11 #include "SkRadialGradient.h" 12 #include "SkTwoPointRadialGradient.h" 13 #include "SkTwoPointConicalGradient.h" 14 #include "SkSweepGradient.h" 15 16 SkGradientShaderBase::SkGradientShaderBase(const SkColor colors[], const SkScalar pos[], 17 int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper) { 18 SkASSERT(colorCount > 1); 19 20 fCacheAlpha = 256; // init to a value that paint.getAlpha() can't return 21 22 fMapper = mapper; 23 SkSafeRef(mapper); 24 25 SkASSERT((unsigned)mode < SkShader::kTileModeCount); 26 SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs)); 27 fTileMode = mode; 28 fTileProc = gTileProcs[mode]; 29 30 fCache16 = fCache16Storage = NULL; 31 fCache32 = NULL; 32 fCache32PixelRef = NULL; 33 34 /* Note: we let the caller skip the first and/or last position. 35 i.e. pos[0] = 0.3, pos[1] = 0.7 36 In these cases, we insert dummy entries to ensure that the final data 37 will be bracketed by [0, 1]. 38 i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1 39 40 Thus colorCount (the caller's value, and fColorCount (our value) may 41 differ by up to 2. In the above example: 42 colorCount = 2 43 fColorCount = 4 44 */ 45 fColorCount = colorCount; 46 // check if we need to add in dummy start and/or end position/colors 47 bool dummyFirst = false; 48 bool dummyLast = false; 49 if (pos) { 50 dummyFirst = pos[0] != 0; 51 dummyLast = pos[colorCount - 1] != SK_Scalar1; 52 fColorCount += dummyFirst + dummyLast; 53 } 54 55 if (fColorCount > kColorStorageCount) { 56 size_t size = sizeof(SkColor) + sizeof(Rec); 57 fOrigColors = reinterpret_cast<SkColor*>( 58 sk_malloc_throw(size * fColorCount)); 59 } 60 else { 61 fOrigColors = fStorage; 62 } 63 64 // Now copy over the colors, adding the dummies as needed 65 { 66 SkColor* origColors = fOrigColors; 67 if (dummyFirst) { 68 *origColors++ = colors[0]; 69 } 70 memcpy(origColors, colors, colorCount * sizeof(SkColor)); 71 if (dummyLast) { 72 origColors += colorCount; 73 *origColors = colors[colorCount - 1]; 74 } 75 } 76 77 fRecs = (Rec*)(fOrigColors + fColorCount); 78 if (fColorCount > 2) { 79 Rec* recs = fRecs; 80 recs->fPos = 0; 81 // recs->fScale = 0; // unused; 82 recs += 1; 83 if (pos) { 84 /* We need to convert the user's array of relative positions into 85 fixed-point positions and scale factors. We need these results 86 to be strictly monotonic (no two values equal or out of order). 87 Hence this complex loop that just jams a zero for the scale 88 value if it sees a segment out of order, and it assures that 89 we start at 0 and end at 1.0 90 */ 91 SkFixed prev = 0; 92 int startIndex = dummyFirst ? 0 : 1; 93 int count = colorCount + dummyLast; 94 for (int i = startIndex; i < count; i++) { 95 // force the last value to be 1.0 96 SkFixed curr; 97 if (i == colorCount) { // we're really at the dummyLast 98 curr = SK_Fixed1; 99 } else { 100 curr = SkScalarToFixed(pos[i]); 101 } 102 // pin curr withing range 103 if (curr < 0) { 104 curr = 0; 105 } else if (curr > SK_Fixed1) { 106 curr = SK_Fixed1; 107 } 108 recs->fPos = curr; 109 if (curr > prev) { 110 recs->fScale = (1 << 24) / (curr - prev); 111 } else { 112 recs->fScale = 0; // ignore this segment 113 } 114 // get ready for the next value 115 prev = curr; 116 recs += 1; 117 } 118 } else { // assume even distribution 119 SkFixed dp = SK_Fixed1 / (colorCount - 1); 120 SkFixed p = dp; 121 SkFixed scale = (colorCount - 1) << 8; // (1 << 24) / dp 122 for (int i = 1; i < colorCount; i++) { 123 recs->fPos = p; 124 recs->fScale = scale; 125 recs += 1; 126 p += dp; 127 } 128 } 129 } 130 this->initCommon(); 131 } 132 133 SkGradientShaderBase::SkGradientShaderBase(SkFlattenableReadBuffer& buffer) : 134 INHERITED(buffer) { 135 fCacheAlpha = 256; 136 137 fMapper = buffer.readFlattenableT<SkUnitMapper>(); 138 139 fCache16 = fCache16Storage = NULL; 140 fCache32 = NULL; 141 fCache32PixelRef = NULL; 142 143 int colorCount = fColorCount = buffer.getArrayCount(); 144 if (colorCount > kColorStorageCount) { 145 size_t size = sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec); 146 fOrigColors = (SkColor*)sk_malloc_throw(size * colorCount); 147 } else { 148 fOrigColors = fStorage; 149 } 150 buffer.readColorArray(fOrigColors); 151 152 fTileMode = (TileMode)buffer.readUInt(); 153 fTileProc = gTileProcs[fTileMode]; 154 fRecs = (Rec*)(fOrigColors + colorCount); 155 if (colorCount > 2) { 156 Rec* recs = fRecs; 157 recs[0].fPos = 0; 158 for (int i = 1; i < colorCount; i++) { 159 recs[i].fPos = buffer.readInt(); 160 recs[i].fScale = buffer.readUInt(); 161 } 162 } 163 buffer.readMatrix(&fPtsToUnit); 164 this->initCommon(); 165 } 166 167 SkGradientShaderBase::~SkGradientShaderBase() { 168 if (fCache16Storage) { 169 sk_free(fCache16Storage); 170 } 171 SkSafeUnref(fCache32PixelRef); 172 if (fOrigColors != fStorage) { 173 sk_free(fOrigColors); 174 } 175 SkSafeUnref(fMapper); 176 } 177 178 void SkGradientShaderBase::initCommon() { 179 fFlags = 0; 180 unsigned colorAlpha = 0xFF; 181 for (int i = 0; i < fColorCount; i++) { 182 colorAlpha &= SkColorGetA(fOrigColors[i]); 183 } 184 fColorsAreOpaque = colorAlpha == 0xFF; 185 } 186 187 void SkGradientShaderBase::flatten(SkFlattenableWriteBuffer& buffer) const { 188 this->INHERITED::flatten(buffer); 189 buffer.writeFlattenable(fMapper); 190 buffer.writeColorArray(fOrigColors, fColorCount); 191 buffer.writeUInt(fTileMode); 192 if (fColorCount > 2) { 193 Rec* recs = fRecs; 194 for (int i = 1; i < fColorCount; i++) { 195 buffer.writeInt(recs[i].fPos); 196 buffer.writeUInt(recs[i].fScale); 197 } 198 } 199 buffer.writeMatrix(fPtsToUnit); 200 } 201 202 bool SkGradientShaderBase::isOpaque() const { 203 return fColorsAreOpaque; 204 } 205 206 bool SkGradientShaderBase::setContext(const SkBitmap& device, 207 const SkPaint& paint, 208 const SkMatrix& matrix) { 209 if (!this->INHERITED::setContext(device, paint, matrix)) { 210 return false; 211 } 212 213 const SkMatrix& inverse = this->getTotalInverse(); 214 215 if (!fDstToIndex.setConcat(fPtsToUnit, inverse)) { 216 // need to keep our set/end context calls balanced. 217 this->INHERITED::endContext(); 218 return false; 219 } 220 221 fDstToIndexProc = fDstToIndex.getMapXYProc(); 222 fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex); 223 224 // now convert our colors in to PMColors 225 unsigned paintAlpha = this->getPaintAlpha(); 226 227 fFlags = this->INHERITED::getFlags(); 228 if (fColorsAreOpaque && paintAlpha == 0xFF) { 229 fFlags |= kOpaqueAlpha_Flag; 230 } 231 // we can do span16 as long as our individual colors are opaque, 232 // regardless of the paint's alpha 233 if (fColorsAreOpaque) { 234 fFlags |= kHasSpan16_Flag; 235 } 236 237 this->setCacheAlpha(paintAlpha); 238 return true; 239 } 240 241 void SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const { 242 // if the new alpha differs from the previous time we were called, inval our cache 243 // this will trigger the cache to be rebuilt. 244 // we don't care about the first time, since the cache ptrs will already be NULL 245 if (fCacheAlpha != alpha) { 246 fCache16 = NULL; // inval the cache 247 fCache32 = NULL; // inval the cache 248 fCacheAlpha = alpha; // record the new alpha 249 // inform our subclasses 250 if (fCache32PixelRef) { 251 fCache32PixelRef->notifyPixelsChanged(); 252 } 253 } 254 } 255 256 #define Fixed_To_Dot8(x) (((x) + 0x80) >> 8) 257 258 /** We take the original colors, not our premultiplied PMColors, since we can 259 build a 16bit table as long as the original colors are opaque, even if the 260 paint specifies a non-opaque alpha. 261 */ 262 void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1, 263 int count) { 264 SkASSERT(count > 1); 265 SkASSERT(SkColorGetA(c0) == 0xFF); 266 SkASSERT(SkColorGetA(c1) == 0xFF); 267 268 SkFixed r = SkColorGetR(c0); 269 SkFixed g = SkColorGetG(c0); 270 SkFixed b = SkColorGetB(c0); 271 272 SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1); 273 SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1); 274 SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1); 275 276 r = SkIntToFixed(r) + 0x8000; 277 g = SkIntToFixed(g) + 0x8000; 278 b = SkIntToFixed(b) + 0x8000; 279 280 do { 281 unsigned rr = r >> 16; 282 unsigned gg = g >> 16; 283 unsigned bb = b >> 16; 284 cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb)); 285 cache[kCache16Count] = SkDitherPack888ToRGB16(rr, gg, bb); 286 cache += 1; 287 r += dr; 288 g += dg; 289 b += db; 290 } while (--count != 0); 291 } 292 293 /* 294 * 2x2 dither a fixed-point color component (8.16) down to 8, matching the 295 * semantics of how we 2x2 dither 32->16 296 */ 297 static inline U8CPU dither_fixed_to_8(SkFixed n) { 298 n >>= 8; 299 return ((n << 1) - ((n >> 8 << 8) | (n >> 8))) >> 8; 300 } 301 302 /* 303 * For dithering with premultiply, we want to ceiling the alpha component, 304 * to ensure that it is always >= any color component. 305 */ 306 static inline U8CPU dither_ceil_fixed_to_8(SkFixed n) { 307 n >>= 8; 308 return ((n << 1) - (n | (n >> 8))) >> 8; 309 } 310 311 void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1, 312 int count, U8CPU paintAlpha) { 313 SkASSERT(count > 1); 314 315 // need to apply paintAlpha to our two endpoints 316 SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha); 317 SkFixed da; 318 { 319 int tmp = SkMulDiv255Round(SkColorGetA(c1), paintAlpha); 320 da = SkIntToFixed(tmp - a) / (count - 1); 321 } 322 323 SkFixed r = SkColorGetR(c0); 324 SkFixed g = SkColorGetG(c0); 325 SkFixed b = SkColorGetB(c0); 326 SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1); 327 SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1); 328 SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1); 329 330 a = SkIntToFixed(a) + 0x8000; 331 r = SkIntToFixed(r) + 0x8000; 332 g = SkIntToFixed(g) + 0x8000; 333 b = SkIntToFixed(b) + 0x8000; 334 335 do { 336 cache[0] = SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16); 337 cache[kCache32Count] = 338 SkPremultiplyARGBInline(dither_ceil_fixed_to_8(a), 339 dither_fixed_to_8(r), 340 dither_fixed_to_8(g), 341 dither_fixed_to_8(b)); 342 cache += 1; 343 a += da; 344 r += dr; 345 g += dg; 346 b += db; 347 } while (--count != 0); 348 } 349 350 static inline int SkFixedToFFFF(SkFixed x) { 351 SkASSERT((unsigned)x <= SK_Fixed1); 352 return x - (x >> 16); 353 } 354 355 static inline U16CPU bitsTo16(unsigned x, const unsigned bits) { 356 SkASSERT(x < (1U << bits)); 357 if (6 == bits) { 358 return (x << 10) | (x << 4) | (x >> 2); 359 } 360 if (8 == bits) { 361 return (x << 8) | x; 362 } 363 sk_throw(); 364 return 0; 365 } 366 367 const uint16_t* SkGradientShaderBase::getCache16() const { 368 if (fCache16 == NULL) { 369 // double the count for dither entries 370 const int entryCount = kCache16Count * 2; 371 const size_t allocSize = sizeof(uint16_t) * entryCount; 372 373 if (fCache16Storage == NULL) { // set the storage and our working ptr 374 fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); 375 } 376 fCache16 = fCache16Storage; 377 if (fColorCount == 2) { 378 Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1], 379 kCache16Count); 380 } else { 381 Rec* rec = fRecs; 382 int prevIndex = 0; 383 for (int i = 1; i < fColorCount; i++) { 384 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift; 385 SkASSERT(nextIndex < kCache16Count); 386 387 if (nextIndex > prevIndex) 388 Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1); 389 prevIndex = nextIndex; 390 } 391 } 392 393 if (fMapper) { 394 fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); 395 uint16_t* linear = fCache16; // just computed linear data 396 uint16_t* mapped = fCache16Storage; // storage for mapped data 397 SkUnitMapper* map = fMapper; 398 for (int i = 0; i < kCache16Count; i++) { 399 int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift; 400 mapped[i] = linear[index]; 401 mapped[i + kCache16Count] = linear[index + kCache16Count]; 402 } 403 sk_free(fCache16); 404 fCache16 = fCache16Storage; 405 } 406 } 407 return fCache16; 408 } 409 410 const SkPMColor* SkGradientShaderBase::getCache32() const { 411 if (fCache32 == NULL) { 412 // double the count for dither entries 413 const int entryCount = kCache32Count * 2; 414 const size_t allocSize = sizeof(SkPMColor) * entryCount; 415 416 if (NULL == fCache32PixelRef) { 417 fCache32PixelRef = SkNEW_ARGS(SkMallocPixelRef, 418 (NULL, allocSize, NULL)); 419 } 420 fCache32 = (SkPMColor*)fCache32PixelRef->getAddr(); 421 if (fColorCount == 2) { 422 Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1], 423 kCache32Count, fCacheAlpha); 424 } else { 425 Rec* rec = fRecs; 426 int prevIndex = 0; 427 for (int i = 1; i < fColorCount; i++) { 428 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift; 429 SkASSERT(nextIndex < kCache32Count); 430 431 if (nextIndex > prevIndex) 432 Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1], 433 fOrigColors[i], 434 nextIndex - prevIndex + 1, fCacheAlpha); 435 prevIndex = nextIndex; 436 } 437 } 438 439 if (fMapper) { 440 SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef, 441 (NULL, allocSize, NULL)); 442 SkPMColor* linear = fCache32; // just computed linear data 443 SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data 444 SkUnitMapper* map = fMapper; 445 for (int i = 0; i < kCache32Count; i++) { 446 int index = map->mapUnit16((i << 8) | i) >> 8; 447 mapped[i] = linear[index]; 448 mapped[i + kCache32Count] = linear[index + kCache32Count]; 449 } 450 fCache32PixelRef->unref(); 451 fCache32PixelRef = newPR; 452 fCache32 = (SkPMColor*)newPR->getAddr(); 453 } 454 } 455 return fCache32; 456 } 457 458 /* 459 * Because our caller might rebuild the same (logically the same) gradient 460 * over and over, we'd like to return exactly the same "bitmap" if possible, 461 * allowing the client to utilize a cache of our bitmap (e.g. with a GPU). 462 * To do that, we maintain a private cache of built-bitmaps, based on our 463 * colors and positions. Note: we don't try to flatten the fMapper, so if one 464 * is present, we skip the cache for now. 465 */ 466 void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const { 467 // our caller assumes no external alpha, so we ensure that our cache is 468 // built with 0xFF 469 this->setCacheAlpha(0xFF); 470 471 // don't have a way to put the mapper into our cache-key yet 472 if (fMapper) { 473 // force our cahce32pixelref to be built 474 (void)this->getCache32(); 475 bitmap->setConfig(SkBitmap::kARGB_8888_Config, kCache32Count, 1); 476 bitmap->setPixelRef(fCache32PixelRef); 477 return; 478 } 479 480 // build our key: [numColors + colors[] + {positions[]} ] 481 int count = 1 + fColorCount; 482 if (fColorCount > 2) { 483 count += fColorCount - 1; // fRecs[].fPos 484 } 485 486 SkAutoSTMalloc<16, int32_t> storage(count); 487 int32_t* buffer = storage.get(); 488 489 *buffer++ = fColorCount; 490 memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor)); 491 buffer += fColorCount; 492 if (fColorCount > 2) { 493 for (int i = 1; i < fColorCount; i++) { 494 *buffer++ = fRecs[i].fPos; 495 } 496 } 497 SkASSERT(buffer - storage.get() == count); 498 499 /////////////////////////////////// 500 501 SK_DECLARE_STATIC_MUTEX(gMutex); 502 static SkBitmapCache* gCache; 503 // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp 504 static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32; 505 SkAutoMutexAcquire ama(gMutex); 506 507 if (NULL == gCache) { 508 gCache = SkNEW_ARGS(SkBitmapCache, (MAX_NUM_CACHED_GRADIENT_BITMAPS)); 509 } 510 size_t size = count * sizeof(int32_t); 511 512 if (!gCache->find(storage.get(), size, bitmap)) { 513 // force our cahce32pixelref to be built 514 (void)this->getCache32(); 515 bitmap->setConfig(SkBitmap::kARGB_8888_Config, kCache32Count, 1); 516 bitmap->setPixelRef(fCache32PixelRef); 517 518 gCache->add(storage.get(), size, *bitmap); 519 } 520 } 521 522 void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const { 523 if (info) { 524 if (info->fColorCount >= fColorCount) { 525 if (info->fColors) { 526 memcpy(info->fColors, fOrigColors, fColorCount * sizeof(SkColor)); 527 } 528 if (info->fColorOffsets) { 529 if (fColorCount == 2) { 530 info->fColorOffsets[0] = 0; 531 info->fColorOffsets[1] = SK_Scalar1; 532 } else if (fColorCount > 2) { 533 for (int i = 0; i < fColorCount; ++i) { 534 info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos); 535 } 536 } 537 } 538 } 539 info->fColorCount = fColorCount; 540 info->fTileMode = fTileMode; 541 } 542 } 543 544 #ifdef SK_DEVELOPER 545 void SkGradientShaderBase::toString(SkString* str) const { 546 547 str->appendf("%d colors: ", fColorCount); 548 549 for (int i = 0; i < fColorCount; ++i) { 550 str->appendHex(fOrigColors[i]); 551 if (i < fColorCount-1) { 552 str->append(", "); 553 } 554 } 555 556 if (fColorCount > 2) { 557 str->append(" points: ("); 558 for (int i = 0; i < fColorCount; ++i) { 559 str->appendScalar(SkFixedToScalar(fRecs[i].fPos)); 560 if (i < fColorCount-1) { 561 str->append(", "); 562 } 563 } 564 str->append(")"); 565 } 566 567 static const char* gTileModeName[SkShader::kTileModeCount] = { 568 "clamp", "repeat", "mirror" 569 }; 570 571 str->append(" "); 572 str->append(gTileModeName[fTileMode]); 573 574 // TODO: add "fMapper->toString(str);" when SkUnitMapper::toString is added 575 576 this->INHERITED::toString(str); 577 } 578 #endif 579 580 /////////////////////////////////////////////////////////////////////////////// 581 /////////////////////////////////////////////////////////////////////////////// 582 583 #include "SkEmptyShader.h" 584 585 // assumes colors is SkColor* and pos is SkScalar* 586 #define EXPAND_1_COLOR(count) \ 587 SkColor tmp[2]; \ 588 do { \ 589 if (1 == count) { \ 590 tmp[0] = tmp[1] = colors[0]; \ 591 colors = tmp; \ 592 pos = NULL; \ 593 count = 2; \ 594 } \ 595 } while (0) 596 597 SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2], 598 const SkColor colors[], 599 const SkScalar pos[], int colorCount, 600 SkShader::TileMode mode, 601 SkUnitMapper* mapper) { 602 if (NULL == pts || NULL == colors || colorCount < 1) { 603 return NULL; 604 } 605 EXPAND_1_COLOR(colorCount); 606 607 return SkNEW_ARGS(SkLinearGradient, 608 (pts, colors, pos, colorCount, mode, mapper)); 609 } 610 611 SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius, 612 const SkColor colors[], 613 const SkScalar pos[], int colorCount, 614 SkShader::TileMode mode, 615 SkUnitMapper* mapper) { 616 if (radius <= 0 || NULL == colors || colorCount < 1) { 617 return NULL; 618 } 619 EXPAND_1_COLOR(colorCount); 620 621 return SkNEW_ARGS(SkRadialGradient, 622 (center, radius, colors, pos, colorCount, mode, mapper)); 623 } 624 625 SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start, 626 SkScalar startRadius, 627 const SkPoint& end, 628 SkScalar endRadius, 629 const SkColor colors[], 630 const SkScalar pos[], 631 int colorCount, 632 SkShader::TileMode mode, 633 SkUnitMapper* mapper) { 634 if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) { 635 return NULL; 636 } 637 EXPAND_1_COLOR(colorCount); 638 639 return SkNEW_ARGS(SkTwoPointRadialGradient, 640 (start, startRadius, end, endRadius, colors, pos, 641 colorCount, mode, mapper)); 642 } 643 644 SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start, 645 SkScalar startRadius, 646 const SkPoint& end, 647 SkScalar endRadius, 648 const SkColor colors[], 649 const SkScalar pos[], 650 int colorCount, 651 SkShader::TileMode mode, 652 SkUnitMapper* mapper) { 653 if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) { 654 return NULL; 655 } 656 if (start == end && startRadius == endRadius) { 657 return SkNEW(SkEmptyShader); 658 } 659 EXPAND_1_COLOR(colorCount); 660 661 return SkNEW_ARGS(SkTwoPointConicalGradient, 662 (start, startRadius, end, endRadius, colors, pos, 663 colorCount, mode, mapper)); 664 } 665 666 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy, 667 const SkColor colors[], 668 const SkScalar pos[], 669 int count, SkUnitMapper* mapper) { 670 if (NULL == colors || count < 1) { 671 return NULL; 672 } 673 EXPAND_1_COLOR(count); 674 675 return SkNEW_ARGS(SkSweepGradient, (cx, cy, colors, pos, count, mapper)); 676 } 677 678 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader) 679 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient) 680 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient) 681 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient) 682 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointRadialGradient) 683 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient) 684 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 685 686 /////////////////////////////////////////////////////////////////////////////// 687 688 #if SK_SUPPORT_GPU 689 690 #include "effects/GrTextureStripAtlas.h" 691 #include "SkGr.h" 692 693 GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory) 694 : INHERITED(factory) 695 , fCachedYCoord(SK_ScalarMax) 696 , fFSYUni(GrGLUniformManager::kInvalidUniformHandle) { 697 } 698 699 GrGLGradientEffect::~GrGLGradientEffect() { } 700 701 void GrGLGradientEffect::emitYCoordUniform(GrGLShaderBuilder* builder) { 702 fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, 703 kFloat_GrSLType, "GradientYCoordFS"); 704 } 705 706 void GrGLGradientEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) { 707 const GrGradientEffect& e = GetEffectFromStage<GrGradientEffect>(stage); 708 const GrTexture* texture = e.texture(0); 709 fEffectMatrix.setData(uman, e.getMatrix(), stage.getCoordChangeMatrix(), texture); 710 711 SkScalar yCoord = e.getYCoord(); 712 if (yCoord != fCachedYCoord) { 713 uman.set1f(fFSYUni, yCoord); 714 fCachedYCoord = yCoord; 715 } 716 } 717 718 GrGLEffect::EffectKey GrGLGradientEffect::GenMatrixKey(const GrEffectStage& s) { 719 const GrGradientEffect& e = GetEffectFromStage<GrGradientEffect>(s); 720 const GrTexture* texture = e.texture(0); 721 return GrGLEffectMatrix::GenKey(e.getMatrix(), s.getCoordChangeMatrix(), texture); 722 } 723 724 void GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder, 725 EffectKey key, 726 const char* vertexCoords, 727 const char** fsCoordName, 728 const char** vsVaryingName, 729 GrSLType* vsVaryingType) { 730 fEffectMatrix.emitCodeMakeFSCoords2D(builder, 731 key & kMatrixKeyMask, 732 vertexCoords, 733 fsCoordName, 734 vsVaryingName, 735 vsVaryingType); 736 } 737 738 void GrGLGradientEffect::emitColorLookup(GrGLShaderBuilder* builder, 739 const char* gradientTValue, 740 const char* outputColor, 741 const char* inputColor, 742 const GrGLShaderBuilder::TextureSampler& sampler) { 743 744 SkString* code = &builder->fFSCode; 745 code->appendf("\tvec2 coord = vec2(%s, %s);\n", 746 gradientTValue, 747 builder->getUniformVariable(fFSYUni).c_str()); 748 code->appendf("\t%s = ", outputColor); 749 builder->appendTextureLookupAndModulate(code, inputColor, sampler, "coord"); 750 code->append(";\n"); 751 } 752 753 ///////////////////////////////////////////////////////////////////// 754 755 GrGradientEffect::GrGradientEffect(GrContext* ctx, 756 const SkGradientShaderBase& shader, 757 const SkMatrix& matrix, 758 SkShader::TileMode tileMode) { 759 // TODO: check for simple cases where we don't need a texture: 760 //GradientInfo info; 761 //shader.asAGradient(&info); 762 //if (info.fColorCount == 2) { ... 763 764 fMatrix = matrix; 765 766 SkBitmap bitmap; 767 shader.getGradientTableBitmap(&bitmap); 768 769 fIsOpaque = shader.isOpaque(); 770 771 GrTextureStripAtlas::Desc desc; 772 desc.fWidth = bitmap.width(); 773 desc.fHeight = 32; 774 desc.fRowHeight = bitmap.height(); 775 desc.fContext = ctx; 776 desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config()); 777 fAtlas = GrTextureStripAtlas::GetAtlas(desc); 778 GrAssert(NULL != fAtlas); 779 780 // We always filter the gradient table. Each table is one row of a texture, so always y-clamp. 781 GrTextureParams params; 782 params.setBilerp(true); 783 params.setTileModeX(tileMode); 784 785 fRow = fAtlas->lockRow(bitmap); 786 if (-1 != fRow) { 787 fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf * 788 fAtlas->getVerticalScaleFactor(); 789 fTextureAccess.reset(fAtlas->getTexture(), params); 790 } else { 791 GrTexture* texture = GrLockAndRefCachedBitmapTexture(ctx, bitmap, ¶ms); 792 fTextureAccess.reset(texture, params); 793 fYCoord = SK_ScalarHalf; 794 795 // Unlock immediately, this is not great, but we don't have a way of 796 // knowing when else to unlock it currently, so it may get purged from 797 // the cache, but it'll still be ref'd until it's no longer being used. 798 GrUnlockAndUnrefCachedBitmapTexture(texture); 799 } 800 this->addTextureAccess(&fTextureAccess); 801 } 802 803 GrGradientEffect::~GrGradientEffect() { 804 if (this->useAtlas()) { 805 fAtlas->unlockRow(fRow); 806 } 807 } 808 809 bool GrGradientEffect::onIsEqual(const GrEffect& effect) const { 810 const GrGradientEffect& s = CastEffect<GrGradientEffect>(effect); 811 return fTextureAccess.getTexture() == s.fTextureAccess.getTexture() && 812 fTextureAccess.getParams().getTileModeX() == 813 s.fTextureAccess.getParams().getTileModeX() && 814 this->useAtlas() == s.useAtlas() && 815 fYCoord == s.getYCoord() && 816 fMatrix.cheapEqualTo(s.getMatrix()); 817 } 818 819 void GrGradientEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 820 if (fIsOpaque && (kA_ValidComponentFlag & *validFlags) && 0xff == GrColorUnpackA(*color)) { 821 *validFlags = kA_ValidComponentFlag; 822 } else { 823 *validFlags = 0; 824 } 825 } 826 827 int GrGradientEffect::RandomGradientParams(SkRandom* random, 828 SkColor colors[], 829 SkScalar** stops, 830 SkShader::TileMode* tm) { 831 int outColors = random->nextRangeU(1, kMaxRandomGradientColors); 832 833 // if one color, omit stops, otherwise randomly decide whether or not to 834 if (outColors == 1 || (outColors >= 2 && random->nextBool())) { 835 *stops = NULL; 836 } 837 838 SkScalar stop = 0.f; 839 for (int i = 0; i < outColors; ++i) { 840 colors[i] = random->nextU(); 841 if (NULL != *stops) { 842 (*stops)[i] = stop; 843 stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f; 844 } 845 } 846 *tm = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount)); 847 848 return outColors; 849 } 850 851 #endif 852