• 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 "SkImageFilter.h"
14 #include "SkImageFilterCache.h"
15 #include "SkImageGenerator.h"
16 #include "SkImagePriv.h"
17 #include "SkImageShader.h"
18 #include "SkImage_Base.h"
19 #include "SkNextID.h"
20 #include "SkPicture.h"
21 #include "SkPixelRef.h"
22 #include "SkReadPixelsRec.h"
23 #include "SkSpecialImage.h"
24 #include "SkString.h"
25 #include "SkSurface.h"
26 
27 #if SK_SUPPORT_GPU
28 #include "GrTexture.h"
29 #include "GrContext.h"
30 #include "SkImage_Gpu.h"
31 #endif
32 
SkImage(int width,int height,uint32_t uniqueID)33 SkImage::SkImage(int width, int height, uint32_t uniqueID)
34     : fWidth(width)
35     , fHeight(height)
36     , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID)
37 {
38     SkASSERT(width > 0);
39     SkASSERT(height > 0);
40 }
41 
peekPixels(SkPixmap * pm) const42 bool SkImage::peekPixels(SkPixmap* pm) const {
43     SkPixmap tmp;
44     if (!pm) {
45         pm = &tmp;
46     }
47     return as_IB(this)->onPeekPixels(pm);
48 }
49 
readPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint chint) const50 bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
51                            int srcX, int srcY, CachingHint chint) const {
52     return as_IB(this)->onReadPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
53 }
54 
scalePixels(const SkPixmap & dst,SkFilterQuality quality,CachingHint chint) const55 bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingHint chint) const {
56     if (this->width() == dst.width() && this->height() == dst.height()) {
57         return this->readPixels(dst, 0, 0, chint);
58     }
59 
60     // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself
61     //       can scale more efficiently) we should take advantage of it here.
62     //
63     SkBitmap bm;
64     if (as_IB(this)->getROPixels(&bm, dst.info().colorSpace(), chint)) {
65         SkPixmap pmap;
66         // Note: By calling the pixmap scaler, we never cache the final result, so the chint
67         //       is (currently) only being applied to the getROPixels. If we get a request to
68         //       also attempt to cache the final (scaled) result, we would add that logic here.
69         //
70         return bm.peekPixels(&pmap) && pmap.scalePixels(dst, quality);
71     }
72     return false;
73 }
74 
75 ///////////////////////////////////////////////////////////////////////////////////////////////////
76 
alphaType() const77 SkAlphaType SkImage::alphaType() const {
78     return as_IB(this)->onAlphaType();
79 }
80 
colorSpace() const81 SkColorSpace* SkImage::colorSpace() const {
82     return as_IB(this)->onImageInfo().colorSpace();
83 }
84 
refColorSpace() const85 sk_sp<SkColorSpace> SkImage::refColorSpace() const {
86     return as_IB(this)->onImageInfo().refColorSpace();
87 }
88 
makeShader(SkShader::TileMode tileX,SkShader::TileMode tileY,const SkMatrix * localMatrix) const89 sk_sp<SkShader> SkImage::makeShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
90                                     const SkMatrix* localMatrix) const {
91     return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tileX, tileY, localMatrix);
92 }
93 
encodeToData(SkEncodedImageFormat type,int quality) const94 sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const {
95     SkBitmap bm;
96     SkColorSpace* legacyColorSpace = nullptr;
97     if (as_IB(this)->getROPixels(&bm, legacyColorSpace)) {
98         return SkEncodeBitmap(bm, type, quality);
99     }
100     return nullptr;
101 }
102 
encodeToData() const103 sk_sp<SkData> SkImage::encodeToData() const {
104     if (auto encoded = this->refEncodedData()) {
105         return encoded;
106     }
107 
108     SkBitmap bm;
109     SkPixmap pmap;
110     SkColorSpace* legacyColorSpace = nullptr;
111     if (as_IB(this)->getROPixels(&bm, legacyColorSpace) && bm.peekPixels(&pmap)) {
112         return SkEncodePixmap(pmap, SkEncodedImageFormat::kPNG, 100);
113     }
114     return nullptr;
115 }
116 
refEncodedData() const117 sk_sp<SkData> SkImage::refEncodedData() const {
118     return sk_sp<SkData>(as_IB(this)->onRefEncoded());
119 }
120 
MakeFromEncoded(sk_sp<SkData> encoded,const SkIRect * subset)121 sk_sp<SkImage> SkImage::MakeFromEncoded(sk_sp<SkData> encoded, const SkIRect* subset) {
122     if (nullptr == encoded || 0 == encoded->size()) {
123         return nullptr;
124     }
125     return SkImage::MakeFromGenerator(SkImageGenerator::MakeFromEncoded(encoded), subset);
126 }
127 
128 ///////////////////////////////////////////////////////////////////////////////////////////////////
129 
toString(SkString * str) const130 const char* SkImage::toString(SkString* str) const {
131     str->appendf("image: (id:%d (%d, %d) %s)", this->uniqueID(), this->width(), this->height(),
132                  this->isOpaque() ? "opaque" : "");
133     return str->c_str();
134 }
135 
makeSubset(const SkIRect & subset) const136 sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset) const {
137     if (subset.isEmpty()) {
138         return nullptr;
139     }
140 
141     const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
142     if (!bounds.contains(subset)) {
143         return nullptr;
144     }
145 
146     // optimization : return self if the subset == our bounds
147     if (bounds == subset) {
148         return sk_ref_sp(const_cast<SkImage*>(this));
149     }
150     return as_IB(this)->onMakeSubset(subset);
151 }
152 
153 #if SK_SUPPORT_GPU
154 
getTexture() const155 GrTexture* SkImage::getTexture() const {
156     return as_IB(this)->onGetTexture();
157 }
158 
isTextureBacked() const159 bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->peekProxy()); }
160 
getTextureHandle(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const161 GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO,
162                                           GrSurfaceOrigin* origin) const {
163     return as_IB(this)->onGetTextureHandle(flushPendingGrContextIO, origin);
164 }
165 
isValid(GrContext * context) const166 bool SkImage::isValid(GrContext* context) const {
167     if (context && context->abandoned()) {
168         return false;
169     }
170     return as_IB(this)->onIsValid(context);
171 }
172 
173 #else
174 
getTexture() const175 GrTexture* SkImage::getTexture() const { return nullptr; }
176 
isTextureBacked() const177 bool SkImage::isTextureBacked() const { return false; }
178 
getTextureHandle(bool,GrSurfaceOrigin *) const179 GrBackendObject SkImage::getTextureHandle(bool, GrSurfaceOrigin*) const { return 0; }
180 
isValid(GrContext * context) const181 bool SkImage::isValid(GrContext* context) const {
182     if (context) {
183         return false;
184     }
185     return as_IB(this)->onIsValid(context);
186 }
187 
188 #endif
189 
190 ///////////////////////////////////////////////////////////////////////////////
191 
SkImage_Base(int width,int height,uint32_t uniqueID)192 SkImage_Base::SkImage_Base(int width, int height, uint32_t uniqueID)
193     : INHERITED(width, height, uniqueID)
194     , fAddedToCache(false)
195 {}
196 
~SkImage_Base()197 SkImage_Base::~SkImage_Base() {
198     if (fAddedToCache.load()) {
199         SkNotifyBitmapGenIDIsStale(this->uniqueID());
200     }
201 }
202 
readPixels(const SkPixmap & pmap,int srcX,int srcY,CachingHint chint) const203 bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const {
204     return this->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX, srcY, chint);
205 }
206 
207 ///////////////////////////////////////////////////////////////////////////////////////////////////
208 
MakeFromBitmap(const SkBitmap & bm)209 sk_sp<SkImage> SkImage::MakeFromBitmap(const SkBitmap& bm) {
210     SkPixelRef* pr = bm.pixelRef();
211     if (nullptr == pr) {
212         return nullptr;
213     }
214 
215     return SkMakeImageFromRasterBitmap(bm, kIfMutable_SkCopyPixelsMode);
216 }
217 
asLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode mode) const218 bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
219     return as_IB(this)->onAsLegacyBitmap(bitmap, mode);
220 }
221 
onAsLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode mode) const222 bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
223     // As the base-class, all we can do is make a copy (regardless of mode).
224     // Subclasses that want to be more optimal should override.
225     SkImageInfo info = this->onImageInfo().makeColorType(kN32_SkColorType).makeColorSpace(nullptr);
226     if (!bitmap->tryAllocPixels(info)) {
227         return false;
228     }
229     if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
230         bitmap->reset();
231         return false;
232     }
233 
234     if (kRO_LegacyBitmapMode == mode) {
235         bitmap->setImmutable();
236     }
237     return true;
238 }
239 
MakeFromPicture(sk_sp<SkPicture> picture,const SkISize & dimensions,const SkMatrix * matrix,const SkPaint * paint,BitDepth bitDepth,sk_sp<SkColorSpace> colorSpace)240 sk_sp<SkImage> SkImage::MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions,
241                                         const SkMatrix* matrix, const SkPaint* paint,
242                                         BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace) {
243     return MakeFromGenerator(SkImageGenerator::MakeFromPicture(dimensions, std::move(picture),
244                                                                matrix, paint, bitDepth,
245                                                                std::move(colorSpace)));
246 }
247 
makeWithFilter(const SkImageFilter * filter,const SkIRect & subset,const SkIRect & clipBounds,SkIRect * outSubset,SkIPoint * offset) const248 sk_sp<SkImage> SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRect& subset,
249                                        const SkIRect& clipBounds, SkIRect* outSubset,
250                                        SkIPoint* offset) const {
251     if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) {
252         return nullptr;
253     }
254     SkColorSpace* colorSpace = as_IB(this)->onImageInfo().colorSpace();
255     sk_sp<SkSpecialImage> srcSpecialImage = SkSpecialImage::MakeFromImage(
256         subset, sk_ref_sp(const_cast<SkImage*>(this)), colorSpace);
257     if (!srcSpecialImage) {
258         return nullptr;
259     }
260 
261     sk_sp<SkImageFilterCache> cache(
262         SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize));
263     SkImageFilter::OutputProperties outputProperties(colorSpace);
264     SkImageFilter::Context context(SkMatrix::I(), clipBounds, cache.get(), outputProperties);
265 
266     sk_sp<SkSpecialImage> result = filter->filterImage(srcSpecialImage.get(), context, offset);
267     if (!result) {
268         return nullptr;
269     }
270 
271     *outSubset = SkIRect::MakeWH(result->width(), result->height());
272     if (!outSubset->intersect(clipBounds.makeOffset(-offset->x(), -offset->y()))) {
273         return nullptr;
274     }
275     offset->fX += outSubset->x();
276     offset->fY += outSubset->y();
277 
278     // Note that here we're returning the special image's entire backing store, loose padding
279     // and all!
280     return result->asImage();
281 }
282 
isLazyGenerated() const283 bool SkImage::isLazyGenerated() const {
284     return as_IB(this)->onIsLazyGenerated();
285 }
286 
isAlphaOnly() const287 bool SkImage::isAlphaOnly() const {
288     return as_IB(this)->onImageInfo().colorType() == kAlpha_8_SkColorType;
289 }
290 
makeColorSpace(sk_sp<SkColorSpace> target,SkTransferFunctionBehavior premulBehavior) const291 sk_sp<SkImage> SkImage::makeColorSpace(sk_sp<SkColorSpace> target,
292                                        SkTransferFunctionBehavior premulBehavior) const {
293     SkColorSpaceTransferFn fn;
294     if (!target || !target->isNumericalTransferFn(&fn)) {
295         return nullptr;
296     }
297 
298     // No need to create a new image if:
299     // (1) The color spaces are equal.
300     // (2) The color type is kAlpha8.
301     if (SkColorSpace::Equals(this->colorSpace(), target.get()) ||
302             kAlpha_8_SkColorType == as_IB(this)->onImageInfo().colorType()) {
303         return sk_ref_sp(const_cast<SkImage*>(this));
304     }
305 
306     SkColorType targetColorType = kN32_SkColorType;
307     if (SkTransferFunctionBehavior::kRespect == premulBehavior && target->gammaIsLinear()) {
308         targetColorType = kRGBA_F16_SkColorType;
309     }
310 
311     // TODO: We might consider making this a deferred conversion?
312     return as_IB(this)->onMakeColorSpace(std::move(target), targetColorType, premulBehavior);
313 }
314 
makeNonTextureImage() const315 sk_sp<SkImage> SkImage::makeNonTextureImage() const {
316     if (!this->isTextureBacked()) {
317         return sk_ref_sp(const_cast<SkImage*>(this));
318     }
319     return this->makeRasterImage();
320 }
321 
makeRasterImage() const322 sk_sp<SkImage> SkImage::makeRasterImage() const {
323     SkPixmap pm;
324     if (this->peekPixels(&pm)) {
325         return sk_ref_sp(const_cast<SkImage*>(this));
326     }
327 
328     const SkImageInfo info = as_IB(this)->onImageInfo();
329     const size_t rowBytes = info.minRowBytes();
330     size_t size = info.computeByteSize(rowBytes);
331     if (SkImageInfo::ByteSizeOverflowed(size)) {
332         return nullptr;
333     }
334 
335     sk_sp<SkData> data = SkData::MakeUninitialized(size);
336     pm = { info.makeColorSpace(nullptr), data->writable_data(), info.minRowBytes() };
337     if (!this->readPixels(pm, 0, 0)) {
338         return nullptr;
339     }
340 
341     return SkImage::MakeRasterData(info, std::move(data), rowBytes);
342 }
343 
344 //////////////////////////////////////////////////////////////////////////////////////
345 
346 #if !SK_SUPPORT_GPU
347 
MakeTextureFromMipMap(GrContext *,const SkImageInfo &,const GrMipLevel texels[],int mipLevelCount,SkBudgeted,SkDestinationSurfaceColorMode)348 sk_sp<SkImage> MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMipLevel texels[],
349                                      int mipLevelCount, SkBudgeted, SkDestinationSurfaceColorMode) {
350     return nullptr;
351 }
352 
MakeFromTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)353 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
354                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
355                                         SkAlphaType at, sk_sp<SkColorSpace> cs,
356                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
357     return nullptr;
358 }
359 
getDeferredTextureImageData(const GrContextThreadSafeProxy &,const DeferredTextureImageUsageParams[],int paramCnt,void * buffer,SkColorSpace * dstColorSpace,SkColorType dstColorType) const360 size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy&,
361                                             const DeferredTextureImageUsageParams[],
362                                             int paramCnt, void* buffer,
363                                             SkColorSpace* dstColorSpace,
364                                             SkColorType dstColorType) const {
365     return 0;
366 }
367 
MakeFromDeferredTextureImageData(GrContext * context,const void *,SkBudgeted)368 sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void*,
369                                                          SkBudgeted) {
370     return nullptr;
371 }
372 
MakeFromTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)373 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
374                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
375                                         SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
376                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
377     return nullptr;
378 }
379 
MakeBackendTextureFromSkImage(GrContext *,sk_sp<SkImage>,GrBackendTexture *,BackendTextureReleaseProc *)380 bool SkImage::MakeBackendTextureFromSkImage(GrContext*,
381                                             sk_sp<SkImage>,
382                                             GrBackendTexture*,
383                                             BackendTextureReleaseProc*) {
384     return false;
385 }
386 
MakeFromAdoptedTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> cs)387 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
388                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
389                                                SkAlphaType at, sk_sp<SkColorSpace> cs) {
390     return nullptr;
391 }
392 
MakeFromAdoptedTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs)393 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
394                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
395                                                SkColorType ct, SkAlphaType at,
396                                                sk_sp<SkColorSpace> cs) {
397     return nullptr;
398 }
399 
MakeFromYUVTexturesCopy(GrContext * ctx,SkYUVColorSpace space,const GrBackendObject yuvTextureHandles[3],const SkISize yuvSizes[3],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)400 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace space,
401                                                 const GrBackendObject yuvTextureHandles[3],
402                                                 const SkISize yuvSizes[3],
403                                                 GrSurfaceOrigin origin,
404                                                 sk_sp<SkColorSpace> imageColorSpace) {
405     return nullptr;
406 }
407 
MakeFromYUVTexturesCopy(GrContext * ctx,SkYUVColorSpace space,const GrBackendTexture yuvTextureHandles[3],const SkISize yuvSizes[3],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)408 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace space,
409                                                 const GrBackendTexture yuvTextureHandles[3],
410                                                 const SkISize yuvSizes[3],
411                                                 GrSurfaceOrigin origin,
412                                                 sk_sp<SkColorSpace> imageColorSpace) {
413     return nullptr;
414 }
415 
makeTextureImage(GrContext *,SkColorSpace * dstColorSpace) const416 sk_sp<SkImage> SkImage::makeTextureImage(GrContext*, SkColorSpace* dstColorSpace) const {
417     return nullptr;
418 }
419 
420 #endif
421 
422 ///////////////////////////////////////////////////////////////////////////////////////////////////
423 
MakeTextureFromMipMap(GrContext *,const SkImageInfo &,const GrMipLevel texels[],int mipLevelCount,SkBudgeted)424 sk_sp<SkImage> MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMipLevel texels[],
425                                      int mipLevelCount, SkBudgeted) {
426     return nullptr;
427 }
428 
429 ///////////////////////////////////////////////////////////////////////////////////////////////////
430 
SkImage_pinAsTexture(const SkImage * image,GrContext * ctx)431 bool SkImage_pinAsTexture(const SkImage* image, GrContext* ctx) {
432     SkASSERT(image);
433     SkASSERT(ctx);
434     return as_IB(image)->onPinAsTexture(ctx);
435 }
436 
SkImage_unpinAsTexture(const SkImage * image,GrContext * ctx)437 void SkImage_unpinAsTexture(const SkImage* image, GrContext* ctx) {
438     SkASSERT(image);
439     SkASSERT(ctx);
440     as_IB(image)->onUnpinAsTexture(ctx);
441 }
442 
443 ///////////////////////////////////////////////////////////////////////////////////////////////////
444 
SkImageMakeRasterCopyAndAssignColorSpace(const SkImage * src,SkColorSpace * colorSpace)445 sk_sp<SkImage> SkImageMakeRasterCopyAndAssignColorSpace(const SkImage* src,
446                                                         SkColorSpace* colorSpace) {
447     // Read the pixels out of the source image, with no conversion
448     SkImageInfo info = as_IB(src)->onImageInfo();
449     if (kUnknown_SkColorType == info.colorType()) {
450         SkDEBUGFAIL("Unexpected color type");
451         return nullptr;
452     }
453 
454     size_t rowBytes = info.minRowBytes();
455     size_t size = info.computeByteSize(rowBytes);
456     if (SkImageInfo::ByteSizeOverflowed(size)) {
457         return nullptr;
458     }
459     auto data = SkData::MakeUninitialized(size);
460     if (!data) {
461         return nullptr;
462     }
463 
464     SkPixmap pm(info, data->writable_data(), rowBytes);
465     if (!src->readPixels(pm, 0, 0, SkImage::kDisallow_CachingHint)) {
466         return nullptr;
467     }
468 
469     // Wrap them in a new image with a different color space
470     return SkImage::MakeRasterData(info.makeColorSpace(sk_ref_sp(colorSpace)), data, rowBytes);
471 }
472