• 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 ((int32_t)mrb != mrb) {
118         return reset_return_false(this);
119     }
120     if ((int64_t)rowBytes != (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 
222 ///////////////////////////////////////////////////////////////////////////////
223 
tryAllocPixels(const SkImageInfo & requestedInfo,size_t rowBytes)224 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
225     if (!this->setInfo(requestedInfo, rowBytes)) {
226         return reset_return_false(this);
227     }
228 
229     // setInfo may have corrected info (e.g. 565 is always opaque).
230     const SkImageInfo& correctedInfo = this->info();
231     if (kUnknown_SkColorType == correctedInfo.colorType()) {
232         return true;
233     }
234     // setInfo may have computed a valid rowbytes if 0 were passed in
235     rowBytes = this->rowBytes();
236 
237     sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes);
238     if (!pr) {
239         return reset_return_false(this);
240     }
241     this->setPixelRef(std::move(pr), 0, 0);
242     if (nullptr == this->getPixels()) {
243         return reset_return_false(this);
244     }
245     SkDEBUGCODE(this->validate();)
246     return true;
247 }
248 
tryAllocPixelsFlags(const SkImageInfo & requestedInfo,uint32_t allocFlags)249 bool SkBitmap::tryAllocPixelsFlags(const SkImageInfo& requestedInfo, uint32_t allocFlags) {
250     if (!this->setInfo(requestedInfo)) {
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 
257     sk_sp<SkPixelRef> pr = (allocFlags & kZeroPixels_AllocFlag) ?
258         SkMallocPixelRef::MakeZeroed(correctedInfo, correctedInfo.minRowBytes()) :
259         SkMallocPixelRef::MakeAllocate(correctedInfo, correctedInfo.minRowBytes());
260     if (!pr) {
261         return reset_return_false(this);
262     }
263     this->setPixelRef(std::move(pr), 0, 0);
264     if (nullptr == this->getPixels()) {
265         return reset_return_false(this);
266     }
267     SkDEBUGCODE(this->validate();)
268     return true;
269 }
270 
invoke_release_proc(void (* proc)(void * pixels,void * ctx),void * pixels,void * ctx)271 static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
272     if (proc) {
273         proc(pixels, ctx);
274     }
275 }
276 
installPixels(const SkImageInfo & requestedInfo,void * pixels,size_t rb,void (* releaseProc)(void * addr,void * context),void * context)277 bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
278                              void (*releaseProc)(void* addr, void* context), void* context) {
279     if (!this->setInfo(requestedInfo, rb)) {
280         invoke_release_proc(releaseProc, pixels, context);
281         this->reset();
282         return false;
283     }
284     if (nullptr == pixels) {
285         invoke_release_proc(releaseProc, pixels, context);
286         return true;    // we behaved as if they called setInfo()
287     }
288 
289     // setInfo may have corrected info (e.g. 565 is always opaque).
290     const SkImageInfo& correctedInfo = this->info();
291 
292     sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithProc(correctedInfo, rb, pixels,
293                                                           releaseProc, context);
294     if (!pr) {
295         this->reset();
296         return false;
297     }
298 
299     this->setPixelRef(std::move(pr), 0, 0);
300     SkDEBUGCODE(this->validate();)
301     return true;
302 }
303 
installPixels(const SkPixmap & pixmap)304 bool SkBitmap::installPixels(const SkPixmap& pixmap) {
305     return this->installPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(),
306                                nullptr, nullptr);
307 }
308 
installMaskPixels(const SkMask & mask)309 bool SkBitmap::installMaskPixels(const SkMask& mask) {
310     if (SkMask::kA8_Format != mask.fFormat) {
311         this->reset();
312         return false;
313     }
314     return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
315                                                    mask.fBounds.height()),
316                                mask.fImage, mask.fRowBytes);
317 }
318 
319 ///////////////////////////////////////////////////////////////////////////////
320 
getGenerationID() const321 uint32_t SkBitmap::getGenerationID() const {
322     return fPixelRef ? fPixelRef->getGenerationID() : 0;
323 }
324 
notifyPixelsChanged() const325 void SkBitmap::notifyPixelsChanged() const {
326     SkASSERT(!this->isImmutable());
327     if (fPixelRef) {
328         fPixelRef->notifyPixelsChanged();
329     }
330 }
331 
332 ///////////////////////////////////////////////////////////////////////////////
333 
334 /** We explicitly use the same allocator for our pixels that SkMask does,
335  so that we can freely assign memory allocated by one class to the other.
336  */
allocPixelRef(SkBitmap * dst)337 bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst) {
338     const SkImageInfo info = dst->info();
339     if (kUnknown_SkColorType == info.colorType()) {
340 //        SkDebugf("unsupported config for info %d\n", dst->config());
341         return false;
342     }
343 
344     sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes());
345     if (!pr) {
346         return false;
347     }
348 
349     dst->setPixelRef(std::move(pr), 0, 0);
350     SkDEBUGCODE(dst->validate();)
351     return true;
352 }
353 
354 ///////////////////////////////////////////////////////////////////////////////
355 
isImmutable() const356 bool SkBitmap::isImmutable() const {
357     return fPixelRef ? fPixelRef->isImmutable() : false;
358 }
359 
setImmutable()360 void SkBitmap::setImmutable() {
361     if (fPixelRef) {
362         fPixelRef->setImmutable();
363     }
364 }
365 
isVolatile() const366 bool SkBitmap::isVolatile() const {
367     return (fFlags & kImageIsVolatile_Flag) != 0;
368 }
369 
setIsVolatile(bool isVolatile)370 void SkBitmap::setIsVolatile(bool isVolatile) {
371     if (isVolatile) {
372         fFlags |= kImageIsVolatile_Flag;
373     } else {
374         fFlags &= ~kImageIsVolatile_Flag;
375     }
376 }
377 
getAddr(int x,int y) const378 void* SkBitmap::getAddr(int x, int y) const {
379     SkASSERT((unsigned)x < (unsigned)this->width());
380     SkASSERT((unsigned)y < (unsigned)this->height());
381 
382     char* base = (char*)this->getPixels();
383     if (base) {
384         base += (y * this->rowBytes()) + (x << this->shiftPerPixel());
385     }
386     return base;
387 }
388 
389 ///////////////////////////////////////////////////////////////////////////////
390 ///////////////////////////////////////////////////////////////////////////////
391 
erase(SkColor c,const SkIRect & area) const392 void SkBitmap::erase(SkColor c, const SkIRect& area) const {
393     SkDEBUGCODE(this->validate();)
394 
395     if (kUnknown_SkColorType == this->colorType()) {
396         // TODO: can we ASSERT that we never get here?
397         return; // can't erase. Should we bzero so the memory is not uninitialized?
398     }
399 
400     SkPixmap result;
401     if (!this->peekPixels(&result)) {
402         return;
403     }
404 
405     if (result.erase(c, area)) {
406         this->notifyPixelsChanged();
407     }
408 }
409 
eraseColor(SkColor c) const410 void SkBitmap::eraseColor(SkColor c) const {
411     this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
412 }
413 
414 //////////////////////////////////////////////////////////////////////////////////////
415 //////////////////////////////////////////////////////////////////////////////////////
416 
extractSubset(SkBitmap * result,const SkIRect & subset) const417 bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
418     SkDEBUGCODE(this->validate();)
419 
420     if (nullptr == result || !fPixelRef) {
421         return false;   // no src pixels
422     }
423 
424     SkIRect srcRect, r;
425     srcRect.set(0, 0, this->width(), this->height());
426     if (!r.intersect(srcRect, subset)) {
427         return false;   // r is empty (i.e. no intersection)
428     }
429 
430     // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
431     // exited above.
432     SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
433     SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
434 
435     SkBitmap dst;
436     dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes());
437     dst.setIsVolatile(this->isVolatile());
438 
439     if (fPixelRef) {
440         SkIPoint origin = this->pixelRefOrigin();
441         // share the pixelref with a custom offset
442         dst.setPixelRef(fPixelRef, origin.x() + r.fLeft, origin.y() + r.fTop);
443     }
444     SkDEBUGCODE(dst.validate();)
445 
446     // we know we're good, so commit to result
447     result->swap(dst);
448     return true;
449 }
450 
451 ///////////////////////////////////////////////////////////////////////////////
452 
readPixels(const SkImageInfo & requestedDstInfo,void * dstPixels,size_t dstRB,int x,int y) const453 bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
454                           int x, int y) const {
455     SkPixmap src;
456     if (!this->peekPixels(&src)) {
457         return false;
458     }
459     return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
460 }
461 
readPixels(const SkPixmap & dst,int srcX,int srcY) const462 bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
463     return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
464 }
465 
writePixels(const SkPixmap & src,int dstX,int dstY)466 bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) {
467     if (!SkImageInfoValidConversion(this->info(), src.info())) {
468         return false;
469     }
470 
471     SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
472     if (!rec.trim(this->width(), this->height())) {
473         return false;
474     }
475 
476     void* dstPixels = this->getAddr(rec.fX, rec.fY);
477     const SkImageInfo dstInfo = this->info().makeWH(rec.fInfo.width(), rec.fInfo.height());
478     SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes);
479     this->notifyPixelsChanged();
480     return true;
481 }
482 
483 ///////////////////////////////////////////////////////////////////////////////
484 
GetBitmapAlpha(const SkBitmap & src,uint8_t * SK_RESTRICT alpha,int alphaRowBytes)485 static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
486     SkASSERT(alpha != nullptr);
487     SkASSERT(alphaRowBytes >= src.width());
488 
489     SkPixmap pmap;
490     if (!src.peekPixels(&pmap)) {
491         for (int y = 0; y < src.height(); ++y) {
492             memset(alpha, 0, src.width());
493             alpha += alphaRowBytes;
494         }
495         return false;
496     }
497     SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
498                     pmap.info(), pmap.addr(), pmap.rowBytes());
499     return true;
500 }
501 
502 #include "SkPaint.h"
503 #include "SkMaskFilter.h"
504 #include "SkMatrix.h"
505 
extractAlpha(SkBitmap * dst,const SkPaint * paint,Allocator * allocator,SkIPoint * offset) const506 bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
507                             Allocator *allocator, SkIPoint* offset) const {
508     SkDEBUGCODE(this->validate();)
509 
510     SkBitmap    tmpBitmap;
511     SkMatrix    identity;
512     SkMask      srcM, dstM;
513 
514     if (this->width() == 0 || this->height() == 0) {
515         return false;
516     }
517     srcM.fBounds.set(0, 0, this->width(), this->height());
518     srcM.fRowBytes = SkAlign4(this->width());
519     srcM.fFormat = SkMask::kA8_Format;
520 
521     SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
522 
523     // compute our (larger?) dst bounds if we have a filter
524     if (filter) {
525         identity.reset();
526         if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) {
527             goto NO_FILTER_CASE;
528         }
529         dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
530     } else {
531     NO_FILTER_CASE:
532         tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
533         if (!tmpBitmap.tryAllocPixels(allocator)) {
534             // Allocation of pixels for alpha bitmap failed.
535             SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
536                     tmpBitmap.width(), tmpBitmap.height());
537             return false;
538         }
539         GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
540         if (offset) {
541             offset->set(0, 0);
542         }
543         tmpBitmap.swap(*dst);
544         return true;
545     }
546     srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
547     SkAutoMaskFreeImage srcCleanup(srcM.fImage);
548 
549     GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
550     if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) {
551         goto NO_FILTER_CASE;
552     }
553     SkAutoMaskFreeImage dstCleanup(dstM.fImage);
554 
555     tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
556                       dstM.fRowBytes);
557     if (!tmpBitmap.tryAllocPixels(allocator)) {
558         // Allocation of pixels for alpha bitmap failed.
559         SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
560                 tmpBitmap.width(), tmpBitmap.height());
561         return false;
562     }
563     memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
564     if (offset) {
565         offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
566     }
567     SkDEBUGCODE(tmpBitmap.validate();)
568 
569     tmpBitmap.swap(*dst);
570     return true;
571 }
572 
573 ///////////////////////////////////////////////////////////////////////////////
574 
575 #ifdef SK_DEBUG
validate() const576 void SkBitmap::validate() const {
577     this->info().validate();
578 
579     SkASSERT(this->info().validRowBytes(this->rowBytes()));
580     uint8_t allFlags = kImageIsVolatile_Flag;
581     SkASSERT((~allFlags & fFlags) == 0);
582 
583     if (fPixelRef && fPixelRef->pixels()) {
584         SkASSERT(this->getPixels());
585     } else {
586         SkASSERT(!this->getPixels());
587     }
588 
589     if (this->getPixels()) {
590         SkASSERT(fPixelRef);
591         SkASSERT(fPixelRef->rowBytes() == this->rowBytes());
592         SkIPoint origin = this->pixelRefOrigin();
593         SkASSERT(origin.fX >= 0);
594         SkASSERT(origin.fY >= 0);
595         SkASSERT(fPixelRef->width() >= (int)this->width() + origin.fX);
596         SkASSERT(fPixelRef->height() >= (int)this->height() + origin.fY);
597         SkASSERT(fPixelRef->rowBytes() >= this->info().minRowBytes());
598     }
599 }
600 #endif
601 
602 ///////////////////////////////////////////////////////////////////////////////
603 
peekPixels(SkPixmap * pmap) const604 bool SkBitmap::peekPixels(SkPixmap* pmap) const {
605     if (this->getPixels()) {
606         if (pmap) {
607             *pmap = fPixmap;
608         }
609         return true;
610     }
611     return false;
612 }
613 
614 ///////////////////////////////////////////////////////////////////////////////
615 
616 #ifdef SK_DEBUG
validate() const617 void SkImageInfo::validate() const {
618     SkASSERT(fDimensions.width() >= 0);
619     SkASSERT(fDimensions.height() >= 0);
620     SkASSERT(SkColorTypeIsValid(fColorType));
621     SkASSERT(SkAlphaTypeIsValid(fAlphaType));
622 }
623 #endif
624