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