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 "include/core/SkBitmap.h" 9 10#include "include/core/SkData.h" 11#include "include/core/SkMallocPixelRef.h" 12#include "include/core/SkMath.h" 13#include "include/core/SkPixelRef.h" 14#include "include/core/SkRect.h" 15#include "include/core/SkScalar.h" 16#include "include/core/SkUnPreMultiply.h" 17#include "include/private/SkColorData.h" 18#include "include/private/SkHalf.h" 19#include "include/private/SkImageInfoPriv.h" 20#include "include/private/SkTemplates.h" 21#include "include/private/SkTo.h" 22#include "src/core/SkConvertPixels.h" 23#include "src/core/SkMask.h" 24#include "src/core/SkMaskFilterBase.h" 25#include "src/core/SkMipmap.h" 26#include "src/core/SkPixelRefPriv.h" 27#include "src/core/SkPixmapPriv.h" 28#include "src/core/SkReadBuffer.h" 29#include "src/core/SkWriteBuffer.h" 30#include "src/core/SkWritePixelsRec.h" 31 32#include <cstring> 33#include <utility> 34 35static bool reset_return_false(SkBitmap* bm) { 36 bm->reset(); 37 return false; 38} 39 40SkBitmap::SkBitmap() {} 41 42SkBitmap::SkBitmap(const SkBitmap& src) 43 : fPixelRef (src.fPixelRef) 44 , fPixmap (src.fPixmap) 45 , fMips (src.fMips) 46{ 47 SkDEBUGCODE(src.validate();) 48 SkDEBUGCODE(this->validate();) 49} 50 51SkBitmap::SkBitmap(SkBitmap&& other) 52 : fPixelRef (std::move(other.fPixelRef)) 53 , fPixmap (std::move(other.fPixmap)) 54 , fMips (std::move(other.fMips)) 55{ 56 SkASSERT(!other.fPixelRef); 57 other.fPixmap.reset(); 58} 59 60SkBitmap::~SkBitmap() {} 61 62SkBitmap& SkBitmap::operator=(const SkBitmap& src) { 63 if (this != &src) { 64 fPixelRef = src.fPixelRef; 65 fPixmap = src.fPixmap; 66 fMips = src.fMips; 67 } 68 SkDEBUGCODE(this->validate();) 69 return *this; 70} 71 72SkBitmap& SkBitmap::operator=(SkBitmap&& other) { 73 if (this != &other) { 74 fPixelRef = std::move(other.fPixelRef); 75 fPixmap = std::move(other.fPixmap); 76 fMips = std::move(other.fMips); 77 SkASSERT(!other.fPixelRef); 78 other.fPixmap.reset(); 79 } 80 return *this; 81} 82 83void SkBitmap::swap(SkBitmap& other) { 84 using std::swap; 85 swap(*this, other); 86 SkDEBUGCODE(this->validate();) 87} 88 89void SkBitmap::reset() { 90 fPixelRef = nullptr; // Free pixels. 91 fPixmap.reset(); 92 fMips.reset(); 93} 94 95void SkBitmap::getBounds(SkRect* bounds) const { 96 SkASSERT(bounds); 97 *bounds = SkRect::Make(this->dimensions()); 98} 99 100void SkBitmap::getBounds(SkIRect* bounds) const { 101 SkASSERT(bounds); 102 *bounds = fPixmap.bounds(); 103} 104 105/////////////////////////////////////////////////////////////////////////////// 106 107bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) { 108 SkAlphaType newAT = info.alphaType(); 109 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) { 110 return reset_return_false(this); 111 } 112 // don't look at info.alphaType(), since newAT is the real value... 113 114 // require that rowBytes fit in 31bits 115 int64_t mrb = info.minRowBytes64(); 116 if (!SkTFitsIn<int32_t>(mrb)) { 117 return reset_return_false(this); 118 } 119 if (!SkTFitsIn<int32_t>(rowBytes)) { 120 return reset_return_false(this); 121 } 122 123 if (info.width() < 0 || info.height() < 0) { 124 return reset_return_false(this); 125 } 126 127 if (kUnknown_SkColorType == info.colorType()) { 128 rowBytes = 0; 129 } else if (0 == rowBytes) { 130 rowBytes = (size_t)mrb; 131 } else if (!info.validRowBytes(rowBytes)) { 132 return reset_return_false(this); 133 } 134 135 fPixelRef = nullptr; // Free pixels. 136 fPixmap.reset(info.makeAlphaType(newAT), nullptr, SkToU32(rowBytes)); 137 SkDEBUGCODE(this->validate();) 138 return true; 139} 140 141 142 143bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) { 144 if (!SkColorTypeValidateAlphaType(this->colorType(), newAlphaType, &newAlphaType)) { 145 return false; 146 } 147 if (this->alphaType() != newAlphaType) { 148 auto newInfo = fPixmap.info().makeAlphaType(newAlphaType); 149 fPixmap.reset(std::move(newInfo), fPixmap.addr(), fPixmap.rowBytes()); 150 } 151 SkDEBUGCODE(this->validate();) 152 return true; 153} 154 155SkIPoint SkBitmap::pixelRefOrigin() const { 156 const char* addr = (const char*)fPixmap.addr(); 157 const char* pix = (const char*)(fPixelRef ? fPixelRef->pixels() : nullptr); 158 size_t rb = this->rowBytes(); 159 if (!pix || 0 == rb) { 160 return {0, 0}; 161 } 162 SkASSERT(this->bytesPerPixel() > 0); 163 SkASSERT(this->bytesPerPixel() == (1 << this->shiftPerPixel())); 164 SkASSERT(addr >= pix); 165 size_t off = addr - pix; 166 return {SkToS32((off % rb) >> this->shiftPerPixel()), SkToS32(off / rb)}; 167} 168 169void SkBitmap::setPixelRef(sk_sp<SkPixelRef> pr, int dx, int dy) { 170#ifdef SK_DEBUG 171 if (pr) { 172 if (kUnknown_SkColorType != this->colorType()) { 173 SkASSERT(dx >= 0 && this->width() + dx <= pr->width()); 174 SkASSERT(dy >= 0 && this->height() + dy <= pr->height()); 175 } 176 } 177#endif 178 fPixelRef = kUnknown_SkColorType != this->colorType() ? std::move(pr) : nullptr; 179 void* p = nullptr; 180 size_t rowBytes = this->rowBytes(); 181 // ignore dx,dy if there is no pixelref 182 if (fPixelRef) { 183 rowBytes = fPixelRef->rowBytes(); 184 // TODO(reed): Enforce that PixelRefs must have non-null pixels. 185 p = fPixelRef->pixels(); 186 if (p) { 187 p = (char*)p + dy * rowBytes + dx * this->bytesPerPixel(); 188 } 189 } 190 SkPixmapPriv::ResetPixmapKeepInfo(&fPixmap, p, rowBytes); 191 SkDEBUGCODE(this->validate();) 192} 193 194void SkBitmap::setPixels(void* p) { 195 if (kUnknown_SkColorType == this->colorType()) { 196 p = nullptr; 197 } 198 size_t rb = this->rowBytes(); 199 SkPixmapPriv::ResetPixmapKeepInfo(&fPixmap, p, rb); 200 fPixelRef = p ? sk_make_sp<SkPixelRef>(this->width(), this->height(), p, rb) : nullptr; 201 SkDEBUGCODE(this->validate();) 202} 203 204bool SkBitmap::tryAllocPixels(Allocator* allocator) { 205 HeapAllocator stdalloc; 206 207 if (nullptr == allocator) { 208 allocator = &stdalloc; 209 } 210 return allocator->allocPixelRef(this); 211} 212 213bool SkBitmap::tryAllocN32Pixels(int width, int height, bool isOpaque) { 214 SkImageInfo info = SkImageInfo::MakeN32(width, height, 215 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); 216 return this->tryAllocPixels(info); 217} 218 219void SkBitmap::allocN32Pixels(int width, int height, bool isOpaque) { 220 SkImageInfo info = SkImageInfo::MakeN32(width, height, 221 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); 222 this->allocPixels(info); 223} 224 225void SkBitmap::allocPixels() { 226 this->allocPixels((Allocator*)nullptr); 227} 228 229void SkBitmap::allocPixels(Allocator* allocator) { 230 if (!this->tryAllocPixels(allocator)) { 231 const SkImageInfo& info = this->info(); 232 SK_ABORT("SkBitmap::tryAllocPixels failed " 233 "ColorType:%d AlphaType:%d [w:%d h:%d] rb:%zu", 234 info.colorType(), info.alphaType(), info.width(), info.height(), this->rowBytes()); 235 } 236} 237 238void SkBitmap::allocPixelsFlags(const SkImageInfo& info, uint32_t flags) { 239 SkASSERT_RELEASE(this->tryAllocPixelsFlags(info, flags)); 240} 241 242void SkBitmap::allocPixels(const SkImageInfo& info, size_t rowBytes) { 243 SkASSERT_RELEASE(this->tryAllocPixels(info, rowBytes)); 244} 245 246void SkBitmap::allocPixels(const SkImageInfo& info) { 247 this->allocPixels(info, info.minRowBytes()); 248} 249 250/////////////////////////////////////////////////////////////////////////////// 251 252bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) { 253 if (!this->setInfo(requestedInfo, rowBytes)) { 254 return reset_return_false(this); 255 } 256 257 // setInfo may have corrected info (e.g. 565 is always opaque). 258 const SkImageInfo& correctedInfo = this->info(); 259 if (kUnknown_SkColorType == correctedInfo.colorType()) { 260 return true; 261 } 262 // setInfo may have computed a valid rowbytes if 0 were passed in 263 rowBytes = this->rowBytes(); 264 265 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes); 266 if (!pr) { 267 return reset_return_false(this); 268 } 269 this->setPixelRef(std::move(pr), 0, 0); 270 if (nullptr == this->getPixels()) { 271 return reset_return_false(this); 272 } 273 SkDEBUGCODE(this->validate();) 274 return true; 275} 276 277bool SkBitmap::tryAllocPixelsFlags(const SkImageInfo& requestedInfo, uint32_t allocFlags) { 278 if (!this->setInfo(requestedInfo)) { 279 return reset_return_false(this); 280 } 281 282 // setInfo may have corrected info (e.g. 565 is always opaque). 283 const SkImageInfo& correctedInfo = this->info(); 284 285 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, 286 correctedInfo.minRowBytes()); 287 if (!pr) { 288 return reset_return_false(this); 289 } 290 this->setPixelRef(std::move(pr), 0, 0); 291 if (nullptr == this->getPixels()) { 292 return reset_return_false(this); 293 } 294 SkDEBUGCODE(this->validate();) 295 return true; 296} 297 298static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) { 299 if (proc) { 300 proc(pixels, ctx); 301 } 302} 303 304bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb, 305 void (*releaseProc)(void* addr, void* context), void* context) { 306 if (!this->setInfo(requestedInfo, rb)) { 307 invoke_release_proc(releaseProc, pixels, context); 308 this->reset(); 309 return false; 310 } 311 if (nullptr == pixels) { 312 invoke_release_proc(releaseProc, pixels, context); 313 return true; // we behaved as if they called setInfo() 314 } 315 316 // setInfo may have corrected info (e.g. 565 is always opaque). 317 const SkImageInfo& correctedInfo = this->info(); 318 this->setPixelRef( 319 SkMakePixelRefWithProc(correctedInfo.width(), correctedInfo.height(), 320 rb, pixels, releaseProc, context), 0, 0); 321 SkDEBUGCODE(this->validate();) 322 return true; 323} 324 325bool SkBitmap::installPixels(const SkPixmap& pixmap) { 326 return this->installPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(), 327 nullptr, nullptr); 328} 329 330bool SkBitmap::installMaskPixels(const SkMask& mask) { 331 if (SkMask::kA8_Format != mask.fFormat) { 332 this->reset(); 333 return false; 334 } 335 return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), 336 mask.fBounds.height()), 337 mask.fImage, mask.fRowBytes); 338} 339 340/////////////////////////////////////////////////////////////////////////////// 341 342uint32_t SkBitmap::getGenerationID() const { 343 return fPixelRef ? fPixelRef->getGenerationID() : 0; 344} 345 346void SkBitmap::notifyPixelsChanged() const { 347 SkASSERT(!this->isImmutable()); 348 if (fPixelRef) { 349 fPixelRef->notifyPixelsChanged(); 350 } 351} 352 353/////////////////////////////////////////////////////////////////////////////// 354 355/** We explicitly use the same allocator for our pixels that SkMask does, 356 so that we can freely assign memory allocated by one class to the other. 357 */ 358bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst) { 359 const SkImageInfo& info = dst->info(); 360 if (kUnknown_SkColorType == info.colorType()) { 361// SkDebugf("unsupported config for info %d\n", dst->config()); 362 return false; 363 } 364 365 sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes()); 366 if (!pr) { 367 return false; 368 } 369 370 dst->setPixelRef(std::move(pr), 0, 0); 371 SkDEBUGCODE(dst->validate();) 372 return true; 373} 374 375/////////////////////////////////////////////////////////////////////////////// 376 377bool SkBitmap::isImmutable() const { 378 return fPixelRef ? fPixelRef->isImmutable() : false; 379} 380 381void SkBitmap::setImmutable() { 382 if (fPixelRef) { 383 fPixelRef->setImmutable(); 384 } 385} 386 387void* SkBitmap::getAddr(int x, int y) const { 388 SkASSERT((unsigned)x < (unsigned)this->width()); 389 SkASSERT((unsigned)y < (unsigned)this->height()); 390 391 char* base = (char*)this->getPixels(); 392 if (base) { 393 base += (y * this->rowBytes()) + (x << this->shiftPerPixel()); 394 } 395 return base; 396} 397 398/////////////////////////////////////////////////////////////////////////////// 399/////////////////////////////////////////////////////////////////////////////// 400 401void SkBitmap::erase(SkColor c, const SkIRect& area) const { 402 SkDEBUGCODE(this->validate();) 403 404 if (kUnknown_SkColorType == this->colorType()) { 405 // TODO: can we ASSERT that we never get here? 406 return; // can't erase. Should we bzero so the memory is not uninitialized? 407 } 408 409 SkPixmap result; 410 if (!this->peekPixels(&result)) { 411 return; 412 } 413 414 if (result.erase(c, area)) { 415 this->notifyPixelsChanged(); 416 } 417} 418 419void SkBitmap::eraseColor(SkColor c) const { 420 this->erase(c, SkIRect::MakeWH(this->width(), this->height())); 421} 422 423////////////////////////////////////////////////////////////////////////////////////// 424////////////////////////////////////////////////////////////////////////////////////// 425 426bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { 427 SkDEBUGCODE(this->validate();) 428 429 if (nullptr == result || !fPixelRef) { 430 return false; // no src pixels 431 } 432 433 SkIRect srcRect, r; 434 srcRect.setWH(this->width(), this->height()); 435 if (!r.intersect(srcRect, subset)) { 436 return false; // r is empty (i.e. no intersection) 437 } 438 439 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have 440 // exited above. 441 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width())); 442 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height())); 443 444 SkBitmap dst; 445 dst.setInfo(this->info().makeDimensions(r.size()), this->rowBytes()); 446 447 if (fPixelRef) { 448 SkIPoint origin = this->pixelRefOrigin(); 449 // share the pixelref with a custom offset 450 dst.setPixelRef(fPixelRef, origin.x() + r.fLeft, origin.y() + r.fTop); 451 } 452 SkDEBUGCODE(dst.validate();) 453 454 // we know we're good, so commit to result 455 result->swap(dst); 456 return true; 457} 458 459/////////////////////////////////////////////////////////////////////////////// 460 461bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB, 462 int x, int y) const { 463 SkPixmap src; 464 if (!this->peekPixels(&src)) { 465 return false; 466 } 467 return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y); 468} 469 470bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const { 471 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY); 472} 473 474bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) { 475 if (!SkImageInfoValidConversion(this->info(), src.info())) { 476 return false; 477 } 478 479 SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY); 480 if (!rec.trim(this->width(), this->height())) { 481 return false; 482 } 483 484 void* dstPixels = this->getAddr(rec.fX, rec.fY); 485 const SkImageInfo dstInfo = this->info().makeDimensions(rec.fInfo.dimensions()); 486 if (!SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), 487 rec.fInfo, rec.fPixels, rec.fRowBytes)) { 488 return false; 489 } 490 this->notifyPixelsChanged(); 491 return true; 492} 493 494/////////////////////////////////////////////////////////////////////////////// 495 496static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) { 497 SkASSERT(alpha != nullptr); 498 SkASSERT(alphaRowBytes >= src.width()); 499 500 SkPixmap pmap; 501 if (!src.peekPixels(&pmap)) { 502 for (int y = 0; y < src.height(); ++y) { 503 memset(alpha, 0, src.width()); 504 alpha += alphaRowBytes; 505 } 506 return false; 507 } 508 return SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes, 509 pmap.info(), pmap.addr(), pmap.rowBytes()); 510} 511 512#include "include/core/SkMaskFilter.h" 513#include "include/core/SkMatrix.h" 514#include "include/core/SkPaint.h" 515 516bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, 517 Allocator *allocator, SkIPoint* offset) const { 518 SkDEBUGCODE(this->validate();) 519 520 SkBitmap tmpBitmap; 521 SkMatrix identity; 522 SkMask srcM, dstM; 523 524 if (this->width() == 0 || this->height() == 0) { 525 return false; 526 } 527 srcM.fBounds.setWH(this->width(), this->height()); 528 srcM.fRowBytes = SkAlign4(this->width()); 529 srcM.fFormat = SkMask::kA8_Format; 530 531 SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr; 532 533 // compute our (larger?) dst bounds if we have a filter 534 if (filter) { 535 identity.reset(); 536 if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) { 537 goto NO_FILTER_CASE; 538 } 539 dstM.fRowBytes = SkAlign4(dstM.fBounds.width()); 540 } else { 541 NO_FILTER_CASE: 542 tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes); 543 if (!tmpBitmap.tryAllocPixels(allocator)) { 544 // Allocation of pixels for alpha bitmap failed. 545 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 546 tmpBitmap.width(), tmpBitmap.height()); 547 return false; 548 } 549 GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes); 550 if (offset) { 551 offset->set(0, 0); 552 } 553 tmpBitmap.swap(*dst); 554 return true; 555 } 556 srcM.fImage = SkMask::AllocImage(srcM.computeImageSize()); 557 SkAutoMaskFreeImage srcCleanup(srcM.fImage); 558 559 GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes); 560 if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) { 561 goto NO_FILTER_CASE; 562 } 563 SkAutoMaskFreeImage dstCleanup(dstM.fImage); 564 565 tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()), 566 dstM.fRowBytes); 567 if (!tmpBitmap.tryAllocPixels(allocator)) { 568 // Allocation of pixels for alpha bitmap failed. 569 SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n", 570 tmpBitmap.width(), tmpBitmap.height()); 571 return false; 572 } 573 memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize()); 574 if (offset) { 575 offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop); 576 } 577 SkDEBUGCODE(tmpBitmap.validate();) 578 579 tmpBitmap.swap(*dst); 580 return true; 581} 582 583/////////////////////////////////////////////////////////////////////////////// 584 585#ifdef SK_DEBUG 586void SkBitmap::validate() const { 587 this->info().validate(); 588 589 SkASSERT(this->info().validRowBytes(this->rowBytes())); 590 591 if (fPixelRef && fPixelRef->pixels()) { 592 SkASSERT(this->getPixels()); 593 } else { 594 SkASSERT(!this->getPixels()); 595 } 596 597 if (this->getPixels()) { 598 SkASSERT(fPixelRef); 599 SkASSERT(fPixelRef->rowBytes() == this->rowBytes()); 600 SkIPoint origin = this->pixelRefOrigin(); 601 SkASSERT(origin.fX >= 0); 602 SkASSERT(origin.fY >= 0); 603 SkASSERT(fPixelRef->width() >= (int)this->width() + origin.fX); 604 SkASSERT(fPixelRef->height() >= (int)this->height() + origin.fY); 605 SkASSERT(fPixelRef->rowBytes() >= this->info().minRowBytes()); 606 } 607} 608#endif 609 610/////////////////////////////////////////////////////////////////////////////// 611 612bool SkBitmap::peekPixels(SkPixmap* pmap) const { 613 if (this->getPixels()) { 614 if (pmap) { 615 *pmap = fPixmap; 616 } 617 return true; 618 } 619 return false; 620} 621 622sk_sp<SkImage> SkBitmap::asImage() const { 623 return SkImage::MakeFromBitmap(*this); 624} 625