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 "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkData.h"
11 #include "include/core/SkPixelRef.h"
12 #include "include/core/SkSurface.h"
13 #include "include/private/SkImageInfoPriv.h"
14 #include "src/codec/SkColorTable.h"
15 #include "src/core/SkConvertPixels.h"
16 #include "src/core/SkImagePriv.h"
17 #include "src/core/SkTLazy.h"
18 #include "src/image/SkImage_Base.h"
19 #include "src/shaders/SkBitmapProcShader.h"
20 
21 #if SK_SUPPORT_GPU
22 #include "include/gpu/GrContext.h"
23 #include "src/gpu/GrTextureAdjuster.h"
24 #include "src/gpu/SkGr.h"
25 #endif
26 
27 // fixes https://bug.skia.org/5096
is_not_subset(const SkBitmap & bm)28 static bool is_not_subset(const SkBitmap& bm) {
29     SkASSERT(bm.pixelRef());
30     SkISize dim = SkISize::Make(bm.pixelRef()->width(), bm.pixelRef()->height());
31     SkASSERT(dim != bm.dimensions() || bm.pixelRefOrigin().isZero());
32     return dim == bm.dimensions();
33 }
34 
35 class SkImage_Raster : public SkImage_Base {
36 public:
ValidArgs(const SkImageInfo & info,size_t rowBytes,size_t * minSize)37     static bool ValidArgs(const SkImageInfo& info, size_t rowBytes, size_t* minSize) {
38         const int maxDimension = SK_MaxS32 >> 2;
39 
40         if (info.width() <= 0 || info.height() <= 0) {
41             return false;
42         }
43         if (info.width() > maxDimension || info.height() > maxDimension) {
44             return false;
45         }
46         if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) {
47             return false;
48         }
49         if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) {
50             return false;
51         }
52 
53         if (kUnknown_SkColorType == info.colorType()) {
54             return false;
55         }
56         if (!info.validRowBytes(rowBytes)) {
57             return false;
58         }
59 
60         size_t size = info.computeByteSize(rowBytes);
61         if (SkImageInfo::ByteSizeOverflowed(size)) {
62             return false;
63         }
64 
65         if (minSize) {
66             *minSize = size;
67         }
68         return true;
69     }
70 
71     SkImage_Raster(const SkImageInfo&, sk_sp<SkData>, size_t rb,
72                    uint32_t id = kNeedNewImageUniqueID);
73     ~SkImage_Raster() override;
74 
75     bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override;
76     bool onPeekPixels(SkPixmap*) const override;
onPeekBitmap() const77     const SkBitmap* onPeekBitmap() const override { return &fBitmap; }
78 
79 #if SK_SUPPORT_GPU
80     sk_sp<GrTextureProxy> asTextureProxyRef(GrRecordingContext*, const GrSamplerState&,
81                                             SkScalar scaleAdjust[2]) const override;
82 #endif
83 
84     bool getROPixels(SkBitmap*, CachingHint) const override;
85     sk_sp<SkImage> onMakeSubset(GrRecordingContext*, const SkIRect&) const override;
86 
getPixelRef() const87     SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
88 
89     bool onAsLegacyBitmap(SkBitmap*) const override;
90 
SkImage_Raster(const SkBitmap & bm,bool bitmapMayBeMutable=false)91     SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false)
92             : INHERITED(bm.info(),
93                         is_not_subset(bm) ? bm.getGenerationID() : (uint32_t)kNeedNewImageUniqueID)
94             , fBitmap(bm) {
95         SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable());
96     }
97 
98     sk_sp<SkImage> onMakeColorTypeAndColorSpace(GrRecordingContext*,
99                                                 SkColorType, sk_sp<SkColorSpace>) const override;
100 
101     sk_sp<SkImage> onReinterpretColorSpace(sk_sp<SkColorSpace>) const override;
102 
onIsValid(GrContext * context) const103     bool onIsValid(GrContext* context) const override { return true; }
notifyAddedToRasterCache() const104     void notifyAddedToRasterCache() const override {
105         // We explicitly DON'T want to call INHERITED::notifyAddedToRasterCache. That ties the
106         // lifetime of derived/cached resources to the image. In this case, we only want cached
107         // data (eg mips) tied to the lifetime of the underlying pixelRef.
108         SkASSERT(fBitmap.pixelRef());
109         fBitmap.pixelRef()->notifyAddedToCache();
110     }
111 
112 #if SK_SUPPORT_GPU
113     sk_sp<GrTextureProxy> refPinnedTextureProxy(GrRecordingContext*,
114                                                 uint32_t* uniqueID) const override;
115     bool onPinAsTexture(GrContext*) const override;
116     void onUnpinAsTexture(GrContext*) const override;
117 #endif
118 
119 private:
120     SkBitmap fBitmap;
121 
122 #if SK_SUPPORT_GPU
123     mutable sk_sp<GrTextureProxy> fPinnedProxy;
124     mutable int32_t fPinnedCount = 0;
125     mutable uint32_t fPinnedUniqueID = 0;
126 #endif
127 
128     typedef SkImage_Base INHERITED;
129 };
130 
131 ///////////////////////////////////////////////////////////////////////////////
132 
release_data(void * addr,void * context)133 static void release_data(void* addr, void* context) {
134     SkData* data = static_cast<SkData*>(context);
135     data->unref();
136 }
137 
SkImage_Raster(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes,uint32_t id)138 SkImage_Raster::SkImage_Raster(const SkImageInfo& info, sk_sp<SkData> data, size_t rowBytes,
139                                uint32_t id)
140         : INHERITED(info, id) {
141     void* addr = const_cast<void*>(data->data());
142 
143     fBitmap.installPixels(info, addr, rowBytes, release_data, data.release());
144     fBitmap.setImmutable();
145 }
146 
~SkImage_Raster()147 SkImage_Raster::~SkImage_Raster() {
148 #if SK_SUPPORT_GPU
149     SkASSERT(nullptr == fPinnedProxy.get());  // want the caller to have manually unpinned
150 #endif
151 }
152 
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint) const153 bool SkImage_Raster::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
154                                   int srcX, int srcY, CachingHint) const {
155     SkBitmap shallowCopy(fBitmap);
156     return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
157 }
158 
onPeekPixels(SkPixmap * pm) const159 bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const {
160     return fBitmap.peekPixels(pm);
161 }
162 
getROPixels(SkBitmap * dst,CachingHint) const163 bool SkImage_Raster::getROPixels(SkBitmap* dst, CachingHint) const {
164     *dst = fBitmap;
165     return true;
166 }
167 
168 #if SK_SUPPORT_GPU
asTextureProxyRef(GrRecordingContext * context,const GrSamplerState & params,SkScalar scaleAdjust[2]) const169 sk_sp<GrTextureProxy> SkImage_Raster::asTextureProxyRef(GrRecordingContext* context,
170                                                         const GrSamplerState& params,
171                                                         SkScalar scaleAdjust[2]) const {
172     if (!context) {
173         return nullptr;
174     }
175 
176     uint32_t uniqueID;
177     sk_sp<GrTextureProxy> tex = this->refPinnedTextureProxy(context, &uniqueID);
178     if (tex) {
179         GrTextureAdjuster adjuster(context, fPinnedProxy,
180                                    SkColorTypeToGrColorType(fBitmap.colorType()),
181                                    fBitmap.alphaType(), fPinnedUniqueID, fBitmap.colorSpace());
182         return adjuster.refTextureProxyForParams(params, scaleAdjust);
183     }
184 
185     return GrRefCachedBitmapTextureProxy(context, fBitmap, params, scaleAdjust);
186 }
187 #endif
188 
189 #if SK_SUPPORT_GPU
190 
refPinnedTextureProxy(GrRecordingContext *,uint32_t * uniqueID) const191 sk_sp<GrTextureProxy> SkImage_Raster::refPinnedTextureProxy(GrRecordingContext*,
192                                                             uint32_t* uniqueID) const {
193     if (fPinnedProxy) {
194         SkASSERT(fPinnedCount > 0);
195         SkASSERT(fPinnedUniqueID != 0);
196         *uniqueID = fPinnedUniqueID;
197         return fPinnedProxy;
198     }
199     return nullptr;
200 }
201 
onPinAsTexture(GrContext * ctx) const202 bool SkImage_Raster::onPinAsTexture(GrContext* ctx) const {
203     if (fPinnedProxy) {
204         SkASSERT(fPinnedCount > 0);
205         SkASSERT(fPinnedUniqueID != 0);
206     } else {
207         SkASSERT(fPinnedCount == 0);
208         SkASSERT(fPinnedUniqueID == 0);
209         fPinnedProxy = GrRefCachedBitmapTextureProxy(ctx, fBitmap, GrSamplerState::ClampNearest(),
210                                                      nullptr);
211         if (!fPinnedProxy) {
212             return false;
213         }
214         fPinnedUniqueID = fBitmap.getGenerationID();
215     }
216     // Note: we only increment if the texture was successfully pinned
217     ++fPinnedCount;
218     return true;
219 }
220 
onUnpinAsTexture(GrContext * ctx) const221 void SkImage_Raster::onUnpinAsTexture(GrContext* ctx) const {
222     // Note: we always decrement, even if fPinnedTexture is null
223     SkASSERT(fPinnedCount > 0);
224     SkASSERT(fPinnedUniqueID != 0);
225 
226     if (0 == --fPinnedCount) {
227         fPinnedProxy.reset(nullptr);
228         fPinnedUniqueID = 0;
229     }
230 }
231 #endif
232 
onMakeSubset(GrRecordingContext *,const SkIRect & subset) const233 sk_sp<SkImage> SkImage_Raster::onMakeSubset(GrRecordingContext*, const SkIRect& subset) const {
234     SkImageInfo info = fBitmap.info().makeDimensions(subset.size());
235     SkBitmap bitmap;
236     if (!bitmap.tryAllocPixels(info)) {
237         return nullptr;
238     }
239 
240     void* dst = bitmap.getPixels();
241     void* src = fBitmap.getAddr(subset.x(), subset.y());
242     if (!dst || !src) {
243         SkDEBUGFAIL("SkImage_Raster::onMakeSubset with nullptr src or dst");
244         return nullptr;
245     }
246 
247     SkRectMemcpy(dst, bitmap.rowBytes(), src, fBitmap.rowBytes(), bitmap.rowBytes(),
248                  subset.height());
249 
250     bitmap.setImmutable();
251     return MakeFromBitmap(bitmap);
252 }
253 
254 ///////////////////////////////////////////////////////////////////////////////
255 
MakeRasterCopyPriv(const SkPixmap & pmap,uint32_t id)256 sk_sp<SkImage> MakeRasterCopyPriv(const SkPixmap& pmap, uint32_t id) {
257     size_t size;
258     if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
259         return nullptr;
260     }
261 
262     // Here we actually make a copy of the caller's pixel data
263     sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size));
264     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), id);
265 }
266 
MakeRasterCopy(const SkPixmap & pmap)267 sk_sp<SkImage> SkImage::MakeRasterCopy(const SkPixmap& pmap) {
268     return MakeRasterCopyPriv(pmap, kNeedNewImageUniqueID);
269 }
270 
MakeRasterData(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes)271 sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> data,
272                                        size_t rowBytes) {
273     size_t size;
274     if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !data) {
275         return nullptr;
276     }
277 
278     // did they give us enough data?
279     if (data->size() < size) {
280         return nullptr;
281     }
282 
283     return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes);
284 }
285 
MakeFromRaster(const SkPixmap & pmap,RasterReleaseProc proc,ReleaseContext ctx)286 sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc,
287                                        ReleaseContext ctx) {
288     size_t size;
289     if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
290         return nullptr;
291     }
292 
293     sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx));
294     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes());
295 }
296 
SkMakeImageFromRasterBitmapPriv(const SkBitmap & bm,SkCopyPixelsMode cpm,uint32_t idForCopy)297 sk_sp<SkImage> SkMakeImageFromRasterBitmapPriv(const SkBitmap& bm, SkCopyPixelsMode cpm,
298                                                uint32_t idForCopy) {
299     if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) {
300         SkPixmap pmap;
301         if (bm.peekPixels(&pmap)) {
302             return MakeRasterCopyPriv(pmap, idForCopy);
303         } else {
304             return sk_sp<SkImage>();
305         }
306     }
307 
308     return sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm);
309 }
310 
SkMakeImageFromRasterBitmap(const SkBitmap & bm,SkCopyPixelsMode cpm)311 sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) {
312     if (!SkImageInfoIsValid(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) {
313         return nullptr;
314     }
315 
316     return SkMakeImageFromRasterBitmapPriv(bm, cpm, kNeedNewImageUniqueID);
317 }
318 
SkBitmapImageGetPixelRef(const SkImage * image)319 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
320     return ((const SkImage_Raster*)image)->getPixelRef();
321 }
322 
onAsLegacyBitmap(SkBitmap * bitmap) const323 bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap) const {
324     // When we're a snapshot from a surface, our bitmap may not be marked immutable
325     // even though logically always we are, but in that case we can't physically share our
326     // pixelref since the caller might call setImmutable() themselves
327     // (thus changing our state).
328     if (fBitmap.isImmutable()) {
329         SkIPoint origin = fBitmap.pixelRefOrigin();
330         bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes());
331         bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()), origin.x(), origin.y());
332         return true;
333     }
334     return this->INHERITED::onAsLegacyBitmap(bitmap);
335 }
336 
337 ///////////////////////////////////////////////////////////////////////////////
338 
onMakeColorTypeAndColorSpace(GrRecordingContext *,SkColorType targetCT,sk_sp<SkColorSpace> targetCS) const339 sk_sp<SkImage> SkImage_Raster::onMakeColorTypeAndColorSpace(GrRecordingContext*,
340                                                             SkColorType targetCT,
341                                                             sk_sp<SkColorSpace> targetCS) const {
342     SkPixmap src;
343     SkAssertResult(fBitmap.peekPixels(&src));
344 
345     SkBitmap dst;
346     dst.allocPixels(fBitmap.info().makeColorType(targetCT).makeColorSpace(targetCS));
347 
348     SkAssertResult(dst.writePixels(src));
349     dst.setImmutable();
350     return SkImage::MakeFromBitmap(dst);
351 }
352 
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const353 sk_sp<SkImage> SkImage_Raster::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
354     // TODO: If our bitmap is immutable, then we could theoretically create another image sharing
355     // our pixelRef. That doesn't work (without more invasive logic), because the image gets its
356     // gen ID from the bitmap, which gets it from the pixelRef.
357     SkPixmap pixmap = fBitmap.pixmap();
358     pixmap.setColorSpace(std::move(newCS));
359     return SkImage::MakeRasterCopy(pixmap);
360 }
361