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