LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkBitmap.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 250 623 40.1 %
Date: 2017-07-14 16:53:18 Functions: 26 54 48.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13