SkBitmap.cpp revision 5b5bba36dcbc69b0033c2acc9981734956394816
1 2/* 3 * Copyright 2008 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#include "SkBitmap.h" 11#include "SkColorPriv.h" 12#include "SkDither.h" 13#include "SkFlattenable.h" 14#include "SkMallocPixelRef.h" 15#include "SkMask.h" 16#include "SkOrderedReadBuffer.h" 17#include "SkOrderedWriteBuffer.h" 18#include "SkPixelRef.h" 19#include "SkThread.h" 20#include "SkUnPreMultiply.h" 21#include "SkUtils.h" 22#include "SkPackBits.h" 23#include <new> 24 25SK_DEFINE_INST_COUNT(SkBitmap::Allocator) 26 27static bool isPos32Bits(const Sk64& value) { 28 return !value.isNeg() && value.is32(); 29} 30 31struct MipLevel { 32 void* fPixels; 33 uint32_t fRowBytes; 34 uint32_t fWidth, fHeight; 35}; 36 37struct SkBitmap::MipMap : SkNoncopyable { 38 int32_t fRefCnt; 39 int fLevelCount; 40// MipLevel fLevel[fLevelCount]; 41// Pixels[] 42 43 static MipMap* Alloc(int levelCount, size_t pixelSize) { 44 if (levelCount < 0) { 45 return NULL; 46 } 47 Sk64 size; 48 size.setMul(levelCount + 1, sizeof(MipLevel)); 49 size.add(sizeof(MipMap)); 50 size.add(pixelSize); 51 if (!isPos32Bits(size)) { 52 return NULL; 53 } 54 MipMap* mm = (MipMap*)sk_malloc_throw(size.get32()); 55 mm->fRefCnt = 1; 56 mm->fLevelCount = levelCount; 57 return mm; 58 } 59 60 const MipLevel* levels() const { return (const MipLevel*)(this + 1); } 61 MipLevel* levels() { return (MipLevel*)(this + 1); } 62 63 const void* pixels() const { return levels() + fLevelCount; } 64 void* pixels() { return levels() + fLevelCount; } 65 66 void ref() { 67 if (SK_MaxS32 == sk_atomic_inc(&fRefCnt)) { 68 sk_throw(); 69 } 70 } 71 void unref() { 72 SkASSERT(fRefCnt > 0); 73 if (sk_atomic_dec(&fRefCnt) == 1) { 74 sk_free(this); 75 } 76 } 77}; 78 79/////////////////////////////////////////////////////////////////////////////// 80/////////////////////////////////////////////////////////////////////////////// 81 82SkBitmap::SkBitmap() { 83 sk_bzero(this, sizeof(*this)); 84} 85 86SkBitmap::SkBitmap(const SkBitmap& src) { 87 SkDEBUGCODE(src.validate();) 88 sk_bzero(this, sizeof(*this)); 89 *this = src; 90 SkDEBUGCODE(this->validate();) 91} 92 93SkBitmap::~SkBitmap() { 94 SkDEBUGCODE(this->validate();) 95 this->freePixels(); 96} 97 98SkBitmap& SkBitmap::operator=(const SkBitmap& src) { 99 if (this != &src) { 100 this->freePixels(); 101 memcpy(this, &src, sizeof(src)); 102 103 // inc src reference counts 104 SkSafeRef(src.fPixelRef); 105 SkSafeRef(src.fMipMap); 106 107 // we reset our locks if we get blown away 108 fPixelLockCount = 0; 109 110 /* The src could be in 3 states 111 1. no pixelref, in which case we just copy/ref the pixels/ctable 112 2. unlocked pixelref, pixels/ctable should be null 113 3. locked pixelref, we should lock the ref again ourselves 114 */ 115 if (NULL == fPixelRef) { 116 // leave fPixels as it is 117 SkSafeRef(fColorTable); // ref the user's ctable if present 118 } else { // we have a pixelref, so pixels/ctable reflect it 119 // ignore the values from the memcpy 120 fPixels = NULL; 121 fColorTable = NULL; 122 // Note that what to for genID is somewhat arbitrary. We have no 123 // way to track changes to raw pixels across multiple SkBitmaps. 124 // Would benefit from an SkRawPixelRef type created by 125 // setPixels. 126 // Just leave the memcpy'ed one but they'll get out of sync 127 // as soon either is modified. 128 } 129 } 130 131 SkDEBUGCODE(this->validate();) 132 return *this; 133} 134 135void SkBitmap::swap(SkBitmap& other) { 136 SkTSwap(fColorTable, other.fColorTable); 137 SkTSwap(fPixelRef, other.fPixelRef); 138 SkTSwap(fPixelRefOffset, other.fPixelRefOffset); 139 SkTSwap(fPixelLockCount, other.fPixelLockCount); 140 SkTSwap(fMipMap, other.fMipMap); 141 SkTSwap(fPixels, other.fPixels); 142 SkTSwap(fRowBytes, other.fRowBytes); 143 SkTSwap(fWidth, other.fWidth); 144 SkTSwap(fHeight, other.fHeight); 145 SkTSwap(fConfig, other.fConfig); 146 SkTSwap(fFlags, other.fFlags); 147 SkTSwap(fBytesPerPixel, other.fBytesPerPixel); 148 149 SkDEBUGCODE(this->validate();) 150} 151 152void SkBitmap::reset() { 153 this->freePixels(); 154 sk_bzero(this, sizeof(*this)); 155} 156 157int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) { 158 int bpp; 159 switch (config) { 160 case kNo_Config: 161 case kA1_Config: 162 bpp = 0; // not applicable 163 break; 164 case kRLE_Index8_Config: 165 case kA8_Config: 166 case kIndex8_Config: 167 bpp = 1; 168 break; 169 case kRGB_565_Config: 170 case kARGB_4444_Config: 171 bpp = 2; 172 break; 173 case kARGB_8888_Config: 174 bpp = 4; 175 break; 176 default: 177 SkDEBUGFAIL("unknown config"); 178 bpp = 0; // error 179 break; 180 } 181 return bpp; 182} 183 184int SkBitmap::ComputeRowBytes(Config c, int width) { 185 if (width < 0) { 186 return 0; 187 } 188 189 Sk64 rowBytes; 190 rowBytes.setZero(); 191 192 switch (c) { 193 case kNo_Config: 194 case kRLE_Index8_Config: 195 break; 196 case kA1_Config: 197 rowBytes.set(width); 198 rowBytes.add(7); 199 rowBytes.shiftRight(3); 200 break; 201 case kA8_Config: 202 case kIndex8_Config: 203 rowBytes.set(width); 204 break; 205 case kRGB_565_Config: 206 case kARGB_4444_Config: 207 rowBytes.set(width); 208 rowBytes.shiftLeft(1); 209 break; 210 case kARGB_8888_Config: 211 rowBytes.set(width); 212 rowBytes.shiftLeft(2); 213 break; 214 default: 215 SkDEBUGFAIL("unknown config"); 216 break; 217 } 218 return isPos32Bits(rowBytes) ? rowBytes.get32() : 0; 219} 220 221Sk64 SkBitmap::ComputeSize64(Config c, int width, int height) { 222 Sk64 size; 223 size.setMul(SkBitmap::ComputeRowBytes(c, width), height); 224 return size; 225} 226 227size_t SkBitmap::ComputeSize(Config c, int width, int height) { 228 Sk64 size = SkBitmap::ComputeSize64(c, width, height); 229 return isPos32Bits(size) ? size.get32() : 0; 230} 231 232Sk64 SkBitmap::ComputeSafeSize64(Config config, 233 uint32_t width, 234 uint32_t height, 235 uint32_t rowBytes) { 236 Sk64 safeSize; 237 safeSize.setZero(); 238 if (height > 0) { 239 safeSize.set(ComputeRowBytes(config, width)); 240 Sk64 sizeAllButLastRow; 241 sizeAllButLastRow.setMul(height - 1, rowBytes); 242 safeSize.add(sizeAllButLastRow); 243 } 244 SkASSERT(!safeSize.isNeg()); 245 return safeSize; 246} 247 248size_t SkBitmap::ComputeSafeSize(Config config, 249 uint32_t width, 250 uint32_t height, 251 uint32_t rowBytes) { 252 Sk64 safeSize = ComputeSafeSize64(config, width, height, rowBytes); 253 return (safeSize.is32() ? safeSize.get32() : 0); 254} 255 256void SkBitmap::getBounds(SkRect* bounds) const { 257 SkASSERT(bounds); 258 bounds->set(0, 0, 259 SkIntToScalar(fWidth), SkIntToScalar(fHeight)); 260} 261 262void SkBitmap::getBounds(SkIRect* bounds) const { 263 SkASSERT(bounds); 264 bounds->set(0, 0, fWidth, fHeight); 265} 266 267/////////////////////////////////////////////////////////////////////////////// 268 269void SkBitmap::setConfig(Config c, int width, int height, int rowBytes) { 270 this->freePixels(); 271 272 if ((width | height | rowBytes) < 0) { 273 goto err; 274 } 275 276 if (rowBytes == 0) { 277 rowBytes = SkBitmap::ComputeRowBytes(c, width); 278 if (0 == rowBytes && kNo_Config != c) { 279 goto err; 280 } 281 } 282 283 fConfig = SkToU8(c); 284 fWidth = width; 285 fHeight = height; 286 fRowBytes = rowBytes; 287 288 fBytesPerPixel = (uint8_t)ComputeBytesPerPixel(c); 289 290 SkDEBUGCODE(this->validate();) 291 return; 292 293 // if we got here, we had an error, so we reset the bitmap to empty 294err: 295 this->reset(); 296} 297 298void SkBitmap::updatePixelsFromRef() const { 299 if (NULL != fPixelRef) { 300 if (fPixelLockCount > 0) { 301 SkASSERT(fPixelRef->isLocked()); 302 303 void* p = fPixelRef->pixels(); 304 if (NULL != p) { 305 p = (char*)p + fPixelRefOffset; 306 } 307 fPixels = p; 308 SkRefCnt_SafeAssign(fColorTable, fPixelRef->colorTable()); 309 } else { 310 SkASSERT(0 == fPixelLockCount); 311 fPixels = NULL; 312 if (fColorTable) { 313 fColorTable->unref(); 314 fColorTable = NULL; 315 } 316 } 317 } 318} 319 320SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, size_t offset) { 321 // do this first, we that we never have a non-zero offset with a null ref 322 if (NULL == pr) { 323 offset = 0; 324 } 325 326 if (fPixelRef != pr || fPixelRefOffset != offset) { 327 if (fPixelRef != pr) { 328 this->freePixels(); 329 SkASSERT(NULL == fPixelRef); 330 331 SkSafeRef(pr); 332 fPixelRef = pr; 333 } 334 fPixelRefOffset = offset; 335 this->updatePixelsFromRef(); 336 } 337 338 SkDEBUGCODE(this->validate();) 339 return pr; 340} 341 342void SkBitmap::lockPixels() const { 343 if (NULL != fPixelRef && 1 == ++fPixelLockCount) { 344 fPixelRef->lockPixels(); 345 this->updatePixelsFromRef(); 346 } 347 SkDEBUGCODE(this->validate();) 348} 349 350void SkBitmap::unlockPixels() const { 351 SkASSERT(NULL == fPixelRef || fPixelLockCount > 0); 352 353 if (NULL != fPixelRef && 0 == --fPixelLockCount) { 354 fPixelRef->unlockPixels(); 355 this->updatePixelsFromRef(); 356 } 357 SkDEBUGCODE(this->validate();) 358} 359 360bool SkBitmap::lockPixelsAreWritable() const { 361 return (fPixelRef) ? fPixelRef->lockPixelsAreWritable() : false; 362} 363 364void SkBitmap::setPixels(void* p, SkColorTable* ctable) { 365 if (NULL == p) { 366 this->setPixelRef(NULL, 0); 367 return; 368 } 369 370 Sk64 size = this->getSize64(); 371 SkASSERT(!size.isNeg() && size.is32()); 372 373 this->setPixelRef(new SkMallocPixelRef(p, size.get32(), ctable, false))->unref(); 374 // since we're already allocated, we lockPixels right away 375 this->lockPixels(); 376 SkDEBUGCODE(this->validate();) 377} 378 379bool SkBitmap::allocPixels(Allocator* allocator, SkColorTable* ctable) { 380 HeapAllocator stdalloc; 381 382 if (NULL == allocator) { 383 allocator = &stdalloc; 384 } 385 return allocator->allocPixelRef(this, ctable); 386} 387 388void SkBitmap::freePixels() { 389 // if we're gonna free the pixels, we certainly need to free the mipmap 390 this->freeMipMap(); 391 392 if (fColorTable) { 393 fColorTable->unref(); 394 fColorTable = NULL; 395 } 396 397 if (NULL != fPixelRef) { 398 if (fPixelLockCount > 0) { 399 fPixelRef->unlockPixels(); 400 } 401 fPixelRef->unref(); 402 fPixelRef = NULL; 403 fPixelRefOffset = 0; 404 } 405 fPixelLockCount = 0; 406 fPixels = NULL; 407} 408 409void SkBitmap::freeMipMap() { 410 if (fMipMap) { 411 fMipMap->unref(); 412 fMipMap = NULL; 413 } 414} 415 416uint32_t SkBitmap::getGenerationID() const { 417 return (fPixelRef) ? fPixelRef->getGenerationID() : 0; 418} 419 420void SkBitmap::notifyPixelsChanged() const { 421 SkASSERT(!this->isImmutable()); 422 if (fPixelRef) { 423 fPixelRef->notifyPixelsChanged(); 424 } 425} 426 427SkGpuTexture* SkBitmap::getTexture() const { 428 return fPixelRef ? fPixelRef->getTexture() : NULL; 429} 430 431/////////////////////////////////////////////////////////////////////////////// 432 433/** We explicitly use the same allocator for our pixels that SkMask does, 434 so that we can freely assign memory allocated by one class to the other. 435 */ 436bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst, 437 SkColorTable* ctable) { 438 Sk64 size = dst->getSize64(); 439 if (size.isNeg() || !size.is32()) { 440 return false; 441 } 442 443 void* addr = sk_malloc_flags(size.get32(), 0); // returns NULL on failure 444 if (NULL == addr) { 445 return false; 446 } 447 448 dst->setPixelRef(new SkMallocPixelRef(addr, size.get32(), ctable))->unref(); 449 // since we're already allocated, we lockPixels right away 450 dst->lockPixels(); 451 return true; 452} 453 454/////////////////////////////////////////////////////////////////////////////// 455 456size_t SkBitmap::getSafeSize() const { 457 // This is intended to be a size_t version of ComputeSafeSize64(), just 458 // faster. The computation is meant to be identical. 459 return (fHeight ? ((fHeight - 1) * fRowBytes) + 460 ComputeRowBytes(getConfig(), fWidth): 0); 461} 462 463Sk64 SkBitmap::getSafeSize64() const { 464 return ComputeSafeSize64(getConfig(), fWidth, fHeight, fRowBytes); 465} 466 467bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize, 468 int dstRowBytes, bool preserveDstPad) const { 469 470 if (dstRowBytes == -1) 471 dstRowBytes = fRowBytes; 472 SkASSERT(dstRowBytes >= 0); 473 474 if (getConfig() == kRLE_Index8_Config || 475 dstRowBytes < ComputeRowBytes(getConfig(), fWidth) || 476 dst == NULL || (getPixels() == NULL && pixelRef() == NULL)) 477 return false; 478 479 if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == fRowBytes) { 480 size_t safeSize = getSafeSize(); 481 if (safeSize > dstSize || safeSize == 0) 482 return false; 483 else { 484 SkAutoLockPixels lock(*this); 485 // This implementation will write bytes beyond the end of each row, 486 // excluding the last row, if the bitmap's stride is greater than 487 // strictly required by the current config. 488 memcpy(dst, getPixels(), safeSize); 489 490 return true; 491 } 492 } else { 493 // If destination has different stride than us, then copy line by line. 494 if (ComputeSafeSize(getConfig(), fWidth, fHeight, dstRowBytes) > 495 dstSize) 496 return false; 497 else { 498 // Just copy what we need on each line. 499 uint32_t rowBytes = ComputeRowBytes(getConfig(), fWidth); 500 SkAutoLockPixels lock(*this); 501 const uint8_t* srcP = reinterpret_cast<const uint8_t*>(getPixels()); 502 uint8_t* dstP = reinterpret_cast<uint8_t*>(dst); 503 for (uint32_t row = 0; row < fHeight; 504 row++, srcP += fRowBytes, dstP += dstRowBytes) { 505 memcpy(dstP, srcP, rowBytes); 506 } 507 508 return true; 509 } 510 } 511} 512 513/////////////////////////////////////////////////////////////////////////////// 514 515bool SkBitmap::isImmutable() const { 516 return fPixelRef ? fPixelRef->isImmutable() : 517 fFlags & kImageIsImmutable_Flag; 518} 519 520void SkBitmap::setImmutable() { 521 if (fPixelRef) { 522 fPixelRef->setImmutable(); 523 } else { 524 fFlags |= kImageIsImmutable_Flag; 525 } 526} 527 528bool SkBitmap::isOpaque() const { 529 switch (fConfig) { 530 case kNo_Config: 531 return true; 532 533 case kA1_Config: 534 case kA8_Config: 535 case kARGB_4444_Config: 536 case kARGB_8888_Config: 537 return (fFlags & kImageIsOpaque_Flag) != 0; 538 539 case kIndex8_Config: 540 case kRLE_Index8_Config: { 541 uint32_t flags = 0; 542 543 this->lockPixels(); 544 // if lockPixels failed, we may not have a ctable ptr 545 if (fColorTable) { 546 flags = fColorTable->getFlags(); 547 } 548 this->unlockPixels(); 549 550 return (flags & SkColorTable::kColorsAreOpaque_Flag) != 0; 551 } 552 553 case kRGB_565_Config: 554 return true; 555 556 default: 557 SkDEBUGFAIL("unknown bitmap config pased to isOpaque"); 558 return false; 559 } 560} 561 562void SkBitmap::setIsOpaque(bool isOpaque) { 563 /* we record this regardless of fConfig, though it is ignored in 564 isOpaque() for configs that can't support per-pixel alpha. 565 */ 566 if (isOpaque) { 567 fFlags |= kImageIsOpaque_Flag; 568 } else { 569 fFlags &= ~kImageIsOpaque_Flag; 570 } 571} 572 573bool SkBitmap::isVolatile() const { 574 return (fFlags & kImageIsVolatile_Flag) != 0; 575} 576 577void SkBitmap::setIsVolatile(bool isVolatile) { 578 if (isVolatile) { 579 fFlags |= kImageIsVolatile_Flag; 580 } else { 581 fFlags &= ~kImageIsVolatile_Flag; 582 } 583} 584 585void* SkBitmap::getAddr(int x, int y) const { 586 SkASSERT((unsigned)x < (unsigned)this->width()); 587 SkASSERT((unsigned)y < (unsigned)this->height()); 588 589 char* base = (char*)this->getPixels(); 590 if (base) { 591 base += y * this->rowBytes(); 592 switch (this->config()) { 593 case SkBitmap::kARGB_8888_Config: 594 base += x << 2; 595 break; 596 case SkBitmap::kARGB_4444_Config: 597 case SkBitmap::kRGB_565_Config: 598 base += x << 1; 599 break; 600 case SkBitmap::kA8_Config: 601 case SkBitmap::kIndex8_Config: 602 base += x; 603 break; 604 case SkBitmap::kA1_Config: 605 base += x >> 3; 606 break; 607 case kRLE_Index8_Config: 608 SkDEBUGFAIL("Can't return addr for kRLE_Index8_Config"); 609 base = NULL; 610 break; 611 default: 612 SkDEBUGFAIL("Can't return addr for config"); 613 base = NULL; 614 break; 615 } 616 } 617 return base; 618} 619 620SkColor SkBitmap::getColor(int x, int y) const { 621 SkASSERT((unsigned)x < (unsigned)this->width()); 622 SkASSERT((unsigned)y < (unsigned)this->height()); 623 624 switch (this->config()) { 625 case SkBitmap::kA1_Config: { 626 uint8_t* addr = this->getAddr1(x, y); 627 uint8_t mask = 1 << (7 - (x % 8)); 628 if (addr[0] & mask) { 629 return SK_ColorBLACK; 630 } else { 631 return 0; 632 } 633 } 634 case SkBitmap::kA8_Config: { 635 uint8_t* addr = this->getAddr8(x, y); 636 return SkColorSetA(0, addr[0]); 637 } 638 case SkBitmap::kIndex8_Config: { 639 SkPMColor c = this->getIndex8Color(x, y); 640 return SkUnPreMultiply::PMColorToColor(c); 641 } 642 case SkBitmap::kRGB_565_Config: { 643 uint16_t* addr = this->getAddr16(x, y); 644 return SkPixel16ToColor(addr[0]); 645 } 646 case SkBitmap::kARGB_4444_Config: { 647 uint16_t* addr = this->getAddr16(x, y); 648 SkPMColor c = SkPixel4444ToPixel32(addr[0]); 649 return SkUnPreMultiply::PMColorToColor(c); 650 } 651 case SkBitmap::kARGB_8888_Config: { 652 uint32_t* addr = this->getAddr32(x, y); 653 return SkUnPreMultiply::PMColorToColor(addr[0]); 654 } 655 case kRLE_Index8_Config: { 656 uint8_t dst; 657 const SkBitmap::RLEPixels* rle = 658 (const SkBitmap::RLEPixels*)this->getPixels(); 659 SkPackBits::Unpack8(&dst, x, 1, rle->packedAtY(y)); 660 return SkUnPreMultiply::PMColorToColor((*fColorTable)[dst]); 661 } 662 case kNo_Config: 663 case kConfigCount: 664 SkASSERT(false); 665 return 0; 666 } 667 SkASSERT(false); // Not reached. 668 return 0; 669} 670 671/////////////////////////////////////////////////////////////////////////////// 672/////////////////////////////////////////////////////////////////////////////// 673 674void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { 675 SkDEBUGCODE(this->validate();) 676 677 if (0 == fWidth || 0 == fHeight || 678 kNo_Config == fConfig || kIndex8_Config == fConfig) { 679 return; 680 } 681 682 SkAutoLockPixels alp(*this); 683 // perform this check after the lock call 684 if (!this->readyToDraw()) { 685 return; 686 } 687 688 int height = fHeight; 689 const int width = fWidth; 690 const int rowBytes = fRowBytes; 691 692 // make rgb premultiplied 693 if (255 != a) { 694 r = SkAlphaMul(r, a); 695 g = SkAlphaMul(g, a); 696 b = SkAlphaMul(b, a); 697 } 698 699 switch (fConfig) { 700 case kA1_Config: { 701 uint8_t* p = (uint8_t*)fPixels; 702 const int count = (width + 7) >> 3; 703 a = (a >> 7) ? 0xFF : 0; 704 SkASSERT(count <= rowBytes); 705 while (--height >= 0) { 706 memset(p, a, count); 707 p += rowBytes; 708 } 709 break; 710 } 711 case kA8_Config: { 712 uint8_t* p = (uint8_t*)fPixels; 713 while (--height >= 0) { 714 memset(p, a, width); 715 p += rowBytes; 716 } 717 break; 718 } 719 case kARGB_4444_Config: 720 case kRGB_565_Config: { 721 uint16_t* p = (uint16_t*)fPixels; 722 uint16_t v; 723 724 if (kARGB_4444_Config == fConfig) { 725 v = SkPackARGB4444(a >> 4, r >> 4, g >> 4, b >> 4); 726 } else { // kRGB_565_Config 727 v = SkPackRGB16(r >> (8 - SK_R16_BITS), g >> (8 - SK_G16_BITS), 728 b >> (8 - SK_B16_BITS)); 729 } 730 while (--height >= 0) { 731 sk_memset16(p, v, width); 732 p = (uint16_t*)((char*)p + rowBytes); 733 } 734 break; 735 } 736 case kARGB_8888_Config: { 737 uint32_t* p = (uint32_t*)fPixels; 738 uint32_t v = SkPackARGB32(a, r, g, b); 739 740 while (--height >= 0) { 741 sk_memset32(p, v, width); 742 p = (uint32_t*)((char*)p + rowBytes); 743 } 744 break; 745 } 746 } 747 748 this->notifyPixelsChanged(); 749} 750 751////////////////////////////////////////////////////////////////////////////////////// 752////////////////////////////////////////////////////////////////////////////////////// 753 754#define SUB_OFFSET_FAILURE ((size_t)-1) 755 756static size_t getSubOffset(const SkBitmap& bm, int x, int y) { 757 SkASSERT((unsigned)x < (unsigned)bm.width()); 758 SkASSERT((unsigned)y < (unsigned)bm.height()); 759 760 switch (bm.getConfig()) { 761 case SkBitmap::kA8_Config: 762 case SkBitmap:: kIndex8_Config: 763 // x is fine as is for the calculation 764 break; 765 766 case SkBitmap::kRGB_565_Config: 767 case SkBitmap::kARGB_4444_Config: 768 x <<= 1; 769 break; 770 771 case SkBitmap::kARGB_8888_Config: 772 x <<= 2; 773 break; 774 775 case SkBitmap::kNo_Config: 776 case SkBitmap::kA1_Config: 777 default: 778 return SUB_OFFSET_FAILURE; 779 } 780 return y * bm.rowBytes() + x; 781} 782 783bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { 784 SkDEBUGCODE(this->validate();) 785 786 if (NULL == result || NULL == fPixelRef) { 787 return false; // no src pixels 788 } 789 790 SkIRect srcRect, r; 791 srcRect.set(0, 0, this->width(), this->height()); 792 if (!r.intersect(srcRect, subset)) { 793 return false; // r is empty (i.e. no intersection) 794 } 795 796 if (kRLE_Index8_Config == fConfig) { 797 SkAutoLockPixels alp(*this); 798 // don't call readyToDraw(), since we can operate w/o a colortable 799 // at this stage 800 if (this->getPixels() == NULL) { 801 return false; 802 } 803 SkBitmap bm; 804 805 bm.setConfig(kIndex8_Config, r.width(), r.height()); 806 bm.allocPixels(this->getColorTable()); 807 if (NULL == bm.getPixels()) { 808 return false; 809 } 810 811 const RLEPixels* rle = (const RLEPixels*)this->getPixels(); 812 uint8_t* dst = bm.getAddr8(0, 0); 813 const int width = bm.width(); 814 const int rowBytes = bm.rowBytes(); 815 816 for (int y = r.fTop; y < r.fBottom; y++) { 817 SkPackBits::Unpack8(dst, r.fLeft, width, rle->packedAtY(y)); 818 dst += rowBytes; 819 } 820 result->swap(bm); 821 return true; 822 } 823 824 size_t offset = getSubOffset(*this, r.fLeft, r.fTop); 825 if (SUB_OFFSET_FAILURE == offset) { 826 return false; // config not supported 827 } 828 829 SkBitmap dst; 830 dst.setConfig(this->config(), r.width(), r.height(), this->rowBytes()); 831 dst.setIsVolatile(this->isVolatile()); 832 833 if (fPixelRef) { 834 // share the pixelref with a custom offset 835 dst.setPixelRef(fPixelRef, fPixelRefOffset + offset); 836 } 837 SkDEBUGCODE(dst.validate();) 838 839 // we know we're good, so commit to result 840 result->swap(dst); 841 return true; 842} 843 844/////////////////////////////////////////////////////////////////////////////// 845 846#include "SkCanvas.h" 847#include "SkPaint.h" 848 849bool SkBitmap::canCopyTo(Config dstConfig) const { 850 if (this->getConfig() == kNo_Config) { 851 return false; 852 } 853 854 bool sameConfigs = (this->config() == dstConfig); 855 switch (dstConfig) { 856 case kA8_Config: 857 case kARGB_4444_Config: 858 case kRGB_565_Config: 859 case kARGB_8888_Config: 860 break; 861 case kA1_Config: 862 case kIndex8_Config: 863 if (!sameConfigs) { 864 return false; 865 } 866 break; 867 default: 868 return false; 869 } 870 871 // do not copy src if srcConfig == kA1_Config while dstConfig != kA1_Config 872 if (this->getConfig() == kA1_Config && !sameConfigs) { 873 return false; 874 } 875 876 return true; 877} 878 879bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const { 880 if (!this->canCopyTo(dstConfig)) { 881 return false; 882 } 883 884 // if we have a texture, first get those pixels 885 SkBitmap tmpSrc; 886 const SkBitmap* src = this; 887 888 if (fPixelRef && fPixelRef->readPixels(&tmpSrc)) { 889 SkASSERT(tmpSrc.width() == this->width()); 890 SkASSERT(tmpSrc.height() == this->height()); 891 892 // did we get lucky and we can just return tmpSrc? 893 if (tmpSrc.config() == dstConfig && NULL == alloc) { 894 dst->swap(tmpSrc); 895 if (dst->pixelRef()) { 896 dst->pixelRef()->fGenerationID = fPixelRef->getGenerationID(); 897 } 898 return true; 899 } 900 901 // fall through to the raster case 902 src = &tmpSrc; 903 } 904 905 // we lock this now, since we may need its colortable 906 SkAutoLockPixels srclock(*src); 907 if (!src->readyToDraw()) { 908 return false; 909 } 910 911 SkBitmap tmpDst; 912 tmpDst.setConfig(dstConfig, src->width(), src->height()); 913 914 // allocate colortable if srcConfig == kIndex8_Config 915 SkColorTable* ctable = (dstConfig == kIndex8_Config) ? 916 new SkColorTable(*src->getColorTable()) : NULL; 917 SkAutoUnref au(ctable); 918 if (!tmpDst.allocPixels(alloc, ctable)) { 919 return false; 920 } 921 922 if (!tmpDst.readyToDraw()) { 923 // allocator/lock failed 924 return false; 925 } 926 927 /* do memcpy for the same configs cases, else use drawing 928 */ 929 if (src->config() == dstConfig) { 930 if (tmpDst.getSize() == src->getSize()) { 931 memcpy(tmpDst.getPixels(), src->getPixels(), src->getSafeSize()); 932 SkPixelRef* pixelRef = tmpDst.pixelRef(); 933 if (pixelRef != NULL) { 934 pixelRef->fGenerationID = this->getGenerationID(); 935 } 936 } else { 937 const char* srcP = reinterpret_cast<const char*>(src->getPixels()); 938 char* dstP = reinterpret_cast<char*>(tmpDst.getPixels()); 939 // to be sure we don't read too much, only copy our logical pixels 940 size_t bytesToCopy = tmpDst.width() * tmpDst.bytesPerPixel(); 941 for (int y = 0; y < tmpDst.height(); y++) { 942 memcpy(dstP, srcP, bytesToCopy); 943 srcP += src->rowBytes(); 944 dstP += tmpDst.rowBytes(); 945 } 946 } 947 } else { 948 // if the src has alpha, we have to clear the dst first 949 if (!src->isOpaque()) { 950 tmpDst.eraseColor(0); 951 } 952 953 SkCanvas canvas(tmpDst); 954 SkPaint paint; 955 956 paint.setDither(true); 957 canvas.drawBitmap(*src, 0, 0, &paint); 958 } 959 960 tmpDst.setIsOpaque(src->isOpaque()); 961 962 dst->swap(tmpDst); 963 return true; 964} 965 966bool SkBitmap::deepCopyTo(SkBitmap* dst, Config dstConfig) const { 967 if (!this->canCopyTo(dstConfig)) { 968 return false; 969 } 970 971 // If we have a PixelRef, and it supports deep copy, use it. 972 // Currently supported only by texture-backed bitmaps. 973 if (fPixelRef) { 974 SkPixelRef* pixelRef = fPixelRef->deepCopy(dstConfig); 975 if (pixelRef) { 976 if (dstConfig == fConfig) { 977 pixelRef->fGenerationID = fPixelRef->getGenerationID(); 978 } 979 dst->setConfig(dstConfig, fWidth, fHeight); 980 dst->setPixelRef(pixelRef)->unref(); 981 return true; 982 } 983 } 984 985 if (this->getTexture()) { 986 return false; 987 } else { 988 return this->copyTo(dst, dstConfig, NULL); 989 } 990} 991 992/////////////////////////////////////////////////////////////////////////////// 993/////////////////////////////////////////////////////////////////////////////// 994 995static void downsampleby2_proc32(SkBitmap* dst, int x, int y, 996 const SkBitmap& src) { 997 x <<= 1; 998 y <<= 1; 999 const SkPMColor* p = src.getAddr32(x, y); 1000 const SkPMColor* baseP = p; 1001 SkPMColor c, ag, rb; 1002 1003 c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; 1004 if (x < src.width() - 1) { 1005 p += 1; 1006 } 1007 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; 1008 1009 p = baseP; 1010 if (y < src.height() - 1) { 1011 p += src.rowBytes() >> 2; 1012 } 1013 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; 1014 if (x < src.width() - 1) { 1015 p += 1; 1016 } 1017 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; 1018 1019 *dst->getAddr32(x >> 1, y >> 1) = 1020 ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00); 1021} 1022 1023static inline uint32_t expand16(U16CPU c) { 1024 return (c & ~SK_G16_MASK_IN_PLACE) | ((c & SK_G16_MASK_IN_PLACE) << 16); 1025} 1026 1027// returns dirt in the top 16bits, but we don't care, since we only 1028// store the low 16bits. 1029static inline U16CPU pack16(uint32_t c) { 1030 return (c & ~SK_G16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE); 1031} 1032 1033static void downsampleby2_proc16(SkBitmap* dst, int x, int y, 1034 const SkBitmap& src) { 1035 x <<= 1; 1036 y <<= 1; 1037 const uint16_t* p = src.getAddr16(x, y); 1038 const uint16_t* baseP = p; 1039 SkPMColor c; 1040 1041 c = expand16(*p); 1042 if (x < src.width() - 1) { 1043 p += 1; 1044 } 1045 c += expand16(*p); 1046 1047 p = baseP; 1048 if (y < src.height() - 1) { 1049 p += src.rowBytes() >> 1; 1050 } 1051 c += expand16(*p); 1052 if (x < src.width() - 1) { 1053 p += 1; 1054 } 1055 c += expand16(*p); 1056 1057 *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)pack16(c >> 2); 1058} 1059 1060static uint32_t expand4444(U16CPU c) { 1061 return (c & 0xF0F) | ((c & ~0xF0F) << 12); 1062} 1063 1064static U16CPU collaps4444(uint32_t c) { 1065 return (c & 0xF0F) | ((c >> 12) & ~0xF0F); 1066} 1067 1068static void downsampleby2_proc4444(SkBitmap* dst, int x, int y, 1069 const SkBitmap& src) { 1070 x <<= 1; 1071 y <<= 1; 1072 const uint16_t* p = src.getAddr16(x, y); 1073 const uint16_t* baseP = p; 1074 uint32_t c; 1075 1076 c = expand4444(*p); 1077 if (x < src.width() - 1) { 1078 p += 1; 1079 } 1080 c += expand4444(*p); 1081 1082 p = baseP; 1083 if (y < src.height() - 1) { 1084 p += src.rowBytes() >> 1; 1085 } 1086 c += expand4444(*p); 1087 if (x < src.width() - 1) { 1088 p += 1; 1089 } 1090 c += expand4444(*p); 1091 1092 *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)collaps4444(c >> 2); 1093} 1094 1095void SkBitmap::buildMipMap(bool forceRebuild) { 1096 if (forceRebuild) 1097 this->freeMipMap(); 1098 else if (fMipMap) 1099 return; // we're already built 1100 1101 SkASSERT(NULL == fMipMap); 1102 1103 void (*proc)(SkBitmap* dst, int x, int y, const SkBitmap& src); 1104 1105 const SkBitmap::Config config = this->getConfig(); 1106 1107 switch (config) { 1108 case kARGB_8888_Config: 1109 proc = downsampleby2_proc32; 1110 break; 1111 case kRGB_565_Config: 1112 proc = downsampleby2_proc16; 1113 break; 1114 case kARGB_4444_Config: 1115 proc = downsampleby2_proc4444; 1116 break; 1117 case kIndex8_Config: 1118 case kA8_Config: 1119 default: 1120 return; // don't build mipmaps for these configs 1121 } 1122 1123 SkAutoLockPixels alp(*this); 1124 if (!this->readyToDraw()) { 1125 return; 1126 } 1127 1128 // whip through our loop to compute the exact size needed 1129 size_t size = 0; 1130 int maxLevels = 0; 1131 { 1132 int width = this->width(); 1133 int height = this->height(); 1134 for (;;) { 1135 width >>= 1; 1136 height >>= 1; 1137 if (0 == width || 0 == height) { 1138 break; 1139 } 1140 size += ComputeRowBytes(config, width) * height; 1141 maxLevels += 1; 1142 } 1143 } 1144 1145 // nothing to build 1146 if (0 == maxLevels) { 1147 return; 1148 } 1149 1150 SkBitmap srcBM(*this); 1151 srcBM.lockPixels(); 1152 if (!srcBM.readyToDraw()) { 1153 return; 1154 } 1155 1156 MipMap* mm = MipMap::Alloc(maxLevels, size); 1157 if (NULL == mm) { 1158 return; 1159 } 1160 1161 MipLevel* level = mm->levels(); 1162 uint8_t* addr = (uint8_t*)mm->pixels(); 1163 int width = this->width(); 1164 int height = this->height(); 1165 unsigned rowBytes; 1166 SkBitmap dstBM; 1167 1168 for (int i = 0; i < maxLevels; i++) { 1169 width >>= 1; 1170 height >>= 1; 1171 rowBytes = ComputeRowBytes(config, width); 1172 1173 level[i].fPixels = addr; 1174 level[i].fWidth = width; 1175 level[i].fHeight = height; 1176 level[i].fRowBytes = rowBytes; 1177 1178 dstBM.setConfig(config, width, height, rowBytes); 1179 dstBM.setPixels(addr); 1180 1181 srcBM.lockPixels(); 1182 for (int y = 0; y < height; y++) { 1183 for (int x = 0; x < width; x++) { 1184 proc(&dstBM, x, y, srcBM); 1185 } 1186 } 1187 srcBM.unlockPixels(); 1188 1189 srcBM = dstBM; 1190 addr += height * rowBytes; 1191 } 1192 SkASSERT(addr == (uint8_t*)mm->pixels() + size); 1193 fMipMap = mm; 1194} 1195 1196bool SkBitmap::hasMipMap() const { 1197 return fMipMap != NULL; 1198} 1199 1200int SkBitmap::extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy) { 1201 if (NULL == fMipMap) { 1202 return 0; 1203 } 1204 1205 int level = ComputeMipLevel(sx, sy) >> 16; 1206 SkASSERT(level >= 0); 1207 if (level <= 0) { 1208 return 0; 1209 } 1210 1211 if (level >= fMipMap->fLevelCount) { 1212 level = fMipMap->fLevelCount - 1; 1213 } 1214 if (dst) { 1215 const MipLevel& mip = fMipMap->levels()[level - 1]; 1216 dst->setConfig((SkBitmap::Config)this->config(), 1217 mip.fWidth, mip.fHeight, mip.fRowBytes); 1218 dst->setPixels(mip.fPixels); 1219 } 1220 return level; 1221} 1222 1223SkFixed SkBitmap::ComputeMipLevel(SkFixed sx, SkFixed sy) { 1224 sx = SkAbs32(sx); 1225 sy = SkAbs32(sy); 1226 if (sx < sy) { 1227 sx = sy; 1228 } 1229 if (sx < SK_Fixed1) { 1230 return 0; 1231 } 1232 int clz = SkCLZ(sx); 1233 SkASSERT(clz >= 1 && clz <= 15); 1234 return SkIntToFixed(15 - clz) + ((unsigned)(sx << (clz + 1)) >> 16); 1235} 1236 1237/////////////////////////////////////////////////////////////////////////////// 1238 1239static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, 1240 int alphaRowBytes) { 1241 SkASSERT(alpha != NULL); 1242 SkASSERT(alphaRowBytes >= src.width()); 1243 1244 SkBitmap::Config config = src.getConfig(); 1245 int w = src.width(); 1246 int h = src.height(); 1247 int rb = src.rowBytes(); 1248 1249 SkAutoLockPixels alp(src); 1250 if (!src.readyToDraw()) { 1251 // zero out the alpha buffer and return 1252 while (--h >= 0) { 1253 memset(alpha, 0, w); 1254 alpha += alphaRowBytes; 1255 } 1256 return false; 1257 } 1258 1259 if (SkBitmap::kA8_Config == config && !src.isOpaque()) { 1260 const uint8_t* s = src.getAddr8(0, 0); 1261 while (--h >= 0) { 1262 memcpy(alpha, s, w); 1263 s += rb; 1264 alpha += alphaRowBytes; 1265 } 1266 } else if (SkBitmap::kARGB_8888_Config == config && !src.isOpaque()) { 1267 const SkPMColor* SK_RESTRICT s = src.getAddr32(0, 0); 1268 while (--h >= 0) { 1269 for (int x = 0; x < w; x++) { 1270 alpha[x] = SkGetPackedA32(s[x]); 1271 } 1272 s = (const SkPMColor*)((const char*)s + rb); 1273 alpha += alphaRowBytes; 1274 } 1275 } else if (SkBitmap::kARGB_4444_Config == config && !src.isOpaque()) { 1276 const SkPMColor16* SK_RESTRICT s = src.getAddr16(0, 0); 1277 while (--h >= 0) { 1278 for (int x = 0; x < w; x++) { 1279 alpha[x] = SkPacked4444ToA32(s[x]); 1280 } 1281 s = (const SkPMColor16*)((const char*)s + rb); 1282 alpha += alphaRowBytes; 1283 } 1284 } else if (SkBitmap::kIndex8_Config == config && !src.isOpaque()) { 1285 SkColorTable* ct = src.getColorTable(); 1286 if (ct) { 1287 const SkPMColor* SK_RESTRICT table = ct->lockColors(); 1288 const uint8_t* SK_RESTRICT s = src.getAddr8(0, 0); 1289 while (--h >= 0) { 1290 for (int x = 0; x < w; x++) { 1291 alpha[x] = SkGetPackedA32(table[s[x]]); 1292 } 1293 s += rb; 1294 alpha += alphaRowBytes; 1295 } 1296 ct->unlockColors(false); 1297 } 1298 } else { // src is opaque, so just fill alpha[] with 0xFF 1299 memset(alpha, 0xFF, h * alphaRowBytes); 1300 } 1301 return true; 1302} 1303 1304#include "SkPaint.h" 1305#include "SkMaskFilter.h" 1306#include "SkMatrix.h" 1307 1308bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, 1309 Allocator *allocator, SkIPoint* offset) const { 1310 SkDEBUGCODE(this->validate();) 1311 1312 SkBitmap tmpBitmap; 1313 SkMatrix identity; 1314 SkMask srcM, dstM; 1315 1316 srcM.fBounds.set(0, 0, this->width(), this->height()); 1317 srcM.fRowBytes = SkAlign4(this->width()); 1318 srcM.fFormat = SkMask::kA8_Format; 1319 1320 SkMaskFilter* filter = paint ? paint->getMaskFilter() : NULL; 1321 1322 // compute our (larger?) dst bounds if we have a filter 1323 if (NULL != filter) { 1324 identity.reset(); 1325 srcM.fImage = NULL; 1326 if (!filter->filterMask(&dstM, srcM, identity, NULL)) { 1327 goto NO_FILTER_CASE; 1328 } 1329 dstM.fRowBytes = SkAlign4(dstM.fBounds.width()); 1330 } else { 1331 NO_FILTER_CASE: 1332 tmpBitmap.setConfig(SkBitmap::kA8_Config, this->width(), this->height(), 1333 srcM.fRowBytes); 1334 if (!tmpBitmap.allocPixels(allocator, NULL)) { 1335 // Allocation of pixels for alpha bitmap failed. 1336 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 1337 tmpBitmap.width(), tmpBitmap.height()); 1338 return false; 1339 } 1340 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes); 1341 if (offset) { 1342 offset->set(0, 0); 1343 } 1344 tmpBitmap.swap(*dst); 1345 return true; 1346 } 1347 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize()); 1348 SkAutoMaskFreeImage srcCleanup(srcM.fImage); 1349 1350 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes); 1351 if (!filter->filterMask(&dstM, srcM, identity, NULL)) { 1352 goto NO_FILTER_CASE; 1353 } 1354 SkAutoMaskFreeImage dstCleanup(dstM.fImage); 1355 1356 tmpBitmap.setConfig(SkBitmap::kA8_Config, dstM.fBounds.width(), 1357 dstM.fBounds.height(), dstM.fRowBytes); 1358 if (!tmpBitmap.allocPixels(allocator, NULL)) { 1359 // Allocation of pixels for alpha bitmap failed. 1360 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 1361 tmpBitmap.width(), tmpBitmap.height()); 1362 return false; 1363 } 1364 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize()); 1365 if (offset) { 1366 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop); 1367 } 1368 SkDEBUGCODE(tmpBitmap.validate();) 1369 1370 tmpBitmap.swap(*dst); 1371 return true; 1372} 1373 1374/////////////////////////////////////////////////////////////////////////////// 1375 1376enum { 1377 SERIALIZE_PIXELTYPE_NONE, 1378 SERIALIZE_PIXELTYPE_REF_DATA 1379}; 1380 1381void SkBitmap::flatten(SkFlattenableWriteBuffer& buffer) const { 1382 buffer.writeInt(fWidth); 1383 buffer.writeInt(fHeight); 1384 buffer.writeInt(fRowBytes); 1385 buffer.writeInt(fConfig); 1386 buffer.writeBool(this->isOpaque()); 1387 1388 if (fPixelRef) { 1389 if (fPixelRef->getFactory()) { 1390 buffer.writeInt(SERIALIZE_PIXELTYPE_REF_DATA); 1391 buffer.writeUInt(fPixelRefOffset); 1392 buffer.writeFlattenable(fPixelRef); 1393 return; 1394 } 1395 // if we get here, we can't record the pixels 1396 buffer.writeInt(SERIALIZE_PIXELTYPE_NONE); 1397 } else { 1398 buffer.writeInt(SERIALIZE_PIXELTYPE_NONE); 1399 } 1400} 1401 1402void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) { 1403 this->reset(); 1404 1405 int width = buffer.readInt(); 1406 int height = buffer.readInt(); 1407 int rowBytes = buffer.readInt(); 1408 int config = buffer.readInt(); 1409 1410 this->setConfig((Config)config, width, height, rowBytes); 1411 this->setIsOpaque(buffer.readBool()); 1412 1413 int reftype = buffer.readInt(); 1414 switch (reftype) { 1415 case SERIALIZE_PIXELTYPE_REF_DATA: { 1416 size_t offset = buffer.readUInt(); 1417 SkPixelRef* pr = buffer.readFlattenableT<SkPixelRef>(); 1418 SkSafeUnref(this->setPixelRef(pr, offset)); 1419 break; 1420 } 1421 case SERIALIZE_PIXELTYPE_NONE: 1422 break; 1423 default: 1424 SkDEBUGFAIL("unrecognized pixeltype in serialized data"); 1425 sk_throw(); 1426 } 1427} 1428 1429/////////////////////////////////////////////////////////////////////////////// 1430 1431SkBitmap::RLEPixels::RLEPixels(int width, int height) { 1432 fHeight = height; 1433 fYPtrs = (uint8_t**)sk_malloc_throw(height * sizeof(uint8_t*)); 1434 sk_bzero(fYPtrs, height * sizeof(uint8_t*)); 1435} 1436 1437SkBitmap::RLEPixels::~RLEPixels() { 1438 sk_free(fYPtrs); 1439} 1440 1441/////////////////////////////////////////////////////////////////////////////// 1442 1443#ifdef SK_DEBUG 1444void SkBitmap::validate() const { 1445 SkASSERT(fConfig < kConfigCount); 1446 SkASSERT(fRowBytes >= (unsigned)ComputeRowBytes((Config)fConfig, fWidth)); 1447 SkASSERT(fFlags <= (kImageIsOpaque_Flag | kImageIsVolatile_Flag | kImageIsImmutable_Flag)); 1448 SkASSERT(fPixelLockCount >= 0); 1449 SkASSERT(NULL == fColorTable || (unsigned)fColorTable->getRefCnt() < 10000); 1450 SkASSERT((uint8_t)ComputeBytesPerPixel((Config)fConfig) == fBytesPerPixel); 1451 1452#if 0 // these asserts are not thread-correct, so disable for now 1453 if (fPixelRef) { 1454 if (fPixelLockCount > 0) { 1455 SkASSERT(fPixelRef->isLocked()); 1456 } else { 1457 SkASSERT(NULL == fPixels); 1458 SkASSERT(NULL == fColorTable); 1459 } 1460 } 1461#endif 1462} 1463#endif 1464