Home | History | Annotate | Download | only in image
      1 /*
      2  * Copyright 2012 Google Inc.
      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 "SkSurface_Base.h"
      9 #include "SkImageInfoPriv.h"
     10 #include "SkImagePriv.h"
     11 #include "SkCanvas.h"
     12 #include "SkDevice.h"
     13 #include "SkMallocPixelRef.h"
     14 
     15 class SkSurface_Raster : public SkSurface_Base {
     16 public:
     17     SkSurface_Raster(const SkImageInfo&, void*, size_t rb,
     18                      void (*releaseProc)(void* pixels, void* context), void* context,
     19                      const SkSurfaceProps*);
     20     SkSurface_Raster(const SkImageInfo& info, sk_sp<SkPixelRef>, const SkSurfaceProps*);
     21 
     22     SkCanvas* onNewCanvas() override;
     23     sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override;
     24     sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subset) override;
     25     void onWritePixels(const SkPixmap&, int x, int y) override;
     26     void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override;
     27     void onCopyOnWrite(ContentChangeMode) override;
     28     void onRestoreBackingMutability() override;
     29 
     30 private:
     31     SkBitmap    fBitmap;
     32     size_t      fRowBytes;
     33     bool        fWeOwnThePixels;
     34 
     35     typedef SkSurface_Base INHERITED;
     36 };
     37 
     38 ///////////////////////////////////////////////////////////////////////////////
     39 
     40 bool SkSurfaceValidateRasterInfo(const SkImageInfo& info, size_t rowBytes) {
     41     if (!SkImageInfoIsValid(info)) {
     42         return false;
     43     }
     44 
     45     if (kIgnoreRowBytesValue == rowBytes) {
     46         return true;
     47     }
     48 
     49     int shift = info.shiftPerPixel();
     50 
     51     uint64_t minRB = (uint64_t)info.width() << shift;
     52     if (minRB > rowBytes) {
     53         return false;
     54     }
     55 
     56     size_t alignedRowBytes = rowBytes >> shift << shift;
     57     if (alignedRowBytes != rowBytes) {
     58         return false;
     59     }
     60 
     61     uint64_t size = sk_64_mul(info.height(), rowBytes);
     62     static const size_t kMaxTotalSize = SK_MaxS32;
     63     if (size > kMaxTotalSize) {
     64         return false;
     65     }
     66 
     67     return true;
     68 }
     69 
     70 SkSurface_Raster::SkSurface_Raster(const SkImageInfo& info, void* pixels, size_t rb,
     71                                    void (*releaseProc)(void* pixels, void* context), void* context,
     72                                    const SkSurfaceProps* props)
     73     : INHERITED(info, props)
     74 {
     75     fBitmap.installPixels(info, pixels, rb, releaseProc, context);
     76     fRowBytes = 0;              // don't need to track the rowbytes
     77     fWeOwnThePixels = false;    // We are "Direct"
     78 }
     79 
     80 SkSurface_Raster::SkSurface_Raster(const SkImageInfo& info, sk_sp<SkPixelRef> pr,
     81                                    const SkSurfaceProps* props)
     82     : INHERITED(pr->width(), pr->height(), props)
     83 {
     84     fBitmap.setInfo(info, pr->rowBytes());
     85     fRowBytes = pr->rowBytes(); // we track this, so that subsequent re-allocs will match
     86     fBitmap.setPixelRef(std::move(pr), 0, 0);
     87     fWeOwnThePixels = true;
     88 }
     89 
     90 SkCanvas* SkSurface_Raster::onNewCanvas() { return new SkCanvas(fBitmap, this->props()); }
     91 
     92 sk_sp<SkSurface> SkSurface_Raster::onNewSurface(const SkImageInfo& info) {
     93     return SkSurface::MakeRaster(info, &this->props());
     94 }
     95 
     96 void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
     97                               const SkPaint* paint) {
     98     canvas->drawBitmap(fBitmap, x, y, paint);
     99 }
    100 
    101 sk_sp<SkImage> SkSurface_Raster::onNewImageSnapshot(const SkIRect* subset) {
    102     if (subset) {
    103         SkASSERT(SkIRect::MakeWH(fBitmap.width(), fBitmap.height()).contains(*subset));
    104         SkBitmap dst;
    105         dst.allocPixels(fBitmap.info().makeWH(subset->width(), subset->height()));
    106         SkAssertResult(fBitmap.readPixels(dst.pixmap(), subset->left(), subset->top()));
    107         dst.setImmutable(); // key, so MakeFromBitmap doesn't make a copy of the buffer
    108         return SkImage::MakeFromBitmap(dst);
    109     }
    110 
    111     SkCopyPixelsMode cpm = kIfMutable_SkCopyPixelsMode;
    112     if (fWeOwnThePixels) {
    113         // SkImage_raster requires these pixels are immutable for its full lifetime.
    114         // We'll undo this via onRestoreBackingMutability() if we can avoid the COW.
    115         if (SkPixelRef* pr = fBitmap.pixelRef()) {
    116             pr->setTemporarilyImmutable();
    117         }
    118     } else {
    119         cpm = kAlways_SkCopyPixelsMode;
    120     }
    121 
    122     // Our pixels are in memory, so read access on the snapshot SkImage could be cheap.
    123     // Lock the shared pixel ref to ensure peekPixels() is usable.
    124     return SkMakeImageFromRasterBitmap(fBitmap, cpm);
    125 }
    126 
    127 void SkSurface_Raster::onWritePixels(const SkPixmap& src, int x, int y) {
    128     fBitmap.writePixels(src, x, y);
    129 }
    130 
    131 void SkSurface_Raster::onRestoreBackingMutability() {
    132     SkASSERT(!this->hasCachedImage());  // Shouldn't be any snapshots out there.
    133     if (SkPixelRef* pr = fBitmap.pixelRef()) {
    134         pr->restoreMutability();
    135     }
    136 }
    137 
    138 void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
    139     // are we sharing pixelrefs with the image?
    140     sk_sp<SkImage> cached(this->refCachedImage());
    141     SkASSERT(cached);
    142     if (SkBitmapImageGetPixelRef(cached.get()) == fBitmap.pixelRef()) {
    143         SkASSERT(fWeOwnThePixels);
    144         if (kDiscard_ContentChangeMode == mode) {
    145             fBitmap.allocPixels();
    146         } else {
    147             SkBitmap prev(fBitmap);
    148             fBitmap.allocPixels();
    149             SkASSERT(prev.info() == fBitmap.info());
    150             SkASSERT(prev.rowBytes() == fBitmap.rowBytes());
    151             memcpy(fBitmap.getPixels(), prev.getPixels(), fBitmap.computeByteSize());
    152         }
    153         SkASSERT(fBitmap.rowBytes() == fRowBytes);  // be sure we always use the same value
    154 
    155         // Now fBitmap is a deep copy of itself (and therefore different from
    156         // what is being used by the image. Next we update the canvas to use
    157         // this as its backend, so we can't modify the image's pixels anymore.
    158         SkASSERT(this->getCachedCanvas());
    159         this->getCachedCanvas()->getDevice()->replaceBitmapBackendForRasterSurface(fBitmap);
    160     }
    161 }
    162 
    163 ///////////////////////////////////////////////////////////////////////////////
    164 
    165 sk_sp<SkSurface> SkSurface::MakeRasterDirectReleaseProc(const SkImageInfo& info, void* pixels,
    166         size_t rb, void (*releaseProc)(void* pixels, void* context), void* context,
    167         const SkSurfaceProps* props) {
    168     if (nullptr == releaseProc) {
    169         context = nullptr;
    170     }
    171     if (!SkSurfaceValidateRasterInfo(info, rb)) {
    172         return nullptr;
    173     }
    174     if (nullptr == pixels) {
    175         return nullptr;
    176     }
    177 
    178     return sk_make_sp<SkSurface_Raster>(info, pixels, rb, releaseProc, context, props);
    179 }
    180 
    181 sk_sp<SkSurface> SkSurface::MakeRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes,
    182                                              const SkSurfaceProps* props) {
    183     return MakeRasterDirectReleaseProc(info, pixels, rowBytes, nullptr, nullptr, props);
    184 }
    185 
    186 sk_sp<SkSurface> SkSurface::MakeRaster(const SkImageInfo& info, size_t rowBytes,
    187                                        const SkSurfaceProps* props) {
    188     if (!SkSurfaceValidateRasterInfo(info)) {
    189         return nullptr;
    190     }
    191 
    192     sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeZeroed(info, rowBytes);
    193     if (!pr) {
    194         return nullptr;
    195     }
    196     if (rowBytes) {
    197         SkASSERT(pr->rowBytes() == rowBytes);
    198     }
    199     return sk_make_sp<SkSurface_Raster>(info, std::move(pr), props);
    200 }
    201