• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkColorSpaceXformPriv.h"
14 #include "SkColorTable.h"
15 #include "SkConvertPixels.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
is_not_subset(const SkBitmap & bm)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:
ValidArgs(const Info & info,size_t rowBytes,size_t * minSize)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 (!info.validRowBytes(rowBytes)) {
60             return false;
61         }
62 
63         size_t size = info.computeByteSize(rowBytes);
64         if (SkImageInfo::ByteSizeOverflowed(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 
onImageInfo() const78     SkImageInfo onImageInfo() const override {
79         return fBitmap.info();
80     }
onAlphaType() const81     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;
onPeekBitmap() const87     const SkBitmap* onPeekBitmap() const override { return &fBitmap; }
88 
89 #if SK_SUPPORT_GPU
90     sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerState&, SkColorSpace*,
91                                             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 
getPixelRef() const98     SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
99 
100     bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const override;
101 
SkImage_Raster(const SkBitmap & bm,bool bitmapMayBeMutable=false)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 
onIsValid(GrContext * context) const114     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 
release_data(void * addr,void * context)136 static void release_data(void* addr, void* context) {
137     SkData* data = static_cast<SkData*>(context);
138     data->unref();
139 }
140 
SkImage_Raster(const Info & info,sk_sp<SkData> data,size_t rowBytes,uint32_t id)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 
~SkImage_Raster()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 
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint) const156 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 
onPeekPixels(SkPixmap * pm) const162 bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const {
163     return fBitmap.peekPixels(pm);
164 }
165 
getROPixels(SkBitmap * dst,SkColorSpace * dstColorSpace,CachingHint) const166 bool SkImage_Raster::getROPixels(SkBitmap* dst, SkColorSpace* dstColorSpace, CachingHint) const {
167     *dst = fBitmap;
168     return true;
169 }
170 
171 #if SK_SUPPORT_GPU
asTextureProxyRef(GrContext * context,const GrSamplerState & params,SkColorSpace * dstColorSpace,sk_sp<SkColorSpace> * texColorSpace,SkScalar scaleAdjust[2]) const172 sk_sp<GrTextureProxy> SkImage_Raster::asTextureProxyRef(GrContext* context,
173                                                         const GrSamplerState& 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, fBitmap.alphaType(), fPinnedUniqueID,
189                                    fBitmap.colorSpace());
190         return adjuster.refTextureProxySafeForParams(params, scaleAdjust);
191     }
192 
193     return GrRefCachedBitmapTextureProxy(context, fBitmap, params, scaleAdjust);
194 }
195 #endif
196 
197 #if SK_SUPPORT_GPU
198 
refPinnedTextureProxy(uint32_t * uniqueID) const199 sk_sp<GrTextureProxy> SkImage_Raster::refPinnedTextureProxy(uint32_t* uniqueID) const {
200     if (fPinnedProxy) {
201         SkASSERT(fPinnedCount > 0);
202         SkASSERT(fPinnedUniqueID != 0);
203         *uniqueID = fPinnedUniqueID;
204         return fPinnedProxy;
205     }
206     return nullptr;
207 }
208 
onPinAsTexture(GrContext * ctx) const209 bool SkImage_Raster::onPinAsTexture(GrContext* ctx) const {
210     if (fPinnedProxy) {
211         SkASSERT(fPinnedCount > 0);
212         SkASSERT(fPinnedUniqueID != 0);
213     } else {
214         SkASSERT(fPinnedCount == 0);
215         SkASSERT(fPinnedUniqueID == 0);
216         fPinnedProxy = GrRefCachedBitmapTextureProxy(ctx, fBitmap, GrSamplerState::ClampNearest(),
217                                                      nullptr);
218         if (!fPinnedProxy) {
219             return false;
220         }
221         fPinnedUniqueID = fBitmap.getGenerationID();
222     }
223     // Note: we only increment if the texture was successfully pinned
224     ++fPinnedCount;
225     return true;
226 }
227 
onUnpinAsTexture(GrContext * ctx) const228 void SkImage_Raster::onUnpinAsTexture(GrContext* ctx) const {
229     // Note: we always decrement, even if fPinnedTexture is null
230     SkASSERT(fPinnedCount > 0);
231     SkASSERT(fPinnedUniqueID != 0);
232 
233     if (0 == --fPinnedCount) {
234         fPinnedProxy.reset(nullptr);
235         fPinnedUniqueID = 0;
236     }
237 }
238 #endif
239 
onMakeSubset(const SkIRect & subset) const240 sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset) const {
241     SkImageInfo info = fBitmap.info().makeWH(subset.width(), subset.height());
242     SkBitmap bitmap;
243     if (!bitmap.tryAllocPixels(info)) {
244         return nullptr;
245     }
246 
247     void* dst = bitmap.getPixels();
248     void* src = fBitmap.getAddr(subset.x(), subset.y());
249     if (!dst || !src) {
250         SkDEBUGFAIL("SkImage_Raster::onMakeSubset with nullptr src or dst");
251         return nullptr;
252     }
253 
254     SkRectMemcpy(dst, bitmap.rowBytes(), src, fBitmap.rowBytes(), bitmap.rowBytes(),
255                  subset.height());
256 
257     bitmap.setImmutable();
258     return MakeFromBitmap(bitmap);
259 }
260 
261 ///////////////////////////////////////////////////////////////////////////////
262 
MakeRasterCopyPriv(const SkPixmap & pmap,uint32_t id)263 sk_sp<SkImage> MakeRasterCopyPriv(const SkPixmap& pmap, uint32_t id) {
264     size_t size;
265     if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
266         return nullptr;
267     }
268 
269     // Here we actually make a copy of the caller's pixel data
270     sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size));
271     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), id);
272 }
273 
MakeRasterCopy(const SkPixmap & pmap)274 sk_sp<SkImage> SkImage::MakeRasterCopy(const SkPixmap& pmap) {
275     return MakeRasterCopyPriv(pmap, kNeedNewImageUniqueID);
276 }
277 
MakeRasterData(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes)278 sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> data,
279                                        size_t rowBytes) {
280     size_t size;
281     if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !data) {
282         return nullptr;
283     }
284 
285     // did they give us enough data?
286     if (data->size() < size) {
287         return nullptr;
288     }
289 
290     return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes);
291 }
292 
MakeFromRaster(const SkPixmap & pmap,RasterReleaseProc proc,ReleaseContext ctx)293 sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc,
294                                        ReleaseContext ctx) {
295     size_t size;
296     if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
297         return nullptr;
298     }
299 
300     sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx));
301     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes());
302 }
303 
SkMakeImageFromRasterBitmapPriv(const SkBitmap & bm,SkCopyPixelsMode cpm,uint32_t idForCopy)304 sk_sp<SkImage> SkMakeImageFromRasterBitmapPriv(const SkBitmap& bm, SkCopyPixelsMode cpm,
305                                                uint32_t idForCopy) {
306     if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) {
307         SkPixmap pmap;
308         if (bm.peekPixels(&pmap)) {
309             return MakeRasterCopyPriv(pmap, idForCopy);
310         } else {
311             return sk_sp<SkImage>();
312         }
313     }
314 
315     return sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm);
316 }
317 
SkMakeImageFromRasterBitmap(const SkBitmap & bm,SkCopyPixelsMode cpm)318 sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) {
319     if (!SkImageInfoIsValidAllowNumericalCS(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) {
320         return nullptr;
321     }
322 
323     return SkMakeImageFromRasterBitmapPriv(bm, cpm, kNeedNewImageUniqueID);
324 }
325 
SkBitmapImageGetPixelRef(const SkImage * image)326 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
327     return ((const SkImage_Raster*)image)->getPixelRef();
328 }
329 
onAsLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode mode) const330 bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
331     if (kRO_LegacyBitmapMode == mode) {
332         // When we're a snapshot from a surface, our bitmap may not be marked immutable
333         // even though logically always we are, but in that case we can't physically share our
334         // pixelref since the caller might call setImmutable() themselves
335         // (thus changing our state).
336         if (fBitmap.isImmutable()) {
337             SkIPoint origin = fBitmap.pixelRefOrigin();
338             bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes());
339             bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()), origin.x(), origin.y());
340             return true;
341         }
342     }
343     return this->INHERITED::onAsLegacyBitmap(bitmap, mode);
344 }
345 
346 ///////////////////////////////////////////////////////////////////////////////
347 
onMakeColorSpace(sk_sp<SkColorSpace> target,SkColorType targetColorType,SkTransferFunctionBehavior premulBehavior) const348 sk_sp<SkImage> SkImage_Raster::onMakeColorSpace(sk_sp<SkColorSpace> target,
349                                                 SkColorType targetColorType,
350                                                 SkTransferFunctionBehavior premulBehavior) const {
351     SkPixmap src;
352     SkAssertResult(fBitmap.peekPixels(&src));
353 
354     // Treat nullptr srcs as sRGB.
355     if (!src.colorSpace()) {
356         if (target->isSRGB()) {
357             return sk_ref_sp(const_cast<SkImage*>((SkImage*)this));
358         }
359 
360         src.setColorSpace(SkColorSpace::MakeSRGB());
361     }
362 
363     SkImageInfo dstInfo = fBitmap.info().makeColorType(targetColorType).makeColorSpace(target);
364     SkBitmap dst;
365     dst.allocPixels(dstInfo);
366 
367     SkAssertResult(dst.writePixels(src, 0, 0, premulBehavior));
368     dst.setImmutable();
369     return SkImage::MakeFromBitmap(dst);
370 }
371