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