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