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