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