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