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