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 "SkColorTable.h"
12#include "SkConvertPixels.h"
13#include "SkData.h"
14#include "SkFilterQuality.h"
15#include "SkHalf.h"
16#include "SkImageInfoPriv.h"
17#include "SkMallocPixelRef.h"
18#include "SkMask.h"
19#include "SkMath.h"
20#include "SkPixelRef.h"
21#include "SkReadBuffer.h"
22#include "SkRect.h"
23#include "SkScalar.h"
24#include "SkTemplates.h"
25#include "SkUnPreMultiply.h"
26#include "SkWriteBuffer.h"
27#include "SkWritePixelsRec.h"
28
29#include <string.h>
30
31static bool reset_return_false(SkBitmap* bm) {
32    bm->reset();
33    return false;
34}
35
36SkBitmap::SkBitmap()
37    : fPixels        (nullptr)
38    , fPixelRefOrigin{0, 0}
39    , fRowBytes      (0)
40    , fFlags         (0) {}
41
42SkBitmap::SkBitmap(const SkBitmap& src)
43    : fPixelRef      (src.fPixelRef)
44    , fPixels        (src.fPixels)
45    , fPixelRefOrigin(src.fPixelRefOrigin)
46    , fInfo          (src.fInfo)
47    , fRowBytes      (src.fRowBytes)
48    , fFlags         (src.fFlags)
49{
50    SkDEBUGCODE(src.validate();)
51    SkDEBUGCODE(this->validate();)
52}
53
54SkBitmap::SkBitmap(SkBitmap&& other)
55    : fPixelRef      (std::move(other.fPixelRef))
56    , fPixels                  (other.fPixels)
57    , fPixelRefOrigin          (other.fPixelRefOrigin)
58    , fInfo          (std::move(other.fInfo))
59    , fRowBytes                (other.fRowBytes)
60    , fFlags                   (other.fFlags)
61{
62    SkASSERT(!other.fPixelRef);
63    other.fInfo.reset();
64    other.fPixels         = nullptr;
65    other.fPixelRefOrigin = SkIPoint{0, 0};
66    other.fRowBytes       = 0;
67    other.fFlags          = 0;
68}
69
70SkBitmap::~SkBitmap() {}
71
72SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
73    if (this != &src) {
74        fPixelRef       = src.fPixelRef;
75        fPixels         = src.fPixels;
76        fPixelRefOrigin = src.fPixelRefOrigin;
77        fInfo           = src.fInfo;
78        fRowBytes       = src.fRowBytes;
79        fFlags          = src.fFlags;
80    }
81    SkDEBUGCODE(this->validate();)
82    return *this;
83}
84
85SkBitmap& SkBitmap::operator=(SkBitmap&& other) {
86    if (this != &other) {
87        fPixelRef       = std::move(other.fPixelRef);
88        fInfo           = std::move(other.fInfo);
89        fPixels         = other.fPixels;
90        fPixelRefOrigin = other.fPixelRefOrigin;
91        fRowBytes       = other.fRowBytes;
92        fFlags          = other.fFlags;
93        SkASSERT(!other.fPixelRef);
94        other.fInfo.reset();
95        other.fPixels         = nullptr;
96        other.fPixelRefOrigin = SkIPoint{0, 0};
97        other.fRowBytes       = 0;
98        other.fFlags          = 0;
99    }
100    return *this;
101}
102
103void SkBitmap::swap(SkBitmap& other) {
104    SkTSwap(*this, other);
105    SkDEBUGCODE(this->validate();)
106}
107
108void SkBitmap::reset() {
109    this->freePixels();
110    this->fInfo.reset();
111    sk_bzero(this, sizeof(*this));
112}
113
114void SkBitmap::getBounds(SkRect* bounds) const {
115    SkASSERT(bounds);
116    bounds->set(0, 0,
117                SkIntToScalar(fInfo.width()), SkIntToScalar(fInfo.height()));
118}
119
120void SkBitmap::getBounds(SkIRect* bounds) const {
121    SkASSERT(bounds);
122    bounds->set(0, 0, fInfo.width(), fInfo.height());
123}
124
125///////////////////////////////////////////////////////////////////////////////
126
127bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
128    SkAlphaType newAT = info.alphaType();
129    if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
130        return reset_return_false(this);
131    }
132    // don't look at info.alphaType(), since newAT is the real value...
133
134    // require that rowBytes fit in 31bits
135    int64_t mrb = info.minRowBytes64();
136    if ((int32_t)mrb != mrb) {
137        return reset_return_false(this);
138    }
139    if ((int64_t)rowBytes != (int32_t)rowBytes) {
140        return reset_return_false(this);
141    }
142
143    if (info.width() < 0 || info.height() < 0) {
144        return reset_return_false(this);
145    }
146
147    if (kUnknown_SkColorType == info.colorType()) {
148        rowBytes = 0;
149    } else if (0 == rowBytes) {
150        rowBytes = (size_t)mrb;
151    } else if (!info.validRowBytes(rowBytes)) {
152        return reset_return_false(this);
153    }
154
155    this->freePixels();
156
157    fInfo = info.makeAlphaType(newAT);
158    fRowBytes = SkToU32(rowBytes);
159    SkDEBUGCODE(this->validate();)
160    return true;
161}
162
163bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
164    if (!SkColorTypeValidateAlphaType(fInfo.colorType(), newAlphaType, &newAlphaType)) {
165        return false;
166    }
167    if (fInfo.alphaType() != newAlphaType) {
168        fInfo = fInfo.makeAlphaType(newAlphaType);
169    }
170    SkDEBUGCODE(this->validate();)
171    return true;
172}
173
174void SkBitmap::updatePixelsFromRef() {
175    void* p = nullptr;
176    if (fPixelRef) {
177        // wish we could assert that a pixelref *always* has pixels
178        p = fPixelRef->pixels();
179        if (p) {
180            SkASSERT(fRowBytes == fPixelRef->rowBytes());
181            p = (char*)p
182                + fPixelRefOrigin.fY * fRowBytes
183                + fPixelRefOrigin.fX * fInfo.bytesPerPixel();
184        }
185    }
186    fPixels = p;
187}
188
189void SkBitmap::setPixelRef(sk_sp<SkPixelRef> pr, int dx, int dy) {
190#ifdef SK_DEBUG
191    if (pr) {
192        if (kUnknown_SkColorType != fInfo.colorType()) {
193            SkASSERT(fInfo.width() + dx <= pr->width());
194            SkASSERT(fInfo.height() + dy <= pr->height());
195        }
196    }
197#endif
198
199    fPixelRef = std::move(pr);
200    if (fPixelRef) {
201        fPixelRefOrigin.set(SkTPin(dx, 0, fPixelRef->width()), SkTPin(dy, 0, fPixelRef->height()));
202        this->updatePixelsFromRef();
203    } else {
204        // ignore dx,dy if there is no pixelref
205        fPixelRefOrigin.setZero();
206        fPixels = nullptr;
207    }
208
209    SkDEBUGCODE(this->validate();)
210}
211
212void SkBitmap::setPixels(void* p) {
213    if (nullptr == p) {
214        this->setPixelRef(nullptr, 0, 0);
215        return;
216    }
217
218    if (kUnknown_SkColorType == fInfo.colorType()) {
219        this->setPixelRef(nullptr, 0, 0);
220        return;
221    }
222
223    this->setPixelRef(SkMallocPixelRef::MakeDirect(fInfo, p, fRowBytes), 0, 0);
224    if (!fPixelRef) {
225        return;
226    }
227    SkDEBUGCODE(this->validate();)
228}
229
230bool SkBitmap::tryAllocPixels(Allocator* allocator) {
231    HeapAllocator stdalloc;
232
233    if (nullptr == allocator) {
234        allocator = &stdalloc;
235    }
236#ifdef SK_SUPPORT_LEGACY_COLORTABLE
237    return allocator->allocPixelRef(this, nullptr);
238#else
239    return allocator->allocPixelRef(this);
240#endif
241}
242
243///////////////////////////////////////////////////////////////////////////////
244
245bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
246    if (!this->setInfo(requestedInfo, rowBytes)) {
247        return reset_return_false(this);
248    }
249
250    // setInfo may have corrected info (e.g. 565 is always opaque).
251    const SkImageInfo& correctedInfo = this->info();
252    // setInfo may have computed a valid rowbytes if 0 were passed in
253    rowBytes = this->rowBytes();
254
255    sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes);
256    if (!pr) {
257        return reset_return_false(this);
258    }
259    this->setPixelRef(std::move(pr), 0, 0);
260    if (nullptr == this->getPixels()) {
261        return reset_return_false(this);
262    }
263    SkDEBUGCODE(this->validate();)
264    return true;
265}
266
267bool SkBitmap::tryAllocPixelsFlags(const SkImageInfo& requestedInfo, uint32_t allocFlags) {
268    if (!this->setInfo(requestedInfo)) {
269        return reset_return_false(this);
270    }
271
272    // setInfo may have corrected info (e.g. 565 is always opaque).
273    const SkImageInfo& correctedInfo = this->info();
274
275    sk_sp<SkPixelRef> pr = (allocFlags & kZeroPixels_AllocFlag) ?
276        SkMallocPixelRef::MakeZeroed(correctedInfo, correctedInfo.minRowBytes()) :
277        SkMallocPixelRef::MakeAllocate(correctedInfo, correctedInfo.minRowBytes());
278    if (!pr) {
279        return reset_return_false(this);
280    }
281    this->setPixelRef(std::move(pr), 0, 0);
282    if (nullptr == this->getPixels()) {
283        return reset_return_false(this);
284    }
285    SkDEBUGCODE(this->validate();)
286    return true;
287}
288
289static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
290    if (proc) {
291        proc(pixels, ctx);
292    }
293}
294
295bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
296                             void (*releaseProc)(void* addr, void* context), void* context) {
297    if (!this->setInfo(requestedInfo, rb)) {
298        invoke_release_proc(releaseProc, pixels, context);
299        this->reset();
300        return false;
301    }
302    if (nullptr == pixels) {
303        invoke_release_proc(releaseProc, pixels, context);
304        return true;    // we behaved as if they called setInfo()
305    }
306
307    // setInfo may have corrected info (e.g. 565 is always opaque).
308    const SkImageInfo& correctedInfo = this->info();
309
310    sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithProc(correctedInfo, rb, pixels,
311                                                          releaseProc, context);
312    if (!pr) {
313        this->reset();
314        return false;
315    }
316
317    this->setPixelRef(std::move(pr), 0, 0);
318    SkDEBUGCODE(this->validate();)
319    return true;
320}
321
322bool SkBitmap::installPixels(const SkPixmap& pixmap) {
323    return this->installPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(),
324                               nullptr, nullptr);
325}
326
327bool SkBitmap::installMaskPixels(const SkMask& mask) {
328    if (SkMask::kA8_Format != mask.fFormat) {
329        this->reset();
330        return false;
331    }
332    return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
333                                                   mask.fBounds.height()),
334                               mask.fImage, mask.fRowBytes);
335}
336
337///////////////////////////////////////////////////////////////////////////////
338
339void SkBitmap::freePixels() {
340    fPixelRef = nullptr;
341    fPixelRefOrigin.setZero();
342    fPixels = nullptr;
343}
344
345uint32_t SkBitmap::getGenerationID() const {
346    return fPixelRef ? fPixelRef->getGenerationID() : 0;
347}
348
349void SkBitmap::notifyPixelsChanged() const {
350    SkASSERT(!this->isImmutable());
351    if (fPixelRef) {
352        fPixelRef->notifyPixelsChanged();
353    }
354}
355
356///////////////////////////////////////////////////////////////////////////////
357
358/** We explicitly use the same allocator for our pixels that SkMask does,
359 so that we can freely assign memory allocated by one class to the other.
360 */
361bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst
362#ifdef SK_SUPPORT_LEGACY_COLORTABLE
363                                            , SkColorTable*
364#endif
365                                            ) {
366    const SkImageInfo info = dst->info();
367    if (kUnknown_SkColorType == info.colorType()) {
368//        SkDebugf("unsupported config for info %d\n", dst->config());
369        return false;
370    }
371
372    sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes());
373    if (!pr) {
374        return false;
375    }
376
377    dst->setPixelRef(std::move(pr), 0, 0);
378    SkDEBUGCODE(dst->validate();)
379    return true;
380}
381
382///////////////////////////////////////////////////////////////////////////////
383
384bool SkBitmap::isImmutable() const {
385    return fPixelRef ? fPixelRef->isImmutable() : false;
386}
387
388void SkBitmap::setImmutable() {
389    if (fPixelRef) {
390        fPixelRef->setImmutable();
391    }
392}
393
394bool SkBitmap::isVolatile() const {
395    return (fFlags & kImageIsVolatile_Flag) != 0;
396}
397
398void SkBitmap::setIsVolatile(bool isVolatile) {
399    if (isVolatile) {
400        fFlags |= kImageIsVolatile_Flag;
401    } else {
402        fFlags &= ~kImageIsVolatile_Flag;
403    }
404}
405
406void* SkBitmap::getAddr(int x, int y) const {
407    SkASSERT((unsigned)x < (unsigned)this->width());
408    SkASSERT((unsigned)y < (unsigned)this->height());
409
410    char* base = (char*)this->getPixels();
411    if (base) {
412        base += y * this->rowBytes();
413        switch (this->colorType()) {
414            case kRGBA_F16_SkColorType:
415                base += x << 3;
416                break;
417            case kRGBA_8888_SkColorType:
418            case kBGRA_8888_SkColorType:
419                base += x << 2;
420                break;
421            case kARGB_4444_SkColorType:
422            case kRGB_565_SkColorType:
423                base += x << 1;
424                break;
425            case kAlpha_8_SkColorType:
426            case kGray_8_SkColorType:
427                base += x;
428                break;
429            default:
430                SkDEBUGFAIL("Can't return addr for config");
431                base = nullptr;
432                break;
433        }
434    }
435    return base;
436}
437
438///////////////////////////////////////////////////////////////////////////////
439///////////////////////////////////////////////////////////////////////////////
440
441void SkBitmap::erase(SkColor c, const SkIRect& area) const {
442    SkDEBUGCODE(this->validate();)
443
444    switch (fInfo.colorType()) {
445        case kUnknown_SkColorType:
446            // TODO: can we ASSERT that we never get here?
447            return; // can't erase. Should we bzero so the memory is not uninitialized?
448        default:
449            break;
450    }
451
452    SkPixmap result;
453    if (!this->peekPixels(&result)) {
454        return;
455    }
456
457    if (result.erase(c, area)) {
458        this->notifyPixelsChanged();
459    }
460}
461
462void SkBitmap::eraseColor(SkColor c) const {
463    this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
464}
465
466//////////////////////////////////////////////////////////////////////////////////////
467//////////////////////////////////////////////////////////////////////////////////////
468
469bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
470    SkDEBUGCODE(this->validate();)
471
472    if (nullptr == result || !fPixelRef) {
473        return false;   // no src pixels
474    }
475
476    SkIRect srcRect, r;
477    srcRect.set(0, 0, this->width(), this->height());
478    if (!r.intersect(srcRect, subset)) {
479        return false;   // r is empty (i.e. no intersection)
480    }
481
482    // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
483    // exited above.
484    SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
485    SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
486
487    SkBitmap dst;
488    dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes());
489    dst.setIsVolatile(this->isVolatile());
490
491    if (fPixelRef) {
492        SkIPoint origin = fPixelRefOrigin;
493        origin.fX += r.fLeft;
494        origin.fY += r.fTop;
495        // share the pixelref with a custom offset
496        dst.setPixelRef(fPixelRef, origin.x(), origin.y());
497    }
498    SkDEBUGCODE(dst.validate();)
499
500    // we know we're good, so commit to result
501    result->swap(dst);
502    return true;
503}
504
505///////////////////////////////////////////////////////////////////////////////
506
507bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
508                          int x, int y, SkTransferFunctionBehavior behavior) const {
509    SkPixmap src;
510    if (!this->peekPixels(&src)) {
511        return false;
512    }
513    return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y, behavior);
514}
515
516bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
517    return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
518}
519
520bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY,
521                           SkTransferFunctionBehavior behavior) {
522    if (!SkImageInfoValidConversion(fInfo, src.info())) {
523        return false;
524    }
525
526    SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
527    if (!rec.trim(fInfo.width(), fInfo.height())) {
528        return false;
529    }
530
531    void* dstPixels = this->getAddr(rec.fX, rec.fY);
532    const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
533    SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes,
534                    nullptr, behavior);
535    return true;
536}
537
538///////////////////////////////////////////////////////////////////////////////
539
540static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
541    SkASSERT(alpha != nullptr);
542    SkASSERT(alphaRowBytes >= src.width());
543
544    SkPixmap pmap;
545    if (!src.peekPixels(&pmap)) {
546        for (int y = 0; y < src.height(); ++y) {
547            memset(alpha, 0, src.width());
548            alpha += alphaRowBytes;
549        }
550        return false;
551    }
552    SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
553                    pmap.info(), pmap.addr(), pmap.rowBytes(), nullptr,
554                    SkTransferFunctionBehavior::kRespect);
555    return true;
556}
557
558#include "SkPaint.h"
559#include "SkMaskFilter.h"
560#include "SkMatrix.h"
561
562bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
563                            Allocator *allocator, SkIPoint* offset) const {
564    SkDEBUGCODE(this->validate();)
565
566    SkBitmap    tmpBitmap;
567    SkMatrix    identity;
568    SkMask      srcM, dstM;
569
570    srcM.fBounds.set(0, 0, this->width(), this->height());
571    srcM.fRowBytes = SkAlign4(this->width());
572    srcM.fFormat = SkMask::kA8_Format;
573
574    SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
575
576    // compute our (larger?) dst bounds if we have a filter
577    if (filter) {
578        identity.reset();
579        if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
580            goto NO_FILTER_CASE;
581        }
582        dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
583    } else {
584    NO_FILTER_CASE:
585        tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
586        if (!tmpBitmap.tryAllocPixels(allocator)) {
587            // Allocation of pixels for alpha bitmap failed.
588            SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
589                    tmpBitmap.width(), tmpBitmap.height());
590            return false;
591        }
592        GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
593        if (offset) {
594            offset->set(0, 0);
595        }
596        tmpBitmap.swap(*dst);
597        return true;
598    }
599    srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
600    SkAutoMaskFreeImage srcCleanup(srcM.fImage);
601
602    GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
603    if (!filter->filterMask(&dstM, srcM, identity, nullptr)) {
604        goto NO_FILTER_CASE;
605    }
606    SkAutoMaskFreeImage dstCleanup(dstM.fImage);
607
608    tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
609                      dstM.fRowBytes);
610    if (!tmpBitmap.tryAllocPixels(allocator)) {
611        // Allocation of pixels for alpha bitmap failed.
612        SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
613                tmpBitmap.width(), tmpBitmap.height());
614        return false;
615    }
616    memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
617    if (offset) {
618        offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
619    }
620    SkDEBUGCODE(tmpBitmap.validate();)
621
622    tmpBitmap.swap(*dst);
623    return true;
624}
625
626///////////////////////////////////////////////////////////////////////////////
627
628static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) {
629    const SkImageInfo& info = pmap.info();
630    const size_t snugRB = info.width() * info.bytesPerPixel();
631    const char* src = (const char*)pmap.addr();
632    const size_t ramRB = pmap.rowBytes();
633
634    buffer->write32(SkToU32(snugRB));
635    info.flatten(*buffer);
636
637    const size_t size = snugRB * info.height();
638    SkAutoTMalloc<char> storage(size);
639    char* dst = storage.get();
640    for (int y = 0; y < info.height(); ++y) {
641        memcpy(dst, src, snugRB);
642        dst += snugRB;
643        src += ramRB;
644    }
645    buffer->writeByteArray(storage.get(), size);
646    // no colortable
647    buffer->writeBool(false);
648}
649
650void SkBitmap::WriteRawPixels(SkWriteBuffer* buffer, const SkBitmap& bitmap) {
651    const SkImageInfo info = bitmap.info();
652    if (0 == info.width() || 0 == info.height() || bitmap.isNull()) {
653        buffer->writeUInt(0); // instead of snugRB, signaling no pixels
654        return;
655    }
656
657    SkPixmap result;
658    if (!bitmap.peekPixels(&result)) {
659        buffer->writeUInt(0); // instead of snugRB, signaling no pixels
660        return;
661    }
662
663    write_raw_pixels(buffer, result);
664}
665
666bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) {
667    const size_t snugRB = buffer->readUInt();
668    if (0 == snugRB) {  // no pixels
669        return false;
670    }
671
672    SkImageInfo info;
673    info.unflatten(*buffer);
674
675    if (info.width() < 0 || info.height() < 0) {
676        return false;
677    }
678
679    // If there was an error reading "info" or if it is bogus,
680    // don't use it to compute minRowBytes()
681    if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(),
682                                                       info.alphaType()))) {
683        return false;
684    }
685
686    const size_t ramRB = info.minRowBytes();
687    const int height = SkMax32(info.height(), 0);
688    const uint64_t snugSize = sk_64_mul(snugRB, height);
689    const uint64_t ramSize = sk_64_mul(ramRB, height);
690    static const uint64_t max_size_t = (size_t)(-1);
691    if (!buffer->validate((snugSize <= ramSize) && (ramSize <= max_size_t))) {
692        return false;
693    }
694
695    sk_sp<SkData> data(SkData::MakeUninitialized(SkToSizeT(ramSize)));
696    unsigned char* dst = (unsigned char*)data->writable_data();
697    buffer->readByteArray(dst, SkToSizeT(snugSize));
698
699    if (snugSize != ramSize) {
700        const unsigned char* srcRow = dst + snugRB * (height - 1);
701        unsigned char* dstRow = dst + ramRB * (height - 1);
702        for (int y = height - 1; y >= 1; --y) {
703            memmove(dstRow, srcRow, snugRB);
704            srcRow -= snugRB;
705            dstRow -= ramRB;
706        }
707        SkASSERT(srcRow == dstRow); // first row does not need to be moved
708    }
709
710    if (buffer->readBool()) {
711        sk_sp<SkColorTable> ctable = SkColorTable::Create(*buffer);
712        if (!ctable) {
713            return false;
714        }
715
716        if (info.isEmpty()) {
717            // require an empty ctable
718            if (ctable->count() != 0) {
719                buffer->validate(false);
720                return false;
721            }
722        } else {
723            // require a non-empty ctable
724            if (ctable->count() == 0) {
725                buffer->validate(false);
726                return false;
727            }
728            unsigned char maxIndex = ctable->count() - 1;
729            for (uint64_t i = 0; i < ramSize; ++i) {
730                dst[i] = SkTMin(dst[i], maxIndex);
731            }
732        }
733    }
734
735    sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeWithData(info, info.minRowBytes(),
736                                                          std::move(data));
737    if (!pr) {
738        return false;
739    }
740    bitmap->setInfo(info);
741    bitmap->setPixelRef(std::move(pr), 0, 0);
742    return true;
743}
744
745enum {
746    SERIALIZE_PIXELTYPE_NONE,
747    SERIALIZE_PIXELTYPE_REF_DATA
748};
749
750///////////////////////////////////////////////////////////////////////////////
751
752#ifdef SK_DEBUG
753void SkBitmap::validate() const {
754    fInfo.validate();
755
756    // ImageInfo may not require this, but Bitmap ensures that opaque-only
757    // colorTypes report opaque for their alphatype
758    if (kRGB_565_SkColorType == fInfo.colorType()) {
759        SkASSERT(kOpaque_SkAlphaType == fInfo.alphaType());
760    }
761
762    SkASSERT(fInfo.validRowBytes(fRowBytes));
763    uint8_t allFlags = kImageIsVolatile_Flag;
764#ifdef SK_BUILD_FOR_ANDROID
765    allFlags |= kHasHardwareMipMap_Flag;
766#endif
767    SkASSERT((~allFlags & fFlags) == 0);
768
769    if (fPixelRef && fPixelRef->pixels()) {
770        SkASSERT(fPixels);
771    } else {
772        SkASSERT(!fPixels);
773    }
774
775    if (fPixels) {
776        SkASSERT(fPixelRef);
777        SkASSERT(fPixelRef->rowBytes() == fRowBytes);
778        SkASSERT(fPixelRefOrigin.fX >= 0);
779        SkASSERT(fPixelRefOrigin.fY >= 0);
780        SkASSERT(fPixelRef->width() >= (int)this->width() + fPixelRefOrigin.fX);
781        SkASSERT(fPixelRef->height() >= (int)this->height() + fPixelRefOrigin.fY);
782        SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes());
783    }
784}
785#endif
786
787#ifndef SK_IGNORE_TO_STRING
788#include "SkString.h"
789void SkBitmap::toString(SkString* str) const {
790
791    static const char* gColorTypeNames[kLastEnum_SkColorType + 1] = {
792        "UNKNOWN", "A8", "565", "4444", "RGBA", "BGRA", "INDEX8",
793    };
794
795    str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
796                 gColorTypeNames[this->colorType()]);
797
798    str->append(" (");
799    if (this->isOpaque()) {
800        str->append("opaque");
801    } else {
802        str->append("transparent");
803    }
804    if (this->isImmutable()) {
805        str->append(", immutable");
806    } else {
807        str->append(", not-immutable");
808    }
809    str->append(")");
810
811    str->appendf(" pixelref:%p", this->pixelRef());
812    str->append(")");
813}
814#endif
815
816///////////////////////////////////////////////////////////////////////////////
817
818bool SkBitmap::peekPixels(SkPixmap* pmap) const {
819    if (fPixels) {
820        if (pmap) {
821            pmap->reset(fInfo, fPixels, fRowBytes);
822        }
823        return true;
824    }
825    return false;
826}
827
828///////////////////////////////////////////////////////////////////////////////
829
830#ifdef SK_DEBUG
831void SkImageInfo::validate() const {
832    SkASSERT(fWidth >= 0);
833    SkASSERT(fHeight >= 0);
834    SkASSERT(SkColorTypeIsValid(fColorType));
835    SkASSERT(SkAlphaTypeIsValid(fAlphaType));
836}
837#endif
838