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 "SkImage_Base.h"
      9 #include "SkBitmap.h"
     10 #include "SkCanvas.h"
     11 #include "SkColorTable.h"
     12 #include "SkData.h"
     13 #include "SkImagePriv.h"
     14 #include "SkPixelRef.h"
     15 #include "SkSurface.h"
     16 
     17 #if SK_SUPPORT_GPU
     18 #include "GrContext.h"
     19 #include "SkGr.h"
     20 #include "SkGrPriv.h"
     21 #endif
     22 
     23 class SkImage_Raster : public SkImage_Base {
     24 public:
     25     static bool ValidArgs(const Info& info, size_t rowBytes, bool hasColorTable,
     26                           size_t* minSize) {
     27         const int maxDimension = SK_MaxS32 >> 2;
     28 
     29         if (info.width() <= 0 || info.height() <= 0) {
     30             return false;
     31         }
     32         if (info.width() > maxDimension || info.height() > maxDimension) {
     33             return false;
     34         }
     35         if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) {
     36             return false;
     37         }
     38         if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) {
     39             return false;
     40         }
     41 
     42         if (kUnknown_SkColorType == info.colorType()) {
     43             return false;
     44         }
     45 
     46         const bool needsCT = kIndex_8_SkColorType == info.colorType();
     47         if (needsCT != hasColorTable) {
     48             return false;
     49         }
     50 
     51         if (rowBytes < info.minRowBytes()) {
     52             return false;
     53         }
     54 
     55         size_t size = info.getSafeSize(rowBytes);
     56         if (0 == size) {
     57             return false;
     58         }
     59 
     60         if (minSize) {
     61             *minSize = size;
     62         }
     63         return true;
     64     }
     65 
     66     SkImage_Raster(const SkImageInfo&, SkData*, size_t rb, SkColorTable*);
     67     virtual ~SkImage_Raster();
     68 
     69     bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override;
     70     const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const override;
     71     SkData* onRefEncoded(GrContext*) const override;
     72     bool getROPixels(SkBitmap*, CachingHint) const override;
     73     GrTexture* asTextureRef(GrContext*, const GrTextureParams&) const override;
     74     SkImage* onNewSubset(const SkIRect&) const override;
     75 
     76     // exposed for SkSurface_Raster via SkNewImageFromPixelRef
     77     SkImage_Raster(const SkImageInfo&, SkPixelRef*, const SkIPoint& origin, size_t rowBytes);
     78 
     79     SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
     80 
     81     bool isOpaque() const override;
     82     bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const override;
     83 
     84     SkImage_Raster(const SkBitmap& bm)
     85         : INHERITED(bm.width(), bm.height(), bm.getGenerationID())
     86         , fBitmap(bm)
     87     {
     88         if (bm.pixelRef()->isPreLocked()) {
     89             // we only preemptively lock if there is no chance of triggering something expensive
     90             // like a lazy decode or imagegenerator. PreLocked means it is flat pixels already.
     91             fBitmap.lockPixels();
     92         }
     93         SkASSERT(fBitmap.isImmutable());
     94     }
     95 
     96     bool onIsLazyGenerated() const override {
     97         return fBitmap.pixelRef() && fBitmap.pixelRef()->isLazyGenerated();
     98     }
     99 
    100 private:
    101     SkBitmap fBitmap;
    102 
    103     typedef SkImage_Base INHERITED;
    104 };
    105 
    106 ///////////////////////////////////////////////////////////////////////////////
    107 
    108 static void release_data(void* addr, void* context) {
    109     SkData* data = static_cast<SkData*>(context);
    110     data->unref();
    111 }
    112 
    113 SkImage_Raster::SkImage_Raster(const Info& info, SkData* data, size_t rowBytes,
    114                                SkColorTable* ctable)
    115     : INHERITED(info.width(), info.height(), kNeedNewImageUniqueID)
    116 {
    117     data->ref();
    118     void* addr = const_cast<void*>(data->data());
    119 
    120     fBitmap.installPixels(info, addr, rowBytes, ctable, release_data, data);
    121     fBitmap.setImmutable();
    122     fBitmap.lockPixels();
    123 }
    124 
    125 SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, const SkIPoint& pixelRefOrigin,
    126                                size_t rowBytes)
    127     : INHERITED(info.width(), info.height(), pr->getGenerationID())
    128 {
    129     fBitmap.setInfo(info, rowBytes);
    130     fBitmap.setPixelRef(pr, pixelRefOrigin);
    131     fBitmap.lockPixels();
    132     SkASSERT(fBitmap.isImmutable());
    133 }
    134 
    135 SkImage_Raster::~SkImage_Raster() {}
    136 
    137 bool SkImage_Raster::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
    138                                   int srcX, int srcY, CachingHint) const {
    139     SkBitmap shallowCopy(fBitmap);
    140     return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
    141 }
    142 
    143 const void* SkImage_Raster::onPeekPixels(SkImageInfo* infoPtr, size_t* rowBytesPtr) const {
    144     const SkImageInfo info = fBitmap.info();
    145     if ((kUnknown_SkColorType == info.colorType()) || !fBitmap.getPixels()) {
    146         return nullptr;
    147     }
    148     *infoPtr = info;
    149     *rowBytesPtr = fBitmap.rowBytes();
    150     return fBitmap.getPixels();
    151 }
    152 
    153 SkData* SkImage_Raster::onRefEncoded(GrContext*) const {
    154     SkPixelRef* pr = fBitmap.pixelRef();
    155     const SkImageInfo prInfo = pr->info();
    156     const SkImageInfo bmInfo = fBitmap.info();
    157 
    158     // we only try if we (the image) cover the entire area of the pixelRef
    159     if (prInfo.width() == bmInfo.width() && prInfo.height() == bmInfo.height()) {
    160         return pr->refEncodedData();
    161     }
    162     return nullptr;
    163 }
    164 
    165 bool SkImage_Raster::getROPixels(SkBitmap* dst, CachingHint) const {
    166     *dst = fBitmap;
    167     return true;
    168 }
    169 
    170 GrTexture* SkImage_Raster::asTextureRef(GrContext* ctx, const GrTextureParams& params) const {
    171 #if SK_SUPPORT_GPU
    172     if (!ctx) {
    173         return nullptr;
    174     }
    175 
    176     return GrRefCachedBitmapTexture(ctx, fBitmap, params);
    177 #endif
    178 
    179     return nullptr;
    180 }
    181 
    182 SkImage* SkImage_Raster::onNewSubset(const SkIRect& subset) const {
    183     // TODO : could consider heurist of sharing pixels, if subset is pretty close to complete
    184 
    185     SkImageInfo info = SkImageInfo::MakeN32(subset.width(), subset.height(), fBitmap.alphaType());
    186     SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
    187     if (!surface) {
    188         return nullptr;
    189     }
    190     surface->getCanvas()->clear(0);
    191     surface->getCanvas()->drawImage(this, SkIntToScalar(-subset.x()), SkIntToScalar(-subset.y()),
    192                                     nullptr);
    193     return surface->newImageSnapshot();
    194 }
    195 
    196 ///////////////////////////////////////////////////////////////////////////////
    197 
    198 SkImage* SkImage::NewRasterCopy(const SkImageInfo& info, const void* pixels, size_t rowBytes,
    199                                 SkColorTable* ctable) {
    200     size_t size;
    201     if (!SkImage_Raster::ValidArgs(info, rowBytes, ctable != nullptr, &size) || !pixels) {
    202         return nullptr;
    203     }
    204 
    205     // Here we actually make a copy of the caller's pixel data
    206     SkAutoDataUnref data(SkData::NewWithCopy(pixels, size));
    207     return new SkImage_Raster(info, data, rowBytes, ctable);
    208 }
    209 
    210 
    211 SkImage* SkImage::NewRasterData(const SkImageInfo& info, SkData* data, size_t rowBytes) {
    212     size_t size;
    213     if (!SkImage_Raster::ValidArgs(info, rowBytes, false, &size) || !data) {
    214         return nullptr;
    215     }
    216 
    217     // did they give us enough data?
    218     if (data->size() < size) {
    219         return nullptr;
    220     }
    221 
    222     SkColorTable* ctable = nullptr;
    223     return new SkImage_Raster(info, data, rowBytes, ctable);
    224 }
    225 
    226 SkImage* SkImage::NewFromRaster(const SkImageInfo& info, const void* pixels, size_t rowBytes,
    227                                 RasterReleaseProc proc, ReleaseContext ctx) {
    228     size_t size;
    229     if (!SkImage_Raster::ValidArgs(info, rowBytes, false, &size) || !pixels) {
    230         return nullptr;
    231     }
    232 
    233     SkColorTable* ctable = nullptr;
    234     SkAutoDataUnref data(SkData::NewWithProc(pixels, size, proc, ctx));
    235     return new SkImage_Raster(info, data, rowBytes, ctable);
    236 }
    237 
    238 SkImage* SkNewImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr,
    239                                 const SkIPoint& pixelRefOrigin, size_t rowBytes) {
    240     if (!SkImage_Raster::ValidArgs(info, rowBytes, false, nullptr)) {
    241         return nullptr;
    242     }
    243     return new SkImage_Raster(info, pr, pixelRefOrigin, rowBytes);
    244 }
    245 
    246 SkImage* SkNewImageFromRasterBitmap(const SkBitmap& bm, ForceCopyMode forceCopy) {
    247     SkASSERT(nullptr == bm.getTexture());
    248 
    249     bool hasColorTable = false;
    250     if (kIndex_8_SkColorType == bm.colorType()) {
    251         SkAutoLockPixels autoLockPixels(bm);
    252         hasColorTable = bm.getColorTable() != nullptr;
    253     }
    254 
    255     if (!SkImage_Raster::ValidArgs(bm.info(), bm.rowBytes(), hasColorTable, nullptr)) {
    256         return nullptr;
    257     }
    258 
    259     SkImage* image = nullptr;
    260     if (kYes_ForceCopyMode == forceCopy || !bm.isImmutable()) {
    261         SkBitmap tmp(bm);
    262         tmp.lockPixels();
    263         if (tmp.getPixels()) {
    264             image = SkImage::NewRasterCopy(tmp.info(), tmp.getPixels(), tmp.rowBytes(),
    265                                            tmp.getColorTable());
    266         }
    267     } else {
    268         image = new SkImage_Raster(bm);
    269     }
    270     return image;
    271 }
    272 
    273 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
    274     return ((const SkImage_Raster*)image)->getPixelRef();
    275 }
    276 
    277 bool SkImage_Raster::isOpaque() const {
    278     return fBitmap.isOpaque();
    279 }
    280 
    281 bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
    282     if (kRO_LegacyBitmapMode == mode) {
    283         // When we're a snapshot from a surface, our bitmap may not be marked immutable
    284         // even though logically always we are, but in that case we can't physically share our
    285         // pixelref since the caller might call setImmutable() themselves
    286         // (thus changing our state).
    287         if (fBitmap.isImmutable()) {
    288             bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes());
    289             bitmap->setPixelRef(fBitmap.pixelRef(), fBitmap.pixelRefOrigin());
    290             return true;
    291         }
    292     }
    293     return this->INHERITED::onAsLegacyBitmap(bitmap, mode);
    294 }
    295