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