SkBitmap.cpp revision ace7bd5623354ffabbd224d5b76550bab159c296
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 "SkMallocPixelRef.h"
15#include "SkMask.h"
16#include "SkPixelRef.h"
17#include "SkThread.h"
18#include "SkUnPreMultiply.h"
19#include "SkUtils.h"
20#include "SkPackBits.h"
21#include <new>
22
23extern int32_t SkNextPixelRefGenerationID();
24
25static bool isPos32Bits(const Sk64& value) {
26    return !value.isNeg() && value.is32();
27}
28
29struct MipLevel {
30    void*       fPixels;
31    uint32_t    fRowBytes;
32    uint32_t    fWidth, fHeight;
33};
34
35struct SkBitmap::MipMap : SkNoncopyable {
36    int32_t fRefCnt;
37    int     fLevelCount;
38//  MipLevel    fLevel[fLevelCount];
39//  Pixels[]
40
41    static MipMap* Alloc(int levelCount, size_t pixelSize) {
42        if (levelCount < 0) {
43            return NULL;
44        }
45        Sk64 size;
46        size.setMul(levelCount + 1, sizeof(MipLevel));
47        size.add(sizeof(MipMap));
48        size.add(pixelSize);
49        if (!isPos32Bits(size)) {
50            return NULL;
51        }
52        MipMap* mm = (MipMap*)sk_malloc_throw(size.get32());
53        mm->fRefCnt = 1;
54        mm->fLevelCount = levelCount;
55        return mm;
56    }
57
58    const MipLevel* levels() const { return (const MipLevel*)(this + 1); }
59    MipLevel* levels() { return (MipLevel*)(this + 1); }
60
61    const void* pixels() const { return levels() + fLevelCount; }
62    void* pixels() { return levels() + fLevelCount; }
63
64    void ref() {
65        if (SK_MaxS32 == sk_atomic_inc(&fRefCnt)) {
66            sk_throw();
67        }
68    }
69    void unref() {
70        SkASSERT(fRefCnt > 0);
71        if (sk_atomic_dec(&fRefCnt) == 1) {
72            sk_free(this);
73        }
74    }
75};
76
77///////////////////////////////////////////////////////////////////////////////
78///////////////////////////////////////////////////////////////////////////////
79
80SkBitmap::SkBitmap() {
81    sk_bzero(this, sizeof(*this));
82}
83
84SkBitmap::SkBitmap(const SkBitmap& src) {
85    SkDEBUGCODE(src.validate();)
86    sk_bzero(this, sizeof(*this));
87    *this = src;
88    SkDEBUGCODE(this->validate();)
89}
90
91SkBitmap::~SkBitmap() {
92    SkDEBUGCODE(this->validate();)
93    this->freePixels();
94}
95
96SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
97    if (this != &src) {
98        this->freePixels();
99        memcpy(this, &src, sizeof(src));
100
101        // inc src reference counts
102        SkSafeRef(src.fPixelRef);
103        SkSafeRef(src.fMipMap);
104
105        // we reset our locks if we get blown away
106        fPixelLockCount = 0;
107
108        /*  The src could be in 3 states
109            1. no pixelref, in which case we just copy/ref the pixels/ctable
110            2. unlocked pixelref, pixels/ctable should be null
111            3. locked pixelref, we should lock the ref again ourselves
112        */
113        if (NULL == fPixelRef) {
114            // leave fPixels as it is
115            SkSafeRef(fColorTable); // ref the user's ctable if present
116        } else {    // we have a pixelref, so pixels/ctable reflect it
117            // ignore the values from the memcpy
118            fPixels = NULL;
119            fColorTable = NULL;
120            // Note that what to for genID is somewhat arbitrary. We have no
121            // way to track changes to raw pixels across multiple SkBitmaps.
122            // Would benefit from an SkRawPixelRef type created by
123            // setPixels.
124            // Just leave the memcpy'ed one but they'll get out of sync
125            // as soon either is modified.
126        }
127    }
128
129    SkDEBUGCODE(this->validate();)
130    return *this;
131}
132
133void SkBitmap::swap(SkBitmap& other) {
134    SkTSwap(fColorTable, other.fColorTable);
135    SkTSwap(fPixelRef, other.fPixelRef);
136    SkTSwap(fPixelRefOffset, other.fPixelRefOffset);
137    SkTSwap(fPixelLockCount, other.fPixelLockCount);
138    SkTSwap(fMipMap, other.fMipMap);
139    SkTSwap(fPixels, other.fPixels);
140    SkTSwap(fRawPixelGenerationID, other.fRawPixelGenerationID);
141    SkTSwap(fRowBytes, other.fRowBytes);
142    SkTSwap(fWidth, other.fWidth);
143    SkTSwap(fHeight, other.fHeight);
144    SkTSwap(fConfig, other.fConfig);
145    SkTSwap(fFlags, other.fFlags);
146    SkTSwap(fBytesPerPixel, other.fBytesPerPixel);
147
148    SkDEBUGCODE(this->validate();)
149}
150
151void SkBitmap::reset() {
152    this->freePixels();
153    sk_bzero(this, sizeof(*this));
154}
155
156int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) {
157    int bpp;
158    switch (config) {
159        case kNo_Config:
160        case kA1_Config:
161            bpp = 0;   // not applicable
162            break;
163        case kRLE_Index8_Config:
164        case kA8_Config:
165        case kIndex8_Config:
166            bpp = 1;
167            break;
168        case kRGB_565_Config:
169        case kARGB_4444_Config:
170            bpp = 2;
171            break;
172        case kARGB_8888_Config:
173            bpp = 4;
174            break;
175        default:
176            SkASSERT(!"unknown config");
177            bpp = 0;   // error
178            break;
179    }
180    return bpp;
181}
182
183int SkBitmap::ComputeRowBytes(Config c, int width) {
184    if (width < 0) {
185        return 0;
186    }
187
188    Sk64 rowBytes;
189    rowBytes.setZero();
190
191    switch (c) {
192        case kNo_Config:
193        case kRLE_Index8_Config:
194            break;
195        case kA1_Config:
196            rowBytes.set(width);
197            rowBytes.add(7);
198            rowBytes.shiftRight(3);
199            break;
200        case kA8_Config:
201        case kIndex8_Config:
202            rowBytes.set(width);
203            break;
204        case kRGB_565_Config:
205        case kARGB_4444_Config:
206            rowBytes.set(width);
207            rowBytes.shiftLeft(1);
208            break;
209        case kARGB_8888_Config:
210            rowBytes.set(width);
211            rowBytes.shiftLeft(2);
212            break;
213        default:
214            SkASSERT(!"unknown config");
215            break;
216    }
217    return isPos32Bits(rowBytes) ? rowBytes.get32() : 0;
218}
219
220Sk64 SkBitmap::ComputeSize64(Config c, int width, int height) {
221    Sk64 size;
222    size.setMul(SkBitmap::ComputeRowBytes(c, width), height);
223    return size;
224}
225
226size_t SkBitmap::ComputeSize(Config c, int width, int height) {
227    Sk64 size = SkBitmap::ComputeSize64(c, width, height);
228    return isPos32Bits(size) ? size.get32() : 0;
229}
230
231Sk64 SkBitmap::ComputeSafeSize64(Config config,
232                                 uint32_t width,
233                                 uint32_t height,
234                                 uint32_t rowBytes) {
235    Sk64 safeSize;
236    safeSize.setZero();
237    if (height > 0) {
238        safeSize.set(ComputeRowBytes(config, width));
239        Sk64 sizeAllButLastRow;
240        sizeAllButLastRow.setMul(height - 1, rowBytes);
241        safeSize.add(sizeAllButLastRow);
242    }
243    SkASSERT(!safeSize.isNeg());
244    return safeSize;
245}
246
247size_t SkBitmap::ComputeSafeSize(Config config,
248                                 uint32_t width,
249                                 uint32_t height,
250                                 uint32_t rowBytes) {
251    Sk64 safeSize = ComputeSafeSize64(config, width, height, rowBytes);
252    return (safeSize.is32() ? safeSize.get32() : 0);
253}
254
255void SkBitmap::setConfig(Config c, int width, int height, int rowBytes) {
256    this->freePixels();
257
258    if ((width | height | rowBytes) < 0) {
259        goto err;
260    }
261
262    if (rowBytes == 0) {
263        rowBytes = SkBitmap::ComputeRowBytes(c, width);
264        if (0 == rowBytes && kNo_Config != c) {
265            goto err;
266        }
267    }
268
269    fConfig     = SkToU8(c);
270    fWidth      = width;
271    fHeight     = height;
272    fRowBytes   = rowBytes;
273
274    fBytesPerPixel = (uint8_t)ComputeBytesPerPixel(c);
275
276    SkDEBUGCODE(this->validate();)
277    return;
278
279    // if we got here, we had an error, so we reset the bitmap to empty
280err:
281    this->reset();
282}
283
284void SkBitmap::updatePixelsFromRef() const {
285    if (NULL != fPixelRef) {
286        if (fPixelLockCount > 0) {
287            SkASSERT(fPixelRef->getLockCount() > 0);
288
289            void* p = fPixelRef->pixels();
290            if (NULL != p) {
291                p = (char*)p + fPixelRefOffset;
292            }
293            fPixels = p;
294            SkRefCnt_SafeAssign(fColorTable, fPixelRef->colorTable());
295        } else {
296            SkASSERT(0 == fPixelLockCount);
297            fPixels = NULL;
298            if (fColorTable) {
299                fColorTable->unref();
300                fColorTable = NULL;
301            }
302        }
303    }
304}
305
306SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, size_t offset) {
307    // do this first, we that we never have a non-zero offset with a null ref
308    if (NULL == pr) {
309        offset = 0;
310    }
311
312    if (fPixelRef != pr || fPixelRefOffset != offset) {
313        if (fPixelRef != pr) {
314            this->freePixels();
315            SkASSERT(NULL == fPixelRef);
316
317            SkSafeRef(pr);
318            fPixelRef = pr;
319        }
320        fPixelRefOffset = offset;
321        this->updatePixelsFromRef();
322    }
323
324    SkDEBUGCODE(this->validate();)
325    return pr;
326}
327
328void SkBitmap::lockPixels() const {
329    if (NULL != fPixelRef && 1 == ++fPixelLockCount) {
330        fPixelRef->lockPixels();
331        this->updatePixelsFromRef();
332    }
333    SkDEBUGCODE(this->validate();)
334}
335
336void SkBitmap::unlockPixels() const {
337    SkASSERT(NULL == fPixelRef || fPixelLockCount > 0);
338
339    if (NULL != fPixelRef && 0 == --fPixelLockCount) {
340        fPixelRef->unlockPixels();
341        this->updatePixelsFromRef();
342    }
343    SkDEBUGCODE(this->validate();)
344}
345
346bool SkBitmap::lockPixelsAreWritable() const {
347    if (fPixelRef) {
348        return fPixelRef->lockPixelsAreWritable();
349    } else {
350        return fPixels != NULL;
351    }
352}
353
354void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
355    this->freePixels();
356    fPixels = p;
357    SkRefCnt_SafeAssign(fColorTable, ctable);
358
359    SkDEBUGCODE(this->validate();)
360}
361
362bool SkBitmap::allocPixels(Allocator* allocator, SkColorTable* ctable) {
363    HeapAllocator stdalloc;
364
365    if (NULL == allocator) {
366        allocator = &stdalloc;
367    }
368    return allocator->allocPixelRef(this, ctable);
369}
370
371void SkBitmap::freePixels() {
372    // if we're gonna free the pixels, we certainly need to free the mipmap
373    this->freeMipMap();
374
375    if (fColorTable) {
376        fColorTable->unref();
377        fColorTable = NULL;
378    }
379
380    if (NULL != fPixelRef) {
381        if (fPixelLockCount > 0) {
382            fPixelRef->unlockPixels();
383        }
384        fPixelRef->unref();
385        fPixelRef = NULL;
386        fPixelRefOffset = 0;
387    }
388    fPixelLockCount = 0;
389    fPixels = NULL;
390}
391
392void SkBitmap::freeMipMap() {
393    if (fMipMap) {
394        fMipMap->unref();
395        fMipMap = NULL;
396    }
397}
398
399uint32_t SkBitmap::getGenerationID() const {
400    if (fPixelRef) {
401        return fPixelRef->getGenerationID();
402    } else {
403        SkASSERT(fPixels || !fRawPixelGenerationID);
404        if (fPixels && !fRawPixelGenerationID) {
405            fRawPixelGenerationID = SkNextPixelRefGenerationID();
406        }
407        return fRawPixelGenerationID;
408    }
409}
410
411void SkBitmap::notifyPixelsChanged() const {
412    if (fPixelRef) {
413        fPixelRef->notifyPixelsChanged();
414    } else {
415        fRawPixelGenerationID = 0; // will grab next ID in getGenerationID
416    }
417}
418
419SkGpuTexture* SkBitmap::getTexture() const {
420    return fPixelRef ? fPixelRef->getTexture() : NULL;
421}
422
423///////////////////////////////////////////////////////////////////////////////
424
425/** We explicitly use the same allocator for our pixels that SkMask does,
426 so that we can freely assign memory allocated by one class to the other.
427 */
428bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst,
429                                            SkColorTable* ctable) {
430    Sk64 size = dst->getSize64();
431    if (size.isNeg() || !size.is32()) {
432        return false;
433    }
434
435    void* addr = sk_malloc_flags(size.get32(), 0);  // returns NULL on failure
436    if (NULL == addr) {
437        return false;
438    }
439
440    dst->setPixelRef(new SkMallocPixelRef(addr, size.get32(), ctable))->unref();
441    // since we're already allocated, we lockPixels right away
442    dst->lockPixels();
443    return true;
444}
445
446///////////////////////////////////////////////////////////////////////////////
447
448size_t SkBitmap::getSafeSize() const {
449    // This is intended to be a size_t version of ComputeSafeSize64(), just
450    // faster. The computation is meant to be identical.
451    return (fHeight ? ((fHeight - 1) * fRowBytes) +
452            ComputeRowBytes(getConfig(), fWidth): 0);
453}
454
455Sk64 SkBitmap::getSafeSize64() const {
456    return ComputeSafeSize64(getConfig(), fWidth, fHeight, fRowBytes);
457}
458
459bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize, int dstRowBytes)
460     const {
461
462    if (dstRowBytes == -1)
463        dstRowBytes = fRowBytes;
464    SkASSERT(dstRowBytes >= 0);
465
466    if (getConfig() == kRLE_Index8_Config ||
467        dstRowBytes < ComputeRowBytes(getConfig(), fWidth) ||
468        dst == NULL || (getPixels() == NULL && pixelRef() == NULL))
469        return false;
470
471    if (static_cast<uint32_t>(dstRowBytes) == fRowBytes) {
472        size_t safeSize = getSafeSize();
473        if (safeSize > dstSize || safeSize == 0)
474            return false;
475        else {
476            SkAutoLockPixels lock(*this);
477            // This implementation will write bytes beyond the end of each row,
478            // excluding the last row, if the bitmap's stride is greater than
479            // strictly required by the current config.
480            memcpy(dst, getPixels(), safeSize);
481
482            return true;
483        }
484    } else {
485        // If destination has different stride than us, then copy line by line.
486        if (ComputeSafeSize(getConfig(), fWidth, fHeight, dstRowBytes) >
487            dstSize)
488            return false;
489        else {
490            // Just copy what we need on each line.
491            uint32_t rowBytes = ComputeRowBytes(getConfig(), fWidth);
492            SkAutoLockPixels lock(*this);
493            const uint8_t* srcP = reinterpret_cast<const uint8_t*>(getPixels());
494            uint8_t* dstP = reinterpret_cast<uint8_t*>(dst);
495            for (uint32_t row = 0; row < fHeight;
496                 row++, srcP += fRowBytes, dstP += dstRowBytes) {
497                memcpy(dstP, srcP, rowBytes);
498            }
499
500            return true;
501        }
502    }
503}
504
505///////////////////////////////////////////////////////////////////////////////
506
507bool SkBitmap::isOpaque() const {
508    switch (fConfig) {
509        case kNo_Config:
510            return true;
511
512        case kA1_Config:
513        case kA8_Config:
514        case kARGB_4444_Config:
515        case kARGB_8888_Config:
516            return (fFlags & kImageIsOpaque_Flag) != 0;
517
518        case kIndex8_Config:
519        case kRLE_Index8_Config: {
520                uint32_t flags = 0;
521
522                this->lockPixels();
523                // if lockPixels failed, we may not have a ctable ptr
524                if (fColorTable) {
525                    flags = fColorTable->getFlags();
526                }
527                this->unlockPixels();
528
529                return (flags & SkColorTable::kColorsAreOpaque_Flag) != 0;
530            }
531
532        case kRGB_565_Config:
533            return true;
534
535        default:
536            SkASSERT(!"unknown bitmap config pased to isOpaque");
537            return false;
538    }
539}
540
541void SkBitmap::setIsOpaque(bool isOpaque) {
542    /*  we record this regardless of fConfig, though it is ignored in
543        isOpaque() for configs that can't support per-pixel alpha.
544    */
545    if (isOpaque) {
546        fFlags |= kImageIsOpaque_Flag;
547    } else {
548        fFlags &= ~kImageIsOpaque_Flag;
549    }
550}
551
552bool SkBitmap::isVolatile() const {
553    return (fFlags & kImageIsVolatile_Flag) != 0;
554}
555
556void SkBitmap::setIsVolatile(bool isVolatile) {
557    if (isVolatile) {
558        fFlags |= kImageIsVolatile_Flag;
559    } else {
560        fFlags &= ~kImageIsVolatile_Flag;
561    }
562}
563
564void* SkBitmap::getAddr(int x, int y) const {
565    SkASSERT((unsigned)x < (unsigned)this->width());
566    SkASSERT((unsigned)y < (unsigned)this->height());
567
568    char* base = (char*)this->getPixels();
569    if (base) {
570        base += y * this->rowBytes();
571        switch (this->config()) {
572            case SkBitmap::kARGB_8888_Config:
573                base += x << 2;
574                break;
575            case SkBitmap::kARGB_4444_Config:
576            case SkBitmap::kRGB_565_Config:
577                base += x << 1;
578                break;
579            case SkBitmap::kA8_Config:
580            case SkBitmap::kIndex8_Config:
581                base += x;
582                break;
583            case SkBitmap::kA1_Config:
584                base += x >> 3;
585                break;
586            case kRLE_Index8_Config:
587                SkASSERT(!"Can't return addr for kRLE_Index8_Config");
588                base = NULL;
589                break;
590            default:
591                SkASSERT(!"Can't return addr for config");
592                base = NULL;
593                break;
594        }
595    }
596    return base;
597}
598
599SkColor SkBitmap::getColor(int x, int y) const {
600    SkASSERT((unsigned)x < (unsigned)this->width());
601    SkASSERT((unsigned)y < (unsigned)this->height());
602
603    switch (this->config()) {
604        case SkBitmap::kA1_Config: {
605            uint8_t* addr = this->getAddr1(x, y);
606            uint8_t mask = 1 << (7  - (x % 8));
607            if (addr[0] & mask) {
608                return SK_ColorBLACK;
609            } else {
610                return 0;
611            }
612        }
613        case SkBitmap::kA8_Config: {
614            uint8_t* addr = this->getAddr8(x, y);
615            return SkColorSetA(0, addr[0]);
616        }
617        case SkBitmap::kIndex8_Config: {
618            SkPMColor c = this->getIndex8Color(x, y);
619            return SkUnPreMultiply::PMColorToColor(c);
620        }
621        case SkBitmap::kRGB_565_Config: {
622            uint16_t* addr = this->getAddr16(x, y);
623            return SkPixel16ToColor(addr[0]);
624        }
625        case SkBitmap::kARGB_4444_Config: {
626            uint16_t* addr = this->getAddr16(x, y);
627            SkPMColor c = SkPixel4444ToPixel32(addr[0]);
628            return SkUnPreMultiply::PMColorToColor(c);
629        }
630        case SkBitmap::kARGB_8888_Config: {
631            uint32_t* addr = this->getAddr32(x, y);
632            return SkUnPreMultiply::PMColorToColor(addr[0]);
633        }
634        case kRLE_Index8_Config: {
635            uint8_t dst;
636            const SkBitmap::RLEPixels* rle =
637                (const SkBitmap::RLEPixels*)this->getPixels();
638            SkPackBits::Unpack8(&dst, x, 1, rle->packedAtY(y));
639            return SkUnPreMultiply::PMColorToColor((*fColorTable)[dst]);
640        }
641        case kNo_Config:
642        case kConfigCount:
643            SkASSERT(false);
644            return 0;
645    }
646    SkASSERT(false);  // Not reached.
647    return 0;
648}
649
650///////////////////////////////////////////////////////////////////////////////
651///////////////////////////////////////////////////////////////////////////////
652
653void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const {
654    SkDEBUGCODE(this->validate();)
655
656    if (0 == fWidth || 0 == fHeight ||
657            kNo_Config == fConfig || kIndex8_Config == fConfig) {
658        return;
659    }
660
661    SkAutoLockPixels alp(*this);
662    // perform this check after the lock call
663    if (!this->readyToDraw()) {
664        return;
665    }
666
667    int height = fHeight;
668    const int width = fWidth;
669    const int rowBytes = fRowBytes;
670
671    // make rgb premultiplied
672    if (255 != a) {
673        r = SkAlphaMul(r, a);
674        g = SkAlphaMul(g, a);
675        b = SkAlphaMul(b, a);
676    }
677
678    switch (fConfig) {
679        case kA1_Config: {
680            uint8_t* p = (uint8_t*)fPixels;
681            const int count = (width + 7) >> 3;
682            a = (a >> 7) ? 0xFF : 0;
683            SkASSERT(count <= rowBytes);
684            while (--height >= 0) {
685                memset(p, a, count);
686                p += rowBytes;
687            }
688            break;
689        }
690        case kA8_Config: {
691            uint8_t* p = (uint8_t*)fPixels;
692            while (--height >= 0) {
693                memset(p, a, width);
694                p += rowBytes;
695            }
696            break;
697        }
698        case kARGB_4444_Config:
699        case kRGB_565_Config: {
700            uint16_t* p = (uint16_t*)fPixels;
701            uint16_t v;
702
703            if (kARGB_4444_Config == fConfig) {
704                v = SkPackARGB4444(a >> 4, r >> 4, g >> 4, b >> 4);
705            } else {    // kRGB_565_Config
706                v = SkPackRGB16(r >> (8 - SK_R16_BITS), g >> (8 - SK_G16_BITS),
707                                b >> (8 - SK_B16_BITS));
708            }
709            while (--height >= 0) {
710                sk_memset16(p, v, width);
711                p = (uint16_t*)((char*)p + rowBytes);
712            }
713            break;
714        }
715        case kARGB_8888_Config: {
716            uint32_t* p = (uint32_t*)fPixels;
717            uint32_t  v = SkPackARGB32(a, r, g, b);
718
719            while (--height >= 0) {
720                sk_memset32(p, v, width);
721                p = (uint32_t*)((char*)p + rowBytes);
722            }
723            break;
724        }
725    }
726
727    this->notifyPixelsChanged();
728}
729
730//////////////////////////////////////////////////////////////////////////////////////
731//////////////////////////////////////////////////////////////////////////////////////
732
733#define SUB_OFFSET_FAILURE  ((size_t)-1)
734
735static size_t getSubOffset(const SkBitmap& bm, int x, int y) {
736    SkASSERT((unsigned)x < (unsigned)bm.width());
737    SkASSERT((unsigned)y < (unsigned)bm.height());
738
739    switch (bm.getConfig()) {
740        case SkBitmap::kA8_Config:
741        case SkBitmap:: kIndex8_Config:
742            // x is fine as is for the calculation
743            break;
744
745        case SkBitmap::kRGB_565_Config:
746        case SkBitmap::kARGB_4444_Config:
747            x <<= 1;
748            break;
749
750        case SkBitmap::kARGB_8888_Config:
751            x <<= 2;
752            break;
753
754        case SkBitmap::kNo_Config:
755        case SkBitmap::kA1_Config:
756        default:
757            return SUB_OFFSET_FAILURE;
758    }
759    return y * bm.rowBytes() + x;
760}
761
762bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
763    SkDEBUGCODE(this->validate();)
764
765    if (NULL == result || (NULL == fPixelRef && NULL == fPixels)) {
766        return false;   // no src pixels
767    }
768
769    SkIRect srcRect, r;
770    srcRect.set(0, 0, this->width(), this->height());
771    if (!r.intersect(srcRect, subset)) {
772        return false;   // r is empty (i.e. no intersection)
773    }
774
775    if (kRLE_Index8_Config == fConfig) {
776        SkAutoLockPixels alp(*this);
777        // don't call readyToDraw(), since we can operate w/o a colortable
778        // at this stage
779        if (this->getPixels() == NULL) {
780            return false;
781        }
782        SkBitmap bm;
783
784        bm.setConfig(kIndex8_Config, r.width(), r.height());
785        bm.allocPixels(this->getColorTable());
786        if (NULL == bm.getPixels()) {
787            return false;
788        }
789
790        const RLEPixels* rle = (const RLEPixels*)this->getPixels();
791        uint8_t* dst = bm.getAddr8(0, 0);
792        const int width = bm.width();
793        const int rowBytes = bm.rowBytes();
794
795        for (int y = r.fTop; y < r.fBottom; y++) {
796            SkPackBits::Unpack8(dst, r.fLeft, width, rle->packedAtY(y));
797            dst += rowBytes;
798        }
799        result->swap(bm);
800        return true;
801    }
802
803    size_t offset = getSubOffset(*this, r.fLeft, r.fTop);
804    if (SUB_OFFSET_FAILURE == offset) {
805        return false;   // config not supported
806    }
807
808    SkBitmap dst;
809    dst.setConfig(this->config(), r.width(), r.height(), this->rowBytes());
810
811    if (fPixelRef) {
812        // share the pixelref with a custom offset
813        dst.setPixelRef(fPixelRef, fPixelRefOffset + offset);
814    } else {
815        // share the pixels (owned by the caller)
816        dst.setPixels((char*)fPixels + offset, this->getColorTable());
817    }
818    SkDEBUGCODE(dst.validate();)
819
820    // we know we're good, so commit to result
821    result->swap(dst);
822    return true;
823}
824
825///////////////////////////////////////////////////////////////////////////////
826
827#include "SkCanvas.h"
828#include "SkPaint.h"
829
830bool SkBitmap::canCopyTo(Config dstConfig) const {
831    if (this->getConfig() == kNo_Config) {
832        return false;
833    }
834
835    bool sameConfigs = (this->config() == dstConfig);
836    switch (dstConfig) {
837        case kA8_Config:
838        case kARGB_4444_Config:
839        case kRGB_565_Config:
840        case kARGB_8888_Config:
841            break;
842        case kA1_Config:
843        case kIndex8_Config:
844            if (!sameConfigs) {
845                return false;
846            }
847            break;
848        default:
849            return false;
850    }
851
852    // do not copy src if srcConfig == kA1_Config while dstConfig != kA1_Config
853    if (this->getConfig() == kA1_Config && !sameConfigs) {
854        return false;
855    }
856
857    return true;
858}
859
860bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const {
861    if (!this->canCopyTo(dstConfig)) {
862        return false;
863    }
864
865    // if we have a texture, first get those pixels
866    SkBitmap tmpSrc;
867    const SkBitmap* src = this;
868
869    if (fPixelRef && fPixelRef->readPixels(&tmpSrc)) {
870        SkASSERT(tmpSrc.width() == this->width());
871        SkASSERT(tmpSrc.height() == this->height());
872
873        // did we get lucky and we can just return tmpSrc?
874        if (tmpSrc.config() == dstConfig && NULL == alloc) {
875            dst->swap(tmpSrc);
876            return true;
877        }
878
879        // fall through to the raster case
880        src = &tmpSrc;
881    }
882
883    // we lock this now, since we may need its colortable
884    SkAutoLockPixels srclock(*src);
885    if (!src->readyToDraw()) {
886        return false;
887    }
888
889    SkBitmap tmpDst;
890    tmpDst.setConfig(dstConfig, src->width(), src->height());
891
892    // allocate colortable if srcConfig == kIndex8_Config
893    SkColorTable* ctable = (dstConfig == kIndex8_Config) ?
894    new SkColorTable(*src->getColorTable()) : NULL;
895    SkAutoUnref au(ctable);
896    if (!tmpDst.allocPixels(alloc, ctable)) {
897        return false;
898    }
899
900    SkAutoLockPixels dstlock(tmpDst);
901    if (!tmpDst.readyToDraw()) {
902        // allocator/lock failed
903        return false;
904    }
905
906    /* do memcpy for the same configs cases, else use drawing
907    */
908    if (src->config() == dstConfig) {
909        if (tmpDst.getSize() == src->getSize()) {
910            memcpy(tmpDst.getPixels(), src->getPixels(), src->getSafeSize());
911        } else {
912            const char* srcP = reinterpret_cast<const char*>(src->getPixels());
913            char* dstP = reinterpret_cast<char*>(tmpDst.getPixels());
914            // to be sure we don't read too much, only copy our logical pixels
915            size_t bytesToCopy = tmpDst.width() * tmpDst.bytesPerPixel();
916            for (int y = 0; y < tmpDst.height(); y++) {
917                memcpy(dstP, srcP, bytesToCopy);
918                srcP += src->rowBytes();
919                dstP += tmpDst.rowBytes();
920            }
921        }
922    } else {
923        // if the src has alpha, we have to clear the dst first
924        if (!src->isOpaque()) {
925            tmpDst.eraseColor(0);
926        }
927
928        SkCanvas canvas(tmpDst);
929        SkPaint  paint;
930
931        paint.setDither(true);
932        canvas.drawBitmap(*src, 0, 0, &paint);
933    }
934
935    tmpDst.setIsOpaque(src->isOpaque());
936
937    dst->swap(tmpDst);
938    return true;
939}
940
941///////////////////////////////////////////////////////////////////////////////
942///////////////////////////////////////////////////////////////////////////////
943
944static void downsampleby2_proc32(SkBitmap* dst, int x, int y,
945                                 const SkBitmap& src) {
946    x <<= 1;
947    y <<= 1;
948    const SkPMColor* p = src.getAddr32(x, y);
949    const SkPMColor* baseP = p;
950    SkPMColor c, ag, rb;
951
952    c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF;
953    if (x < src.width() - 1) {
954        p += 1;
955    }
956    c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
957
958    p = baseP;
959    if (y < src.height() - 1) {
960        p += src.rowBytes() >> 2;
961    }
962    c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
963    if (x < src.width() - 1) {
964        p += 1;
965    }
966    c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
967
968    *dst->getAddr32(x >> 1, y >> 1) =
969        ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00);
970}
971
972static inline uint32_t expand16(U16CPU c) {
973    return (c & ~SK_G16_MASK_IN_PLACE) | ((c & SK_G16_MASK_IN_PLACE) << 16);
974}
975
976// returns dirt in the top 16bits, but we don't care, since we only
977// store the low 16bits.
978static inline U16CPU pack16(uint32_t c) {
979    return (c & ~SK_G16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE);
980}
981
982static void downsampleby2_proc16(SkBitmap* dst, int x, int y,
983                                 const SkBitmap& src) {
984    x <<= 1;
985    y <<= 1;
986    const uint16_t* p = src.getAddr16(x, y);
987    const uint16_t* baseP = p;
988    SkPMColor       c;
989
990    c = expand16(*p);
991    if (x < src.width() - 1) {
992        p += 1;
993    }
994    c += expand16(*p);
995
996    p = baseP;
997    if (y < src.height() - 1) {
998        p += src.rowBytes() >> 1;
999    }
1000    c += expand16(*p);
1001    if (x < src.width() - 1) {
1002        p += 1;
1003    }
1004    c += expand16(*p);
1005
1006    *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)pack16(c >> 2);
1007}
1008
1009static uint32_t expand4444(U16CPU c) {
1010    return (c & 0xF0F) | ((c & ~0xF0F) << 12);
1011}
1012
1013static U16CPU collaps4444(uint32_t c) {
1014    return (c & 0xF0F) | ((c >> 12) & ~0xF0F);
1015}
1016
1017static void downsampleby2_proc4444(SkBitmap* dst, int x, int y,
1018                                   const SkBitmap& src) {
1019    x <<= 1;
1020    y <<= 1;
1021    const uint16_t* p = src.getAddr16(x, y);
1022    const uint16_t* baseP = p;
1023    uint32_t        c;
1024
1025    c = expand4444(*p);
1026    if (x < src.width() - 1) {
1027        p += 1;
1028    }
1029    c += expand4444(*p);
1030
1031    p = baseP;
1032    if (y < src.height() - 1) {
1033        p += src.rowBytes() >> 1;
1034    }
1035    c += expand4444(*p);
1036    if (x < src.width() - 1) {
1037        p += 1;
1038    }
1039    c += expand4444(*p);
1040
1041    *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)collaps4444(c >> 2);
1042}
1043
1044void SkBitmap::buildMipMap(bool forceRebuild) {
1045    if (forceRebuild)
1046        this->freeMipMap();
1047    else if (fMipMap)
1048        return; // we're already built
1049
1050    SkASSERT(NULL == fMipMap);
1051
1052    void (*proc)(SkBitmap* dst, int x, int y, const SkBitmap& src);
1053
1054    const SkBitmap::Config config = this->getConfig();
1055
1056    switch (config) {
1057        case kARGB_8888_Config:
1058            proc = downsampleby2_proc32;
1059            break;
1060        case kRGB_565_Config:
1061            proc = downsampleby2_proc16;
1062            break;
1063        case kARGB_4444_Config:
1064            proc = downsampleby2_proc4444;
1065            break;
1066        case kIndex8_Config:
1067        case kA8_Config:
1068        default:
1069            return; // don't build mipmaps for these configs
1070    }
1071
1072    SkAutoLockPixels alp(*this);
1073    if (!this->readyToDraw()) {
1074        return;
1075    }
1076
1077    // whip through our loop to compute the exact size needed
1078    size_t  size = 0;
1079    int     maxLevels = 0;
1080    {
1081        int width = this->width();
1082        int height = this->height();
1083        for (;;) {
1084            width >>= 1;
1085            height >>= 1;
1086            if (0 == width || 0 == height) {
1087                break;
1088            }
1089            size += ComputeRowBytes(config, width) * height;
1090            maxLevels += 1;
1091        }
1092    }
1093
1094    // nothing to build
1095    if (0 == maxLevels) {
1096        return;
1097    }
1098
1099    SkBitmap srcBM(*this);
1100    srcBM.lockPixels();
1101    if (!srcBM.readyToDraw()) {
1102        return;
1103    }
1104
1105    MipMap* mm = MipMap::Alloc(maxLevels, size);
1106    if (NULL == mm) {
1107        return;
1108    }
1109
1110    MipLevel*   level = mm->levels();
1111    uint8_t*    addr = (uint8_t*)mm->pixels();
1112    int         width = this->width();
1113    int         height = this->height();
1114    unsigned    rowBytes = this->rowBytes();
1115    SkBitmap    dstBM;
1116
1117    for (int i = 0; i < maxLevels; i++) {
1118        width >>= 1;
1119        height >>= 1;
1120        rowBytes = ComputeRowBytes(config, width);
1121
1122        level[i].fPixels   = addr;
1123        level[i].fWidth    = width;
1124        level[i].fHeight   = height;
1125        level[i].fRowBytes = rowBytes;
1126
1127        dstBM.setConfig(config, width, height, rowBytes);
1128        dstBM.setPixels(addr);
1129
1130        for (int y = 0; y < height; y++) {
1131            for (int x = 0; x < width; x++) {
1132                proc(&dstBM, x, y, srcBM);
1133            }
1134        }
1135
1136        srcBM = dstBM;
1137        addr += height * rowBytes;
1138    }
1139    SkASSERT(addr == (uint8_t*)mm->pixels() + size);
1140    fMipMap = mm;
1141}
1142
1143bool SkBitmap::hasMipMap() const {
1144    return fMipMap != NULL;
1145}
1146
1147int SkBitmap::extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy) {
1148    if (NULL == fMipMap) {
1149        return 0;
1150    }
1151
1152    int level = ComputeMipLevel(sx, sy) >> 16;
1153    SkASSERT(level >= 0);
1154    if (level <= 0) {
1155        return 0;
1156    }
1157
1158    if (level >= fMipMap->fLevelCount) {
1159        level = fMipMap->fLevelCount - 1;
1160    }
1161    if (dst) {
1162        const MipLevel& mip = fMipMap->levels()[level - 1];
1163        dst->setConfig((SkBitmap::Config)this->config(),
1164                       mip.fWidth, mip.fHeight, mip.fRowBytes);
1165        dst->setPixels(mip.fPixels);
1166    }
1167    return level;
1168}
1169
1170SkFixed SkBitmap::ComputeMipLevel(SkFixed sx, SkFixed sy) {
1171    sx = SkAbs32(sx);
1172    sy = SkAbs32(sy);
1173    if (sx < sy) {
1174        sx = sy;
1175    }
1176    if (sx < SK_Fixed1) {
1177        return 0;
1178    }
1179    int clz = SkCLZ(sx);
1180    SkASSERT(clz >= 1 && clz <= 15);
1181    return SkIntToFixed(15 - clz) + ((unsigned)(sx << (clz + 1)) >> 16);
1182}
1183
1184///////////////////////////////////////////////////////////////////////////////
1185
1186static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha,
1187                           int alphaRowBytes) {
1188    SkASSERT(alpha != NULL);
1189    SkASSERT(alphaRowBytes >= src.width());
1190
1191    SkBitmap::Config config = src.getConfig();
1192    int              w = src.width();
1193    int              h = src.height();
1194    int              rb = src.rowBytes();
1195
1196    SkAutoLockPixels alp(src);
1197    if (!src.readyToDraw()) {
1198        // zero out the alpha buffer and return
1199        while (--h >= 0) {
1200            memset(alpha, 0, w);
1201            alpha += alphaRowBytes;
1202        }
1203        return false;
1204    }
1205
1206    if (SkBitmap::kA8_Config == config && !src.isOpaque()) {
1207        const uint8_t* s = src.getAddr8(0, 0);
1208        while (--h >= 0) {
1209            memcpy(alpha, s, w);
1210            s += rb;
1211            alpha += alphaRowBytes;
1212        }
1213    } else if (SkBitmap::kARGB_8888_Config == config && !src.isOpaque()) {
1214        const SkPMColor* SK_RESTRICT s = src.getAddr32(0, 0);
1215        while (--h >= 0) {
1216            for (int x = 0; x < w; x++) {
1217                alpha[x] = SkGetPackedA32(s[x]);
1218            }
1219            s = (const SkPMColor*)((const char*)s + rb);
1220            alpha += alphaRowBytes;
1221        }
1222    } else if (SkBitmap::kARGB_4444_Config == config && !src.isOpaque()) {
1223        const SkPMColor16* SK_RESTRICT s = src.getAddr16(0, 0);
1224        while (--h >= 0) {
1225            for (int x = 0; x < w; x++) {
1226                alpha[x] = SkPacked4444ToA32(s[x]);
1227            }
1228            s = (const SkPMColor16*)((const char*)s + rb);
1229            alpha += alphaRowBytes;
1230        }
1231    } else if (SkBitmap::kIndex8_Config == config && !src.isOpaque()) {
1232        SkColorTable* ct = src.getColorTable();
1233        if (ct) {
1234            const SkPMColor* SK_RESTRICT table = ct->lockColors();
1235            const uint8_t* SK_RESTRICT s = src.getAddr8(0, 0);
1236            while (--h >= 0) {
1237                for (int x = 0; x < w; x++) {
1238                    alpha[x] = SkGetPackedA32(table[s[x]]);
1239                }
1240                s += rb;
1241                alpha += alphaRowBytes;
1242            }
1243            ct->unlockColors(false);
1244        }
1245    } else {    // src is opaque, so just fill alpha[] with 0xFF
1246        memset(alpha, 0xFF, h * alphaRowBytes);
1247    }
1248    return true;
1249}
1250
1251#include "SkPaint.h"
1252#include "SkMaskFilter.h"
1253#include "SkMatrix.h"
1254
1255bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
1256                            Allocator *allocator, SkIPoint* offset) const {
1257    SkDEBUGCODE(this->validate();)
1258
1259    SkBitmap    tmpBitmap;
1260    SkMatrix    identity;
1261    SkMask      srcM, dstM;
1262
1263    srcM.fBounds.set(0, 0, this->width(), this->height());
1264    srcM.fRowBytes = SkAlign4(this->width());
1265    srcM.fFormat = SkMask::kA8_Format;
1266
1267    SkMaskFilter* filter = paint ? paint->getMaskFilter() : NULL;
1268
1269    // compute our (larger?) dst bounds if we have a filter
1270    if (NULL != filter) {
1271        identity.reset();
1272        srcM.fImage = NULL;
1273        if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
1274            goto NO_FILTER_CASE;
1275        }
1276        dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
1277    } else {
1278    NO_FILTER_CASE:
1279        tmpBitmap.setConfig(SkBitmap::kA8_Config, this->width(), this->height(),
1280                       srcM.fRowBytes);
1281        if (!tmpBitmap.allocPixels(allocator, NULL)) {
1282            // Allocation of pixels for alpha bitmap failed.
1283            SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
1284                    tmpBitmap.width(), tmpBitmap.height());
1285            return false;
1286        }
1287        GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
1288        if (offset) {
1289            offset->set(0, 0);
1290        }
1291        tmpBitmap.swap(*dst);
1292        return true;
1293    }
1294    srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
1295    SkAutoMaskFreeImage srcCleanup(srcM.fImage);
1296
1297    GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
1298    if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
1299        goto NO_FILTER_CASE;
1300    }
1301    SkAutoMaskFreeImage dstCleanup(dstM.fImage);
1302
1303    tmpBitmap.setConfig(SkBitmap::kA8_Config, dstM.fBounds.width(),
1304                   dstM.fBounds.height(), dstM.fRowBytes);
1305    if (!tmpBitmap.allocPixels(allocator, NULL)) {
1306        // Allocation of pixels for alpha bitmap failed.
1307        SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
1308                tmpBitmap.width(), tmpBitmap.height());
1309        return false;
1310    }
1311    memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
1312    if (offset) {
1313        offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
1314    }
1315    SkDEBUGCODE(tmpBitmap.validate();)
1316
1317    tmpBitmap.swap(*dst);
1318    return true;
1319}
1320
1321///////////////////////////////////////////////////////////////////////////////
1322
1323enum {
1324    SERIALIZE_PIXELTYPE_NONE,
1325    SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE,
1326    SERIALIZE_PIXELTYPE_RAW_NO_CTABLE,
1327    SERIALIZE_PIXELTYPE_REF_DATA,
1328    SERIALIZE_PIXELTYPE_REF_PTR,
1329};
1330
1331static void writeString(SkFlattenableWriteBuffer& buffer, const char str[]) {
1332    size_t len = strlen(str);
1333    buffer.write32(len);
1334    buffer.writePad(str, len);
1335}
1336
1337static SkPixelRef::Factory deserialize_factory(SkFlattenableReadBuffer& buffer) {
1338    size_t len = buffer.readInt();
1339    SkAutoSMalloc<256> storage(len + 1);
1340    char* str = (char*)storage.get();
1341    buffer.read(str, len);
1342    str[len] = 0;
1343    return SkPixelRef::NameToFactory(str);
1344}
1345
1346/*
1347    It is tricky to know how much to flatten. If we don't have a pixelref (i.e.
1348    we just have pixels, then we can only flatten the pixels, or write out an
1349    empty bitmap.
1350
1351    With a pixelref, we still have the question of recognizing when two sitings
1352    of the same pixelref are the same, and when they are different. Perhaps we
1353    should look at the generationID and keep a record of that in some dictionary
1354    associated with the buffer. SkGLTextureCache does this sort of thing to know
1355    when to create a new texture.
1356*/
1357void SkBitmap::flatten(SkFlattenableWriteBuffer& buffer) const {
1358    buffer.write32(fWidth);
1359    buffer.write32(fHeight);
1360    buffer.write32(fRowBytes);
1361    buffer.write8(fConfig);
1362    buffer.writeBool(this->isOpaque());
1363
1364    /*  If we are called in this mode, then it is up to the caller to manage
1365        the owner-counts on the pixelref, as we just record the ptr itself.
1366    */
1367    if (!buffer.persistBitmapPixels()) {
1368        if (fPixelRef) {
1369            buffer.write8(SERIALIZE_PIXELTYPE_REF_PTR);
1370            buffer.write32(fPixelRefOffset);
1371            buffer.writeRefCnt(fPixelRef);
1372            return;
1373        } else {
1374            // we ignore the non-persist request, since we don't have a ref
1375            // ... or we could just write an empty bitmap...
1376            // (true) will write an empty bitmap, (false) will flatten the pix
1377            if (true) {
1378                buffer.write8(SERIALIZE_PIXELTYPE_NONE);
1379                return;
1380            }
1381        }
1382    }
1383
1384    if (fPixelRef) {
1385        SkPixelRef::Factory fact = fPixelRef->getFactory();
1386        if (fact) {
1387            const char* name = SkPixelRef::FactoryToName(fact);
1388            if (name && *name) {
1389                buffer.write8(SERIALIZE_PIXELTYPE_REF_DATA);
1390                buffer.write32(fPixelRefOffset);
1391                writeString(buffer, name);
1392                fPixelRef->flatten(buffer);
1393                return;
1394            }
1395        }
1396        // if we get here, we can't record the pixels
1397        buffer.write8(SERIALIZE_PIXELTYPE_NONE);
1398    } else if (fPixels) {
1399        if (fColorTable) {
1400            buffer.write8(SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE);
1401            fColorTable->flatten(buffer);
1402        } else {
1403            buffer.write8(SERIALIZE_PIXELTYPE_RAW_NO_CTABLE);
1404        }
1405        buffer.writePad(fPixels, this->getSafeSize());
1406        // There is no writeZeroPad() fcn, so write individual bytes.
1407        if (this->getSize() > this->getSafeSize()) {
1408            size_t deltaSize = this->getSize() - this->getSafeSize();
1409            // Need aligned pointer to write into due to internal implementa-
1410            // tion of SkWriter32.
1411            memset(buffer.reserve(SkAlign4(deltaSize)), 0, deltaSize);
1412        }
1413    } else {
1414        buffer.write8(SERIALIZE_PIXELTYPE_NONE);
1415    }
1416}
1417
1418void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) {
1419    this->reset();
1420
1421    int width = buffer.readInt();
1422    int height = buffer.readInt();
1423    int rowBytes = buffer.readInt();
1424    int config = buffer.readU8();
1425
1426    this->setConfig((Config)config, width, height, rowBytes);
1427    this->setIsOpaque(buffer.readBool());
1428
1429    int reftype = buffer.readU8();
1430    switch (reftype) {
1431        case SERIALIZE_PIXELTYPE_REF_PTR: {
1432            size_t offset = buffer.readU32();
1433            SkPixelRef* pr = (SkPixelRef*)buffer.readRefCnt();
1434            this->setPixelRef(pr, offset);
1435            break;
1436        }
1437        case SERIALIZE_PIXELTYPE_REF_DATA: {
1438            size_t offset = buffer.readU32();
1439            SkPixelRef::Factory fact = deserialize_factory(buffer);
1440            SkPixelRef* pr = fact(buffer);
1441            SkSafeUnref(this->setPixelRef(pr, offset));
1442            break;
1443        }
1444        case SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE:
1445        case SERIALIZE_PIXELTYPE_RAW_NO_CTABLE: {
1446            SkColorTable* ctable = NULL;
1447            if (SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE == reftype) {
1448                ctable = SkNEW_ARGS(SkColorTable, (buffer));
1449            }
1450            size_t size = this->getSize();
1451            if (this->allocPixels(ctable)) {
1452                this->lockPixels();
1453                // Just read what we need.
1454                buffer.read(this->getPixels(), this->getSafeSize());
1455                // Keep aligned for subsequent reads.
1456                buffer.skip(size - this->getSafeSize());
1457                this->unlockPixels();
1458            } else {
1459                buffer.skip(size); // Still skip the full-sized buffer though.
1460            }
1461            SkSafeUnref(ctable);
1462            break;
1463        }
1464        case SERIALIZE_PIXELTYPE_NONE:
1465            break;
1466        default:
1467            SkASSERT(!"unrecognized pixeltype in serialized data");
1468            sk_throw();
1469    }
1470}
1471
1472///////////////////////////////////////////////////////////////////////////////
1473
1474SkBitmap::RLEPixels::RLEPixels(int width, int height) {
1475    fHeight = height;
1476    fYPtrs = (uint8_t**)sk_malloc_throw(height * sizeof(uint8_t*));
1477    sk_bzero(fYPtrs, height * sizeof(uint8_t*));
1478}
1479
1480SkBitmap::RLEPixels::~RLEPixels() {
1481    sk_free(fYPtrs);
1482}
1483
1484///////////////////////////////////////////////////////////////////////////////
1485
1486#ifdef SK_DEBUG
1487void SkBitmap::validate() const {
1488    SkASSERT(fConfig < kConfigCount);
1489    SkASSERT(fRowBytes >= (unsigned)ComputeRowBytes((Config)fConfig, fWidth));
1490    SkASSERT(fFlags <= (kImageIsOpaque_Flag | kImageIsVolatile_Flag));
1491    SkASSERT(fPixelLockCount >= 0);
1492    SkASSERT(NULL == fColorTable || (unsigned)fColorTable->getRefCnt() < 10000);
1493    SkASSERT((uint8_t)ComputeBytesPerPixel((Config)fConfig) == fBytesPerPixel);
1494
1495#if 0   // these asserts are not thread-correct, so disable for now
1496    if (fPixelRef) {
1497        if (fPixelLockCount > 0) {
1498            SkASSERT(fPixelRef->getLockCount() > 0);
1499        } else {
1500            SkASSERT(NULL == fPixels);
1501            SkASSERT(NULL == fColorTable);
1502        }
1503    }
1504#endif
1505}
1506#endif
1507