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