Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkBitmap.cpp
1
2 /*
3  * Copyright 2008 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8
9
10 #include "SkBitmap.h"
11 #include "SkColorPriv.h"
12 #include "SkDither.h"
13 #include "SkFlattenable.h"
14 #include "SkImagePriv.h"
15 #include "SkMallocPixelRef.h"
16 #include "SkMask.h"
17 #include "SkReadBuffer.h"
18 #include "SkWriteBuffer.h"
19 #include "SkPixelRef.h"
20 #include "SkThread.h"
21 #include "SkUnPreMultiply.h"
22 #include "SkUtils.h"
23 #include "SkValidationUtils.h"
24 #include "SkPackBits.h"
25 #include <new>
26
27 static bool reset_return_false(SkBitmap* bm) {
28     bm->reset();
29     return false;
30 }
31
32 SkBitmap::SkBitmap() {
33     sk_bzero(this, sizeof(*this));
34 }
35
36 SkBitmap::SkBitmap(const SkBitmap& src) {
37     SkDEBUGCODE(src.validate();)
38     sk_bzero(this, sizeof(*this));
39     *this = src;
40     SkDEBUGCODE(this->validate();)
41 }
42
43 SkBitmap::~SkBitmap() {
44     SkDEBUGCODE(this->validate();)
45     this->freePixels();
46 }
47
48 SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
49     if (this != &src) {
50         this->freePixels();
51         memcpy(this, &src, sizeof(src));
52
53         // inc src reference counts
54         SkSafeRef(src.fPixelRef);
55
56         // we reset our locks if we get blown away
57         fPixelLockCount = 0;
58
59         if (fPixelRef) {
60             // ignore the values from the memcpy
61             fPixels = NULL;
62             fColorTable = NULL;
63             // Note that what to for genID is somewhat arbitrary. We have no
64             // way to track changes to raw pixels across multiple SkBitmaps.
65             // Would benefit from an SkRawPixelRef type created by
66             // setPixels.
67             // Just leave the memcpy'ed one but they'll get out of sync
68             // as soon either is modified.
69         }
70     }
71
72     SkDEBUGCODE(this->validate();)
73     return *this;
74 }
75
76 void SkBitmap::swap(SkBitmap& other) {
77     SkTSwap(fColorTable, other.fColorTable);
78     SkTSwap(fPixelRef, other.fPixelRef);
79     SkTSwap(fPixelRefOrigin, other.fPixelRefOrigin);
80     SkTSwap(fPixelLockCount, other.fPixelLockCount);
81     SkTSwap(fPixels, other.fPixels);
82     SkTSwap(fInfo, other.fInfo);
83     SkTSwap(fRowBytes, other.fRowBytes);
84     SkTSwap(fFlags, other.fFlags);
85
86     SkDEBUGCODE(this->validate();)
87 }
88
89 void SkBitmap::reset() {
90     this->freePixels();
91     sk_bzero(this, sizeof(*this));
92 }
93
94 void SkBitmap::getBounds(SkRect* bounds) const {
95     SkASSERT(bounds);
96     bounds->set(0, 0,
97                 SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height()));
98 }
99
100 void SkBitmap::getBounds(SkIRect* bounds) const {
101     SkASSERT(bounds);
102     bounds->set(0, 0, fInfo.width(), fInfo.height());
103 }
104
105 ///////////////////////////////////////////////////////////////////////////////
106
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 ((int32_t)mrb != mrb) {
117         return reset_return_false(this);
118     }
119     if ((int64_t)rowBytes != (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     this->freePixels();
136
137     fInfo = info.makeAlphaType(newAT);
138     fRowBytes = SkToU32(rowBytes);
139     return true;
140 }
141
142 bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
143     if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) {
144         return false;
145     }
146     if (fInfo.alphaType() != newAlphaType) {
147         fInfo = fInfo.makeAlphaType(newAlphaType);
148         if (fPixelRef) {
149             fPixelRef->changeAlphaType(newAlphaType);
150         }
151     }
152     return true;
153 }
154
155 void SkBitmap::updatePixelsFromRef() const {
156     if (fPixelRef) {
157         if (fPixelLockCount > 0) {
158             SkASSERT(fPixelRef->isLocked());
159
160             void* p = fPixelRef->pixels();
161             if (p) {
162                 p = (char*)p
163                     + fPixelRefOrigin.fY * fRowBytes
164                     + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
165             }
166             fPixels = p;
167             fColorTable = fPixelRef->colorTable();
168         } else {
169             SkASSERT(0 == fPixelLockCount);
170             fPixels = NULL;
171             fColorTable = NULL;
172         }
173     }
174 }
175
176 SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) {
177 #ifdef SK_DEBUG
178     if (pr) {
179         if (kUnknown_SkColorType != fInfo.colorType()) {
180             const SkImageInfo& prInfo = pr->info();
181             SkASSERT(fInfo.width() <= prInfo.width());
182             SkASSERT(fInfo.height() <= prInfo.height());
183             SkASSERT(fInfo.colorType() == prInfo.colorType());
184             switch (prInfo.alphaType()) {
185                 case kIgnore_SkAlphaType:
186                     SkASSERT(fInfo.alphaType() == kIgnore_SkAlphaType);
187                     break;
188                 case kOpaque_SkAlphaType:
189                 case kPremul_SkAlphaType:
190                     SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
191                              fInfo.alphaType() == kPremul_SkAlphaType);
192                     break;
193                 case kUnpremul_SkAlphaType:
194                     SkASSERT(fInfo.alphaType() == kOpaque_SkAlphaType ||
195                              fInfo.alphaType() == kUnpremul_SkAlphaType);
196                     break;
197             }
198         }
199     }
200 #endif
201
202     if (pr) {
203         const SkImageInfo& info = pr->info();
204         fPixelRefOrigin.set(SkPin32(dx, 0, info.width()), SkPin32(dy, 0, info.height()));
205     } else {
206         // ignore dx,dy if there is no pixelref
207         fPixelRefOrigin.setZero();
208     }
209
210     if (fPixelRef != pr) {
211         this->freePixels();
212         SkASSERT(NULL == fPixelRef);
213
214         SkSafeRef(pr);
215         fPixelRef = pr;
216         this->updatePixelsFromRef();
217     }
218
219     SkDEBUGCODE(this->validate();)
220     return pr;
221 }
222
223 void SkBitmap::lockPixels() const {
224     if (fPixelRef && 0 == sk_atomic_inc(&fPixelLockCount)) {
225         fPixelRef->lockPixels();
226         this->updatePixelsFromRef();
227     }
228     SkDEBUGCODE(this->validate();)
229 }
230
231 void SkBitmap::unlockPixels() const {
232     SkASSERT(NULL == fPixelRef || fPixelLockCount > 0);
233
234     if (fPixelRef && 1 == sk_atomic_dec(&fPixelLockCount)) {
235         fPixelRef->unlockPixels();
236         this->updatePixelsFromRef();
237     }
238     SkDEBUGCODE(this->validate();)
239 }
240
241 bool SkBitmap::lockPixelsAreWritable() const {
242     return (fPixelRef) ? fPixelRef->lockPixelsAreWritable() : false;
243 }
244
245 void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
246     if (NULL == p) {
247         this->setPixelRef(NULL);
248         return;
249     }
250
251     if (kUnknown_SkColorType == fInfo.colorType()) {
252         this->setPixelRef(NULL);
253         return;
254     }
255
256     SkPixelRef* pr = SkMallocPixelRef::NewDirect(fInfo, p, fRowBytes, ctable);
257     if (NULL == pr) {
258         this->setPixelRef(NULL);
259         return;
260     }
261
262     this->setPixelRef(pr)->unref();
263
264     // since we're already allocated, we lockPixels right away
265     this->lockPixels();
266     SkDEBUGCODE(this->validate();)
267 }
268
269 bool SkBitmap::tryAllocPixels(Allocator* allocator, SkColorTable* ctable) {
270     HeapAllocator stdalloc;
271
272     if (NULL == allocator) {
273         allocator = &stdalloc;
274     }
275     return allocator->allocPixelRef(this, ctable);
276 }
277
278 ///////////////////////////////////////////////////////////////////////////////
279
280 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
281     if (kIndex_8_SkColorType == requestedInfo.colorType()) {
282         return reset_return_false(this);
283     }
284     if (!this->setInfo(requestedInfo, rowBytes)) {
285         return reset_return_false(this);
286     }
287     
288     // setInfo may have corrected info (e.g. 565 is always opaque).
289     const SkImageInfo& correctedInfo = this->info();
290     // setInfo may have computed a valid rowbytes if 0 were passed in
291     rowBytes = this->rowBytes();
292
293     SkMallocPixelRef::PRFactory defaultFactory;
294     
295     SkPixelRef* pr = defaultFactory.create(correctedInfo, rowBytes, NULL);
296     if (NULL == pr) {
297         return reset_return_false(this);
298     }
299     this->setPixelRef(pr)->unref();
300     
301     // TODO: lockPixels could/should return bool or void*/NULL
302     this->lockPixels();
303     if (NULL == this->getPixels()) {
304         return reset_return_false(this);
305     }
306     return true;
307 }
308
309 bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory,
310                                 SkColorTable* ctable) {
311     if (kIndex_8_SkColorType == requestedInfo.colorType() && NULL == ctable) {
312         return reset_return_false(this);
313     }
314     if (!this->setInfo(requestedInfo)) {
315         return reset_return_false(this);
316     }
317
318     // setInfo may have corrected info (e.g. 565 is always opaque).
319     const SkImageInfo& correctedInfo = this->info();
320
321     SkMallocPixelRef::PRFactory defaultFactory;
322     if (NULL == factory) {
323         factory = &defaultFactory;
324     }
325
326     SkPixelRef* pr = factory->create(correctedInfo, correctedInfo.minRowBytes(), ctable);
327     if (NULL == pr) {
328         return reset_return_false(this);
329     }
330     this->setPixelRef(pr)->unref();
331
332     // TODO: lockPixels could/should return bool or void*/NULL
333     this->lockPixels();
334     if (NULL == this->getPixels()) {
335         return reset_return_false(this);
336     }
337     return true;
338 }
339
340 bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
341                              SkColorTable* ct, void (*releaseProc)(void* addr, void* context),
342                              void* context) {
343     if (!this->setInfo(requestedInfo, rb)) {
344         this->reset();
345         return false;
346     }
347
348     // setInfo may have corrected info (e.g. 565 is always opaque).
349     const SkImageInfo& correctedInfo = this->info();
350
351     SkPixelRef* pr = SkMallocPixelRef::NewWithProc(correctedInfo, rb, ct, pixels, releaseProc,
352                                                    context);
353     if (!pr) {
354         this->reset();
355         return false;
356     }
357
358     this->setPixelRef(pr)->unref();
359
360     // since we're already allocated, we lockPixels right away
361     this->lockPixels();
362     SkDEBUGCODE(this->validate();)
363     return true;
364 }
365
366 bool SkBitmap::installMaskPixels(const SkMask& mask) {
367     if (SkMask::kA8_Format != mask.fFormat) {
368         this->reset();
369         return false;
370     }
371     return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
372                                                    mask.fBounds.height()),
373                                mask.fImage, mask.fRowBytes);
374 }
375
376 ///////////////////////////////////////////////////////////////////////////////
377
378 void SkBitmap::freePixels() {
379     if (fPixelRef) {
380         if (fPixelLockCount > 0) {
381             fPixelRef->unlockPixels();
382         }
383         fPixelRef->unref();
384         fPixelRef = NULL;
385         fPixelRefOrigin.setZero();
386     }
387     fPixelLockCount = 0;
388     fPixels = NULL;
389     fColorTable = NULL;
390 }
391
392 uint32_t SkBitmap::getGenerationID() const {
393     return (fPixelRef) ? fPixelRef->getGenerationID() : 0;
394 }
395
396 void SkBitmap::notifyPixelsChanged() const {
397     SkASSERT(!this->isImmutable());
398     if (fPixelRef) {
399         fPixelRef->notifyPixelsChanged();
400     }
401 }
402
403 GrTexture* SkBitmap::getTexture() const {
404     return fPixelRef ? fPixelRef->getTexture() : NULL;
405 }
406
407 ///////////////////////////////////////////////////////////////////////////////
408
409 /** We explicitly use the same allocator for our pixels that SkMask does,
410  so that we can freely assign memory allocated by one class to the other.
411  */
412 bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
413                                             SkColorTable* ctable) {
414     const SkImageInfo info = dst->info();
415     if (kUnknown_SkColorType == info.colorType()) {
416 //        SkDebugf("unsupported config for info %d\n", dst->config());
417         return false;
418     }
419
420     SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), ctable);
421     if (NULL == pr) {
422         return false;
423     }
424
425     dst->setPixelRef(pr)->unref();
426     // since we're already allocated, we lockPixels right away
427     dst->lockPixels();
428     return true;
429 }
430
431 ///////////////////////////////////////////////////////////////////////////////
432
433 bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize,
434                             size_t dstRowBytes, bool preserveDstPad) const {
435
436     if (0 == dstRowBytes) {
437         dstRowBytes = fRowBytes;
438     }
439
440     if (dstRowBytes < fInfo.minRowBytes() ||
441         dst == NULL || (getPixels() == NULL && pixelRef() == NULL)) {
442         return false;
443     }
444
445     if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == fRowBytes) {
446         size_t safeSize = this->getSafeSize();
447         if (safeSize > dstSize || safeSize == 0)
448             return false;
449         else {
450             SkAutoLockPixels lock(*this);
451             // This implementation will write bytes beyond the end of each row,
452             // excluding the last row, if the bitmap's stride is greater than
453             // strictly required by the current config.
454             memcpy(dst, getPixels(), safeSize);
455
456             return true;
457         }
458     } else {
459         // If destination has different stride than us, then copy line by line.
460         if (fInfo.getSafeSize(dstRowBytes) > dstSize) {
461             return false;
462         } else {
463             // Just copy what we need on each line.
464             size_t rowBytes = fInfo.minRowBytes();
465             SkAutoLockPixels lock(*this);
466             const uint8_t* srcP = reinterpret_cast<const uint8_t*>(getPixels());
467             uint8_t* dstP = reinterpret_cast<uint8_t*>(dst);
468             for (int row = 0; row < fInfo.height(); row++, srcP += fRowBytes, dstP += dstRowBytes) {
469                 memcpy(dstP, srcP, rowBytes);
470             }
471
472             return true;
473         }
474     }
475 }
476
477 ///////////////////////////////////////////////////////////////////////////////
478
479 bool SkBitmap::isImmutable() const {
480     return fPixelRef ? fPixelRef->isImmutable() : false;
481 }
482
483 void SkBitmap::setImmutable() {
484     if (fPixelRef) {
485         fPixelRef->setImmutable();
486     }
487 }
488
489 bool SkBitmap::isVolatile() const {
490     return (fFlags & kImageIsVolatile_Flag) != 0;
491 }
492
493 void SkBitmap::setIsVolatile(bool isVolatile) {
494     if (isVolatile) {
495         fFlags |= kImageIsVolatile_Flag;
496     } else {
497         fFlags &= ~kImageIsVolatile_Flag;
498     }
499 }
500
501 void* SkBitmap::getAddr(int x, int y) const {
502     SkASSERT((unsigned)x < (unsigned)this->width());
503     SkASSERT((unsigned)y < (unsigned)this->height());
504
505     char* base = (char*)this->getPixels();
506     if (base) {
507         base += y * this->rowBytes();
508         switch (this->colorType()) {
509             case kRGBA_8888_SkColorType:
510             case kBGRA_8888_SkColorType:
511                 base += x << 2;
512                 break;
513             case kARGB_4444_SkColorType:
514             case kRGB_565_SkColorType:
515                 base += x << 1;
516                 break;
517             case kAlpha_8_SkColorType:
518             case kIndex_8_SkColorType:
519                 base += x;
520                 break;
521             default:
522                 SkDEBUGFAIL("Can't return addr for config");
523                 base = NULL;
524                 break;
525         }
526     }
527     return base;
528 }
529
530 SkColor SkBitmap::getColor(int x, int y) const {
531     SkASSERT((unsigned)x < (unsigned)this->width());
532     SkASSERT((unsigned)y < (unsigned)this->height());
533
534     switch (this->colorType()) {
535         case kAlpha_8_SkColorType: {
536             uint8_t* addr = this->getAddr8(x, y);
537             return SkColorSetA(0, addr[0]);
538         }
539         case kIndex_8_SkColorType: {
540             SkPMColor c = this->getIndex8Color(x, y);
541             return SkUnPreMultiply::PMColorToColor(c);
542         }
543         case kRGB_565_SkColorType: {
544             uint16_t* addr = this->getAddr16(x, y);
545             return SkPixel16ToColor(addr[0]);
546         }
547         case kARGB_4444_SkColorType: {
548             uint16_t* addr = this->getAddr16(x, y);
549             SkPMColor c = SkPixel4444ToPixel32(addr[0]);
550             return SkUnPreMultiply::PMColorToColor(c);
551         }
552         case kBGRA_8888_SkColorType:
553         case kRGBA_8888_SkColorType: {
554             uint32_t* addr = this->getAddr32(x, y);
555             return SkUnPreMultiply::PMColorToColor(addr[0]);
556         }
557         default:
558             SkASSERT(false);
559             return 0;
560     }
561     SkASSERT(false);  // Not reached.
562     return 0;
563 }
564
565 bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) {
566     SkAutoLockPixels alp(bm);
567     if (!bm.getPixels()) {
568         return false;
569     }
570
571     const int height = bm.height();
572     const int width = bm.width();
573
574     switch (bm.colorType()) {
575         case kAlpha_8_SkColorType: {
576             unsigned a = 0xFF;
577             for (int y = 0; y < height; ++y) {
578                 const uint8_t* row = bm.getAddr8(0, y);
579                 for (int x = 0; x < width; ++x) {
580                     a &= row[x];
581                 }
582                 if (0xFF != a) {
583                     return false;
584                 }
585             }
586             return true;
587         } break;
588         case kIndex_8_SkColorType: {
589             SkAutoLockColors alc(bm);
590             const SkPMColor* table = alc.colors();
591             if (!table) {
592                 return false;
593             }
594             SkPMColor c = (SkPMColor)~0;
595             for (int i = bm.getColorTable()->count() - 1; i >= 0; --i) {
596                 c &= table[i];
597             }
598             return 0xFF == SkGetPackedA32(c);
599         } break;
600         case kRGB_565_SkColorType:
601             return true;
602             break;
603         case kARGB_4444_SkColorType: {
604             unsigned c = 0xFFFF;
605             for (int y = 0; y < height; ++y) {
606                 const SkPMColor16* row = bm.getAddr16(0, y);
607                 for (int x = 0; x < width; ++x) {
608                     c &= row[x];
609                 }
610                 if (0xF != SkGetPackedA4444(c)) {
611                     return false;
612                 }
613             }
614             return true;
615         } break;
616         case kBGRA_8888_SkColorType:
617         case kRGBA_8888_SkColorType: {
618             SkPMColor c = (SkPMColor)~0;
619             for (int y = 0; y < height; ++y) {
620                 const SkPMColor* row = bm.getAddr32(0, y);
621                 for (int x = 0; x < width; ++x) {
622                     c &= row[x];
623                 }
624                 if (0xFF != SkGetPackedA32(c)) {
625                     return false;
626                 }
627             }
628             return true;
629         }
630         default:
631             break;
632     }
633     return false;
634 }
635
636
637 ///////////////////////////////////////////////////////////////////////////////
638 ///////////////////////////////////////////////////////////////////////////////
639
640 static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) {
641     unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) |
642                      (SkR32To4444(r) << SK_R4444_SHIFT) |
643                      (SkG32To4444(g) << SK_G4444_SHIFT) |
644                      (SkB32To4444(b) << SK_B4444_SHIFT);
645     return SkToU16(pixel);
646 }
647
648 void SkBitmap::internalErase(const SkIRect& area,
649                              U8CPU a, U8CPU r, U8CPU g, U8CPU b) const {
650 #ifdef SK_DEBUG
651     SkDEBUGCODE(this->validate();)
652     SkASSERT(!area.isEmpty());
653     {
654         SkIRect total = { 0, 0, this->width(), this->height() };
655         SkASSERT(total.contains(area));
656     }
657 #endif
658
659     switch (fInfo.colorType()) {
660         case kUnknown_SkColorType:
661         case kIndex_8_SkColorType:
662             return; // can't erase. Should we bzero so the memory is not uninitialized?
663         default:
664             break;
665     }
666
667     SkAutoLockPixels alp(*this);
668     // perform this check after the lock call
669     if (!this->readyToDraw()) {
670         return;
671     }
672
673     int height = area.height();
674     const int width = area.width();
675     const int rowBytes = fRowBytes;
676
677     switch (this->colorType()) {
678         case kAlpha_8_SkColorType: {
679             uint8_t* p = this->getAddr8(area.fLeft, area.fTop);
680             while (--height >= 0) {
681                 memset(p, a, width);
682                 p += rowBytes;
683             }
684             break;
685         }
686         case kARGB_4444_SkColorType:
687         case kRGB_565_SkColorType: {
688             uint16_t* p = this->getAddr16(area.fLeft, area.fTop);;
689             uint16_t v;
690
691             // make rgb premultiplied
692             if (255 != a) {
693                 r = SkAlphaMul(r, a);
694                 g = SkAlphaMul(g, a);
695                 b = SkAlphaMul(b, a);
696             }
697
698             if (kARGB_4444_SkColorType == this->colorType()) {
699                 v = pack_8888_to_4444(a, r, g, b);
700             } else {
701                 v = SkPackRGB16(r >> (8 - SK_R16_BITS),
702                                 g >> (8 - SK_G16_BITS),
703                                 b >> (8 - SK_B16_BITS));
704             }
705             while (--height >= 0) {
706                 sk_memset16(p, v, width);
707                 p = (uint16_t*)((char*)p + rowBytes);
708             }
709             break;
710         }
711         case kBGRA_8888_SkColorType:
712         case kRGBA_8888_SkColorType: {
713             uint32_t* p = this->getAddr32(area.fLeft, area.fTop);
714
715             if (255 != a && kPremul_SkAlphaType == this->alphaType()) {
716                 r = SkAlphaMul(r, a);
717                 g = SkAlphaMul(g, a);
718                 b = SkAlphaMul(b, a);
719             }
720             uint32_t v = kRGBA_8888_SkColorType == this->colorType() ?
721                          SkPackARGB_as_RGBA(a, r, g, b) : SkPackARGB_as_BGRA(a, r, g, b);
722
723             while (--height >= 0) {
724                 sk_memset32(p, v, width);
725                 p = (uint32_t*)((char*)p + rowBytes);
726             }
727             break;
728         }
729         default:
730             return; // no change, so don't call notifyPixelsChanged()
731     }
732
733     this->notifyPixelsChanged();
734 }
735
736 void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const {
737     SkIRect area = { 0, 0, this->width(), this->height() };
738     if (!area.isEmpty()) {
739         this->internalErase(area, a, r, g, b);
740     }
741 }
742
743 void SkBitmap::eraseArea(const SkIRect& rect, SkColor c) const {
744     SkIRect area = { 0, 0, this->width(), this->height() };
745     if (area.intersect(rect)) {
746         this->internalErase(area, SkColorGetA(c), SkColorGetR(c),
747                             SkColorGetG(c), SkColorGetB(c));
748     }
749 }
750
751 //////////////////////////////////////////////////////////////////////////////////////
752 //////////////////////////////////////////////////////////////////////////////////////
753
754 bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
755     SkDEBUGCODE(this->validate();)
756
757     if (NULL == result || NULL == fPixelRef) {
758         return false;   // no src pixels
759     }
760
761     SkIRect srcRect, r;
762     srcRect.set(0, 0, this->width(), this->height());
763     if (!r.intersect(srcRect, subset)) {
764         return false;   // r is empty (i.e. no intersection)
765     }
766
767     if (fPixelRef->getTexture() != NULL) {
768         // Do a deep copy
769         SkPixelRef* pixelRef = fPixelRef->deepCopy(this->colorType(), &subset);
770         if (pixelRef != NULL) {
771             SkBitmap dst;
772             dst.setInfo(SkImageInfo::Make(subset.width(), subset.height(),
773                                           this->colorType(), this->alphaType()));
774             dst.setIsVolatile(this->isVolatile());
775             dst.setPixelRef(pixelRef)->unref();
776             SkDEBUGCODE(dst.validate());
777             result->swap(dst);
778             return true;
779         }
780     }
781
782     // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
783     // exited above.
784     SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
785     SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
786
787     SkBitmap dst;
788     dst.setInfo(SkImageInfo::Make(r.width(), r.height(), this->colorType(), this->alphaType()),
789                 this->rowBytes());
790     dst.setIsVolatile(this->isVolatile());
791
792     if (fPixelRef) {
793         SkIPoint origin = fPixelRefOrigin;
794         origin.fX += r.fLeft;
795         origin.fY += r.fTop;
796         // share the pixelref with a custom offset
797         dst.setPixelRef(fPixelRef, origin);
798     }
799     SkDEBUGCODE(dst.validate();)
800
801     // we know we're good, so commit to result
802     result->swap(dst);
803     return true;
804 }
805
806 ///////////////////////////////////////////////////////////////////////////////
807
808 #include "SkCanvas.h"
809 #include "SkPaint.h"
810
811 bool SkBitmap::canCopyTo(SkColorType dstColorType) const {
812     const SkColorType srcCT = this->colorType();
813
814     if (srcCT == kUnknown_SkColorType) {
815         return false;
816     }
817
818     bool sameConfigs = (srcCT == dstColorType);
819     switch (dstColorType) {
820         case kAlpha_8_SkColorType:
821         case kRGB_565_SkColorType:
822         case kRGBA_8888_SkColorType:
823         case kBGRA_8888_SkColorType:
824             break;
825         case kIndex_8_SkColorType:
826             if (!sameConfigs) {
827                 return false;
828             }
829             break;
830         case kARGB_4444_SkColorType:
831             return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
832         default:
833             return false;
834     }
835     return true;
836 }
837
838 #include "SkConfig8888.h"
839
840 bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
841                           int x, int y) const {
842     if (kUnknown_SkColorType == requestedDstInfo.colorType()) {
843         return false;
844     }
845     if (NULL == dstPixels || dstRB < requestedDstInfo.minRowBytes()) {
846         return false;
847     }
848     if (0 == requestedDstInfo.width() || 0 == requestedDstInfo.height()) {
849         return false;
850     }
851     
852     SkIRect srcR = SkIRect::MakeXYWH(x, y, requestedDstInfo.width(), requestedDstInfo.height());
853     if (!srcR.intersect(0, 0, this->width(), this->height())) {
854         return false;
855     }
856     
857     // the intersect may have shrunk info's logical size
858     const SkImageInfo dstInfo = requestedDstInfo.makeWH(srcR.width(), srcR.height());
859     
860     // if x or y are negative, then we have to adjust pixels
861     if (x > 0) {
862         x = 0;
863     }
864     if (y > 0) {
865         y = 0;
866     }
867     // here x,y are either 0 or negative
868     dstPixels = ((char*)dstPixels - y * dstRB - x * dstInfo.bytesPerPixel());
869
870     //////////////
871     
872     SkAutoLockPixels alp(*this);
873     
874     // since we don't stop creating un-pixeled devices yet, check for no pixels here
875     if (NULL == this->getPixels()) {
876         return false;
877     }
878     
879     const SkImageInfo srcInfo = this->info().makeWH(dstInfo.width(), dstInfo.height());
880     
881     const void* srcPixels = this->getAddr(srcR.x(), srcR.y());
882     return SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, this->rowBytes(),
883                                    this->getColorTable());
884 }
885
886 bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const {
887     if (!this->canCopyTo(dstColorType)) {
888         return false;
889     }
890
891     // if we have a texture, first get those pixels
892     SkBitmap tmpSrc;
893     const SkBitmap* src = this;
894
895     if (fPixelRef) {
896         SkIRect subset;
897         subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY,
898                        fInfo.width(), fInfo.height());
899         if (fPixelRef->readPixels(&tmpSrc, &subset)) {
900             if (fPixelRef->info().alphaType() == kUnpremul_SkAlphaType) {
901                 // FIXME: The only meaningful implementation of readPixels
902                 // (GrPixelRef) assumes premultiplied pixels.
903                 return false;
904             }
905             SkASSERT(tmpSrc.width() == this->width());
906             SkASSERT(tmpSrc.height() == this->height());
907
908             // did we get lucky and we can just return tmpSrc?
909             if (tmpSrc.colorType() == dstColorType && NULL == alloc) {
910                 dst->swap(tmpSrc);
911                 // If the result is an exact copy, clone the gen ID.
912                 if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) {
913                     dst->pixelRef()->cloneGenID(*fPixelRef);
914                 }
915                 return true;
916             }
917
918             // fall through to the raster case
919             src = &tmpSrc;
920         }
921     }
922
923     // we lock this now, since we may need its colortable
924     SkAutoLockPixels srclock(*src);
925     if (!src->readyToDraw()) {
926         return false;
927     }
928
929     // The only way to be readyToDraw is if fPixelRef is non NULL.
930     SkASSERT(fPixelRef != NULL);
931
932     const SkImageInfo dstInfo = src->info().makeColorType(dstColorType);
933
934     SkBitmap tmpDst;
935     if (!tmpDst.setInfo(dstInfo)) {
936         return false;
937     }
938
939     // allocate colortable if srcConfig == kIndex8_Config
940     SkAutoTUnref<SkColorTable> ctable;
941     if (dstColorType == kIndex_8_SkColorType) {
942         // TODO: can we just ref() the src colortable? Is it reentrant-safe?
943         ctable.reset(SkNEW_ARGS(SkColorTable, (*src->getColorTable())));
944     }
945     if (!tmpDst.tryAllocPixels(alloc, ctable)) {
946         return false;
947     }
948
949     if (!tmpDst.readyToDraw()) {
950         // allocator/lock failed
951         return false;
952     }
953
954     // pixelRef must be non NULL or tmpDst.readyToDraw() would have
955     // returned false.
956     SkASSERT(tmpDst.pixelRef() != NULL);
957
958     if (!src->readPixels(tmpDst.info(), tmpDst.getPixels(), tmpDst.rowBytes(), 0, 0)) {
959         return false;
960     }
961
962     //  (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref.
963     //  The old copyTo impl did this, so we continue it for now.
964     //
965     //  TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be
966     //      if (src_pixelref->info == dst_pixelref->info)
967     //
968     if (src->colorType() == dstColorType && tmpDst.getSize() == src->getSize()) {
969         SkPixelRef* dstPixelRef = tmpDst.pixelRef();
970         if (dstPixelRef->info() == fPixelRef->info()) {
971             dstPixelRef->cloneGenID(*fPixelRef);
972         }
973     }
974
975     dst->swap(tmpDst);
976     return true;
977 }
978
979 bool SkBitmap::deepCopyTo(SkBitmap* dst) const {
980     const SkColorType dstCT = this->colorType();
981
982     if (!this->canCopyTo(dstCT)) {
983         return false;
984     }
985
986     // If we have a PixelRef, and it supports deep copy, use it.
987     // Currently supported only by texture-backed bitmaps.
988     if (fPixelRef) {
989         SkPixelRef* pixelRef = fPixelRef->deepCopy(dstCT, NULL);
990         if (pixelRef) {
991             uint32_t rowBytes;
992             if (this->colorType() == dstCT) {
993                 // Since there is no subset to pass to deepCopy, and deepCopy
994                 // succeeded, the new pixel ref must be identical.
995                 SkASSERT(fPixelRef->info() == pixelRef->info());
996                 pixelRef->cloneGenID(*fPixelRef);
997                 // Use the same rowBytes as the original.
998                 rowBytes = fRowBytes;
999             } else {
1000                 // With the new config, an appropriate fRowBytes will be computed by setInfo.
1001                 rowBytes = 0;
1002             }
1003
1004             const SkImageInfo info = fInfo.makeColorType(dstCT);
1005             if (!dst->setInfo(info, rowBytes)) {
1006                 return false;
1007             }
1008             dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref();
1009             return true;
1010         }
1011     }
1012
1013     if (this->getTexture()) {
1014         return false;
1015     } else {
1016         return this->copyTo(dst, dstCT, NULL);
1017     }
1018 }
1019
1020 ///////////////////////////////////////////////////////////////////////////////
1021
1022 static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha,
1023                            int alphaRowBytes) {
1024     SkASSERT(alpha != NULL);
1025     SkASSERT(alphaRowBytes >= src.width());
1026
1027     SkColorType colorType = src.colorType();
1028     int         w = src.width();
1029     int         h = src.height();
1030     size_t      rb = src.rowBytes();
1031
1032     SkAutoLockPixels alp(src);
1033     if (!src.readyToDraw()) {
1034         // zero out the alpha buffer and return
1035         while (--h >= 0) {
1036             memset(alpha, 0, w);
1037             alpha += alphaRowBytes;
1038         }
1039         return false;
1040     }
1041
1042     if (kAlpha_8_SkColorType == colorType && !src.isOpaque()) {
1043         const uint8_t* s = src.getAddr8(0, 0);
1044         while (--h >= 0) {
1045             memcpy(alpha, s, w);
1046             s += rb;
1047             alpha += alphaRowBytes;
1048         }
1049     } else if (kN32_SkColorType == colorType && !src.isOpaque()) {
1050         const SkPMColor* SK_RESTRICT s = src.getAddr32(0, 0);
1051         while (--h >= 0) {
1052             for (int x = 0; x < w; x++) {
1053                 alpha[x] = SkGetPackedA32(s[x]);
1054             }
1055             s = (const SkPMColor*)((const char*)s + rb);
1056             alpha += alphaRowBytes;
1057         }
1058     } else if (kARGB_4444_SkColorType == colorType && !src.isOpaque()) {
1059         const SkPMColor16* SK_RESTRICT s = src.getAddr16(0, 0);
1060         while (--h >= 0) {
1061             for (int x = 0; x < w; x++) {
1062                 alpha[x] = SkPacked4444ToA32(s[x]);
1063             }
1064             s = (const SkPMColor16*)((const char*)s + rb);
1065             alpha += alphaRowBytes;
1066         }
1067     } else if (kIndex_8_SkColorType == colorType && !src.isOpaque()) {
1068         SkColorTable* ct = src.getColorTable();
1069         if (ct) {
1070             const SkPMColor* SK_RESTRICT table = ct->lockColors();
1071             const uint8_t* SK_RESTRICT s = src.getAddr8(0, 0);
1072             while (--h >= 0) {
1073                 for (int x = 0; x < w; x++) {
1074                     alpha[x] = SkGetPackedA32(table[s[x]]);
1075                 }
1076                 s += rb;
1077                 alpha += alphaRowBytes;
1078             }
1079             ct->unlockColors();
1080         }
1081     } else {    // src is opaque, so just fill alpha[] with 0xFF
1082         memset(alpha, 0xFF, h * alphaRowBytes);
1083     }
1084     return true;
1085 }
1086
1087 #include "SkPaint.h"
1088 #include "SkMaskFilter.h"
1089 #include "SkMatrix.h"
1090
1091 bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
1092                             Allocator *allocator, SkIPoint* offset) const {
1093     SkDEBUGCODE(this->validate();)
1094
1095     SkBitmap    tmpBitmap;
1096     SkMatrix    identity;
1097     SkMask      srcM, dstM;
1098
1099     srcM.fBounds.set(0, 0, this->width(), this->height());
1100     srcM.fRowBytes = SkAlign4(this->width());
1101     srcM.fFormat = SkMask::kA8_Format;
1102
1103     SkMaskFilter* filter = paint ? paint->getMaskFilter() : NULL;
1104
1105     // compute our (larger?) dst bounds if we have a filter
1106     if (filter) {
1107         identity.reset();
1108         srcM.fImage = NULL;
1109         if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
1110             goto NO_FILTER_CASE;
1111         }
1112         dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
1113     } else {
1114     NO_FILTER_CASE:
1115         tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
1116         if (!tmpBitmap.tryAllocPixels(allocator, NULL)) {
1117             // Allocation of pixels for alpha bitmap failed.
1118             SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
1119                     tmpBitmap.width(), tmpBitmap.height());
1120             return false;
1121         }
1122         GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
1123         if (offset) {
1124             offset->set(0, 0);
1125         }
1126         tmpBitmap.swap(*dst);
1127         return true;
1128     }
1129     srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
1130     SkAutoMaskFreeImage srcCleanup(srcM.fImage);
1131
1132     GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
1133     if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
1134         goto NO_FILTER_CASE;
1135     }
1136     SkAutoMaskFreeImage dstCleanup(dstM.fImage);
1137
1138     tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
1139                       dstM.fRowBytes);
1140     if (!tmpBitmap.tryAllocPixels(allocator, NULL)) {
1141         // Allocation of pixels for alpha bitmap failed.
1142         SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
1143                 tmpBitmap.width(), tmpBitmap.height());
1144         return false;
1145     }
1146     memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
1147     if (offset) {
1148         offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
1149     }
1150     SkDEBUGCODE(tmpBitmap.validate();)
1151
1152     tmpBitmap.swap(*dst);
1153     return true;
1154 }
1155
1156 ///////////////////////////////////////////////////////////////////////////////
1157
1158 void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
1159     const SkImageInfo info = bitmap.info();
1160     SkAutoLockPixels alp(bitmap);
1161     if (0 == info.width() || 0 == info.height() || NULL == bitmap.getPixels()) {
1162         buffer->writeUInt(0); // instead of snugRB, signaling no pixels
1163         return;
1164     }
1165
1166     const size_t snugRB = info.width() * info.bytesPerPixel();
1167     const char* src = (const char*)bitmap.getPixels();
1168     const size_t ramRB = bitmap.rowBytes();
1169
1170     buffer->write32(SkToU32(snugRB));
1171     info.flatten(*buffer);
1172
1173     const size_t size = snugRB * info.height();
1174     SkAutoMalloc storage(size);
1175     char* dst = (char*)storage.get();
1176     for (int y = 0; y < info.height(); ++y) {
1177         memcpy(dst, src, snugRB);
1178         dst += snugRB;
1179         src += ramRB;
1180     }
1181     buffer->writeByteArray(storage.get(), size);
1182
1183     SkColorTable* ct = bitmap.getColorTable();
1184     if (kIndex_8_SkColorType == info.colorType() && ct) {
1185         buffer->writeBool(true);
1186         ct->writeToBuffer(*buffer);
1187     } else {
1188         buffer->writeBool(false);
1189     }
1190 }
1191
1192 bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
1193     const size_t snugRB = buffer->readUInt();
1194     if (0 == snugRB) {  // no pixels
1195         return false;
1196     }
1197
1198     SkImageInfo info;
1199     info.unflatten(*buffer);
1200
1201     // If there was an error reading "info", don't use it to compute minRowBytes()
1202     if (!buffer->validate(true)) {
1203         return false;
1204     }
1205
1206     const size_t ramRB = info.minRowBytes();
1207     const int height = info.height();
1208     const size_t snugSize = snugRB * height;
1209     const size_t ramSize = ramRB * height;
1210     if (!buffer->validate(snugSize <= ramSize)) {
1211         return false;
1212     }
1213
1214     SkAutoDataUnref data(SkData::NewUninitialized(ramSize));
1215     char* dst = (char*)data->writable_data();
1216     buffer->readByteArray(dst, snugSize);
1217
1218     if (snugSize != ramSize) {
1219         const char* srcRow = dst + snugRB * (height - 1);
1220         char* dstRow = dst + ramRB * (height - 1);
1221         for (int y = height - 1; y >= 1; --y) {
1222             memmove(dstRow, srcRow, snugRB);
1223             srcRow -= snugRB;
1224             dstRow -= ramRB;
1225         }
1226         SkASSERT(srcRow == dstRow); // first row does not need to be moved
1227     }
1228
1229     SkAutoTUnref<SkColorTable> ctable;
1230     if (buffer->readBool()) {
1231         ctable.reset(SkNEW_ARGS(SkColorTable, (*buffer)));
1232     }
1233
1234     SkAutoTUnref<SkPixelRef> pr(SkMallocPixelRef::NewWithData(info, info.minRowBytes(),
1235                                                               ctable.get(), data.get()));
1236     bitmap->setInfo(pr->info());
1237     bitmap->setPixelRef(pr, 0, 0);
1238     return true;
1239 }
1240
1241 enum {
1242     SERIALIZE_PIXELTYPE_NONE,
1243     SERIALIZE_PIXELTYPE_REF_DATA
1244 };
1245
1246 void SkBitmap::legacyUnflatten(SkReadBuffer& buffer) {
1247 #ifdef SK_SUPPORT_LEGACY_PIXELREF_UNFLATTENABLE
1248     this->reset();
1249
1250     SkImageInfo info;
1251     info.unflatten(buffer);
1252     size_t rowBytes = buffer.readInt();
1253     if (!buffer.validate((info.width() >= 0) && (info.height() >= 0) &&
1254                          SkColorTypeIsValid(info.fColorType) &&
1255                          SkAlphaTypeIsValid(info.fAlphaType) &&
1256                          SkColorTypeValidateAlphaType(info.fColorType, info.fAlphaType) &&
1257                          info.validRowBytes(rowBytes))) {
1258         return;
1259     }
1260
1261     bool configIsValid = this->setInfo(info, rowBytes);
1262     buffer.validate(configIsValid);
1263
1264     int reftype = buffer.readInt();
1265     if (buffer.validate((SERIALIZE_PIXELTYPE_REF_DATA == reftype) ||
1266                         (SERIALIZE_PIXELTYPE_NONE == reftype))) {
1267         switch (reftype) {
1268             case SERIALIZE_PIXELTYPE_REF_DATA: {
1269                 SkIPoint origin;
1270                 origin.fX = buffer.readInt();
1271                 origin.fY = buffer.readInt();
1272                 size_t offset = origin.fY * rowBytes + origin.fX * info.bytesPerPixel();
1273                 SkPixelRef* pr = buffer.readFlattenable<SkPixelRef>();
1274                 if (!buffer.validate((NULL == pr) ||
1275                        (pr->getAllocatedSizeInBytes() >= (offset + this->getSafeSize())))) {
1276                     origin.setZero();
1277                 }
1278                 SkSafeUnref(this->setPixelRef(pr, origin));
1279                 break;
1280             }
1281             case SERIALIZE_PIXELTYPE_NONE:
1282                 break;
1283             default:
1284                 SkDEBUGFAIL("unrecognized pixeltype in serialized data");
1285                 sk_throw();
1286         }
1287     }
1288 #else
1289     sk_throw();
1290 #endif
1291 }
1292
1293 ///////////////////////////////////////////////////////////////////////////////
1294
1295 SkBitmap::RLEPixels::RLEPixels(int width, int height) {
1296     fHeight = height;
1297     fYPtrs = (uint8_t**)sk_calloc_throw(height * sizeof(uint8_t*));
1298 }
1299
1300 SkBitmap::RLEPixels::~RLEPixels() {
1301     sk_free(fYPtrs);
1302 }
1303
1304 ///////////////////////////////////////////////////////////////////////////////
1305
1306 #ifdef SK_DEBUG
1307 void SkBitmap::validate() const {
1308     fInfo.validate();
1309
1310     // ImageInfo may not require this, but Bitmap ensures that opaque-only
1311     // colorTypes report opaque for their alphatype
1312     if (kRGB_565_SkColorType == fInfo.colorType()) {
1313         SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
1314     }
1315
1316     SkASSERT(fInfo.validRowBytes(fRowBytes));
1317     uint8_t allFlags = kImageIsVolatile_Flag;
1318 #ifdef SK_BUILD_FOR_ANDROID
1319     allFlags |= kHasHardwareMipMap_Flag;
1320 #endif
1321     SkASSERT((~allFlags & fFlags) == 0);
1322     SkASSERT(fPixelLockCount >= 0);
1323
1324     if (fPixels) {
1325         SkASSERT(fPixelRef);
1326         SkASSERT(fPixelLockCount > 0);
1327         SkASSERT(fPixelRef->isLocked());
1328         SkASSERT(fPixelRef->rowBytes() == fRowBytes);
1329         SkASSERT(fPixelRefOrigin.fX >= 0);
1330         SkASSERT(fPixelRefOrigin.fY >= 0);
1331         SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX);
1332         SkASSERT(fPixelRef->info().height() >= (int)this->height() + fPixelRefOrigin.fY);
1333         SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
1334     } else {
1335         SkASSERT(NULL == fColorTable);
1336     }
1337 }
1338 #endif
1339
1340 #ifndef SK_IGNORE_TO_STRING
1341 void SkBitmap::toString(SkString* str) const {
1342
1343     static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
1344         "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
1345     };
1346
1347     str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
1348                  gColorTypeNames[this->colorType()]);
1349
1350     str->append(" (");
1351     if (this->isOpaque()) {
1352         str->append("opaque");
1353     } else {
1354         str->append("transparent");
1355     }
1356     if (this->isImmutable()) {
1357         str->append(", immutable");
1358     } else {
1359         str->append(", not-immutable");
1360     }
1361     str->append(")");
1362
1363     SkPixelRef* pr = this->pixelRef();
1364     if (NULL == pr) {
1365         // show null or the explicit pixel address (rare)
1366         str->appendf(" pixels:%p", this->getPixels());
1367     } else {
1368         const char* uri = pr->getURI();
1369         if (uri) {
1370             str->appendf(" uri:\"%s\"", uri);
1371         } else {
1372             str->appendf(" pixelref:%p", pr);
1373         }
1374     }
1375
1376     str->append(")");
1377 }
1378 #endif
1379
1380 ///////////////////////////////////////////////////////////////////////////////
1381
1382 #ifdef SK_DEBUG
1383 void SkImageInfo::validate() const {
1384     SkASSERT(fWidth >= 0);
1385     SkASSERT(fHeight >= 0);
1386     SkASSERT(SkColorTypeIsValid(fColorType));
1387     SkASSERT(SkAlphaTypeIsValid(fAlphaType));
1388 }
1389 #endif