SkBitmap.cpp revision 92fc2ae58331662ec411a048686cb4801e0a909a
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.width()), SkIntToScalar(fInfo.height())); 98} 99 100void SkBitmap::getBounds(SkIRect* bounds) const { 101 SkASSERT(bounds); 102 bounds->set(0, 0, fInfo.width(), fInfo.height()); 103} 104 105/////////////////////////////////////////////////////////////////////////////// 106 107bool 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 142bool 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 155void 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 176SkPixelRef* 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 kUnknown_SkAlphaType: 186 SkASSERT(fInfo.alphaType() == kUnknown_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 223void SkBitmap::lockPixels() const { 224 if (fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) { 225 fPixelRef->lockPixels(); 226 this->updatePixelsFromRef(); 227 } 228 SkDEBUGCODE(this->validate();) 229} 230 231void 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 241bool SkBitmap::lockPixelsAreWritable() const { 242 return (fPixelRef) ? fPixelRef->lockPixelsAreWritable() : false; 243} 244 245void 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 269bool 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 280bool 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 309bool 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 340bool 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 366bool 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 378void 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 392uint32_t SkBitmap::getGenerationID() const { 393 return (fPixelRef) ? fPixelRef->getGenerationID() : 0; 394} 395 396void SkBitmap::notifyPixelsChanged() const { 397 SkASSERT(!this->isImmutable()); 398 if (fPixelRef) { 399 fPixelRef->notifyPixelsChanged(); 400 } 401} 402 403GrTexture* 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 */ 412bool 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 433static bool copy_pixels_to(const SkPixmap& src, void* const dst, size_t dstSize, 434 size_t dstRowBytes, bool preserveDstPad) { 435 const SkImageInfo& info = src.info(); 436 437 if (0 == dstRowBytes) { 438 dstRowBytes = src.rowBytes(); 439 } 440 if (dstRowBytes < info.minRowBytes()) { 441 return false; 442 } 443 444 if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == src.rowBytes()) { 445 size_t safeSize = src.getSafeSize(); 446 if (safeSize > dstSize || safeSize == 0) 447 return false; 448 else { 449 // This implementation will write bytes beyond the end of each row, 450 // excluding the last row, if the bitmap's stride is greater than 451 // strictly required by the current config. 452 memcpy(dst, src.addr(), safeSize); 453 return true; 454 } 455 } else { 456 // If destination has different stride than us, then copy line by line. 457 if (info.getSafeSize(dstRowBytes) > dstSize) { 458 return false; 459 } else { 460 // Just copy what we need on each line. 461 size_t rowBytes = info.minRowBytes(); 462 const uint8_t* srcP = reinterpret_cast<const uint8_t*>(src.addr()); 463 uint8_t* dstP = reinterpret_cast<uint8_t*>(dst); 464 for (int row = 0; row < info.height(); ++row) { 465 memcpy(dstP, srcP, rowBytes); 466 srcP += src.rowBytes(); 467 dstP += dstRowBytes; 468 } 469 470 return true; 471 } 472 } 473} 474 475bool SkBitmap::copyPixelsTo(void* dst, size_t dstSize, size_t dstRB, bool preserveDstPad) const { 476 if (NULL == dst) { 477 return false; 478 } 479 SkAutoPixmapUnlock result; 480 if (!this->requestLock(&result)) { 481 return false; 482 } 483 return copy_pixels_to(result.pixmap(), dst, dstSize, dstRB, preserveDstPad); 484} 485 486/////////////////////////////////////////////////////////////////////////////// 487 488bool SkBitmap::isImmutable() const { 489 return fPixelRef ? fPixelRef->isImmutable() : false; 490} 491 492void SkBitmap::setImmutable() { 493 if (fPixelRef) { 494 fPixelRef->setImmutable(); 495 } 496} 497 498bool SkBitmap::isVolatile() const { 499 return (fFlags & kImageIsVolatile_Flag) != 0; 500} 501 502void SkBitmap::setIsVolatile(bool isVolatile) { 503 if (isVolatile) { 504 fFlags |= kImageIsVolatile_Flag; 505 } else { 506 fFlags &= ~kImageIsVolatile_Flag; 507 } 508} 509 510void* SkBitmap::getAddr(int x, int y) const { 511 SkASSERT((unsigned)x < (unsigned)this->width()); 512 SkASSERT((unsigned)y < (unsigned)this->height()); 513 514 char* base = (char*)this->getPixels(); 515 if (base) { 516 base += y * this->rowBytes(); 517 switch (this->colorType()) { 518 case kRGBA_8888_SkColorType: 519 case kBGRA_8888_SkColorType: 520 base += x << 2; 521 break; 522 case kARGB_4444_SkColorType: 523 case kRGB_565_SkColorType: 524 base += x << 1; 525 break; 526 case kAlpha_8_SkColorType: 527 case kIndex_8_SkColorType: 528 case kGray_8_SkColorType: 529 base += x; 530 break; 531 default: 532 SkDEBUGFAIL("Can't return addr for config"); 533 base = NULL; 534 break; 535 } 536 } 537 return base; 538} 539 540SkColor SkBitmap::getColor(int x, int y) const { 541 SkASSERT((unsigned)x < (unsigned)this->width()); 542 SkASSERT((unsigned)y < (unsigned)this->height()); 543 544 switch (this->colorType()) { 545 case kGray_8_SkColorType: { 546 uint8_t* addr = this->getAddr8(x, y); 547 return SkColorSetRGB(*addr, *addr, *addr); 548 } 549 case kAlpha_8_SkColorType: { 550 uint8_t* addr = this->getAddr8(x, y); 551 return SkColorSetA(0, addr[0]); 552 } 553 case kIndex_8_SkColorType: { 554 SkPMColor c = this->getIndex8Color(x, y); 555 return SkUnPreMultiply::PMColorToColor(c); 556 } 557 case kRGB_565_SkColorType: { 558 uint16_t* addr = this->getAddr16(x, y); 559 return SkPixel16ToColor(addr[0]); 560 } 561 case kARGB_4444_SkColorType: { 562 uint16_t* addr = this->getAddr16(x, y); 563 SkPMColor c = SkPixel4444ToPixel32(addr[0]); 564 return SkUnPreMultiply::PMColorToColor(c); 565 } 566 case kBGRA_8888_SkColorType: 567 case kRGBA_8888_SkColorType: { 568 uint32_t* addr = this->getAddr32(x, y); 569 return SkUnPreMultiply::PMColorToColor(addr[0]); 570 } 571 default: 572 SkASSERT(false); 573 return 0; 574 } 575 SkASSERT(false); // Not reached. 576 return 0; 577} 578 579static bool compute_is_opaque(const SkPixmap& pmap) { 580 const int height = pmap.height(); 581 const int width = pmap.width(); 582 583 switch (pmap.colorType()) { 584 case kAlpha_8_SkColorType: { 585 unsigned a = 0xFF; 586 for (int y = 0; y < height; ++y) { 587 const uint8_t* row = pmap.addr8(0, y); 588 for (int x = 0; x < width; ++x) { 589 a &= row[x]; 590 } 591 if (0xFF != a) { 592 return false; 593 } 594 } 595 return true; 596 } break; 597 case kIndex_8_SkColorType: { 598 const SkColorTable* ctable = pmap.ctable(); 599 if (NULL == ctable) { 600 return false; 601 } 602 const SkPMColor* table = ctable->readColors(); 603 SkPMColor c = (SkPMColor)~0; 604 for (int i = ctable->count() - 1; i >= 0; --i) { 605 c &= table[i]; 606 } 607 return 0xFF == SkGetPackedA32(c); 608 } break; 609 case kRGB_565_SkColorType: 610 case kGray_8_SkColorType: 611 return true; 612 break; 613 case kARGB_4444_SkColorType: { 614 unsigned c = 0xFFFF; 615 for (int y = 0; y < height; ++y) { 616 const SkPMColor16* row = pmap.addr16(0, y); 617 for (int x = 0; x < width; ++x) { 618 c &= row[x]; 619 } 620 if (0xF != SkGetPackedA4444(c)) { 621 return false; 622 } 623 } 624 return true; 625 } break; 626 case kBGRA_8888_SkColorType: 627 case kRGBA_8888_SkColorType: { 628 SkPMColor c = (SkPMColor)~0; 629 for (int y = 0; y < height; ++y) { 630 const SkPMColor* row = pmap.addr32(0, y); 631 for (int x = 0; x < width; ++x) { 632 c &= row[x]; 633 } 634 if (0xFF != SkGetPackedA32(c)) { 635 return false; 636 } 637 } 638 return true; 639 } 640 default: 641 break; 642 } 643 return false; 644} 645 646bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) { 647 SkAutoPixmapUnlock result; 648 if (!bm.requestLock(&result)) { 649 return false; 650 } 651 return compute_is_opaque(result.pixmap()); 652} 653 654 655/////////////////////////////////////////////////////////////////////////////// 656/////////////////////////////////////////////////////////////////////////////// 657 658static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) { 659 unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) | 660 (SkR32To4444(r) << SK_R4444_SHIFT) | 661 (SkG32To4444(g) << SK_G4444_SHIFT) | 662 (SkB32To4444(b) << SK_B4444_SHIFT); 663 return SkToU16(pixel); 664} 665 666static bool internal_erase(const SkPixmap& pmap, const SkIRect& area, 667 U8CPU a, U8CPU r, U8CPU g, U8CPU b) { 668 int height = area.height(); 669 const int width = area.width(); 670 const int rowBytes = pmap.rowBytes(); 671 672 switch (pmap.colorType()) { 673 case kGray_8_SkColorType: { 674 if (255 != a) { 675 r = SkMulDiv255Round(r, a); 676 g = SkMulDiv255Round(g, a); 677 b = SkMulDiv255Round(b, a); 678 } 679 int gray = SkComputeLuminance(r, g, b); 680 uint8_t* p = pmap.writable_addr8(area.fLeft, area.fTop); 681 while (--height >= 0) { 682 memset(p, gray, width); 683 p += rowBytes; 684 } 685 break; 686 } 687 case kAlpha_8_SkColorType: { 688 uint8_t* p = pmap.writable_addr8(area.fLeft, area.fTop); 689 while (--height >= 0) { 690 memset(p, a, width); 691 p += rowBytes; 692 } 693 break; 694 } 695 case kARGB_4444_SkColorType: 696 case kRGB_565_SkColorType: { 697 uint16_t* p = pmap.writable_addr16(area.fLeft, area.fTop); 698 uint16_t v; 699 700 // make rgb premultiplied 701 if (255 != a) { 702 r = SkAlphaMul(r, a); 703 g = SkAlphaMul(g, a); 704 b = SkAlphaMul(b, a); 705 } 706 707 if (kARGB_4444_SkColorType == pmap.colorType()) { 708 v = pack_8888_to_4444(a, r, g, b); 709 } else { 710 v = SkPackRGB16(r >> (8 - SK_R16_BITS), 711 g >> (8 - SK_G16_BITS), 712 b >> (8 - SK_B16_BITS)); 713 } 714 while (--height >= 0) { 715 sk_memset16(p, v, width); 716 p = (uint16_t*)((char*)p + rowBytes); 717 } 718 break; 719 } 720 case kBGRA_8888_SkColorType: 721 case kRGBA_8888_SkColorType: { 722 uint32_t* p = pmap.writable_addr32(area.fLeft, area.fTop); 723 724 if (255 != a && kPremul_SkAlphaType == pmap.alphaType()) { 725 r = SkAlphaMul(r, a); 726 g = SkAlphaMul(g, a); 727 b = SkAlphaMul(b, a); 728 } 729 uint32_t v = kRGBA_8888_SkColorType == pmap.colorType() ? 730 SkPackARGB_as_RGBA(a, r, g, b) : SkPackARGB_as_BGRA(a, r, g, b); 731 732 while (--height >= 0) { 733 sk_memset32(p, v, width); 734 p = (uint32_t*)((char*)p + rowBytes); 735 } 736 break; 737 } 738 default: 739 return false; // no change, so don't call notifyPixelsChanged() 740 } 741 return true; 742} 743 744void SkBitmap::internalErase(const SkIRect& area, U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { 745#ifdef SK_DEBUG 746 SkDEBUGCODE(this->validate();) 747 SkASSERT(!area.isEmpty()); 748 { 749 SkIRect total = { 0, 0, this->width(), this->height() }; 750 SkASSERT(total.contains(area)); 751 } 752#endif 753 754 switch (fInfo.colorType()) { 755 case kUnknown_SkColorType: 756 case kIndex_8_SkColorType: 757 // TODO: can we ASSERT that we never get here? 758 return; // can't erase. Should we bzero so the memory is not uninitialized? 759 default: 760 break; 761 } 762 763 SkAutoPixmapUnlock result; 764 if (!this->requestLock(&result)) { 765 return; 766 } 767 768 if (internal_erase(result.pixmap(), area, a, r, g, b)) { 769 this->notifyPixelsChanged(); 770 } 771} 772 773void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { 774 SkIRect area = { 0, 0, this->width(), this->height() }; 775 if (!area.isEmpty()) { 776 this->internalErase(area, a, r, g, b); 777 } 778} 779 780void SkBitmap::eraseArea(const SkIRect& rect, SkColor c) const { 781 SkIRect area = { 0, 0, this->width(), this->height() }; 782 if (area.intersect(rect)) { 783 this->internalErase(area, SkColorGetA(c), SkColorGetR(c), 784 SkColorGetG(c), SkColorGetB(c)); 785 } 786} 787 788////////////////////////////////////////////////////////////////////////////////////// 789////////////////////////////////////////////////////////////////////////////////////// 790 791bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { 792 SkDEBUGCODE(this->validate();) 793 794 if (NULL == result || NULL == fPixelRef) { 795 return false; // no src pixels 796 } 797 798 SkIRect srcRect, r; 799 srcRect.set(0, 0, this->width(), this->height()); 800 if (!r.intersect(srcRect, subset)) { 801 return false; // r is empty (i.e. no intersection) 802 } 803 804 if (fPixelRef->getTexture() != NULL) { 805 // Do a deep copy 806 SkPixelRef* pixelRef = fPixelRef->deepCopy(this->colorType(), this->profileType(), &subset); 807 if (pixelRef != NULL) { 808 SkBitmap dst; 809 dst.setInfo(SkImageInfo::Make(subset.width(), subset.height(), 810 this->colorType(), this->alphaType())); 811 dst.setIsVolatile(this->isVolatile()); 812 dst.setPixelRef(pixelRef)->unref(); 813 SkDEBUGCODE(dst.validate()); 814 result->swap(dst); 815 return true; 816 } 817 } 818 819 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have 820 // exited above. 821 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width())); 822 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height())); 823 824 SkBitmap dst; 825 dst.setInfo(SkImageInfo::Make(r.width(), r.height(), this->colorType(), this->alphaType()), 826 this->rowBytes()); 827 dst.setIsVolatile(this->isVolatile()); 828 829 if (fPixelRef) { 830 SkIPoint origin = fPixelRefOrigin; 831 origin.fX += r.fLeft; 832 origin.fY += r.fTop; 833 // share the pixelref with a custom offset 834 dst.setPixelRef(fPixelRef, origin); 835 } 836 SkDEBUGCODE(dst.validate();) 837 838 // we know we're good, so commit to result 839 result->swap(dst); 840 return true; 841} 842 843/////////////////////////////////////////////////////////////////////////////// 844 845#include "SkCanvas.h" 846#include "SkPaint.h" 847 848bool SkBitmap::canCopyTo(SkColorType dstColorType) const { 849 const SkColorType srcCT = this->colorType(); 850 851 if (srcCT == kUnknown_SkColorType) { 852 return false; 853 } 854 855 bool sameConfigs = (srcCT == dstColorType); 856 switch (dstColorType) { 857 case kAlpha_8_SkColorType: 858 case kRGB_565_SkColorType: 859 case kRGBA_8888_SkColorType: 860 case kBGRA_8888_SkColorType: 861 break; 862 case kIndex_8_SkColorType: 863 if (!sameConfigs) { 864 return false; 865 } 866 break; 867 case kARGB_4444_SkColorType: 868 return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT; 869 case kGray_8_SkColorType: 870 switch (srcCT) { 871 case kGray_8_SkColorType: 872 case kRGBA_8888_SkColorType: 873 case kBGRA_8888_SkColorType: 874 return true; 875 default: 876 break; 877 } 878 return false; 879 default: 880 return false; 881 } 882 return true; 883} 884 885#include "SkConfig8888.h" 886 887bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB, 888 int x, int y) const { 889 if (kUnknown_SkColorType == requestedDstInfo.colorType()) { 890 return false; 891 } 892 if (NULL == dstPixels || dstRB < requestedDstInfo.minRowBytes()) { 893 return false; 894 } 895 if (0 == requestedDstInfo.width() || 0 == requestedDstInfo.height()) { 896 return false; 897 } 898 899 SkIRect srcR = SkIRect::MakeXYWH(x, y, requestedDstInfo.width(), requestedDstInfo.height()); 900 if (!srcR.intersect(0, 0, this->width(), this->height())) { 901 return false; 902 } 903 904 // the intersect may have shrunk info's logical size 905 const SkImageInfo dstInfo = requestedDstInfo.makeWH(srcR.width(), srcR.height()); 906 907 // if x or y are negative, then we have to adjust pixels 908 if (x > 0) { 909 x = 0; 910 } 911 if (y > 0) { 912 y = 0; 913 } 914 // here x,y are either 0 or negative 915 dstPixels = ((char*)dstPixels - y * dstRB - x * dstInfo.bytesPerPixel()); 916 917 ////////////// 918 919 SkAutoPixmapUnlock result; 920 if (!this->requestLock(&result)) { 921 return false; 922 } 923 const SkPixmap& pmap = result.pixmap(); 924 const SkImageInfo srcInfo = pmap.info().makeWH(dstInfo.width(), dstInfo.height()); 925 926 const void* srcPixels = pmap.addr(srcR.x(), srcR.y()); 927 return SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, pmap.rowBytes(), 928 pmap.ctable()); 929} 930 931bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const { 932 if (!this->canCopyTo(dstColorType)) { 933 return false; 934 } 935 936 // if we have a texture, first get those pixels 937 SkBitmap tmpSrc; 938 const SkBitmap* src = this; 939 940 if (fPixelRef) { 941 SkIRect subset; 942 subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY, 943 fInfo.width(), fInfo.height()); 944 if (fPixelRef->readPixels(&tmpSrc, &subset)) { 945 if (fPixelRef->info().alphaType() == kUnpremul_SkAlphaType) { 946 // FIXME: The only meaningful implementation of readPixels 947 // (GrPixelRef) assumes premultiplied pixels. 948 return false; 949 } 950 SkASSERT(tmpSrc.width() == this->width()); 951 SkASSERT(tmpSrc.height() == this->height()); 952 953 // did we get lucky and we can just return tmpSrc? 954 if (tmpSrc.colorType() == dstColorType && NULL == alloc) { 955 dst->swap(tmpSrc); 956 // If the result is an exact copy, clone the gen ID. 957 if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) { 958 dst->pixelRef()->cloneGenID(*fPixelRef); 959 } 960 return true; 961 } 962 963 // fall through to the raster case 964 src = &tmpSrc; 965 } 966 } 967 968 // we lock this now, since we may need its colortable 969 SkAutoLockPixels srclock(*src); 970 if (!src->readyToDraw()) { 971 return false; 972 } 973 974 // The only way to be readyToDraw is if fPixelRef is non NULL. 975 SkASSERT(fPixelRef != NULL); 976 977 const SkImageInfo dstInfo = src->info().makeColorType(dstColorType); 978 979 SkBitmap tmpDst; 980 if (!tmpDst.setInfo(dstInfo)) { 981 return false; 982 } 983 984 // allocate colortable if srcConfig == kIndex8_Config 985 SkAutoTUnref<SkColorTable> ctable; 986 if (dstColorType == kIndex_8_SkColorType) { 987 ctable.reset(SkRef(src->getColorTable())); 988 } 989 if (!tmpDst.tryAllocPixels(alloc, ctable)) { 990 return false; 991 } 992 993 if (!tmpDst.readyToDraw()) { 994 // allocator/lock failed 995 return false; 996 } 997 998 // pixelRef must be non NULL or tmpDst.readyToDraw() would have 999 // returned false. 1000 SkASSERT(tmpDst.pixelRef() != NULL); 1001 1002 if (!src->readPixels(tmpDst.info(), tmpDst.getPixels(), tmpDst.rowBytes(), 0, 0)) { 1003 return false; 1004 } 1005 1006 // (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref. 1007 // The old copyTo impl did this, so we continue it for now. 1008 // 1009 // TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be 1010 // if (src_pixelref->info == dst_pixelref->info) 1011 // 1012 if (src->colorType() == dstColorType && tmpDst.getSize() == src->getSize()) { 1013 SkPixelRef* dstPixelRef = tmpDst.pixelRef(); 1014 if (dstPixelRef->info() == fPixelRef->info()) { 1015 dstPixelRef->cloneGenID(*fPixelRef); 1016 } 1017 } 1018 1019 dst->swap(tmpDst); 1020 return true; 1021} 1022 1023bool SkBitmap::deepCopyTo(SkBitmap* dst) const { 1024 const SkColorType dstCT = this->colorType(); 1025 const SkColorProfileType dstPT = this->profileType(); 1026 1027 if (!this->canCopyTo(dstCT)) { 1028 return false; 1029 } 1030 1031 // If we have a PixelRef, and it supports deep copy, use it. 1032 // Currently supported only by texture-backed bitmaps. 1033 if (fPixelRef) { 1034 SkPixelRef* pixelRef = fPixelRef->deepCopy(dstCT, dstPT, NULL); 1035 if (pixelRef) { 1036 uint32_t rowBytes; 1037 if (this->colorType() == dstCT && this->profileType() == dstPT) { 1038 // Since there is no subset to pass to deepCopy, and deepCopy 1039 // succeeded, the new pixel ref must be identical. 1040 SkASSERT(fPixelRef->info() == pixelRef->info()); 1041 pixelRef->cloneGenID(*fPixelRef); 1042 // Use the same rowBytes as the original. 1043 rowBytes = fRowBytes; 1044 } else { 1045 // With the new config, an appropriate fRowBytes will be computed by setInfo. 1046 rowBytes = 0; 1047 } 1048 1049 const SkImageInfo info = fInfo.makeColorType(dstCT); 1050 if (!dst->setInfo(info, rowBytes)) { 1051 return false; 1052 } 1053 dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref(); 1054 return true; 1055 } 1056 } 1057 1058 if (this->getTexture()) { 1059 return false; 1060 } else { 1061 return this->copyTo(dst, dstCT, NULL); 1062 } 1063} 1064 1065/////////////////////////////////////////////////////////////////////////////// 1066 1067static void rect_memset(uint8_t* array, U8CPU value, SkISize size, size_t rowBytes) { 1068 for (int y = 0; y < size.height(); ++y) { 1069 memset(array, value, size.width()); 1070 array += rowBytes; 1071 } 1072} 1073 1074static void get_bitmap_alpha(const SkPixmap& pmap, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) { 1075 SkColorType colorType = pmap.colorType(); 1076 int w = pmap.width(); 1077 int h = pmap.height(); 1078 size_t rb = pmap.rowBytes(); 1079 1080 if (kAlpha_8_SkColorType == colorType && !pmap.isOpaque()) { 1081 const uint8_t* s = pmap.addr8(0, 0); 1082 while (--h >= 0) { 1083 memcpy(alpha, s, w); 1084 s += rb; 1085 alpha += alphaRowBytes; 1086 } 1087 } else if (kN32_SkColorType == colorType && !pmap.isOpaque()) { 1088 const SkPMColor* SK_RESTRICT s = pmap.addr32(0, 0); 1089 while (--h >= 0) { 1090 for (int x = 0; x < w; x++) { 1091 alpha[x] = SkGetPackedA32(s[x]); 1092 } 1093 s = (const SkPMColor*)((const char*)s + rb); 1094 alpha += alphaRowBytes; 1095 } 1096 } else if (kARGB_4444_SkColorType == colorType && !pmap.isOpaque()) { 1097 const SkPMColor16* SK_RESTRICT s = pmap.addr16(0, 0); 1098 while (--h >= 0) { 1099 for (int x = 0; x < w; x++) { 1100 alpha[x] = SkPacked4444ToA32(s[x]); 1101 } 1102 s = (const SkPMColor16*)((const char*)s + rb); 1103 alpha += alphaRowBytes; 1104 } 1105 } else if (kIndex_8_SkColorType == colorType && !pmap.isOpaque()) { 1106 const SkColorTable* ct = pmap.ctable(); 1107 if (ct) { 1108 const SkPMColor* SK_RESTRICT table = ct->readColors(); 1109 const uint8_t* SK_RESTRICT s = pmap.addr8(0, 0); 1110 while (--h >= 0) { 1111 for (int x = 0; x < w; x++) { 1112 alpha[x] = SkGetPackedA32(table[s[x]]); 1113 } 1114 s += rb; 1115 alpha += alphaRowBytes; 1116 } 1117 } 1118 } else { // src is opaque, so just fill alpha[] with 0xFF 1119 rect_memset(alpha, 0xFF, pmap.info().dimensions(), alphaRowBytes); 1120 } 1121} 1122 1123static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) { 1124 SkASSERT(alpha != NULL); 1125 SkASSERT(alphaRowBytes >= src.width()); 1126 1127 SkAutoPixmapUnlock apl; 1128 if (!src.requestLock(&apl)) { 1129 rect_memset(alpha, 0, src.info().dimensions(), alphaRowBytes); 1130 return false; 1131 } 1132 get_bitmap_alpha(apl.pixmap(), alpha, alphaRowBytes); 1133 return true; 1134} 1135 1136#include "SkPaint.h" 1137#include "SkMaskFilter.h" 1138#include "SkMatrix.h" 1139 1140bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, 1141 Allocator *allocator, SkIPoint* offset) const { 1142 SkDEBUGCODE(this->validate();) 1143 1144 SkBitmap tmpBitmap; 1145 SkMatrix identity; 1146 SkMask srcM, dstM; 1147 1148 srcM.fBounds.set(0, 0, this->width(), this->height()); 1149 srcM.fRowBytes = SkAlign4(this->width()); 1150 srcM.fFormat = SkMask::kA8_Format; 1151 1152 SkMaskFilter* filter = paint ? paint->getMaskFilter() : NULL; 1153 1154 // compute our (larger?) dst bounds if we have a filter 1155 if (filter) { 1156 identity.reset(); 1157 srcM.fImage = NULL; 1158 if (!filter->filterMask(&dstM, srcM, identity, NULL)) { 1159 goto NO_FILTER_CASE; 1160 } 1161 dstM.fRowBytes = SkAlign4(dstM.fBounds.width()); 1162 } else { 1163 NO_FILTER_CASE: 1164 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes); 1165 if (!tmpBitmap.tryAllocPixels(allocator, NULL)) { 1166 // Allocation of pixels for alpha bitmap failed. 1167 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 1168 tmpBitmap.width(), tmpBitmap.height()); 1169 return false; 1170 } 1171 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes); 1172 if (offset) { 1173 offset->set(0, 0); 1174 } 1175 tmpBitmap.swap(*dst); 1176 return true; 1177 } 1178 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize()); 1179 SkAutoMaskFreeImage srcCleanup(srcM.fImage); 1180 1181 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes); 1182 if (!filter->filterMask(&dstM, srcM, identity, NULL)) { 1183 goto NO_FILTER_CASE; 1184 } 1185 SkAutoMaskFreeImage dstCleanup(dstM.fImage); 1186 1187 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()), 1188 dstM.fRowBytes); 1189 if (!tmpBitmap.tryAllocPixels(allocator, NULL)) { 1190 // Allocation of pixels for alpha bitmap failed. 1191 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 1192 tmpBitmap.width(), tmpBitmap.height()); 1193 return false; 1194 } 1195 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize()); 1196 if (offset) { 1197 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop); 1198 } 1199 SkDEBUGCODE(tmpBitmap.validate();) 1200 1201 tmpBitmap.swap(*dst); 1202 return true; 1203} 1204 1205/////////////////////////////////////////////////////////////////////////////// 1206 1207static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) { 1208 const SkImageInfo& info = pmap.info(); 1209 const size_t snugRB = info.width() * info.bytesPerPixel(); 1210 const char* src = (const char*)pmap.addr(); 1211 const size_t ramRB = pmap.rowBytes(); 1212 1213 buffer->write32(SkToU32(snugRB)); 1214 info.flatten(*buffer); 1215 1216 const size_t size = snugRB * info.height(); 1217 SkAutoMalloc storage(size); 1218 char* dst = (char*)storage.get(); 1219 for (int y = 0; y < info.height(); ++y) { 1220 memcpy(dst, src, snugRB); 1221 dst += snugRB; 1222 src += ramRB; 1223 } 1224 buffer->writeByteArray(storage.get(), size); 1225 1226 const SkColorTable* ct = pmap.ctable(); 1227 if (kIndex_8_SkColorType == info.colorType() && ct) { 1228 buffer->writeBool(true); 1229 ct->writeToBuffer(*buffer); 1230 } else { 1231 buffer->writeBool(false); 1232 } 1233} 1234 1235void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) { 1236 const SkImageInfo info = bitmap.info(); 1237 if (0 == info.width() || 0 == info.height() || NULL == bitmap.pixelRef()) { 1238 buffer->writeUInt(0); // instead of snugRB, signaling no pixels 1239 return; 1240 } 1241 1242 SkAutoPixmapUnlock result; 1243 if (!bitmap.requestLock(&result)) { 1244 buffer->writeUInt(0); // instead of snugRB, signaling no pixels 1245 return; 1246 } 1247 1248 write_raw_pixels(buffer, result.pixmap()); 1249} 1250 1251bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) { 1252 const size_t snugRB = buffer->readUInt(); 1253 if (0 == snugRB) { // no pixels 1254 return false; 1255 } 1256 1257 SkImageInfo info; 1258 info.unflatten(*buffer); 1259 1260 // If there was an error reading "info", don't use it to compute minRowBytes() 1261 if (!buffer->validate(true)) { 1262 return false; 1263 } 1264 1265 const size_t ramRB = info.minRowBytes(); 1266 const int height = SkMax32(info.height(), 0); 1267 const uint64_t snugSize = sk_64_mul(snugRB, height); 1268 const uint64_t ramSize = sk_64_mul(ramRB, height); 1269 static const uint64_t max_size_t = (size_t)(-1); 1270 if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) { 1271 return false; 1272 } 1273 1274 SkAutoDataUnref data(SkData::NewUninitialized(SkToSizeT(ramSize))); 1275 char* dst = (char*)data->writable_data(); 1276 buffer->readByteArray(dst, SkToSizeT(snugSize)); 1277 1278 if (snugSize != ramSize) { 1279 const char* srcRow = dst + snugRB * (height - 1); 1280 char* dstRow = dst + ramRB * (height - 1); 1281 for (int y = height - 1; y >= 1; --y) { 1282 memmove(dstRow, srcRow, snugRB); 1283 srcRow -= snugRB; 1284 dstRow -= ramRB; 1285 } 1286 SkASSERT(srcRow == dstRow); // first row does not need to be moved 1287 } 1288 1289 SkAutoTUnref<SkColorTable> ctable; 1290 if (buffer->readBool()) { 1291 ctable.reset(SkNEW_ARGS(SkColorTable, (*buffer))); 1292 } 1293 1294 SkAutoTUnref<SkPixelRef> pr(SkMallocPixelRef::NewWithData(info, info.minRowBytes(), 1295 ctable.get(), data.get())); 1296 if (!pr.get()) { 1297 return false; 1298 } 1299 bitmap->setInfo(pr->info()); 1300 bitmap->setPixelRef(pr, 0, 0); 1301 return true; 1302} 1303 1304enum { 1305 SERIALIZE_PIXELTYPE_NONE, 1306 SERIALIZE_PIXELTYPE_REF_DATA 1307}; 1308 1309/////////////////////////////////////////////////////////////////////////////// 1310 1311SkBitmap::RLEPixels::RLEPixels(int width, int height) { 1312 fHeight = height; 1313 fYPtrs = (uint8_t**)sk_calloc_throw(height * sizeof(uint8_t*)); 1314} 1315 1316SkBitmap::RLEPixels::~RLEPixels() { 1317 sk_free(fYPtrs); 1318} 1319 1320/////////////////////////////////////////////////////////////////////////////// 1321 1322#ifdef SK_DEBUG 1323void SkBitmap::validate() const { 1324 fInfo.validate(); 1325 1326 // ImageInfo may not require this, but Bitmap ensures that opaque-only 1327 // colorTypes report opaque for their alphatype 1328 if (kRGB_565_SkColorType == fInfo.colorType()) { 1329 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType()); 1330 } 1331 1332 SkASSERT(fInfo.validRowBytes(fRowBytes)); 1333 uint8_t allFlags = kImageIsVolatile_Flag; 1334#ifdef SK_BUILD_FOR_ANDROID 1335 allFlags |= kHasHardwareMipMap_Flag; 1336#endif 1337 SkASSERT((~allFlags & fFlags) == 0); 1338 SkASSERT(fPixelLockCount >= 0); 1339 1340 if (fPixels) { 1341 SkASSERT(fPixelRef); 1342 SkASSERT(fPixelLockCount > 0); 1343 SkASSERT(fPixelRef->isLocked()); 1344 SkASSERT(fPixelRef->rowBytes() == fRowBytes); 1345 SkASSERT(fPixelRefOrigin.fX >= 0); 1346 SkASSERT(fPixelRefOrigin.fY >= 0); 1347 SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX); 1348 SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY); 1349 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes()); 1350 } else { 1351 SkASSERT(NULL == fColorTable); 1352 } 1353} 1354#endif 1355 1356#ifndef SK_IGNORE_TO_STRING 1357void SkBitmap::toString(SkString* str) const { 1358 1359 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = { 1360 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8", 1361 }; 1362 1363 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(), 1364 gColorTypeNames[this->colorType()]); 1365 1366 str->append(" ("); 1367 if (this->isOpaque()) { 1368 str->append("opaque"); 1369 } else { 1370 str->append("transparent"); 1371 } 1372 if (this->isImmutable()) { 1373 str->append(", immutable"); 1374 } else { 1375 str->append(", not-immutable"); 1376 } 1377 str->append(")"); 1378 1379 SkPixelRef* pr = this->pixelRef(); 1380 if (NULL == pr) { 1381 // show null or the explicit pixel address (rare) 1382 str->appendf(" pixels:%p", this->getPixels()); 1383 } else { 1384 const char* uri = pr->getURI(); 1385 if (uri) { 1386 str->appendf(" uri:\"%s\"", uri); 1387 } else { 1388 str->appendf(" pixelref:%p", pr); 1389 } 1390 } 1391 1392 str->append(")"); 1393} 1394#endif 1395 1396/////////////////////////////////////////////////////////////////////////////// 1397 1398bool SkBitmap::requestLock(SkAutoPixmapUnlock* result) const { 1399 SkASSERT(result); 1400 1401 SkPixelRef* pr = fPixelRef; 1402 if (NULL == pr) { 1403 return false; 1404 } 1405 1406 SkPixelRef::LockRequest req = { fInfo.dimensions(), kNone_SkFilterQuality }; 1407 SkPixelRef::LockResult res; 1408 if (pr->requestLock(req, &res)) { 1409 // The bitmap may be a subset of the pixelref's dimensions 1410 SkASSERT(fPixelRefOrigin.x() + fInfo.width() <= res.fSize.width()); 1411 SkASSERT(fPixelRefOrigin.y() + fInfo.height() <= res.fSize.height()); 1412 const void* addr = (const char*)res.fPixels + SkColorTypeComputeOffset(fInfo.colorType(), 1413 fPixelRefOrigin.x(), 1414 fPixelRefOrigin.y(), 1415 res.fRowBytes); 1416 1417 result->reset(SkPixmap(this->info(), addr, res.fRowBytes, res.fCTable), 1418 res.fUnlockProc, res.fUnlockContext); 1419 return true; 1420 } 1421 return false; 1422} 1423 1424/////////////////////////////////////////////////////////////////////////////// 1425 1426#ifdef SK_DEBUG 1427void SkImageInfo::validate() const { 1428 SkASSERT(fWidth >= 0); 1429 SkASSERT(fHeight >= 0); 1430 SkASSERT(SkColorTypeIsValid(fColorType)); 1431 SkASSERT(SkAlphaTypeIsValid(fAlphaType)); 1432} 1433#endif 1434