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