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