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