SkBitmap.cpp revision 323ae0eb4b8295352b259f8e4bfc80511a2348f9
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 "SkColorTable.h" 12#include "SkConvertPixels.h" 13#include "SkData.h" 14#include "SkFilterQuality.h" 15#include "SkHalf.h" 16#include "SkImageInfoPriv.h" 17#include "SkMallocPixelRef.h" 18#include "SkMask.h" 19#include "SkMath.h" 20#include "SkPixelRef.h" 21#include "SkReadBuffer.h" 22#include "SkRect.h" 23#include "SkScalar.h" 24#include "SkTemplates.h" 25#include "SkUnPreMultiply.h" 26#include "SkWriteBuffer.h" 27#include "SkWritePixelsRec.h" 28 29#include <string.h> 30 31static bool reset_return_false(SkBitmap* bm) { 32 bm->reset(); 33 return false; 34} 35 36SkBitmap::SkBitmap() 37 : fPixels (nullptr) 38 , fPixelRefOrigin{0, 0} 39 , fRowBytes (0) 40 , fFlags (0) {} 41 42SkBitmap::SkBitmap(const SkBitmap& src) 43 : fPixelRef (src.fPixelRef) 44 , fPixels (src.fPixels) 45 , fPixelRefOrigin(src.fPixelRefOrigin) 46 , fInfo (src.fInfo) 47 , fRowBytes (src.fRowBytes) 48 , fFlags (src.fFlags) 49{ 50 SkDEBUGCODE(src.validate();) 51 SkDEBUGCODE(this->validate();) 52} 53 54SkBitmap::SkBitmap(SkBitmap&& other) 55 : fPixelRef (std::move(other.fPixelRef)) 56 , fPixels (other.fPixels) 57 , fPixelRefOrigin (other.fPixelRefOrigin) 58 , fInfo (std::move(other.fInfo)) 59 , fRowBytes (other.fRowBytes) 60 , fFlags (other.fFlags) 61{ 62 SkASSERT(!other.fPixelRef); 63 other.fInfo.reset(); 64 other.fPixels = nullptr; 65 other.fPixelRefOrigin = SkIPoint{0, 0}; 66 other.fRowBytes = 0; 67 other.fFlags = 0; 68} 69 70SkBitmap::~SkBitmap() {} 71 72SkBitmap& SkBitmap::operator=(const SkBitmap& src) { 73 if (this != &src) { 74 fPixelRef = src.fPixelRef; 75 fPixels = src.fPixels; 76 fPixelRefOrigin = src.fPixelRefOrigin; 77 fInfo = src.fInfo; 78 fRowBytes = src.fRowBytes; 79 fFlags = src.fFlags; 80 } 81 SkDEBUGCODE(this->validate();) 82 return *this; 83} 84 85SkBitmap& SkBitmap::operator=(SkBitmap&& other) { 86 if (this != &other) { 87 fPixelRef = std::move(other.fPixelRef); 88 fInfo = std::move(other.fInfo); 89 fPixels = other.fPixels; 90 fPixelRefOrigin = other.fPixelRefOrigin; 91 fRowBytes = other.fRowBytes; 92 fFlags = other.fFlags; 93 SkASSERT(!other.fPixelRef); 94 other.fInfo.reset(); 95 other.fPixels = nullptr; 96 other.fPixelRefOrigin = SkIPoint{0, 0}; 97 other.fRowBytes = 0; 98 other.fFlags = 0; 99 } 100 return *this; 101} 102 103void SkBitmap::swap(SkBitmap& other) { 104 SkTSwap(*this, other); 105 SkDEBUGCODE(this->validate();) 106} 107 108void SkBitmap::reset() { 109 this->freePixels(); 110 this->fInfo.reset(); 111 sk_bzero(this, sizeof(*this)); 112} 113 114void SkBitmap::getBounds(SkRect* bounds) const { 115 SkASSERT(bounds); 116 bounds->set(0, 0, 117 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height())); 118} 119 120void SkBitmap::getBounds(SkIRect* bounds) const { 121 SkASSERT(bounds); 122 bounds->set(0, 0, fInfo.width(), fInfo.height()); 123} 124 125/////////////////////////////////////////////////////////////////////////////// 126 127bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) { 128 SkAlphaType newAT = info.alphaType(); 129 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) { 130 return reset_return_false(this); 131 } 132 // don't look at info.alphaType(), since newAT is the real value... 133 134 // require that rowBytes fit in 31bits 135 int64_t mrb = info.minRowBytes64(); 136 if ((int32_t)mrb != mrb) { 137 return reset_return_false(this); 138 } 139 if ((int64_t)rowBytes != (int32_t)rowBytes) { 140 return reset_return_false(this); 141 } 142 143 if (info.width() < 0 || info.height() < 0) { 144 return reset_return_false(this); 145 } 146 147 if (kUnknown_SkColorType == info.colorType()) { 148 rowBytes = 0; 149 } else if (0 == rowBytes) { 150 rowBytes = (size_t)mrb; 151 } else if (!info.validRowBytes(rowBytes)) { 152 return reset_return_false(this); 153 } 154 155 this->freePixels(); 156 157 fInfo = info.makeAlphaType(newAT); 158 fRowBytes = SkToU32(rowBytes); 159 SkDEBUGCODE(this->validate();) 160 return true; 161} 162 163bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) { 164 if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) { 165 return false; 166 } 167 if (fInfo.alphaType() != newAlphaType) { 168 fInfo = fInfo.makeAlphaType(newAlphaType); 169 } 170 SkDEBUGCODE(this->validate();) 171 return true; 172} 173 174void SkBitmap::updatePixelsFromRef() { 175 void* p = nullptr; 176 if (fPixelRef) { 177 // wish we could assert that a pixelref *always* has pixels 178 p = fPixelRef->pixels(); 179 if (p) { 180 SkASSERT(fRowBytes == fPixelRef->rowBytes()); 181 p = (char*)p 182 + fPixelRefOrigin.fY * fRowBytes 183 + fPixelRefOrigin.fX * fInfo.bytesPerPixel(); 184 } 185 } 186 fPixels = p; 187} 188 189void SkBitmap::setPixelRef(sk_sp<SkPixelRef> pr, int dx, int dy) { 190#ifdef SK_DEBUG 191 if (pr) { 192 if (kUnknown_SkColorType != fInfo.colorType()) { 193 SkASSERT(fInfo.width() + dx <= pr->width()); 194 SkASSERT(fInfo.height() + dy <= pr->height()); 195 } 196 } 197#endif 198 199 fPixelRef = std::move(pr); 200 if (fPixelRef) { 201 fPixelRefOrigin.set(SkTPin(dx, 0, fPixelRef->width()), SkTPin(dy, 0, fPixelRef->height())); 202 this->updatePixelsFromRef(); 203 } else { 204 // ignore dx,dy if there is no pixelref 205 fPixelRefOrigin.setZero(); 206 fPixels = nullptr; 207 } 208 209 SkDEBUGCODE(this->validate();) 210} 211 212void SkBitmap::setPixels(void* p) { 213 if (nullptr == p) { 214 this->setPixelRef(nullptr, 0, 0); 215 return; 216 } 217 218 if (kUnknown_SkColorType == fInfo.colorType()) { 219 this->setPixelRef(nullptr, 0, 0); 220 return; 221 } 222 223 this->setPixelRef(SkMallocPixelRef::MakeDirect(fInfo, p, fRowBytes), 0, 0); 224 if (!fPixelRef) { 225 return; 226 } 227 SkDEBUGCODE(this->validate();) 228} 229 230bool SkBitmap::tryAllocPixels(Allocator* allocator) { 231 HeapAllocator stdalloc; 232 233 if (nullptr == allocator) { 234 allocator = &stdalloc; 235 } 236 return allocator->allocPixelRef(this); 237} 238 239/////////////////////////////////////////////////////////////////////////////// 240 241bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) { 242 if (!this->setInfo(requestedInfo, rowBytes)) { 243 return reset_return_false(this); 244 } 245 246 // setInfo may have corrected info (e.g. 565 is always opaque). 247 const SkImageInfo& correctedInfo = this->info(); 248 // setInfo may have computed a valid rowbytes if 0 were passed in 249 rowBytes = this->rowBytes(); 250 251 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes); 252 if (!pr) { 253 return reset_return_false(this); 254 } 255 this->setPixelRef(std::move(pr), 0, 0); 256 if (nullptr == this->getPixels()) { 257 return reset_return_false(this); 258 } 259 SkDEBUGCODE(this->validate();) 260 return true; 261} 262 263bool SkBitmap::tryAllocPixelsFlags(const SkImageInfo& requestedInfo, uint32_t allocFlags) { 264 if (!this->setInfo(requestedInfo)) { 265 return reset_return_false(this); 266 } 267 268 // setInfo may have corrected info (e.g. 565 is always opaque). 269 const SkImageInfo& correctedInfo = this->info(); 270 271 sk_sp<SkPixelRef> pr = (allocFlags & kZeroPixels_AllocFlag) ? 272 SkMallocPixelRef::MakeZeroed(correctedInfo, correctedInfo.minRowBytes()) : 273 SkMallocPixelRef::MakeAllocate(correctedInfo, correctedInfo.minRowBytes()); 274 if (!pr) { 275 return reset_return_false(this); 276 } 277 this->setPixelRef(std::move(pr), 0, 0); 278 if (nullptr == this->getPixels()) { 279 return reset_return_false(this); 280 } 281 SkDEBUGCODE(this->validate();) 282 return true; 283} 284 285static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) { 286 if (proc) { 287 proc(pixels, ctx); 288 } 289} 290 291bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb, 292 void (*releaseProc)(void* addr, void* context), void* context) { 293 if (!this->setInfo(requestedInfo, rb)) { 294 invoke_release_proc(releaseProc, pixels, context); 295 this->reset(); 296 return false; 297 } 298 if (nullptr == pixels) { 299 invoke_release_proc(releaseProc, pixels, context); 300 return true; // we behaved as if they called setInfo() 301 } 302 303 // setInfo may have corrected info (e.g. 565 is always opaque). 304 const SkImageInfo& correctedInfo = this->info(); 305 306 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithProc(correctedInfo, rb, pixels, 307 releaseProc, context); 308 if (!pr) { 309 this->reset(); 310 return false; 311 } 312 313 this->setPixelRef(std::move(pr), 0, 0); 314 SkDEBUGCODE(this->validate();) 315 return true; 316} 317 318bool SkBitmap::installPixels(const SkPixmap& pixmap) { 319 return this->installPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(), 320 nullptr, nullptr); 321} 322 323bool SkBitmap::installMaskPixels(const SkMask& mask) { 324 if (SkMask::kA8_Format != mask.fFormat) { 325 this->reset(); 326 return false; 327 } 328 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), 329 mask.fBounds.height()), 330 mask.fImage, mask.fRowBytes); 331} 332 333/////////////////////////////////////////////////////////////////////////////// 334 335void SkBitmap::freePixels() { 336 fPixelRef = nullptr; 337 fPixelRefOrigin.setZero(); 338 fPixels = nullptr; 339} 340 341uint32_t SkBitmap::getGenerationID() const { 342 return fPixelRef ? fPixelRef->getGenerationID() : 0; 343} 344 345void SkBitmap::notifyPixelsChanged() const { 346 SkASSERT(!this->isImmutable()); 347 if (fPixelRef) { 348 fPixelRef->notifyPixelsChanged(); 349 } 350} 351 352/////////////////////////////////////////////////////////////////////////////// 353 354/** We explicitly use the same allocator for our pixels that SkMask does, 355 so that we can freely assign memory allocated by one class to the other. 356 */ 357bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst) { 358 const SkImageInfo info = dst->info(); 359 if (kUnknown_SkColorType == info.colorType()) { 360// SkDebugf("unsupported config for info %d\n", dst->config()); 361 return false; 362 } 363 364 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes()); 365 if (!pr) { 366 return false; 367 } 368 369 dst->setPixelRef(std::move(pr), 0, 0); 370 SkDEBUGCODE(dst->validate();) 371 return true; 372} 373 374/////////////////////////////////////////////////////////////////////////////// 375 376bool SkBitmap::isImmutable() const { 377 return fPixelRef ? fPixelRef->isImmutable() : false; 378} 379 380void SkBitmap::setImmutable() { 381 if (fPixelRef) { 382 fPixelRef->setImmutable(); 383 } 384} 385 386bool SkBitmap::isVolatile() const { 387 return (fFlags & kImageIsVolatile_Flag) != 0; 388} 389 390void SkBitmap::setIsVolatile(bool isVolatile) { 391 if (isVolatile) { 392 fFlags |= kImageIsVolatile_Flag; 393 } else { 394 fFlags &= ~kImageIsVolatile_Flag; 395 } 396} 397 398void* SkBitmap::getAddr(int x, int y) const { 399 SkASSERT((unsigned)x < (unsigned)this->width()); 400 SkASSERT((unsigned)y < (unsigned)this->height()); 401 402 char* base = (char*)this->getPixels(); 403 if (base) { 404 base += y * this->rowBytes(); 405 switch (this->colorType()) { 406 case kRGBA_F16_SkColorType: 407 base += x << 3; 408 break; 409 case kRGBA_8888_SkColorType: 410 case kBGRA_8888_SkColorType: 411 base += x << 2; 412 break; 413 case kARGB_4444_SkColorType: 414 case kRGB_565_SkColorType: 415 base += x << 1; 416 break; 417 case kAlpha_8_SkColorType: 418 case kGray_8_SkColorType: 419 base += x; 420 break; 421 default: 422 SkDEBUGFAIL("Can't return addr for config"); 423 base = nullptr; 424 break; 425 } 426 } 427 return base; 428} 429 430/////////////////////////////////////////////////////////////////////////////// 431/////////////////////////////////////////////////////////////////////////////// 432 433void SkBitmap::erase(SkColor c, const SkIRect& area) const { 434 SkDEBUGCODE(this->validate();) 435 436 switch (fInfo.colorType()) { 437 case kUnknown_SkColorType: 438 // TODO: can we ASSERT that we never get here? 439 return; // can't erase. Should we bzero so the memory is not uninitialized? 440 default: 441 break; 442 } 443 444 SkPixmap result; 445 if (!this->peekPixels(&result)) { 446 return; 447 } 448 449 if (result.erase(c, area)) { 450 this->notifyPixelsChanged(); 451 } 452} 453 454void SkBitmap::eraseColor(SkColor c) const { 455 this->erase(c, SkIRect::MakeWH(this->width(), this->height())); 456} 457 458////////////////////////////////////////////////////////////////////////////////////// 459////////////////////////////////////////////////////////////////////////////////////// 460 461bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { 462 SkDEBUGCODE(this->validate();) 463 464 if (nullptr == result || !fPixelRef) { 465 return false; // no src pixels 466 } 467 468 SkIRect srcRect, r; 469 srcRect.set(0, 0, this->width(), this->height()); 470 if (!r.intersect(srcRect, subset)) { 471 return false; // r is empty (i.e. no intersection) 472 } 473 474 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have 475 // exited above. 476 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width())); 477 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height())); 478 479 SkBitmap dst; 480 dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes()); 481 dst.setIsVolatile(this->isVolatile()); 482 483 if (fPixelRef) { 484 SkIPoint origin = fPixelRefOrigin; 485 origin.fX += r.fLeft; 486 origin.fY += r.fTop; 487 // share the pixelref with a custom offset 488 dst.setPixelRef(fPixelRef, origin.x(), origin.y()); 489 } 490 SkDEBUGCODE(dst.validate();) 491 492 // we know we're good, so commit to result 493 result->swap(dst); 494 return true; 495} 496 497/////////////////////////////////////////////////////////////////////////////// 498 499bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB, 500 int x, int y, SkTransferFunctionBehavior behavior) const { 501 SkPixmap src; 502 if (!this->peekPixels(&src)) { 503 return false; 504 } 505 return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y, behavior); 506} 507 508bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const { 509 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY); 510} 511 512bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY, 513 SkTransferFunctionBehavior behavior) { 514 if (!SkImageInfoValidConversion(fInfo, src.info())) { 515 return false; 516 } 517 518 SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY); 519 if (!rec.trim(fInfo.width(), fInfo.height())) { 520 return false; 521 } 522 523 void* dstPixels = this->getAddr(rec.fX, rec.fY); 524 const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height()); 525 SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes, 526 nullptr, behavior); 527 return true; 528} 529 530/////////////////////////////////////////////////////////////////////////////// 531 532static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) { 533 SkASSERT(alpha != nullptr); 534 SkASSERT(alphaRowBytes >= src.width()); 535 536 SkPixmap pmap; 537 if (!src.peekPixels(&pmap)) { 538 for (int y = 0; y < src.height(); ++y) { 539 memset(alpha, 0, src.width()); 540 alpha += alphaRowBytes; 541 } 542 return false; 543 } 544 SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes, 545 pmap.info(), pmap.addr(), pmap.rowBytes(), nullptr, 546 SkTransferFunctionBehavior::kRespect); 547 return true; 548} 549 550#include "SkPaint.h" 551#include "SkMaskFilter.h" 552#include "SkMatrix.h" 553 554bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, 555 Allocator *allocator, SkIPoint* offset) const { 556 SkDEBUGCODE(this->validate();) 557 558 SkBitmap tmpBitmap; 559 SkMatrix identity; 560 SkMask srcM, dstM; 561 562 srcM.fBounds.set(0, 0, this->width(), this->height()); 563 srcM.fRowBytes = SkAlign4(this->width()); 564 srcM.fFormat = SkMask::kA8_Format; 565 566 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr; 567 568 // compute our (larger?) dst bounds if we have a filter 569 if (filter) { 570 identity.reset(); 571 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) { 572 goto NO_FILTER_CASE; 573 } 574 dstM.fRowBytes = SkAlign4(dstM.fBounds.width()); 575 } else { 576 NO_FILTER_CASE: 577 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes); 578 if (!tmpBitmap.tryAllocPixels(allocator)) { 579 // Allocation of pixels for alpha bitmap failed. 580 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 581 tmpBitmap.width(), tmpBitmap.height()); 582 return false; 583 } 584 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes); 585 if (offset) { 586 offset->set(0, 0); 587 } 588 tmpBitmap.swap(*dst); 589 return true; 590 } 591 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize()); 592 SkAutoMaskFreeImage srcCleanup(srcM.fImage); 593 594 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes); 595 if (!filter->filterMask(&dstM, srcM, identity, nullptr)) { 596 goto NO_FILTER_CASE; 597 } 598 SkAutoMaskFreeImage dstCleanup(dstM.fImage); 599 600 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()), 601 dstM.fRowBytes); 602 if (!tmpBitmap.tryAllocPixels(allocator)) { 603 // Allocation of pixels for alpha bitmap failed. 604 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 605 tmpBitmap.width(), tmpBitmap.height()); 606 return false; 607 } 608 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize()); 609 if (offset) { 610 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop); 611 } 612 SkDEBUGCODE(tmpBitmap.validate();) 613 614 tmpBitmap.swap(*dst); 615 return true; 616} 617 618/////////////////////////////////////////////////////////////////////////////// 619 620static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) { 621 const SkImageInfo& info = pmap.info(); 622 const size_t snugRB = info.width() * info.bytesPerPixel(); 623 const char* src = (const char*)pmap.addr(); 624 const size_t ramRB = pmap.rowBytes(); 625 626 buffer->write32(SkToU32(snugRB)); 627 info.flatten(*buffer); 628 629 const size_t size = snugRB * info.height(); 630 SkAutoTMalloc<char> storage(size); 631 char* dst = storage.get(); 632 for (int y = 0; y < info.height(); ++y) { 633 memcpy(dst, src, snugRB); 634 dst += snugRB; 635 src += ramRB; 636 } 637 buffer->writeByteArray(storage.get(), size); 638 // no colortable 639 buffer->writeBool(false); 640} 641 642void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) { 643 const SkImageInfo info = bitmap.info(); 644 if (0 == info.width() || 0 == info.height() || bitmap.isNull()) { 645 buffer->writeUInt(0); // instead of snugRB, signaling no pixels 646 return; 647 } 648 649 SkPixmap result; 650 if (!bitmap.peekPixels(&result)) { 651 buffer->writeUInt(0); // instead of snugRB, signaling no pixels 652 return; 653 } 654 655 write_raw_pixels(buffer, result); 656} 657 658bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) { 659 const size_t snugRB = buffer->readUInt(); 660 if (0 == snugRB) { // no pixels 661 return false; 662 } 663 664 SkImageInfo info; 665 info.unflatten(*buffer); 666 667 if (info.width() < 0 || info.height() < 0) { 668 return false; 669 } 670 671 // If there was an error reading "info" or if it is bogus, 672 // don't use it to compute minRowBytes() 673 if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(), 674 info.alphaType()))) { 675 return false; 676 } 677 678 const size_t ramRB = info.minRowBytes(); 679 const int height = SkMax32(info.height(), 0); 680 const uint64_t snugSize = sk_64_mul(snugRB, height); 681 const uint64_t ramSize = sk_64_mul(ramRB, height); 682 static const uint64_t max_size_t = (size_t)(-1); 683 if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) { 684 return false; 685 } 686 687 sk_sp<SkData> data(SkData::MakeUninitialized(SkToSizeT(ramSize))); 688 unsigned char* dst = (unsigned char*)data->writable_data(); 689 buffer->readByteArray(dst, SkToSizeT(snugSize)); 690 691 if (snugSize != ramSize) { 692 const unsigned char* srcRow = dst + snugRB * (height - 1); 693 unsigned char* dstRow = dst + ramRB * (height - 1); 694 for (int y = height - 1; y >= 1; --y) { 695 memmove(dstRow, srcRow, snugRB); 696 srcRow -= snugRB; 697 dstRow -= ramRB; 698 } 699 SkASSERT(srcRow == dstRow); // first row does not need to be moved 700 } 701 702 if (buffer->readBool()) { 703 SkColorTable::Skip(*buffer); 704 if (!buffer->isValid()) { 705 return false; 706 } 707 } 708 709 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithData(info, info.minRowBytes(), 710 std::move(data)); 711 if (!pr) { 712 return false; 713 } 714 bitmap->setInfo(info); 715 bitmap->setPixelRef(std::move(pr), 0, 0); 716 return true; 717} 718 719enum { 720 SERIALIZE_PIXELTYPE_NONE, 721 SERIALIZE_PIXELTYPE_REF_DATA 722}; 723 724/////////////////////////////////////////////////////////////////////////////// 725 726#ifdef SK_DEBUG 727void SkBitmap::validate() const { 728 fInfo.validate(); 729 730 // ImageInfo may not require this, but Bitmap ensures that opaque-only 731 // colorTypes report opaque for their alphatype 732 if (kRGB_565_SkColorType == fInfo.colorType()) { 733 SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType()); 734 } 735 736 SkASSERT(fInfo.validRowBytes(fRowBytes)); 737 uint8_t allFlags = kImageIsVolatile_Flag; 738#ifdef SK_BUILD_FOR_ANDROID 739 allFlags |= kHasHardwareMipMap_Flag; 740#endif 741 SkASSERT((~allFlags & fFlags) == 0); 742 743 if (fPixelRef && fPixelRef->pixels()) { 744 SkASSERT(fPixels); 745 } else { 746 SkASSERT(!fPixels); 747 } 748 749 if (fPixels) { 750 SkASSERT(fPixelRef); 751 SkASSERT(fPixelRef->rowBytes() == fRowBytes); 752 SkASSERT(fPixelRefOrigin.fX >= 0); 753 SkASSERT(fPixelRefOrigin.fY >= 0); 754 SkASSERT(fPixelRef->width() >= (int)this->width() + fPixelRefOrigin.fX); 755 SkASSERT(fPixelRef->height() >= (int)this->height() + fPixelRefOrigin.fY); 756 SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes()); 757 } 758} 759#endif 760 761#ifndef SK_IGNORE_TO_STRING 762#include "SkString.h" 763void SkBitmap::toString(SkString* str) const { 764 765 static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = { 766 "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8", 767 }; 768 769 str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(), 770 gColorTypeNames[this->colorType()]); 771 772 str->append(" ("); 773 if (this->isOpaque()) { 774 str->append("opaque"); 775 } else { 776 str->append("transparent"); 777 } 778 if (this->isImmutable()) { 779 str->append(", immutable"); 780 } else { 781 str->append(", not-immutable"); 782 } 783 str->append(")"); 784 785 str->appendf(" pixelref:%p", this->pixelRef()); 786 str->append(")"); 787} 788#endif 789 790/////////////////////////////////////////////////////////////////////////////// 791 792bool SkBitmap::peekPixels(SkPixmap* pmap) const { 793 if (fPixels) { 794 if (pmap) { 795 pmap->reset(fInfo, fPixels, fRowBytes); 796 } 797 return true; 798 } 799 return false; 800} 801 802/////////////////////////////////////////////////////////////////////////////// 803 804#ifdef SK_DEBUG 805void SkImageInfo::validate() const { 806 SkASSERT(fWidth >= 0); 807 SkASSERT(fHeight >= 0); 808 SkASSERT(SkColorTypeIsValid(fColorType)); 809 SkASSERT(SkAlphaTypeIsValid(fAlphaType)); 810} 811#endif 812