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