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