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:
ValidArgs(const Info & info,size_t rowBytes,bool hasColorTable,size_t * minSize)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 
getPixelRef() const79     SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
80 
81     bool isOpaque() const override;
82     bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const override;
83 
SkImage_Raster(const SkBitmap & bm)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 
onIsLazyGenerated() const96     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 
release_data(void * addr,void * context)108 static void release_data(void* addr, void* context) {
109     SkData* data = static_cast<SkData*>(context);
110     data->unref();
111 }
112 
SkImage_Raster(const Info & info,SkData * data,size_t rowBytes,SkColorTable * ctable)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 
SkImage_Raster(const Info & info,SkPixelRef * pr,const SkIPoint & pixelRefOrigin,size_t rowBytes)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 
~SkImage_Raster()135 SkImage_Raster::~SkImage_Raster() {}
136 
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint) const137 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 
onPeekPixels(SkImageInfo * infoPtr,size_t * rowBytesPtr) const143 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 
onRefEncoded(GrContext *) const153 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 
getROPixels(SkBitmap * dst,CachingHint) const165 bool SkImage_Raster::getROPixels(SkBitmap* dst, CachingHint) const {
166     *dst = fBitmap;
167     return true;
168 }
169 
asTextureRef(GrContext * ctx,const GrTextureParams & params) const170 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 
onNewSubset(const SkIRect & subset) const182 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 
NewRasterCopy(const SkImageInfo & info,const void * pixels,size_t rowBytes,SkColorTable * ctable)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 
NewRasterData(const SkImageInfo & info,SkData * data,size_t rowBytes)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 
NewFromRaster(const SkImageInfo & info,const void * pixels,size_t rowBytes,RasterReleaseProc proc,ReleaseContext ctx)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 
SkNewImageFromPixelRef(const SkImageInfo & info,SkPixelRef * pr,const SkIPoint & pixelRefOrigin,size_t rowBytes)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 
SkNewImageFromRasterBitmap(const SkBitmap & bm,ForceCopyMode forceCopy)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 
SkBitmapImageGetPixelRef(const SkImage * image)273 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
274     return ((const SkImage_Raster*)image)->getPixelRef();
275 }
276 
isOpaque() const277 bool SkImage_Raster::isOpaque() const {
278     return fBitmap.isOpaque();
279 }
280 
onAsLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode mode) const281 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