xref: /third_party/skia/src/core/SkBitmap.cpp (revision cb93a386)
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 "include/core/SkBitmap.h"
9
10#include "include/core/SkData.h"
11#include "include/core/SkMallocPixelRef.h"
12#include "include/core/SkMath.h"
13#include "include/core/SkPixelRef.h"
14#include "include/core/SkRect.h"
15#include "include/core/SkScalar.h"
16#include "include/core/SkUnPreMultiply.h"
17#include "include/private/SkColorData.h"
18#include "include/private/SkHalf.h"
19#include "include/private/SkImageInfoPriv.h"
20#include "include/private/SkTemplates.h"
21#include "include/private/SkTo.h"
22#include "src/core/SkConvertPixels.h"
23#include "src/core/SkMask.h"
24#include "src/core/SkMaskFilterBase.h"
25#include "src/core/SkMipmap.h"
26#include "src/core/SkPixelRefPriv.h"
27#include "src/core/SkPixmapPriv.h"
28#include "src/core/SkReadBuffer.h"
29#include "src/core/SkWriteBuffer.h"
30#include "src/core/SkWritePixelsRec.h"
31
32#include <cstring>
33#include <utility>
34
35static bool reset_return_false(SkBitmap* bm) {
36    bm->reset();
37    return false;
38}
39
40SkBitmap::SkBitmap() {}
41
42SkBitmap::SkBitmap(const SkBitmap& src)
43    : fPixelRef      (src.fPixelRef)
44    , fPixmap        (src.fPixmap)
45    , fMips          (src.fMips)
46{
47    SkDEBUGCODE(src.validate();)
48    SkDEBUGCODE(this->validate();)
49}
50
51SkBitmap::SkBitmap(SkBitmap&& other)
52    : fPixelRef      (std::move(other.fPixelRef))
53    , fPixmap        (std::move(other.fPixmap))
54    , fMips          (std::move(other.fMips))
55{
56    SkASSERT(!other.fPixelRef);
57    other.fPixmap.reset();
58}
59
60SkBitmap::~SkBitmap() {}
61
62SkBitmap& SkBitmap::operator=(const SkBitmap& src) {
63    if (this != &src) {
64        fPixelRef       = src.fPixelRef;
65        fPixmap         = src.fPixmap;
66        fMips           = src.fMips;
67    }
68    SkDEBUGCODE(this->validate();)
69    return *this;
70}
71
72SkBitmap& SkBitmap::operator=(SkBitmap&& other) {
73    if (this != &other) {
74        fPixelRef       = std::move(other.fPixelRef);
75        fPixmap         = std::move(other.fPixmap);
76        fMips           = std::move(other.fMips);
77        SkASSERT(!other.fPixelRef);
78        other.fPixmap.reset();
79    }
80    return *this;
81}
82
83void SkBitmap::swap(SkBitmap& other) {
84    using std::swap;
85    swap(*this, other);
86    SkDEBUGCODE(this->validate();)
87}
88
89void SkBitmap::reset() {
90    fPixelRef = nullptr;  // Free pixels.
91    fPixmap.reset();
92    fMips.reset();
93}
94
95void SkBitmap::getBounds(SkRect* bounds) const {
96    SkASSERT(bounds);
97    *bounds = SkRect::Make(this->dimensions());
98}
99
100void SkBitmap::getBounds(SkIRect* bounds) const {
101    SkASSERT(bounds);
102    *bounds = fPixmap.bounds();
103}
104
105///////////////////////////////////////////////////////////////////////////////
106
107bool SkBitmap::setInfo(const SkImageInfo& info, size_t rowBytes) {
108    SkAlphaType newAT = info.alphaType();
109    if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAT)) {
110        return reset_return_false(this);
111    }
112    // don't look at info.alphaType(), since newAT is the real value...
113
114    // require that rowBytes fit in 31bits
115    int64_t mrb = info.minRowBytes64();
116    if (!SkTFitsIn<int32_t>(mrb)) {
117        return reset_return_false(this);
118    }
119    if (!SkTFitsIn<int32_t>(rowBytes)) {
120        return reset_return_false(this);
121    }
122
123    if (info.width() < 0 || info.height() < 0) {
124        return reset_return_false(this);
125    }
126
127    if (kUnknown_SkColorType == info.colorType()) {
128        rowBytes = 0;
129    } else if (0 == rowBytes) {
130        rowBytes = (size_t)mrb;
131    } else if (!info.validRowBytes(rowBytes)) {
132        return reset_return_false(this);
133    }
134
135    fPixelRef = nullptr;  // Free pixels.
136    fPixmap.reset(info.makeAlphaType(newAT), nullptr, SkToU32(rowBytes));
137    SkDEBUGCODE(this->validate();)
138    return true;
139}
140
141
142
143bool SkBitmap::setAlphaType(SkAlphaType newAlphaType) {
144    if (!SkColorTypeValidateAlphaType(this->colorType(), newAlphaType, &newAlphaType)) {
145        return false;
146    }
147    if (this->alphaType() != newAlphaType) {
148        auto newInfo = fPixmap.info().makeAlphaType(newAlphaType);
149        fPixmap.reset(std::move(newInfo), fPixmap.addr(), fPixmap.rowBytes());
150    }
151    SkDEBUGCODE(this->validate();)
152    return true;
153}
154
155SkIPoint SkBitmap::pixelRefOrigin() const {
156    const char* addr = (const char*)fPixmap.addr();
157    const char* pix = (const char*)(fPixelRef ? fPixelRef->pixels() : nullptr);
158    size_t rb = this->rowBytes();
159    if (!pix || 0 == rb) {
160        return {0, 0};
161    }
162    SkASSERT(this->bytesPerPixel() > 0);
163    SkASSERT(this->bytesPerPixel() == (1 << this->shiftPerPixel()));
164    SkASSERT(addr >= pix);
165    size_t off = addr - pix;
166    return {SkToS32((off % rb) >> this->shiftPerPixel()), SkToS32(off / rb)};
167}
168
169void SkBitmap::setPixelRef(sk_sp<SkPixelRef> pr, int dx, int dy) {
170#ifdef SK_DEBUG
171    if (pr) {
172        if (kUnknown_SkColorType != this->colorType()) {
173            SkASSERT(dx >= 0 && this->width() + dx <= pr->width());
174            SkASSERT(dy >= 0 && this->height() + dy <= pr->height());
175        }
176    }
177#endif
178    fPixelRef = kUnknown_SkColorType != this->colorType() ? std::move(pr) : nullptr;
179    void* p = nullptr;
180    size_t rowBytes = this->rowBytes();
181    // ignore dx,dy if there is no pixelref
182    if (fPixelRef) {
183        rowBytes = fPixelRef->rowBytes();
184        // TODO(reed):  Enforce that PixelRefs must have non-null pixels.
185        p = fPixelRef->pixels();
186        if (p) {
187            p = (char*)p + dy * rowBytes + dx * this->bytesPerPixel();
188        }
189    }
190    SkPixmapPriv::ResetPixmapKeepInfo(&fPixmap, p, rowBytes);
191    SkDEBUGCODE(this->validate();)
192}
193
194void SkBitmap::setPixels(void* p) {
195    if (kUnknown_SkColorType == this->colorType()) {
196        p = nullptr;
197    }
198    size_t rb = this->rowBytes();
199    SkPixmapPriv::ResetPixmapKeepInfo(&fPixmap, p, rb);
200    fPixelRef = p ? sk_make_sp<SkPixelRef>(this->width(), this->height(), p, rb) : nullptr;
201    SkDEBUGCODE(this->validate();)
202}
203
204bool SkBitmap::tryAllocPixels(Allocator* allocator) {
205    HeapAllocator stdalloc;
206
207    if (nullptr == allocator) {
208        allocator = &stdalloc;
209    }
210    return allocator->allocPixelRef(this);
211}
212
213bool SkBitmap::tryAllocN32Pixels(int width, int height, bool isOpaque) {
214    SkImageInfo info = SkImageInfo::MakeN32(width, height,
215            isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
216    return this->tryAllocPixels(info);
217}
218
219void SkBitmap::allocN32Pixels(int width, int height, bool isOpaque) {
220    SkImageInfo info = SkImageInfo::MakeN32(width, height,
221                                        isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
222    this->allocPixels(info);
223}
224
225void SkBitmap::allocPixels() {
226    this->allocPixels((Allocator*)nullptr);
227}
228
229void SkBitmap::allocPixels(Allocator* allocator) {
230    if (!this->tryAllocPixels(allocator)) {
231        const SkImageInfo& info = this->info();
232        SK_ABORT("SkBitmap::tryAllocPixels failed "
233                 "ColorType:%d AlphaType:%d [w:%d h:%d] rb:%zu",
234                 info.colorType(), info.alphaType(), info.width(), info.height(), this->rowBytes());
235    }
236}
237
238void SkBitmap::allocPixelsFlags(const SkImageInfo& info, uint32_t flags) {
239    SkASSERT_RELEASE(this->tryAllocPixelsFlags(info, flags));
240}
241
242void SkBitmap::allocPixels(const SkImageInfo& info, size_t rowBytes) {
243    SkASSERT_RELEASE(this->tryAllocPixels(info, rowBytes));
244}
245
246void SkBitmap::allocPixels(const SkImageInfo& info) {
247    this->allocPixels(info, info.minRowBytes());
248}
249
250///////////////////////////////////////////////////////////////////////////////
251
252bool SkBitmap::tryAllocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
253    if (!this->setInfo(requestedInfo, rowBytes)) {
254        return reset_return_false(this);
255    }
256
257    // setInfo may have corrected info (e.g. 565 is always opaque).
258    const SkImageInfo& correctedInfo = this->info();
259    if (kUnknown_SkColorType == correctedInfo.colorType()) {
260        return true;
261    }
262    // setInfo may have computed a valid rowbytes if 0 were passed in
263    rowBytes = this->rowBytes();
264
265    sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo, rowBytes);
266    if (!pr) {
267        return reset_return_false(this);
268    }
269    this->setPixelRef(std::move(pr), 0, 0);
270    if (nullptr == this->getPixels()) {
271        return reset_return_false(this);
272    }
273    SkDEBUGCODE(this->validate();)
274    return true;
275}
276
277bool SkBitmap::tryAllocPixelsFlags(const SkImageInfo& requestedInfo, uint32_t allocFlags) {
278    if (!this->setInfo(requestedInfo)) {
279        return reset_return_false(this);
280    }
281
282    // setInfo may have corrected info (e.g. 565 is always opaque).
283    const SkImageInfo& correctedInfo = this->info();
284
285    sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(correctedInfo,
286                                                          correctedInfo.minRowBytes());
287    if (!pr) {
288        return reset_return_false(this);
289    }
290    this->setPixelRef(std::move(pr), 0, 0);
291    if (nullptr == this->getPixels()) {
292        return reset_return_false(this);
293    }
294    SkDEBUGCODE(this->validate();)
295    return true;
296}
297
298static void invoke_release_proc(void (*proc)(void* pixels, void* ctx), void* pixels, void* ctx) {
299    if (proc) {
300        proc(pixels, ctx);
301    }
302}
303
304bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, size_t rb,
305                             void (*releaseProc)(void* addr, void* context), void* context) {
306    if (!this->setInfo(requestedInfo, rb)) {
307        invoke_release_proc(releaseProc, pixels, context);
308        this->reset();
309        return false;
310    }
311    if (nullptr == pixels) {
312        invoke_release_proc(releaseProc, pixels, context);
313        return true;    // we behaved as if they called setInfo()
314    }
315
316    // setInfo may have corrected info (e.g. 565 is always opaque).
317    const SkImageInfo& correctedInfo = this->info();
318    this->setPixelRef(
319            SkMakePixelRefWithProc(correctedInfo.width(), correctedInfo.height(),
320                                   rb, pixels, releaseProc, context), 0, 0);
321    SkDEBUGCODE(this->validate();)
322    return true;
323}
324
325bool SkBitmap::installPixels(const SkPixmap& pixmap) {
326    return this->installPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(),
327                               nullptr, nullptr);
328}
329
330bool SkBitmap::installMaskPixels(const SkMask& mask) {
331    if (SkMask::kA8_Format != mask.fFormat) {
332        this->reset();
333        return false;
334    }
335    return this->installPixels(SkImageInfo::MakeA8(mask.fBounds.width(),
336                                                   mask.fBounds.height()),
337                               mask.fImage, mask.fRowBytes);
338}
339
340///////////////////////////////////////////////////////////////////////////////
341
342uint32_t SkBitmap::getGenerationID() const {
343    return fPixelRef ? fPixelRef->getGenerationID() : 0;
344}
345
346void SkBitmap::notifyPixelsChanged() const {
347    SkASSERT(!this->isImmutable());
348    if (fPixelRef) {
349        fPixelRef->notifyPixelsChanged();
350    }
351}
352
353///////////////////////////////////////////////////////////////////////////////
354
355/** We explicitly use the same allocator for our pixels that SkMask does,
356 so that we can freely assign memory allocated by one class to the other.
357 */
358bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst) {
359    const SkImageInfo& info = dst->info();
360    if (kUnknown_SkColorType == info.colorType()) {
361//        SkDebugf("unsupported config for info %d\n", dst->config());
362        return false;
363    }
364
365    sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes());
366    if (!pr) {
367        return false;
368    }
369
370    dst->setPixelRef(std::move(pr), 0, 0);
371    SkDEBUGCODE(dst->validate();)
372    return true;
373}
374
375///////////////////////////////////////////////////////////////////////////////
376
377bool SkBitmap::isImmutable() const {
378    return fPixelRef ? fPixelRef->isImmutable() : false;
379}
380
381void SkBitmap::setImmutable() {
382    if (fPixelRef) {
383        fPixelRef->setImmutable();
384    }
385}
386
387void* SkBitmap::getAddr(int x, int y) const {
388    SkASSERT((unsigned)x < (unsigned)this->width());
389    SkASSERT((unsigned)y < (unsigned)this->height());
390
391    char* base = (char*)this->getPixels();
392    if (base) {
393        base += (y * this->rowBytes()) + (x << this->shiftPerPixel());
394    }
395    return base;
396}
397
398///////////////////////////////////////////////////////////////////////////////
399///////////////////////////////////////////////////////////////////////////////
400
401void SkBitmap::erase(SkColor c, const SkIRect& area) const {
402    SkDEBUGCODE(this->validate();)
403
404    if (kUnknown_SkColorType == this->colorType()) {
405        // TODO: can we ASSERT that we never get here?
406        return; // can't erase. Should we bzero so the memory is not uninitialized?
407    }
408
409    SkPixmap result;
410    if (!this->peekPixels(&result)) {
411        return;
412    }
413
414    if (result.erase(c, area)) {
415        this->notifyPixelsChanged();
416    }
417}
418
419void SkBitmap::eraseColor(SkColor c) const {
420    this->erase(c, SkIRect::MakeWH(this->width(), this->height()));
421}
422
423//////////////////////////////////////////////////////////////////////////////////////
424//////////////////////////////////////////////////////////////////////////////////////
425
426bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const {
427    SkDEBUGCODE(this->validate();)
428
429    if (nullptr == result || !fPixelRef) {
430        return false;   // no src pixels
431    }
432
433    SkIRect srcRect, r;
434    srcRect.setWH(this->width(), this->height());
435    if (!r.intersect(srcRect, subset)) {
436        return false;   // r is empty (i.e. no intersection)
437    }
438
439    // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
440    // exited above.
441    SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
442    SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
443
444    SkBitmap dst;
445    dst.setInfo(this->info().makeDimensions(r.size()), this->rowBytes());
446
447    if (fPixelRef) {
448        SkIPoint origin = this->pixelRefOrigin();
449        // share the pixelref with a custom offset
450        dst.setPixelRef(fPixelRef, origin.x() + r.fLeft, origin.y() + r.fTop);
451    }
452    SkDEBUGCODE(dst.validate();)
453
454    // we know we're good, so commit to result
455    result->swap(dst);
456    return true;
457}
458
459///////////////////////////////////////////////////////////////////////////////
460
461bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
462                          int x, int y) const {
463    SkPixmap src;
464    if (!this->peekPixels(&src)) {
465        return false;
466    }
467    return src.readPixels(requestedDstInfo, dstPixels, dstRB, x, y);
468}
469
470bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
471    return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
472}
473
474bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) {
475    if (!SkImageInfoValidConversion(this->info(), src.info())) {
476        return false;
477    }
478
479    SkWritePixelsRec rec(src.info(), src.addr(), src.rowBytes(), dstX, dstY);
480    if (!rec.trim(this->width(), this->height())) {
481        return false;
482    }
483
484    void* dstPixels = this->getAddr(rec.fX, rec.fY);
485    const SkImageInfo dstInfo = this->info().makeDimensions(rec.fInfo.dimensions());
486    if (!SkConvertPixels(dstInfo,     dstPixels, this->rowBytes(),
487                         rec.fInfo, rec.fPixels,   rec.fRowBytes)) {
488        return false;
489    }
490    this->notifyPixelsChanged();
491    return true;
492}
493
494///////////////////////////////////////////////////////////////////////////////
495
496static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) {
497    SkASSERT(alpha != nullptr);
498    SkASSERT(alphaRowBytes >= src.width());
499
500    SkPixmap pmap;
501    if (!src.peekPixels(&pmap)) {
502        for (int y = 0; y < src.height(); ++y) {
503            memset(alpha, 0, src.width());
504            alpha += alphaRowBytes;
505        }
506        return false;
507    }
508    return SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
509                           pmap.info(), pmap.addr(), pmap.rowBytes());
510}
511
512#include "include/core/SkMaskFilter.h"
513#include "include/core/SkMatrix.h"
514#include "include/core/SkPaint.h"
515
516bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
517                            Allocator *allocator, SkIPoint* offset) const {
518    SkDEBUGCODE(this->validate();)
519
520    SkBitmap    tmpBitmap;
521    SkMatrix    identity;
522    SkMask      srcM, dstM;
523
524    if (this->width() == 0 || this->height() == 0) {
525        return false;
526    }
527    srcM.fBounds.setWH(this->width(), this->height());
528    srcM.fRowBytes = SkAlign4(this->width());
529    srcM.fFormat = SkMask::kA8_Format;
530
531    SkMaskFilter* filter = paint ? paint->getMaskFilter() : nullptr;
532
533    // compute our (larger?) dst bounds if we have a filter
534    if (filter) {
535        identity.reset();
536        if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) {
537            goto NO_FILTER_CASE;
538        }
539        dstM.fRowBytes = SkAlign4(dstM.fBounds.width());
540    } else {
541    NO_FILTER_CASE:
542        tmpBitmap.setInfo(SkImageInfo::MakeA8(this->width(), this->height()), srcM.fRowBytes);
543        if (!tmpBitmap.tryAllocPixels(allocator)) {
544            // Allocation of pixels for alpha bitmap failed.
545            SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
546                    tmpBitmap.width(), tmpBitmap.height());
547            return false;
548        }
549        GetBitmapAlpha(*this, tmpBitmap.getAddr8(0, 0), srcM.fRowBytes);
550        if (offset) {
551            offset->set(0, 0);
552        }
553        tmpBitmap.swap(*dst);
554        return true;
555    }
556    srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
557    SkAutoMaskFreeImage srcCleanup(srcM.fImage);
558
559    GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
560    if (!as_MFB(filter)->filterMask(&dstM, srcM, identity, nullptr)) {
561        goto NO_FILTER_CASE;
562    }
563    SkAutoMaskFreeImage dstCleanup(dstM.fImage);
564
565    tmpBitmap.setInfo(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
566                      dstM.fRowBytes);
567    if (!tmpBitmap.tryAllocPixels(allocator)) {
568        // Allocation of pixels for alpha bitmap failed.
569        SkDebugf("extractAlpha failed to allocate (%d,%d) alpha bitmap\n",
570                tmpBitmap.width(), tmpBitmap.height());
571        return false;
572    }
573    memcpy(tmpBitmap.getPixels(), dstM.fImage, dstM.computeImageSize());
574    if (offset) {
575        offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);
576    }
577    SkDEBUGCODE(tmpBitmap.validate();)
578
579    tmpBitmap.swap(*dst);
580    return true;
581}
582
583///////////////////////////////////////////////////////////////////////////////
584
585#ifdef SK_DEBUG
586void SkBitmap::validate() const {
587    this->info().validate();
588
589    SkASSERT(this->info().validRowBytes(this->rowBytes()));
590
591    if (fPixelRef && fPixelRef->pixels()) {
592        SkASSERT(this->getPixels());
593    } else {
594        SkASSERT(!this->getPixels());
595    }
596
597    if (this->getPixels()) {
598        SkASSERT(fPixelRef);
599        SkASSERT(fPixelRef->rowBytes() == this->rowBytes());
600        SkIPoint origin = this->pixelRefOrigin();
601        SkASSERT(origin.fX >= 0);
602        SkASSERT(origin.fY >= 0);
603        SkASSERT(fPixelRef->width() >= (int)this->width() + origin.fX);
604        SkASSERT(fPixelRef->height() >= (int)this->height() + origin.fY);
605        SkASSERT(fPixelRef->rowBytes() >= this->info().minRowBytes());
606    }
607}
608#endif
609
610///////////////////////////////////////////////////////////////////////////////
611
612bool SkBitmap::peekPixels(SkPixmap* pmap) const {
613    if (this->getPixels()) {
614        if (pmap) {
615            *pmap = fPixmap;
616        }
617        return true;
618    }
619    return false;
620}
621
622sk_sp<SkImage> SkBitmap::asImage() const {
623    return SkImage::MakeFromBitmap(*this);
624}
625