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