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