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 "SkImagePriv.h" 15 #include "SkMallocPixelRef.h" 16 #include "SkMask.h" 17 #include "SkReadBuffer.h" 18 #include "SkWriteBuffer.h" 19 #include "SkPixelRef.h" 20 #include "SkThread.h" 21 #include "SkUnPreMultiply.h" 22 #include "SkUtils.h" 23 #include "SkValidationUtils.h" 24 #include "SkPackBits.h" 25 #include <new> 26 27 static bool reset_return_false(SkBitmap* bm) { 28 bm->reset(); 29 return false; 30 } 31 32 SkBitmap::SkBitmap() { 33 sk_bzero(this, sizeof(*this)); 34 } 35 36 SkBitmap::SkBitmap(const SkBitmap& src) { 37 SkDEBUGCODE(src.validate();) 38 sk_bzero(this, sizeof(*this)); 39 *this = src; 40 SkDEBUGCODE(this->validate();) 41 } 42 43 SkBitmap::~SkBitmap() { 44 SkDEBUGCODE(this->validate();) 45 this->freePixels(); 46 } 47 48 SkBitmap& SkBitmap::operator=(const SkBitmap& src) { 49 if (this != &src) { 50 this->freePixels(); 51 memcpy(this, &src, sizeof(src)); 52 53 // inc src reference counts 54 SkSafeRef(src.fPixelRef); 55 56 // we reset our locks if we get blown away 57 fPixelLockCount = 0; 58 59 if (fPixelRef) { 60 // ignore the values from the memcpy 61 fPixels = NULL; 62 fColorTable = NULL; 63 // Note that what to for genID is somewhat arbitrary. We have no 64 // way to track changes to raw pixels across multiple SkBitmaps. 65 // Would benefit from an SkRawPixelRef type created by 66 // setPixels. 67 // Just leave the memcpy'ed one but they'll get out of sync 68 // as soon either is modified. 69 } 70 } 71 72 SkDEBUGCODE(this->validate();) 73 return *this; 74 } 75 76 void SkBitmap::swap(SkBitmap& other) { 77 SkTSwap(fColorTable, other.fColorTable); 78 SkTSwap(fPixelRef, other.fPixelRef); 79 SkTSwap(fPixelRefOrigin, other.fPixelRefOrigin); 80 SkTSwap(fPixelLockCount, other.fPixelLockCount); 81 SkTSwap(fPixels, other.fPixels); 82 SkTSwap(fInfo, other.fInfo); 83 SkTSwap(fRowBytes, other.fRowBytes); 84 SkTSwap(fFlags, other.fFlags); 85 86 SkDEBUGCODE(this->validate();) 87 } 88 89 void SkBitmap::reset() { 90 this->freePixels(); 91 sk_bzero(this, sizeof(*this)); 92 } 93 94 void SkBitmap::getBounds(SkRect* bounds) const { 95 SkASSERT(bounds); 96 bounds->set(0, 0, 97 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height())); 98 } 99 100 void SkBitmap::getBounds(SkIRect* bounds) const { 101 SkASSERT(bounds); 102 bounds->set(0, 0, fInfo.width(), fInfo.height()); 103 } 104 105 /////////////////////////////////////////////////////////////////////////////// 106 107 bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) { 108 SkAlphaType newAT = info.alphaType(); 109 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) { 110 return reset_return_false(this); 111 } 112 // don't look at info.alphaType(), since newAT is the real value... 113 114 // require that rowBytes fit in 31bits 115 int64_t mrb = info.minRowBytes64(); 116 if ((int32_t)mrb != mrb) { 117 return reset_return_false(this); 118 } 119 if ((int64_t)rowBytes != (int32_t)rowBytes) { 120 return reset_return_false(this); 121 } 122 123 if (info.width() < 0 || info.height() < 0) { 124 return reset_return_false(this); 125 } 126 127 if (kUnknown_SkColorType == info.colorType()) { 128 rowBytes = 0; 129 } else if (0 == rowBytes) { 130 rowBytes = (size_t)mrb; 131 } else if (!info.validRowBytes(rowBytes)) { 132 return reset_return_false(this); 133 } 134 135 this->freePixels(); 136 137 fInfo = info.makeAlphaType(newAT); 138 fRowBytes = SkToU32(rowBytes); 139 return true; 140 } 141 142 bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) { 143 if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) { 144 return false; 145 } 146 if (fInfo.alphaType() != newAlphaType) { 147 fInfo = fInfo.makeAlphaType(newAlphaType); 148 if (fPixelRef) { 149 fPixelRef->changeAlphaType(newAlphaType); 150 } 151 } 152 return true; 153 } 154 155 void SkBitmap::updatePixelsFromRef() const { 156 if (fPixelRef) { 157 if (fPixelLockCount > 0) { 158 SkASSERT(fPixelRef->isLocked()); 159 160 void* p = fPixelRef->pixels(); 161 if (p) { 162 p = (char*)p 163 + fPixelRefOrigin.fY * fRowBytes 164 + fPixelRefOrigin.fX * fInfo.bytesPerPixel(); 165 } 166 fPixels = p; 167 fColorTable = fPixelRef->colorTable(); 168 } else { 169 SkASSERT(0 == fPixelLockCount); 170 fPixels = NULL; 171 fColorTable = NULL; 172 } 173 } 174 } 175 176 SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) { 177 #ifdef SK_DEBUG 178 if (pr) { 179 if (kUnknown_SkColorType != fInfo.colorType()) { 180 const SkImageInfo& prInfo = pr->info(); 181 SkASSERT(fInfo.width() <= prInfo.width()); 182 SkASSERT(fInfo.height() <= prInfo.height()); 183 SkASSERT(fInfo.colorType() == prInfo.colorType()); 184 switch (prInfo.alphaType()) { 185 case kIgnore_SkAlphaType: 186 SkASSERT(fInfo.alphaType() == kIgnore_SkAlphaType); 187 break; 188 case kOpaque_SkAlphaType: 189 case kPremul_SkAlphaType: 190 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType || 191 fInfo.alphaType() == kPremul_SkAlphaType); 192 break; 193 case kUnpremul_SkAlphaType: 194 SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType || 195 fInfo.alphaType() == kUnpremul_SkAlphaType); 196 break; 197 } 198 } 199 } 200 #endif 201 202 if (pr) { 203 const SkImageInfo& info = pr->info(); 204 fPixelRefOrigin.set(SkPin32(dx, 0, info.width()), SkPin32(dy, 0, info.height())); 205 } else { 206 // ignore dx,dy if there is no pixelref 207 fPixelRefOrigin.setZero(); 208 } 209 210 if (fPixelRef != pr) { 211 this->freePixels(); 212 SkASSERT(NULL == fPixelRef); 213 214 SkSafeRef(pr); 215 fPixelRef = pr; 216 this->updatePixelsFromRef(); 217 } 218 219 SkDEBUGCODE(this->validate();) 220 return pr; 221 } 222 223 void SkBitmap::lockPixels() const { 224 if (fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) { 225 fPixelRef->lockPixels(); 226 this->updatePixelsFromRef(); 227 } 228 SkDEBUGCODE(this->validate();) 229 } 230 231 void SkBitmap::unlockPixels() const { 232 SkASSERT(NULL == fPixelRef || fPixelLockCount > 0); 233 234 if (fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) { 235 fPixelRef->unlockPixels(); 236 this->updatePixelsFromRef(); 237 } 238 SkDEBUGCODE(this->validate();) 239 } 240 241 bool SkBitmap::lockPixelsAreWritable() const { 242 return (fPixelRef) ? fPixelRef->lockPixelsAreWritable() : false; 243 } 244 245 void SkBitmap::setPixels(void* p, SkColorTable* ctable) { 246 if (NULL == p) { 247 this->setPixelRef(NULL); 248 return; 249 } 250 251 if (kUnknown_SkColorType == fInfo.colorType()) { 252 this->setPixelRef(NULL); 253 return; 254 } 255 256 SkPixelRef* pr = SkMallocPixelRef::NewDirect(fInfo, p, fRowBytes, ctable); 257 if (NULL == pr) { 258 this->setPixelRef(NULL); 259 return; 260 } 261 262 this->setPixelRef(pr)->unref(); 263 264 // since we're already allocated, we lockPixels right away 265 this->lockPixels(); 266 SkDEBUGCODE(this->validate();) 267 } 268 269 bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) { 270 HeapAllocator stdalloc; 271 272 if (NULL == allocator) { 273 allocator = &stdalloc; 274 } 275 return allocator->allocPixelRef(this, ctable); 276 } 277 278 /////////////////////////////////////////////////////////////////////////////// 279 280 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) { 281 if (kIndex_8_SkColorType == requestedInfo.colorType()) { 282 return reset_return_false(this); 283 } 284 if (!this->setInfo(requestedInfo, rowBytes)) { 285 return reset_return_false(this); 286 } 287 288 // setInfo may have corrected info (e.g. 565 is always opaque). 289 const SkImageInfo& correctedInfo = this->info(); 290 // setInfo may have computed a valid rowbytes if 0 were passed in 291 rowBytes = this->rowBytes(); 292 293 SkMallocPixelRef::PRFactory defaultFactory; 294 295 SkPixelRef* pr = defaultFactory.create(correctedInfo, rowBytes, NULL); 296 if (NULL == pr) { 297 return reset_return_false(this); 298 } 299 this->setPixelRef(pr)->unref(); 300 301 // TODO: lockPixels could/should return bool or void*/NULL 302 this->lockPixels(); 303 if (NULL == this->getPixels()) { 304 return reset_return_false(this); 305 } 306 return true; 307 } 308 309 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory, 310 SkColorTable* ctable) { 311 if (kIndex_8_SkColorType == requestedInfo.colorType() && NULL == ctable) { 312 return reset_return_false(this); 313 } 314 if (!this->setInfo(requestedInfo)) { 315 return reset_return_false(this); 316 } 317 318 // setInfo may have corrected info (e.g. 565 is always opaque). 319 const SkImageInfo& correctedInfo = this->info(); 320 321 SkMallocPixelRef::PRFactory defaultFactory; 322 if (NULL == factory) { 323 factory = &defaultFactory; 324 } 325 326 SkPixelRef* pr = factory->create(correctedInfo, correctedInfo.minRowBytes(), ctable); 327 if (NULL == pr) { 328 return reset_return_false(this); 329 } 330 this->setPixelRef(pr)->unref(); 331 332 // TODO: lockPixels could/should return bool or void*/NULL 333 this->lockPixels(); 334 if (NULL == this->getPixels()) { 335 return reset_return_false(this); 336 } 337 return true; 338 } 339 340 bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb, 341 SkColorTable* ct, void (*releaseProc)(void* addr, void* context), 342 void* context) { 343 if (!this->setInfo(requestedInfo, rb)) { 344 this->reset(); 345 return false; 346 } 347 348 // setInfo may have corrected info (e.g. 565 is always opaque). 349 const SkImageInfo& correctedInfo = this->info(); 350 351 SkPixelRef* pr = SkMallocPixelRef::NewWithProc(correctedInfo, rb, ct, pixels, releaseProc, 352 context); 353 if (!pr) { 354 this->reset(); 355 return false; 356 } 357 358 this->setPixelRef(pr)->unref(); 359 360 // since we're already allocated, we lockPixels right away 361 this->lockPixels(); 362 SkDEBUGCODE(this->validate();) 363 return true; 364 } 365 366 bool SkBitmap::installMaskPixels(const SkMask& mask) { 367 if (SkMask::kA8_Format != mask.fFormat) { 368 this->reset(); 369 return false; 370 } 371 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), 372 mask.fBounds.height()), 373 mask.fImage, mask.fRowBytes); 374 } 375 376 /////////////////////////////////////////////////////////////////////////////// 377 378 void SkBitmap::freePixels() { 379 if (fPixelRef) { 380 if (fPixelLockCount > 0) { 381 fPixelRef->unlockPixels(); 382 } 383 fPixelRef->unref(); 384 fPixelRef = NULL; 385 fPixelRefOrigin.setZero(); 386 } 387 fPixelLockCount = 0; 388 fPixels = NULL; 389 fColorTable = NULL; 390 } 391 392 uint32_t SkBitmap::getGenerationID() const { 393 return (fPixelRef) ? fPixelRef->getGenerationID() : 0; 394 } 395 396 void SkBitmap::notifyPixelsChanged() const { 397 SkASSERT(!this->isImmutable()); 398 if (fPixelRef) { 399 fPixelRef->notifyPixelsChanged(); 400 } 401 } 402 403 GrTexture* SkBitmap::getTexture() const { 404 return fPixelRef ? fPixelRef->getTexture() : NULL; 405 } 406 407 /////////////////////////////////////////////////////////////////////////////// 408 409 /** We explicitly use the same allocator for our pixels that SkMask does, 410 so that we can freely assign memory allocated by one class to the other. 411 */ 412 bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst, 413 SkColorTable* ctable) { 414 const SkImageInfo info = dst->info(); 415 if (kUnknown_SkColorType == info.colorType()) { 416 // SkDebugf("unsupported config for info %d\n", dst->config()); 417 return false; 418 } 419 420 SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), ctable); 421 if (NULL == pr) { 422 return false; 423 } 424 425 dst->setPixelRef(pr)->unref(); 426 // since we're already allocated, we lockPixels right away 427 dst->lockPixels(); 428 return true; 429 } 430 431 /////////////////////////////////////////////////////////////////////////////// 432 433 bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize, 434 size_t dstRowBytes, bool preserveDstPad) const { 435 436 if (0 == dstRowBytes) { 437 dstRowBytes = fRowBytes; 438 } 439 440 if (dstRowBytes < fInfo.minRowBytes() || 441 dst == NULL || (getPixels() == NULL && pixelRef() == NULL)) { 442 return false; 443 } 444 445 if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == fRowBytes) { 446 size_t safeSize = this->getSafeSize(); 447 if (safeSize > dstSize || safeSize == 0) 448 return false; 449 else { 450 SkAutoLockPixels lock(*this); 451 // This implementation will write bytes beyond the end of each row, 452 // excluding the last row, if the bitmap's stride is greater than 453 // strictly required by the current config. 454 memcpy(dst, getPixels(), safeSize); 455 456 return true; 457 } 458 } else { 459 // If destination has different stride than us, then copy line by line. 460 if (fInfo.getSafeSize(dstRowBytes) > dstSize) { 461 return false; 462 } else { 463 // Just copy what we need on each line. 464 size_t rowBytes = fInfo.minRowBytes(); 465 SkAutoLockPixels lock(*this); 466 const uint8_t* srcP = reinterpret_cast<const uint8_t*>(getPixels()); 467 uint8_t* dstP = reinterpret_cast<uint8_t*>(dst); 468 for (int row = 0; row < fInfo.height(); row++, srcP += fRowBytes, dstP += dstRowBytes) { 469 memcpy(dstP, srcP, rowBytes); 470 } 471 472 return true; 473 } 474 } 475 } 476 477 /////////////////////////////////////////////////////////////////////////////// 478 479 bool SkBitmap::isImmutable() const { 480 return fPixelRef ? fPixelRef->isImmutable() : false; 481 } 482 483 void SkBitmap::setImmutable() { 484 if (fPixelRef) { 485 fPixelRef->setImmutable(); 486 } 487 } 488 489 bool SkBitmap::isVolatile() const { 490 return (fFlags & kImageIsVolatile_Flag) != 0; 491 } 492 493 void SkBitmap::setIsVolatile(bool isVolatile) { 494 if (isVolatile) { 495 fFlags |= kImageIsVolatile_Flag; 496 } else { 497 fFlags &= ~kImageIsVolatile_Flag; 498 } 499 } 500 501 void* SkBitmap::getAddr(int x, int y) const { 502 SkASSERT((unsigned)x < (unsigned)this->width()); 503 SkASSERT((unsigned)y < (unsigned)this->height()); 504 505 char* base = (char*)this->getPixels(); 506 if (base) { 507 base += y * this->rowBytes(); 508 switch (this->colorType()) { 509 case kRGBA_8888_SkColorType: 510 case kBGRA_8888_SkColorType: 511 base += x << 2; 512 break; 513 case kARGB_4444_SkColorType: 514 case kRGB_565_SkColorType: 515 base += x << 1; 516 break; 517 case kAlpha_8_SkColorType: 518 case kIndex_8_SkColorType: 519 base += x; 520 break; 521 default: 522 SkDEBUGFAIL("Can't return addr for config"); 523 base = NULL; 524 break; 525 } 526 } 527 return base; 528 } 529 530 SkColor SkBitmap::getColor(int x, int y) const { 531 SkASSERT((unsigned)x < (unsigned)this->width()); 532 SkASSERT((unsigned)y < (unsigned)this->height()); 533 534 switch (this->colorType()) { 535 case kAlpha_8_SkColorType: { 536 uint8_t* addr = this->getAddr8(x, y); 537 return SkColorSetA(0, addr[0]); 538 } 539 case kIndex_8_SkColorType: { 540 SkPMColor c = this->getIndex8Color(x, y); 541 return SkUnPreMultiply::PMColorToColor(c); 542 } 543 case kRGB_565_SkColorType: { 544 uint16_t* addr = this->getAddr16(x, y); 545 return SkPixel16ToColor(addr[0]); 546 } 547 case kARGB_4444_SkColorType: { 548 uint16_t* addr = this->getAddr16(x, y); 549 SkPMColor c = SkPixel4444ToPixel32(addr[0]); 550 return SkUnPreMultiply::PMColorToColor(c); 551 } 552 case kBGRA_8888_SkColorType: 553 case kRGBA_8888_SkColorType: { 554 uint32_t* addr = this->getAddr32(x, y); 555 return SkUnPreMultiply::PMColorToColor(addr[0]); 556 } 557 default: 558 SkASSERT(false); 559 return 0; 560 } 561 SkASSERT(false); // Not reached. 562 return 0; 563 } 564 565 bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) { 566 SkAutoLockPixels alp(bm); 567 if (!bm.getPixels()) { 568 return false; 569 } 570 571 const int height = bm.height(); 572 const int width = bm.width(); 573 574 switch (bm.colorType()) { 575 case kAlpha_8_SkColorType: { 576 unsigned a = 0xFF; 577 for (int y = 0; y < height; ++y) { 578 const uint8_t* row = bm.getAddr8(0, y); 579 for (int x = 0; x < width; ++x) { 580 a &= row[x]; 581 } 582 if (0xFF != a) { 583 return false; 584 } 585 } 586 return true; 587 } break; 588 case kIndex_8_SkColorType: { 589 SkAutoLockColors alc(bm); 590 const SkPMColor* table = alc.colors(); 591 if (!table) { 592 return false; 593 } 594 SkPMColor c = (SkPMColor)~0; 595 for (int i = bm.getColorTable()->count() - 1; i >= 0; --i) { 596 c &= table[i]; 597 } 598 return 0xFF == SkGetPackedA32(c); 599 } break; 600 case kRGB_565_SkColorType: 601 return true; 602 break; 603 case kARGB_4444_SkColorType: { 604 unsigned c = 0xFFFF; 605 for (int y = 0; y < height; ++y) { 606 const SkPMColor16* row = bm.getAddr16(0, y); 607 for (int x = 0; x < width; ++x) { 608 c &= row[x]; 609 } 610 if (0xF != SkGetPackedA4444(c)) { 611 return false; 612 } 613 } 614 return true; 615 } break; 616 case kBGRA_8888_SkColorType: 617 case kRGBA_8888_SkColorType: { 618 SkPMColor c = (SkPMColor)~0; 619 for (int y = 0; y < height; ++y) { 620 const SkPMColor* row = bm.getAddr32(0, y); 621 for (int x = 0; x < width; ++x) { 622 c &= row[x]; 623 } 624 if (0xFF != SkGetPackedA32(c)) { 625 return false; 626 } 627 } 628 return true; 629 } 630 default: 631 break; 632 } 633 return false; 634 } 635 636 637 /////////////////////////////////////////////////////////////////////////////// 638 /////////////////////////////////////////////////////////////////////////////// 639 640 static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) { 641 unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) | 642 (SkR32To4444(r) << SK_R4444_SHIFT) | 643 (SkG32To4444(g) << SK_G4444_SHIFT) | 644 (SkB32To4444(b) << SK_B4444_SHIFT); 645 return SkToU16(pixel); 646 } 647 648 void SkBitmap::internalErase(const SkIRect& area, 649 U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { 650 #ifdef SK_DEBUG 651 SkDEBUGCODE(this->validate();) 652 SkASSERT(!area.isEmpty()); 653 { 654 SkIRect total = { 0, 0, this->width(), this->height() }; 655 SkASSERT(total.contains(area)); 656 } 657 #endif 658 659 switch (fInfo.colorType()) { 660 case kUnknown_SkColorType: 661 case kIndex_8_SkColorType: 662 return; // can't erase. Should we bzero so the memory is not uninitialized? 663 default: 664 break; 665 } 666 667 SkAutoLockPixels alp(*this); 668 // perform this check after the lock call 669 if (!this->readyToDraw()) { 670 return; 671 } 672 673 int height = area.height(); 674 const int width = area.width(); 675 const int rowBytes = fRowBytes; 676 677 switch (this->colorType()) { 678 case kAlpha_8_SkColorType: { 679 uint8_t* p = this->getAddr8(area.fLeft, area.fTop); 680 while (--height >= 0) { 681 memset(p, a, width); 682 p += rowBytes; 683 } 684 break; 685 } 686 case kARGB_4444_SkColorType: 687 case kRGB_565_SkColorType: { 688 uint16_t* p = this->getAddr16(area.fLeft, area.fTop);; 689 uint16_t v; 690 691 // make rgb premultiplied 692 if (255 != a) { 693 r = SkAlphaMul(r, a); 694 g = SkAlphaMul(g, a); 695 b = SkAlphaMul(b, a); 696 } 697 698 if (kARGB_4444_SkColorType == this->colorType()) { 699 v = pack_8888_to_4444(a, r, g, b); 700 } else { 701 v = SkPackRGB16(r >> (8 - SK_R16_BITS), 702 g >> (8 - SK_G16_BITS), 703 b >> (8 - SK_B16_BITS)); 704 } 705 while (--height >= 0) { 706 sk_memset16(p, v, width); 707 p = (uint16_t*)((char*)p + rowBytes); 708 } 709 break; 710 } 711 case kBGRA_8888_SkColorType: 712 case kRGBA_8888_SkColorType: { 713 uint32_t* p = this->getAddr32(area.fLeft, area.fTop); 714 715 if (255 != a && kPremul_SkAlphaType == this->alphaType()) { 716 r = SkAlphaMul(r, a); 717 g = SkAlphaMul(g, a); 718 b = SkAlphaMul(b, a); 719 } 720 uint32_t v = kRGBA_8888_SkColorType == this->colorType() ? 721 SkPackARGB_as_RGBA(a, r, g, b) : SkPackARGB_as_BGRA(a, r, g, b); 722 723 while (--height >= 0) { 724 sk_memset32(p, v, width); 725 p = (uint32_t*)((char*)p + rowBytes); 726 } 727 break; 728 } 729 default: 730 return; // no change, so don't call notifyPixelsChanged() 731 } 732 733 this->notifyPixelsChanged(); 734 } 735 736 void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { 737 SkIRect area = { 0, 0, this->width(), this->height() }; 738 if (!area.isEmpty()) { 739 this->internalErase(area, a, r, g, b); 740 } 741 } 742 743 void SkBitmap::eraseArea(const SkIRect& rect, SkColor c) const { 744 SkIRect area = { 0, 0, this->width(), this->height() }; 745 if (area.intersect(rect)) { 746 this->internalErase(area, SkColorGetA(c), SkColorGetR(c), 747 SkColorGetG(c), SkColorGetB(c)); 748 } 749 } 750 751 ////////////////////////////////////////////////////////////////////////////////////// 752 ////////////////////////////////////////////////////////////////////////////////////// 753 754 bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { 755 SkDEBUGCODE(this->validate();) 756 757 if (NULL == result || NULL == fPixelRef) { 758 return false; // no src pixels 759 } 760 761 SkIRect srcRect, r; 762 srcRect.set(0, 0, this->width(), this->height()); 763 if (!r.intersect(srcRect, subset)) { 764 return false; // r is empty (i.e. no intersection) 765 } 766 767 if (fPixelRef->getTexture() != NULL) { 768 // Do a deep copy 769 SkPixelRef* pixelRef = fPixelRef->deepCopy(this->colorType(), &subset); 770 if (pixelRef != NULL) { 771 SkBitmap dst; 772 dst.setInfo(SkImageInfo::Make(subset.width(), subset.height(), 773 this->colorType(), this->alphaType())); 774 dst.setIsVolatile(this->isVolatile()); 775 dst.setPixelRef(pixelRef)->unref(); 776 SkDEBUGCODE(dst.validate()); 777 result->swap(dst); 778 return true; 779 } 780 } 781 782 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have 783 // exited above. 784 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width())); 785 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height())); 786 787 SkBitmap dst; 788 dst.setInfo(SkImageInfo::Make(r.width(), r.height(), this->colorType(), this->alphaType()), 789 this->rowBytes()); 790 dst.setIsVolatile(this->isVolatile()); 791 792 if (fPixelRef) { 793 SkIPoint origin = fPixelRefOrigin; 794 origin.fX += r.fLeft; 795 origin.fY += r.fTop; 796 // share the pixelref with a custom offset 797 dst.setPixelRef(fPixelRef, origin); 798 } 799 SkDEBUGCODE(dst.validate();) 800 801 // we know we're good, so commit to result 802 result->swap(dst); 803 return true; 804 } 805 806 /////////////////////////////////////////////////////////////////////////////// 807 808 #include "SkCanvas.h" 809 #include "SkPaint.h" 810 811 bool SkBitmap::canCopyTo(SkColorType dstColorType) const { 812 const SkColorType srcCT = this->colorType(); 813 814 if (srcCT == kUnknown_SkColorType) { 815 return false; 816 } 817 818 bool sameConfigs = (srcCT == dstColorType); 819 switch (dstColorType) { 820 case kAlpha_8_SkColorType: 821 case kRGB_565_SkColorType: 822 case kRGBA_8888_SkColorType: 823 case kBGRA_8888_SkColorType: 824 break; 825 case kIndex_8_SkColorType: 826 if (!sameConfigs) { 827 return false; 828 } 829 break; 830 case kARGB_4444_SkColorType: 831 return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT; 832 default: 833 return false; 834 } 835 return true; 836 } 837 838 #include "SkConfig8888.h" 839 840 bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB, 841 int x, int y) const { 842 if (kUnknown_SkColorType == requestedDstInfo.colorType()) { 843 return false; 844 } 845 if (NULL == dstPixels || dstRB < requestedDstInfo.minRowBytes()) { 846 return false; 847 } 848 if (0 == requestedDstInfo.width() || 0 == requestedDstInfo.height()) { 849 return false; 850 } 851 852 SkIRect srcR = SkIRect::MakeXYWH(x, y, requestedDstInfo.width(), requestedDstInfo.height()); 853 if (!srcR.intersect(0, 0, this->width(), this->height())) { 854 return false; 855 } 856 857 // the intersect may have shrunk info's logical size 858 const SkImageInfo dstInfo = requestedDstInfo.makeWH(srcR.width(), srcR.height()); 859 860 // if x or y are negative, then we have to adjust pixels 861 if (x > 0) { 862 x = 0; 863 } 864 if (y > 0) { 865 y = 0; 866 } 867 // here x,y are either 0 or negative 868 dstPixels = ((char*)dstPixels - y * dstRB - x * dstInfo.bytesPerPixel()); 869 870 ////////////// 871 872 SkAutoLockPixels alp(*this); 873 874 // since we don't stop creating un-pixeled devices yet, check for no pixels here 875 if (NULL == this->getPixels()) { 876 return false; 877 } 878 879 const SkImageInfo srcInfo = this->info().makeWH(dstInfo.width(), dstInfo.height()); 880 881 const void* srcPixels = this->getAddr(srcR.x(), srcR.y()); 882 return SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, this->rowBytes(), 883 this->getColorTable()); 884 } 885 886 bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const { 887 if (!this->canCopyTo(dstColorType)) { 888 return false; 889 } 890 891 // if we have a texture, first get those pixels 892 SkBitmap tmpSrc; 893 const SkBitmap* src = this; 894 895 if (fPixelRef) { 896 SkIRect subset; 897 subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY, 898 fInfo.width(), fInfo.height()); 899 if (fPixelRef->readPixels(&tmpSrc, &subset)) { 900 if (fPixelRef->info().alphaType() == kUnpremul_SkAlphaType) { 901 // FIXME: The only meaningful implementation of readPixels 902 // (GrPixelRef) assumes premultiplied pixels. 903 return false; 904 } 905 SkASSERT(tmpSrc.width() == this->width()); 906 SkASSERT(tmpSrc.height() == this->height()); 907 908 // did we get lucky and we can just return tmpSrc? 909 if (tmpSrc.colorType() == dstColorType && NULL == alloc) { 910 dst->swap(tmpSrc); 911 // If the result is an exact copy, clone the gen ID. 912 if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) { 913 dst->pixelRef()->cloneGenID(*fPixelRef); 914 } 915 return true; 916 } 917 918 // fall through to the raster case 919 src = &tmpSrc; 920 } 921 } 922 923 // we lock this now, since we may need its colortable 924 SkAutoLockPixels srclock(*src); 925 if (!src->readyToDraw()) { 926 return false; 927 } 928 929 // The only way to be readyToDraw is if fPixelRef is non NULL. 930 SkASSERT(fPixelRef != NULL); 931 932 const SkImageInfo dstInfo = src->info().makeColorType(dstColorType); 933 934 SkBitmap tmpDst; 935 if (!tmpDst.setInfo(dstInfo)) { 936 return false; 937 } 938 939 // allocate colortable if srcConfig == kIndex8_Config 940 SkAutoTUnref<SkColorTable> ctable; 941 if (dstColorType == kIndex_8_SkColorType) { 942 // TODO: can we just ref() the src colortable? Is it reentrant-safe? 943 ctable.reset(SkNEW_ARGS(SkColorTable, (*src->getColorTable()))); 944 } 945 if (!tmpDst.tryAllocPixels(alloc, ctable)) { 946 return false; 947 } 948 949 if (!tmpDst.readyToDraw()) { 950 // allocator/lock failed 951 return false; 952 } 953 954 // pixelRef must be non NULL or tmpDst.readyToDraw() would have 955 // returned false. 956 SkASSERT(tmpDst.pixelRef() != NULL); 957 958 if (!src->readPixels(tmpDst.info(), tmpDst.getPixels(), tmpDst.rowBytes(), 0, 0)) { 959 return false; 960 } 961 962 // (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref. 963 // The old copyTo impl did this, so we continue it for now. 964 // 965 // TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be 966 // if (src_pixelref->info == dst_pixelref->info) 967 // 968 if (src->colorType() == dstColorType && tmpDst.getSize() == src->getSize()) { 969 SkPixelRef* dstPixelRef = tmpDst.pixelRef(); 970 if (dstPixelRef->info() == fPixelRef->info()) { 971 dstPixelRef->cloneGenID(*fPixelRef); 972 } 973 } 974 975 dst->swap(tmpDst); 976 return true; 977 } 978 979 bool SkBitmap::deepCopyTo(SkBitmap* dst) const { 980 const SkColorType dstCT = this->colorType(); 981 982 if (!this->canCopyTo(dstCT)) { 983 return false; 984 } 985 986 // If we have a PixelRef, and it supports deep copy, use it. 987 // Currently supported only by texture-backed bitmaps. 988 if (fPixelRef) { 989 SkPixelRef* pixelRef = fPixelRef->deepCopy(dstCT, NULL); 990 if (pixelRef) { 991 uint32_t rowBytes; 992 if (this->colorType() == dstCT) { 993 // Since there is no subset to pass to deepCopy, and deepCopy 994 // succeeded, the new pixel ref must be identical. 995 SkASSERT(fPixelRef->info() == pixelRef->info()); 996 pixelRef->cloneGenID(*fPixelRef); 997 // Use the same rowBytes as the original. 998 rowBytes = fRowBytes; 999 } else { 1000 // With the new config, an appropriate fRowBytes will be computed by setInfo. 1001 rowBytes = 0; 1002 } 1003 1004 const SkImageInfo info = fInfo.makeColorType(dstCT); 1005 if (!dst->setInfo(info, rowBytes)) { 1006 return false; 1007 } 1008 dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref(); 1009 return true; 1010 } 1011 } 1012 1013 if (this->getTexture()) { 1014 return false; 1015 } else { 1016 return this->copyTo(dst, dstCT, NULL); 1017 } 1018 } 1019 1020 /////////////////////////////////////////////////////////////////////////////// 1021 1022 static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, 1023 int alphaRowBytes) { 1024 SkASSERT(alpha != NULL); 1025 SkASSERT(alphaRowBytes >= src.width()); 1026 1027 SkColorType colorType = src.colorType(); 1028 int w = src.width(); 1029 int h = src.height(); 1030 size_t rb = src.rowBytes(); 1031 1032 SkAutoLockPixels alp(src); 1033 if (!src.readyToDraw()) { 1034 // zero out the alpha buffer and return 1035 while (--h >= 0) { 1036 memset(alpha, 0, w); 1037 alpha += alphaRowBytes; 1038 } 1039 return false; 1040 } 1041 1042 if (kAlpha_8_SkColorType == colorType && !src.isOpaque()) { 1043 const uint8_t* s = src.getAddr8(0, 0); 1044 while (--h >= 0) { 1045 memcpy(alpha, s, w); 1046 s += rb; 1047 alpha += alphaRowBytes; 1048 } 1049 } else if (kN32_SkColorType == colorType && !src.isOpaque()) { 1050 const SkPMColor* SK_RESTRICT s = src.getAddr32(0, 0); 1051 while (--h >= 0) { 1052 for (int x = 0; x < w; x++) { 1053 alpha[x] = SkGetPackedA32(s[x]); 1054 } 1055 s = (const SkPMColor*)((const char*)s + rb); 1056 alpha += alphaRowBytes; 1057 } 1058 } else if (kARGB_4444_SkColorType == colorType && !src.isOpaque()) { 1059 const SkPMColor16* SK_RESTRICT s = src.getAddr16(0, 0); 1060 while (--h >= 0) { 1061 for (int x = 0; x < w; x++) { 1062 alpha[x] = SkPacked4444ToA32(s[x]); 1063 } 1064 s = (const SkPMColor16*)((const char*)s + rb); 1065 alpha += alphaRowBytes; 1066 } 1067 } else if (kIndex_8_SkColorType == colorType && !src.isOpaque()) { 1068 SkColorTable* ct = src.getColorTable(); 1069 if (ct) { 1070 const SkPMColor* SK_RESTRICT table = ct->lockColors(); 1071 const uint8_t* SK_RESTRICT s = src.getAddr8(0, 0); 1072 while (--h >= 0) { 1073 for (int x = 0; x < w; x++) { 1074 alpha[x] = SkGetPackedA32(table[s[x]]); 1075 } 1076 s += rb; 1077 alpha += alphaRowBytes; 1078 } 1079 ct->unlockColors(); 1080 } 1081 } else { // src is opaque, so just fill alpha[] with 0xFF 1082 memset(alpha, 0xFF, h * alphaRowBytes); 1083 } 1084 return true; 1085 } 1086 1087 #include "SkPaint.h" 1088 #include "SkMaskFilter.h" 1089 #include "SkMatrix.h" 1090 1091 bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, 1092 Allocator *allocator, SkIPoint* offset) const { 1093 SkDEBUGCODE(this->validate();) 1094 1095 SkBitmap tmpBitmap; 1096 SkMatrix identity; 1097 SkMask srcM, dstM; 1098 1099 srcM.fBounds.set(0, 0, this->width(), this->height()); 1100 srcM.fRowBytes = SkAlign4(this->width()); 1101 srcM.fFormat = SkMask::kA8_Format; 1102 1103 SkMaskFilter* filter = paint ? paint->getMaskFilter() : NULL; 1104 1105 // compute our (larger?) dst bounds if we have a filter 1106 if (filter) { 1107 identity.reset(); 1108 srcM.fImage = NULL; 1109 if (!filter->filterMask(&dstM, srcM, identity, NULL)) { 1110 goto NO_FILTER_CASE; 1111 } 1112 dstM.fRowBytes = SkAlign4(dstM.fBounds.width()); 1113 } else { 1114 NO_FILTER_CASE: 1115 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes); 1116 if (!tmpBitmap.tryAllocPixels(allocator, NULL)) { 1117 // Allocation of pixels for alpha bitmap failed. 1118 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 1119 tmpBitmap.width(), tmpBitmap.height()); 1120 return false; 1121 } 1122 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes); 1123 if (offset) { 1124 offset->set(0, 0); 1125 } 1126 tmpBitmap.swap(*dst); 1127 return true; 1128 } 1129 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize()); 1130 SkAutoMaskFreeImage srcCleanup(srcM.fImage); 1131 1132 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes); 1133 if (!filter->filterMask(&dstM, srcM, identity, NULL)) { 1134 goto NO_FILTER_CASE; 1135 } 1136 SkAutoMaskFreeImage dstCleanup(dstM.fImage); 1137 1138 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()), 1139 dstM.fRowBytes); 1140 if (!tmpBitmap.tryAllocPixels(allocator, NULL)) { 1141 // Allocation of pixels for alpha bitmap failed. 1142 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 1143 tmpBitmap.width(), tmpBitmap.height()); 1144 return false; 1145 } 1146 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize()); 1147 if (offset) { 1148 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop); 1149 } 1150 SkDEBUGCODE(tmpBitmap.validate();) 1151 1152 tmpBitmap.swap(*dst); 1153 return true; 1154 } 1155 1156 /////////////////////////////////////////////////////////////////////////////// 1157 1158 void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) { 1159 const SkImageInfo info = bitmap.info(); 1160 SkAutoLockPixels alp(bitmap); 1161 if (0 == info.width() || 0 == info.height() || NULL == bitmap.getPixels()) { 1162 buffer->writeUInt(0); // instead of snugRB, signaling no pixels 1163 return; 1164 } 1165 1166 const size_t snugRB = info.width() * info.bytesPerPixel(); 1167 const char* src = (const char*)bitmap.getPixels(); 1168 const size_t ramRB = bitmap.rowBytes(); 1169 1170 buffer->write32(SkToU32(snugRB)); 1171 info.flatten(*buffer); 1172 1173 const size_t size = snugRB * info.height(); 1174 SkAutoMalloc storage(size); 1175 char* dst = (char*)storage.get(); 1176 for (int y = 0; y < info.height(); ++y) { 1177 memcpy(dst, src, snugRB); 1178 dst += snugRB; 1179 src += ramRB; 1180 } 1181 buffer->writeByteArray(storage.get(), size); 1182 1183 SkColorTable* ct = bitmap.getColorTable(); 1184 if (kIndex_8_SkColorType == info.colorType() && ct) { 1185 buffer->writeBool(true); 1186 ct->writeToBuffer(*buffer); 1187 } else { 1188 buffer->writeBool(false); 1189 } 1190 } 1191 1192 bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) { 1193 const size_t snugRB = buffer->readUInt(); 1194 if (0 == snugRB) { // no pixels 1195 return false; 1196 } 1197 1198 SkImageInfo info; 1199 info.unflatten(*buffer); 1200 1201 // If there was an error reading "info", don't use it to compute minRowBytes() 1202 if (!buffer->validate(true)) { 1203 return false; 1204 } 1205 1206 const size_t ramRB = info.minRowBytes(); 1207 const int height = info.height(); 1208 const size_t snugSize = snugRB * height; 1209 const size_t ramSize = ramRB * height; 1210 if (!buffer->validate(snugSize <= ramSize)) { 1211 return false; 1212 } 1213 1214 SkAutoDataUnref data(SkData::NewUninitialized(ramSize)); 1215 char* dst = (char*)data->writable_data(); 1216 buffer->readByteArray(dst, snugSize); 1217 1218 if (snugSize != ramSize) { 1219 const char* srcRow = dst + snugRB * (height - 1); 1220 char* dstRow = dst + ramRB * (height - 1); 1221 for (int y = height - 1; y >= 1; --y) { 1222 memmove(dstRow, srcRow, snugRB); 1223 srcRow -= snugRB; 1224 dstRow -= ramRB; 1225 } 1226 SkASSERT(srcRow == dstRow); // first row does not need to be moved 1227 } 1228 1229 SkAutoTUnref<SkColorTable> ctable; 1230 if (buffer->readBool()) { 1231 ctable.reset(SkNEW_ARGS(SkColorTable, (*buffer))); 1232 } 1233 1234 SkAutoTUnref<SkPixelRef> pr(SkMallocPixelRef::NewWithData(info, info.minRowBytes(), 1235 ctable.get(), data.get())); 1236 bitmap->setInfo(pr->info()); 1237 bitmap->setPixelRef(pr, 0, 0); 1238 return true; 1239 } 1240 1241 enum { 1242 SERIALIZE_PIXELTYPE_NONE, 1243 SERIALIZE_PIXELTYPE_REF_DATA 1244 }; 1245 1246 void SkBitmap::legacyUnflatten(SkReadBuffer& buffer) { 1247 #ifdef SK_SUPPORT_LEGACY_PIXELREF_UNFLATTENABLE 1248 this->reset(); 1249 1250 SkImageInfo info; 1251 info.unflatten(buffer); 1252 size_t rowBytes = buffer.readInt(); 1253 if (!buffer.validate((info.width() >= 0) && (info.height() >= 0) && 1254 SkColorTypeIsValid(info.fColorType) && 1255 SkAlphaTypeIsValid(info.fAlphaType) && 1256 SkColorTypeValidateAlphaType(info.fColorType, info.fAlphaType) && 1257 info.validRowBytes(rowBytes))) { 1258 return; 1259 } 1260 1261 bool configIsValid = this->setInfo(info, rowBytes); 1262 buffer.validate(configIsValid); 1263 1264 int reftype = buffer.readInt(); 1265 if (buffer.validate((SERIALIZE_PIXELTYPE_REF_DATA == reftype) || 1266 (SERIALIZE_PIXELTYPE_NONE == reftype))) { 1267 switch (reftype) { 1268 case SERIALIZE_PIXELTYPE_REF_DATA: { 1269 SkIPoint origin; 1270 origin.fX = buffer.readInt(); 1271 origin.fY = buffer.readInt(); 1272 size_t offset = origin.fY * rowBytes + origin.fX * info.bytesPerPixel(); 1273 SkPixelRef* pr = buffer.readFlattenable<SkPixelRef>(); 1274 if (!buffer.validate((NULL == pr) || 1275 (pr->getAllocatedSizeInBytes() >= (offset + this->getSafeSize())))) { 1276 origin.setZero(); 1277 } 1278 SkSafeUnref(this->setPixelRef(pr, origin)); 1279 break; 1280 } 1281 case SERIALIZE_PIXELTYPE_NONE: 1282 break; 1283 default: 1284 SkDEBUGFAIL("unrecognized pixeltype in serialized data"); 1285 sk_throw(); 1286 } 1287 } 1288 #else 1289 sk_throw(); 1290 #endif 1291 } 1292 1293 /////////////////////////////////////////////////////////////////////////////// 1294 1295 SkBitmap::RLEPixels::RLEPixels(int width, int height) { 1296 fHeight = height; 1297 fYPtrs = (uint8_t**)sk_calloc_throw(height * sizeof(uint8_t*)); 1298 } 1299 1300 SkBitmap::RLEPixels::~RLEPixels() { 1301 sk_free(fYPtrs); 1302 } 1303 1304 /////////////////////////////////////////////////////////////////////////////// 1305 1306 #ifdef SK_DEBUG 1307 void SkBitmap::validate() const { 1308 fInfo.validate(); 1309 1310 // ImageInfo may not require this, but Bitmap ensures that opaque-only 1311 // colorTypes report opaque for their alphatype 1312 if (kRGB_565_SkColorType == fInfo.colorType()) { 1313 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType()); 1314 } 1315 1316 SkASSERT(fInfo.validRowBytes(fRowBytes)); 1317 uint8_t allFlags = kImageIsVolatile_Flag; 1318 #ifdef SK_BUILD_FOR_ANDROID 1319 allFlags |= kHasHardwareMipMap_Flag; 1320 #endif 1321 SkASSERT((~allFlags & fFlags) == 0); 1322 SkASSERT(fPixelLockCount >= 0); 1323 1324 if (fPixels) { 1325 SkASSERT(fPixelRef); 1326 SkASSERT(fPixelLockCount > 0); 1327 SkASSERT(fPixelRef->isLocked()); 1328 SkASSERT(fPixelRef->rowBytes() == fRowBytes); 1329 SkASSERT(fPixelRefOrigin.fX >= 0); 1330 SkASSERT(fPixelRefOrigin.fY >= 0); 1331 SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX); 1332 SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY); 1333 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes()); 1334 } else { 1335 SkASSERT(NULL == fColorTable); 1336 } 1337 } 1338 #endif 1339 1340 #ifndef SK_IGNORE_TO_STRING 1341 void SkBitmap::toString(SkString* str) const { 1342 1343 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = { 1344 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8", 1345 }; 1346 1347 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(), 1348 gColorTypeNames[this->colorType()]); 1349 1350 str->append(" ("); 1351 if (this->isOpaque()) { 1352 str->append("opaque"); 1353 } else { 1354 str->append("transparent"); 1355 } 1356 if (this->isImmutable()) { 1357 str->append(", immutable"); 1358 } else { 1359 str->append(", not-immutable"); 1360 } 1361 str->append(")"); 1362 1363 SkPixelRef* pr = this->pixelRef(); 1364 if (NULL == pr) { 1365 // show null or the explicit pixel address (rare) 1366 str->appendf(" pixels:%p", this->getPixels()); 1367 } else { 1368 const char* uri = pr->getURI(); 1369 if (uri) { 1370 str->appendf(" uri:\"%s\"", uri); 1371 } else { 1372 str->appendf(" pixelref:%p", pr); 1373 } 1374 } 1375 1376 str->append(")"); 1377 } 1378 #endif 1379 1380 /////////////////////////////////////////////////////////////////////////////// 1381 1382 #ifdef SK_DEBUG 1383 void SkImageInfo::validate() const { 1384 SkASSERT(fWidth >= 0); 1385 SkASSERT(fHeight >= 0); 1386 SkASSERT(SkColorTypeIsValid(fColorType)); 1387 SkASSERT(SkAlphaTypeIsValid(fAlphaType)); 1388 } 1389 #endif 1390