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