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