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