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 "SkBitmapProcShader.h"
     11 #include "SkCanvas.h"
     12 #include "SkColorSpaceXform_Base.h"
     13 #include "SkColorSpaceXformImageGenerator.h"
     14 #include "SkColorSpaceXformPriv.h"
     15 #include "SkColorTable.h"
     16 #include "SkData.h"
     17 #include "SkImageInfoPriv.h"
     18 #include "SkImagePriv.h"
     19 #include "SkPixelRef.h"
     20 #include "SkSurface.h"
     21 #include "SkTLazy.h"
     22 #include "SkUnPreMultiplyPriv.h"
     23 
     24 #if SK_SUPPORT_GPU
     25 #include "GrContext.h"
     26 #include "GrTextureAdjuster.h"
     27 #include "SkGr.h"
     28 #endif
     29 
     30 // fixes https://bug.skia.org/5096
     31 static bool is_not_subset(const SkBitmap& bm) {
     32     SkASSERT(bm.pixelRef());
     33     SkISize dim = SkISize::Make(bm.pixelRef()->width(), bm.pixelRef()->height());
     34     SkASSERT(dim != bm.dimensions() || bm.pixelRefOrigin().isZero());
     35     return dim == bm.dimensions();
     36 }
     37 
     38 class SkImage_Raster : public SkImage_Base {
     39 public:
     40     static bool ValidArgs(const Info& info, size_t rowBytes, size_t* minSize) {
     41         const int maxDimension = SK_MaxS32 >> 2;
     42 
     43         if (info.width() <= 0 || info.height() <= 0) {
     44             return false;
     45         }
     46         if (info.width() > maxDimension || info.height() > maxDimension) {
     47             return false;
     48         }
     49         if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) {
     50             return false;
     51         }
     52         if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) {
     53             return false;
     54         }
     55 
     56         if (kUnknown_SkColorType == info.colorType()) {
     57             return false;
     58         }
     59         if (rowBytes < info.minRowBytes()) {
     60             return false;
     61         }
     62 
     63         size_t size = info.getSafeSize(rowBytes);
     64         if (0 == size) {
     65             return false;
     66         }
     67 
     68         if (minSize) {
     69             *minSize = size;
     70         }
     71         return true;
     72     }
     73 
     74     SkImage_Raster(const SkImageInfo&, sk_sp<SkData>, size_t rb,
     75                    uint32_t id = kNeedNewImageUniqueID);
     76     ~SkImage_Raster() override;
     77 
     78     SkImageInfo onImageInfo() const override {
     79         return fBitmap.info();
     80     }
     81     SkAlphaType onAlphaType() const override {
     82         return fBitmap.alphaType();
     83     }
     84 
     85     bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override;
     86     bool onPeekPixels(SkPixmap*) const override;
     87     const SkBitmap* onPeekBitmap() const override { return &fBitmap; }
     88 
     89 #if SK_SUPPORT_GPU
     90     sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerParams&,
     91                                             SkColorSpace*, sk_sp<SkColorSpace>*,
     92                                             SkScalar scaleAdjust[2]) const override;
     93 #endif
     94 
     95     bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override;
     96     sk_sp<SkImage> onMakeSubset(const SkIRect&) const override;
     97 
     98     SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
     99 
    100     bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const override;
    101 
    102     SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false)
    103         : INHERITED(bm.width(), bm.height(),
    104                     is_not_subset(bm) ? bm.getGenerationID()
    105                                       : (uint32_t)kNeedNewImageUniqueID)
    106         , fBitmap(bm)
    107     {
    108         SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable());
    109     }
    110 
    111     sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>, SkColorType,
    112                                     SkTransferFunctionBehavior) const override;
    113 
    114     bool onIsValid(GrContext* context) const override { return true; }
    115 
    116 #if SK_SUPPORT_GPU
    117     sk_sp<GrTextureProxy> refPinnedTextureProxy(uint32_t* uniqueID) const override;
    118     bool onPinAsTexture(GrContext*) const override;
    119     void onUnpinAsTexture(GrContext*) const override;
    120 #endif
    121 
    122 private:
    123     SkBitmap fBitmap;
    124 
    125 #if SK_SUPPORT_GPU
    126     mutable sk_sp<GrTextureProxy> fPinnedProxy;
    127     mutable int32_t fPinnedCount = 0;
    128     mutable uint32_t fPinnedUniqueID = 0;
    129 #endif
    130 
    131     typedef SkImage_Base INHERITED;
    132 };
    133 
    134 ///////////////////////////////////////////////////////////////////////////////
    135 
    136 static void release_data(void* addr, void* context) {
    137     SkData* data = static_cast<SkData*>(context);
    138     data->unref();
    139 }
    140 
    141 SkImage_Raster::SkImage_Raster(const Info& info, sk_sp<SkData> data, size_t rowBytes, uint32_t id)
    142     : INHERITED(info.width(), info.height(), id)
    143 {
    144     void* addr = const_cast<void*>(data->data());
    145 
    146     fBitmap.installPixels(info, addr, rowBytes, release_data, data.release());
    147     fBitmap.setImmutable();
    148 }
    149 
    150 SkImage_Raster::~SkImage_Raster() {
    151 #if SK_SUPPORT_GPU
    152     SkASSERT(nullptr == fPinnedProxy.get());  // want the caller to have manually unpinned
    153 #endif
    154 }
    155 
    156 bool SkImage_Raster::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
    157                                   int srcX, int srcY, CachingHint) const {
    158     SkBitmap shallowCopy(fBitmap);
    159     return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
    160 }
    161 
    162 bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const {
    163     return fBitmap.peekPixels(pm);
    164 }
    165 
    166 bool SkImage_Raster::getROPixels(SkBitmap* dst, SkColorSpace* dstColorSpace, CachingHint) const {
    167     *dst = fBitmap;
    168     return true;
    169 }
    170 
    171 #if SK_SUPPORT_GPU
    172 sk_sp<GrTextureProxy> SkImage_Raster::asTextureProxyRef(GrContext* context,
    173                                                         const GrSamplerParams& params,
    174                                                         SkColorSpace* dstColorSpace,
    175                                                         sk_sp<SkColorSpace>* texColorSpace,
    176                                                         SkScalar scaleAdjust[2]) const {
    177     if (!context) {
    178         return nullptr;
    179     }
    180 
    181     if (texColorSpace) {
    182         *texColorSpace = sk_ref_sp(fBitmap.colorSpace());
    183     }
    184 
    185     uint32_t uniqueID;
    186     sk_sp<GrTextureProxy> tex = this->refPinnedTextureProxy(&uniqueID);
    187     if (tex) {
    188         GrTextureAdjuster adjuster(context, fPinnedProxy,
    189                                    fBitmap.alphaType(), fBitmap.bounds(),
    190                                    fPinnedUniqueID, fBitmap.colorSpace());
    191         return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust);
    192     }
    193 
    194     return GrRefCachedBitmapTextureProxy(context, fBitmap, params, scaleAdjust);
    195 }
    196 #endif
    197 
    198 #if SK_SUPPORT_GPU
    199 
    200 sk_sp<GrTextureProxy> SkImage_Raster::refPinnedTextureProxy(uint32_t* uniqueID) const {
    201     if (fPinnedProxy) {
    202         SkASSERT(fPinnedCount > 0);
    203         SkASSERT(fPinnedUniqueID != 0);
    204         *uniqueID = fPinnedUniqueID;
    205         return fPinnedProxy;
    206     }
    207     return nullptr;
    208 }
    209 
    210 bool SkImage_Raster::onPinAsTexture(GrContext* ctx) const {
    211     if (fPinnedProxy) {
    212         SkASSERT(fPinnedCount > 0);
    213         SkASSERT(fPinnedUniqueID != 0);
    214     } else {
    215         SkASSERT(fPinnedCount == 0);
    216         SkASSERT(fPinnedUniqueID == 0);
    217         fPinnedProxy = GrRefCachedBitmapTextureProxy(ctx, fBitmap,
    218                                                      GrSamplerParams::ClampNoFilter(), nullptr);
    219         if (!fPinnedProxy) {
    220             return false;
    221         }
    222         fPinnedUniqueID = fBitmap.getGenerationID();
    223     }
    224     // Note: we only increment if the texture was successfully pinned
    225     ++fPinnedCount;
    226     return true;
    227 }
    228 
    229 void SkImage_Raster::onUnpinAsTexture(GrContext* ctx) const {
    230     // Note: we always decrement, even if fPinnedTexture is null
    231     SkASSERT(fPinnedCount > 0);
    232     SkASSERT(fPinnedUniqueID != 0);
    233 
    234     if (0 == --fPinnedCount) {
    235         fPinnedProxy.reset(nullptr);
    236         fPinnedUniqueID = 0;
    237     }
    238 }
    239 #endif
    240 
    241 sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset) const {
    242     // TODO : could consider heurist of sharing pixels, if subset is pretty close to complete
    243 
    244     SkImageInfo info = SkImageInfo::MakeN32(subset.width(), subset.height(), fBitmap.alphaType());
    245     auto surface(SkSurface::MakeRaster(info));
    246     if (!surface) {
    247         return nullptr;
    248     }
    249     surface->getCanvas()->clear(0);
    250     surface->getCanvas()->drawImage(this, SkIntToScalar(-subset.x()), SkIntToScalar(-subset.y()),
    251                                     nullptr);
    252     return surface->makeImageSnapshot();
    253 }
    254 
    255 ///////////////////////////////////////////////////////////////////////////////
    256 
    257 sk_sp<SkImage> MakeRasterCopyPriv(const SkPixmap& pmap, uint32_t id) {
    258     size_t size;
    259     if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
    260         return nullptr;
    261     }
    262 
    263     // Here we actually make a copy of the caller's pixel data
    264     sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size));
    265     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), id);
    266 }
    267 
    268 sk_sp<SkImage> SkImage::MakeRasterCopy(const SkPixmap& pmap) {
    269     return MakeRasterCopyPriv(pmap, kNeedNewImageUniqueID);
    270 }
    271 
    272 sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> data,
    273                                        size_t rowBytes) {
    274     size_t size;
    275     if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !data) {
    276         return nullptr;
    277     }
    278 
    279     // did they give us enough data?
    280     if (data->size() < size) {
    281         return nullptr;
    282     }
    283 
    284     return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes);
    285 }
    286 
    287 sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc,
    288                                        ReleaseContext ctx) {
    289     size_t size;
    290     if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
    291         return nullptr;
    292     }
    293 
    294     sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx));
    295     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes());
    296 }
    297 
    298 sk_sp<SkImage> SkMakeImageFromRasterBitmapPriv(const SkBitmap& bm, SkCopyPixelsMode cpm,
    299                                                uint32_t idForCopy) {
    300     if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) {
    301         SkPixmap pmap;
    302         if (bm.peekPixels(&pmap)) {
    303             return MakeRasterCopyPriv(pmap, idForCopy);
    304         } else {
    305             return sk_sp<SkImage>();
    306         }
    307     }
    308 
    309     return sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm);
    310 }
    311 
    312 sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) {
    313     if (!SkImageInfoIsValidAllowNumericalCS(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) {
    314         return nullptr;
    315     }
    316 
    317     return SkMakeImageFromRasterBitmapPriv(bm, cpm, kNeedNewImageUniqueID);
    318 }
    319 
    320 sk_sp<SkImage> SkMakeImageInColorSpace(const SkBitmap& bm, sk_sp<SkColorSpace> dstCS, uint32_t id,
    321                                        SkCopyPixelsMode cpm) {
    322     if (!SkImageInfoIsValidAllowNumericalCS(bm.info()) || !bm.getPixels() ||
    323             bm.rowBytes() < bm.info().minRowBytes() || !dstCS) {
    324         return nullptr;
    325     }
    326 
    327     sk_sp<SkColorSpace> srcCS = bm.info().refColorSpace();
    328     if (!srcCS) {
    329         // Treat nullptr as sRGB.
    330         srcCS = SkColorSpace::MakeSRGB();
    331     }
    332 
    333     sk_sp<SkImage> image = nullptr;
    334 
    335     // For the Android use case, this is very likely to be true.
    336     if (SkColorSpace::Equals(srcCS.get(), dstCS.get())) {
    337         SkASSERT(kNeedNewImageUniqueID == id || bm.getGenerationID() == id);
    338         image = SkMakeImageFromRasterBitmapPriv(bm, cpm, id);
    339     } else {
    340         image = SkImage::MakeFromGenerator(SkColorSpaceXformImageGenerator::Make(bm, dstCS, cpm,
    341                                                                                  id));
    342     }
    343 
    344     // If the caller suplied an id, we must propagate that to the image we return
    345     SkASSERT(kNeedNewImageUniqueID == id || image->uniqueID() == id);
    346     return image;
    347 }
    348 
    349 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
    350     return ((const SkImage_Raster*)image)->getPixelRef();
    351 }
    352 
    353 bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
    354     if (kRO_LegacyBitmapMode == mode) {
    355         // When we're a snapshot from a surface, our bitmap may not be marked immutable
    356         // even though logically always we are, but in that case we can't physically share our
    357         // pixelref since the caller might call setImmutable() themselves
    358         // (thus changing our state).
    359         if (fBitmap.isImmutable()) {
    360             bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes());
    361             bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()),
    362                                 fBitmap.pixelRefOrigin().x(),
    363                                 fBitmap.pixelRefOrigin().y());
    364             return true;
    365         }
    366     }
    367     return this->INHERITED::onAsLegacyBitmap(bitmap, mode);
    368 }
    369 
    370 ///////////////////////////////////////////////////////////////////////////////
    371 
    372 sk_sp<SkImage> SkImage_Raster::onMakeColorSpace(sk_sp<SkColorSpace> target,
    373                                                 SkColorType targetColorType,
    374                                                 SkTransferFunctionBehavior premulBehavior) const {
    375     SkPixmap src;
    376     SkAssertResult(fBitmap.peekPixels(&src));
    377 
    378     // Treat nullptr srcs as sRGB.
    379     if (!src.colorSpace()) {
    380         if (target->isSRGB()) {
    381             return sk_ref_sp(const_cast<SkImage*>((SkImage*)this));
    382         }
    383 
    384         src.setColorSpace(SkColorSpace::MakeSRGB());
    385     }
    386 
    387     SkImageInfo dstInfo = fBitmap.info().makeColorType(targetColorType).makeColorSpace(target);
    388     SkBitmap dst;
    389     dst.allocPixels(dstInfo);
    390 
    391     SkAssertResult(dst.writePixels(src, 0, 0, premulBehavior));
    392     dst.setImmutable();
    393     return SkImage::MakeFromBitmap(dst);
    394 }
    395