• 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 "SkBitmap.h"
9 #include "SkBitmapCache.h"
10 #include "SkCanvas.h"
11 #include "SkData.h"
12 #include "SkImageEncoder.h"
13 #include "SkImageGenerator.h"
14 #include "SkImagePriv.h"
15 #include "SkImageShader.h"
16 #include "SkImage_Base.h"
17 #include "SkNextID.h"
18 #include "SkPixelRef.h"
19 #include "SkPixelSerializer.h"
20 #include "SkReadPixelsRec.h"
21 #include "SkString.h"
22 #include "SkSurface.h"
23 
24 #if SK_SUPPORT_GPU
25 #include "GrTexture.h"
26 #include "GrContext.h"
27 #include "SkImage_Gpu.h"
28 #endif
29 
SkImage(int width,int height,uint32_t uniqueID)30 SkImage::SkImage(int width, int height, uint32_t uniqueID)
31     : fWidth(width)
32     , fHeight(height)
33     , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID)
34 {
35     SkASSERT(width > 0);
36     SkASSERT(height > 0);
37 }
38 
peekPixels(SkImageInfo * info,size_t * rowBytes) const39 const void* SkImage::peekPixels(SkImageInfo* info, size_t* rowBytes) const {
40     SkImageInfo infoStorage;
41     size_t rowBytesStorage;
42     if (nullptr == info) {
43         info = &infoStorage;
44     }
45     if (nullptr == rowBytes) {
46         rowBytes = &rowBytesStorage;
47     }
48     return as_IB(this)->onPeekPixels(info, rowBytes);
49 }
50 
readPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint chint) const51 bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
52                            int srcX, int srcY, CachingHint chint) const {
53     SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
54     if (!rec.trim(this->width(), this->height())) {
55         return false;
56     }
57     return as_IB(this)->onReadPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, chint);
58 }
59 
scalePixels(const SkPixmap & dst,SkFilterQuality quality,CachingHint chint) const60 bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingHint chint) const {
61     if (this->width() == dst.width() && this->height() == dst.height()) {
62         return this->readPixels(dst, 0, 0, chint);
63     }
64 
65     // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself
66     //       can scale more efficiently) we should take advantage of it here.
67     //
68     SkBitmap bm;
69     if (as_IB(this)->getROPixels(&bm, chint)) {
70         bm.lockPixels();
71         SkPixmap pmap;
72         // Note: By calling the pixmap scaler, we never cache the final result, so the chint
73         //       is (currently) only being applied to the getROPixels. If we get a request to
74         //       also attempt to cache the final (scaled) result, we would add that logic here.
75         //
76         return bm.peekPixels(&pmap) && pmap.scalePixels(dst, quality);
77     }
78     return false;
79 }
80 
preroll(GrContext * ctx) const81 void SkImage::preroll(GrContext* ctx) const {
82     // For now, and to maintain parity w/ previous pixelref behavior, we just force the image
83     // to produce a cached raster-bitmap form, so that drawing to a raster canvas should be fast.
84     //
85     SkBitmap bm;
86     if (as_IB(this)->getROPixels(&bm)) {
87         bm.lockPixels();
88         bm.unlockPixels();
89     }
90 }
91 
92 ///////////////////////////////////////////////////////////////////////////////////////////////////
93 
newShader(SkShader::TileMode tileX,SkShader::TileMode tileY,const SkMatrix * localMatrix) const94 SkShader* SkImage::newShader(SkShader::TileMode tileX,
95                              SkShader::TileMode tileY,
96                              const SkMatrix* localMatrix) const {
97     return SkImageShader::Create(this, tileX, tileY, localMatrix);
98 }
99 
encode(SkImageEncoder::Type type,int quality) const100 SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const {
101     SkBitmap bm;
102     if (as_IB(this)->getROPixels(&bm)) {
103         return SkImageEncoder::EncodeData(bm, type, quality);
104     }
105     return nullptr;
106 }
107 
encode(SkPixelSerializer * serializer) const108 SkData* SkImage::encode(SkPixelSerializer* serializer) const {
109     SkAutoTUnref<SkPixelSerializer> defaultSerializer;
110     SkPixelSerializer* effectiveSerializer = serializer;
111     if (!effectiveSerializer) {
112         defaultSerializer.reset(SkImageEncoder::CreatePixelSerializer());
113         SkASSERT(defaultSerializer.get());
114         effectiveSerializer = defaultSerializer.get();
115     }
116     SkAutoTUnref<SkData> encoded(this->refEncoded());
117     if (encoded && effectiveSerializer->useEncodedData(encoded->data(), encoded->size())) {
118         return encoded.detach();
119     }
120 
121     SkBitmap bm;
122     SkAutoPixmapUnlock apu;
123     if (as_IB(this)->getROPixels(&bm) && bm.requestLock(&apu)) {
124         return effectiveSerializer->encode(apu.pixmap());
125     }
126 
127     return nullptr;
128 }
129 
refEncoded() const130 SkData* SkImage::refEncoded() const {
131     GrContext* ctx = nullptr;   // should we allow the caller to pass in a ctx?
132     return as_IB(this)->onRefEncoded(ctx);
133 }
134 
NewFromEncoded(SkData * encoded,const SkIRect * subset)135 SkImage* SkImage::NewFromEncoded(SkData* encoded, const SkIRect* subset) {
136     if (nullptr == encoded || 0 == encoded->size()) {
137         return nullptr;
138     }
139     SkImageGenerator* generator = SkImageGenerator::NewFromEncoded(encoded);
140     return generator ? SkImage::NewFromGenerator(generator, subset) : nullptr;
141 }
142 
toString(SkString * str) const143 const char* SkImage::toString(SkString* str) const {
144     str->appendf("image: (id:%d (%d, %d) %s)", this->uniqueID(), this->width(), this->height(),
145                  this->isOpaque() ? "opaque" : "");
146     return str->c_str();
147 }
148 
newSubset(const SkIRect & subset) const149 SkImage* SkImage::newSubset(const SkIRect& subset) const {
150     if (subset.isEmpty()) {
151         return nullptr;
152     }
153 
154     const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
155     if (!bounds.contains(subset)) {
156         return nullptr;
157     }
158 
159     // optimization : return self if the subset == our bounds
160     if (bounds == subset) {
161         return SkRef(const_cast<SkImage*>(this));
162     }
163     return as_IB(this)->onNewSubset(subset);
164 }
165 
166 #if SK_SUPPORT_GPU
167 
getTexture() const168 GrTexture* SkImage::getTexture() const {
169     return as_IB(this)->peekTexture();
170 }
171 
isTextureBacked() const172 bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->getTexture()); }
173 
getTextureHandle(bool flushPendingGrContextIO) const174 GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO) const {
175     GrTexture* texture = as_IB(this)->getTexture();
176     if (texture) {
177         GrContext* context = texture->getContext();
178         if (context) {
179             if (flushPendingGrContextIO) {
180                 context->prepareSurfaceForExternalIO(texture);
181             }
182         }
183         return texture->getTextureHandle();
184     }
185     return 0;
186 }
187 
188 #else
189 
getTexture() const190 GrTexture* SkImage::getTexture() const { return nullptr; }
191 
isTextureBacked() const192 bool SkImage::isTextureBacked() const { return false; }
193 
getTextureHandle(bool) const194 GrBackendObject SkImage::getTextureHandle(bool) const { return 0; }
195 
196 #endif
197 
198 ///////////////////////////////////////////////////////////////////////////////
199 
raster_canvas_supports(const SkImageInfo & info)200 static bool raster_canvas_supports(const SkImageInfo& info) {
201     switch (info.colorType()) {
202         case kN32_SkColorType:
203             return kUnpremul_SkAlphaType != info.alphaType();
204         case kRGB_565_SkColorType:
205             return true;
206         case kAlpha_8_SkColorType:
207             return true;
208         default:
209             break;
210     }
211     return false;
212 }
213 
SkImage_Base(int width,int height,uint32_t uniqueID)214 SkImage_Base::SkImage_Base(int width, int height, uint32_t uniqueID)
215     : INHERITED(width, height, uniqueID)
216     , fAddedToCache(false)
217 {}
218 
~SkImage_Base()219 SkImage_Base::~SkImage_Base() {
220     if (fAddedToCache.load()) {
221         SkNotifyBitmapGenIDIsStale(this->uniqueID());
222     }
223 }
224 
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint) const225 bool SkImage_Base::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
226                                 int srcX, int srcY, CachingHint) const {
227     if (!raster_canvas_supports(dstInfo)) {
228         return false;
229     }
230 
231     SkBitmap bm;
232     bm.installPixels(dstInfo, dstPixels, dstRowBytes);
233     SkCanvas canvas(bm);
234 
235     SkPaint paint;
236     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
237     canvas.drawImage(this, -SkIntToScalar(srcX), -SkIntToScalar(srcY), &paint);
238 
239     return true;
240 }
241 
242 ///////////////////////////////////////////////////////////////////////////////////////////////////
243 
peekPixels(SkPixmap * pmap) const244 bool SkImage::peekPixels(SkPixmap* pmap) const {
245     SkImageInfo info;
246     size_t rowBytes;
247     const void* pixels = this->peekPixels(&info, &rowBytes);
248     if (pixels) {
249         if (pmap) {
250             pmap->reset(info, pixels, rowBytes);
251         }
252         return true;
253     }
254     return false;
255 }
256 
readPixels(const SkPixmap & pmap,int srcX,int srcY,CachingHint chint) const257 bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const {
258     return this->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX, srcY, chint);
259 }
260 
261 #if SK_SUPPORT_GPU
262 #include "GrTextureToYUVPlanes.h"
263 #endif
264 
265 #include "SkRGBAToYUV.h"
266 
readYUV8Planes(const SkISize sizes[3],void * const planes[3],const size_t rowBytes[3],SkYUVColorSpace colorSpace) const267 bool SkImage::readYUV8Planes(const SkISize sizes[3], void* const planes[3],
268                              const size_t rowBytes[3], SkYUVColorSpace colorSpace) const {
269 #if SK_SUPPORT_GPU
270     if (GrTexture* texture = as_IB(this)->peekTexture()) {
271         if (GrTextureToYUVPlanes(texture, sizes, planes, rowBytes, colorSpace)) {
272             return true;
273         }
274     }
275 #endif
276     return SkRGBAToYUV(this, sizes, planes, rowBytes, colorSpace);
277 }
278 
279 ///////////////////////////////////////////////////////////////////////////////////////////////////
280 
NewFromBitmap(const SkBitmap & bm)281 SkImage* SkImage::NewFromBitmap(const SkBitmap& bm) {
282     SkPixelRef* pr = bm.pixelRef();
283     if (nullptr == pr) {
284         return nullptr;
285     }
286 
287 #if SK_SUPPORT_GPU
288     if (GrTexture* tex = pr->getTexture()) {
289         SkAutoTUnref<GrTexture> unrefCopy;
290         if (!bm.isImmutable()) {
291             tex = GrDeepCopyTexture(tex, SkBudgeted::kNo);
292             if (nullptr == tex) {
293                 return nullptr;
294             }
295             unrefCopy.reset(tex);
296         }
297         const SkImageInfo info = bm.info();
298         return new SkImage_Gpu(info.width(), info.height(), bm.getGenerationID(), info.alphaType(),
299                                tex, SkBudgeted::kNo);
300     }
301 #endif
302 
303     // This will check for immutable (share or copy)
304     return SkNewImageFromRasterBitmap(bm);
305 }
306 
asLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode mode) const307 bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
308     return as_IB(this)->onAsLegacyBitmap(bitmap, mode);
309 }
310 
onAsLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode mode) const311 bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
312     // As the base-class, all we can do is make a copy (regardless of mode).
313     // Subclasses that want to be more optimal should override.
314     SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
315                                     this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
316     if (!bitmap->tryAllocPixels(info)) {
317         return false;
318     }
319     if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
320         bitmap->reset();
321         return false;
322     }
323 
324     if (kRO_LegacyBitmapMode == mode) {
325         bitmap->setImmutable();
326     }
327     return true;
328 }
329 
NewFromPicture(const SkPicture * picture,const SkISize & dimensions,const SkMatrix * matrix,const SkPaint * paint)330 SkImage* SkImage::NewFromPicture(const SkPicture* picture, const SkISize& dimensions,
331                                  const SkMatrix* matrix, const SkPaint* paint) {
332     if (!picture) {
333         return nullptr;
334     }
335     return NewFromGenerator(SkImageGenerator::NewFromPicture(dimensions, picture, matrix, paint));
336 }
337 
isLazyGenerated() const338 bool SkImage::isLazyGenerated() const {
339     return as_IB(this)->onIsLazyGenerated();
340 }
341 
342 //////////////////////////////////////////////////////////////////////////////////////
343 
344 #if !SK_SUPPORT_GPU
345 
NewFromTexture(GrContext *,const GrBackendTextureDesc &,SkAlphaType,TextureReleaseProc,ReleaseContext)346 SkImage* SkImage::NewFromTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType,
347                                  TextureReleaseProc, ReleaseContext) {
348     return nullptr;
349 }
350 
NewFromAdoptedTexture(GrContext *,const GrBackendTextureDesc &,SkAlphaType)351 SkImage* SkImage::NewFromAdoptedTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType) {
352     return nullptr;
353 }
354 
NewFromTextureCopy(GrContext *,const GrBackendTextureDesc &,SkAlphaType)355 SkImage* SkImage::NewFromTextureCopy(GrContext*, const GrBackendTextureDesc&, SkAlphaType) {
356     return nullptr;
357 }
358 
newTextureImage(GrContext *) const359 SkImage* SkImage::newTextureImage(GrContext*) const {
360     return nullptr;
361 }
362 
363 #endif
364