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 "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkData.h"
11 #include "include/core/SkImageEncoder.h"
12 #include "include/core/SkImageFilter.h"
13 #include "include/core/SkImageGenerator.h"
14 #include "include/core/SkPicture.h"
15 #include "include/core/SkString.h"
16 #include "include/core/SkSurface.h"
17 #include "src/core/SkBitmapCache.h"
18 #include "src/core/SkCachedData.h"
19 #include "src/core/SkColorSpacePriv.h"
20 #include "src/core/SkImageFilterCache.h"
21 #include "src/core/SkImageFilter_Base.h"
22 #include "src/core/SkImagePriv.h"
23 #include "src/core/SkMipmap.h"
24 #include "src/core/SkMipmapBuilder.h"
25 #include "src/core/SkNextID.h"
26 #include "src/core/SkSpecialImage.h"
27 #include "src/image/SkImage_Base.h"
28 #include "src/image/SkReadPixelsRec.h"
29 #include "src/image/SkRescaleAndReadPixels.h"
30 #include "src/shaders/SkImageShader.h"
31 
32 #if SK_SUPPORT_GPU
33 #include "include/gpu/GrDirectContext.h"
34 #include "src/gpu/GrDirectContextPriv.h"
35 #include "src/gpu/GrFragmentProcessor.h"
36 #include "src/gpu/GrImageContextPriv.h"
37 #include "src/gpu/GrProxyProvider.h"
38 #include "src/gpu/GrRecordingContextPriv.h"
39 #include "src/gpu/SkGr.h"
40 #include "src/gpu/effects/GrBicubicEffect.h"
41 #include "src/gpu/effects/GrTextureEffect.h"
42 #include "src/image/SkImage_Gpu.h"
43 #endif
44 #include "include/gpu/GrBackendSurface.h"
45 #include "include/gpu/GrContextThreadSafeProxy.h"
46 
SkImage(const SkImageInfo & info,uint32_t uniqueID)47 SkImage::SkImage(const SkImageInfo& info, uint32_t uniqueID)
48         : fInfo(info)
49         , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID) {
50     SkASSERT(info.width() > 0);
51     SkASSERT(info.height() > 0);
52 }
53 
peekPixels(SkPixmap * pm) const54 bool SkImage::peekPixels(SkPixmap* pm) const {
55     SkPixmap tmp;
56     if (!pm) {
57         pm = &tmp;
58     }
59     return as_IB(this)->onPeekPixels(pm);
60 }
61 
readPixels(GrDirectContext * dContext,const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint chint) const62 bool SkImage::readPixels(GrDirectContext* dContext, const SkImageInfo& dstInfo, void* dstPixels,
63                          size_t dstRowBytes, int srcX, int srcY, CachingHint chint) const {
64     return as_IB(this)->onReadPixels(dContext, dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
65 }
66 
67 #ifndef SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API
readPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint chint) const68 bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels,
69                          size_t dstRowBytes, int srcX, int srcY, CachingHint chint) const {
70     auto dContext = as_IB(this)->directContext();
71     return this->readPixels(dContext, dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
72 }
73 #endif
74 
asyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)75 void SkImage::asyncRescaleAndReadPixels(const SkImageInfo& info,
76                                         const SkIRect& srcRect,
77                                         RescaleGamma rescaleGamma,
78                                         RescaleMode rescaleMode,
79                                         ReadPixelsCallback callback,
80                                         ReadPixelsContext context) {
81     if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) ||
82         !SkImageInfoIsValid(info)) {
83         callback(context, nullptr);
84         return;
85     }
86     as_IB(this)->onAsyncRescaleAndReadPixels(
87             info, srcRect, rescaleGamma, rescaleMode, callback, context);
88 }
89 
asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)90 void SkImage::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
91                                               sk_sp<SkColorSpace> dstColorSpace,
92                                               const SkIRect& srcRect,
93                                               const SkISize& dstSize,
94                                               RescaleGamma rescaleGamma,
95                                               RescaleMode rescaleMode,
96                                               ReadPixelsCallback callback,
97                                               ReadPixelsContext context) {
98     if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || dstSize.isZero() ||
99         (dstSize.width() & 0b1) || (dstSize.height() & 0b1)) {
100         callback(context, nullptr);
101         return;
102     }
103     as_IB(this)->onAsyncRescaleAndReadPixelsYUV420(yuvColorSpace,
104                                                    std::move(dstColorSpace),
105                                                    srcRect,
106                                                    dstSize,
107                                                    rescaleGamma,
108                                                    rescaleMode,
109                                                    callback,
110                                                    context);
111 }
112 
scalePixels(const SkPixmap & dst,const SkSamplingOptions & sampling,CachingHint chint) const113 bool SkImage::scalePixels(const SkPixmap& dst, const SkSamplingOptions& sampling,
114                           CachingHint chint) const {
115     // Context TODO: Elevate GrDirectContext requirement to public API.
116     auto dContext = as_IB(this)->directContext();
117     if (this->width() == dst.width() && this->height() == dst.height()) {
118         return this->readPixels(dContext, dst, 0, 0, chint);
119     }
120 
121     // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself
122     //       can scale more efficiently) we should take advantage of it here.
123     //
124     SkBitmap bm;
125     if (as_IB(this)->getROPixels(dContext, &bm, chint)) {
126         SkPixmap pmap;
127         // Note: By calling the pixmap scaler, we never cache the final result, so the chint
128         //       is (currently) only being applied to the getROPixels. If we get a request to
129         //       also attempt to cache the final (scaled) result, we would add that logic here.
130         //
131         return bm.peekPixels(&pmap) && pmap.scalePixels(dst, sampling);
132     }
133     return false;
134 }
135 
136 ///////////////////////////////////////////////////////////////////////////////////////////////////
137 
colorType() const138 SkColorType SkImage::colorType() const { return fInfo.colorType(); }
139 
alphaType() const140 SkAlphaType SkImage::alphaType() const { return fInfo.alphaType(); }
141 
colorSpace() const142 SkColorSpace* SkImage::colorSpace() const { return fInfo.colorSpace(); }
143 
refColorSpace() const144 sk_sp<SkColorSpace> SkImage::refColorSpace() const { return fInfo.refColorSpace(); }
145 
makeShader(SkTileMode tmx,SkTileMode tmy,const SkSamplingOptions & sampling,const SkMatrix * localMatrix) const146 sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
147                                     const SkSamplingOptions& sampling,
148                                     const SkMatrix* localMatrix) const {
149     return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy,
150                                sampling, localMatrix);
151 }
152 
encodeToData(SkEncodedImageFormat type,int quality) const153 sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const {
154     // Context TODO: Elevate GrDirectContext requirement to public API.
155     auto dContext = as_IB(this)->directContext();
156     SkBitmap bm;
157     if (as_IB(this)->getROPixels(dContext, &bm)) {
158         return SkEncodeBitmap(bm, type, quality);
159     }
160     return nullptr;
161 }
162 
encodeToData() const163 sk_sp<SkData> SkImage::encodeToData() const {
164     if (auto encoded = this->refEncodedData()) {
165         return encoded;
166     }
167 
168     return this->encodeToData(SkEncodedImageFormat::kPNG, 100);
169 }
170 
refEncodedData() const171 sk_sp<SkData> SkImage::refEncodedData() const {
172     return sk_sp<SkData>(as_IB(this)->onRefEncoded());
173 }
174 
MakeFromEncoded(sk_sp<SkData> encoded)175 sk_sp<SkImage> SkImage::MakeFromEncoded(sk_sp<SkData> encoded) {
176     if (nullptr == encoded || 0 == encoded->size()) {
177         return nullptr;
178     }
179     return SkImage::MakeFromGenerator(SkImageGenerator::MakeFromEncoded(std::move(encoded)));
180 }
181 
182 ///////////////////////////////////////////////////////////////////////////////////////////////////
183 
makeSubset(const SkIRect & subset,GrDirectContext * direct) const184 sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset, GrDirectContext* direct) const {
185     if (subset.isEmpty()) {
186         return nullptr;
187     }
188 
189     const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
190     if (!bounds.contains(subset)) {
191         return nullptr;
192     }
193 
194 #if SK_SUPPORT_GPU
195     auto myContext = as_IB(this)->context();
196     // This check is also performed in the subclass, but we do it here for the short-circuit below.
197     if (myContext && !myContext->priv().matches(direct)) {
198         return nullptr;
199     }
200 #endif
201 
202     // optimization : return self if the subset == our bounds
203     if (bounds == subset) {
204         return sk_ref_sp(const_cast<SkImage*>(this));
205     }
206 
207     return as_IB(this)->onMakeSubset(subset, direct);
208 }
209 
210 #if SK_SUPPORT_GPU
211 
isTextureBacked() const212 bool SkImage::isTextureBacked() const { return as_IB(this)->onIsTextureBacked(); }
213 
textureSize() const214 size_t SkImage::textureSize() const { return as_IB(this)->onTextureSize(); }
215 
getBackendTexture(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const216 GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
217                                             GrSurfaceOrigin* origin) const {
218     return as_IB(this)->onGetBackendTexture(flushPendingGrContextIO, origin);
219 }
220 
isValid(GrRecordingContext * rContext) const221 bool SkImage::isValid(GrRecordingContext* rContext) const {
222     if (rContext && rContext->abandoned()) {
223         return false;
224     }
225     return as_IB(this)->onIsValid(rContext);
226 }
227 
flush(GrDirectContext * dContext,const GrFlushInfo & flushInfo)228 GrSemaphoresSubmitted SkImage::flush(GrDirectContext* dContext, const GrFlushInfo& flushInfo) {
229     return as_IB(this)->onFlush(dContext, flushInfo);
230 }
231 
flushAndSubmit(GrDirectContext * dContext)232 void SkImage::flushAndSubmit(GrDirectContext* dContext) {
233     this->flush(dContext, {});
234     dContext->submit();
235 }
236 
237 #else
238 
isTextureBacked() const239 bool SkImage::isTextureBacked() const { return false; }
240 
getBackendTexture(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const241 GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
242                                             GrSurfaceOrigin* origin) const {
243     return GrBackendTexture(); // invalid
244 }
245 
isValid(GrRecordingContext * rContext) const246 bool SkImage::isValid(GrRecordingContext* rContext) const {
247     if (rContext) {
248         return false;
249     }
250     return as_IB(this)->onIsValid(nullptr);
251 }
252 
flush(GrDirectContext *,const GrFlushInfo &)253 GrSemaphoresSubmitted SkImage::flush(GrDirectContext*, const GrFlushInfo&) {
254     return GrSemaphoresSubmitted::kNo;
255 }
256 
flushAndSubmit(GrDirectContext *)257 void SkImage::flushAndSubmit(GrDirectContext*) {}
258 
259 #endif
260 
261 ///////////////////////////////////////////////////////////////////////////////
262 
SkImage_Base(const SkImageInfo & info,uint32_t uniqueID)263 SkImage_Base::SkImage_Base(const SkImageInfo& info, uint32_t uniqueID)
264         : INHERITED(info, uniqueID), fAddedToRasterCache(false) {}
265 
~SkImage_Base()266 SkImage_Base::~SkImage_Base() {
267     if (fAddedToRasterCache.load()) {
268         SkNotifyBitmapGenIDIsStale(this->uniqueID());
269     }
270 }
271 
onAsyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & origSrcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)272 void SkImage_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
273                                                const SkIRect& origSrcRect,
274                                                RescaleGamma rescaleGamma,
275                                                RescaleMode rescaleMode,
276                                                ReadPixelsCallback callback,
277                                                ReadPixelsContext context) {
278     SkBitmap src;
279     SkPixmap peek;
280     SkIRect srcRect;
281     if (this->peekPixels(&peek)) {
282         src.installPixels(peek);
283         srcRect = origSrcRect;
284     } else {
285         // Context TODO: Elevate GrDirectContext requirement to public API.
286         auto dContext = as_IB(this)->directContext();
287         src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size()));
288         src.allocPixels();
289         if (!this->readPixels(dContext, src.pixmap(), origSrcRect.x(), origSrcRect.y())) {
290             callback(context, nullptr);
291             return;
292         }
293         srcRect = SkIRect::MakeSize(src.dimensions());
294     }
295     return SkRescaleAndReadPixels(src, info, srcRect, rescaleGamma, rescaleMode, callback, context);
296 }
297 
onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,RescaleGamma,RescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)298 void SkImage_Base::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace,
299                                                      sk_sp<SkColorSpace> dstColorSpace,
300                                                      const SkIRect& srcRect,
301                                                      const SkISize& dstSize,
302                                                      RescaleGamma,
303                                                      RescaleMode,
304                                                      ReadPixelsCallback callback,
305                                                      ReadPixelsContext context) {
306     // TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and
307     // call client's callback.
308     callback(context, nullptr);
309 }
310 
311 #if SK_SUPPORT_GPU
asView(GrRecordingContext * context,GrMipmapped mipmapped,GrImageTexGenPolicy policy) const312 std::tuple<GrSurfaceProxyView, GrColorType> SkImage_Base::asView(GrRecordingContext* context,
313                                                                  GrMipmapped mipmapped,
314                                                                  GrImageTexGenPolicy policy) const {
315     if (!context) {
316         return {};
317     }
318     if (!context->priv().caps()->mipmapSupport() || this->dimensions().area() <= 1) {
319         mipmapped = GrMipmapped::kNo;
320     }
321     return this->onAsView(context, mipmapped, policy);
322 }
323 
asFragmentProcessor(GrRecordingContext * rContext,SkSamplingOptions sampling,const SkTileMode tileModes[2],const SkMatrix & m,const SkRect * subset,const SkRect * domain) const324 std::unique_ptr<GrFragmentProcessor> SkImage_Base::asFragmentProcessor(
325         GrRecordingContext* rContext,
326         SkSamplingOptions sampling,
327         const SkTileMode tileModes[2],
328         const SkMatrix& m,
329         const SkRect* subset,
330         const SkRect* domain) const {
331     if (!rContext) {
332         return {};
333     }
334     if (sampling.useCubic && !GrValidCubicResampler(sampling.cubic)) {
335         return {};
336     }
337     if (sampling.mipmap != SkMipmapMode::kNone &&
338         (!rContext->priv().caps()->mipmapSupport() || this->dimensions().area() <= 1)) {
339         sampling = SkSamplingOptions(sampling.filter);
340     }
341     return this->onAsFragmentProcessor(rContext, sampling, tileModes, m, subset, domain);
342 }
343 
MakeFragmentProcessorFromView(GrRecordingContext * rContext,GrSurfaceProxyView view,SkAlphaType at,SkSamplingOptions sampling,const SkTileMode tileModes[2],const SkMatrix & m,const SkRect * subset,const SkRect * domain)344 std::unique_ptr<GrFragmentProcessor> SkImage_Base::MakeFragmentProcessorFromView(
345         GrRecordingContext* rContext,
346         GrSurfaceProxyView view,
347         SkAlphaType at,
348         SkSamplingOptions sampling,
349         const SkTileMode tileModes[2],
350         const SkMatrix& m,
351         const SkRect* subset,
352         const SkRect* domain) {
353     if (!view) {
354         return nullptr;
355     }
356     const GrCaps& caps = *rContext->priv().caps();
357     auto wmx = SkTileModeToWrapMode(tileModes[0]);
358     auto wmy = SkTileModeToWrapMode(tileModes[1]);
359     if (sampling.useCubic) {
360         if (subset) {
361             if (domain) {
362                 return GrBicubicEffect::MakeSubset(std::move(view),
363                                                    at,
364                                                    m,
365                                                    wmx,
366                                                    wmy,
367                                                    *subset,
368                                                    *domain,
369                                                    sampling.cubic,
370                                                    GrBicubicEffect::Direction::kXY,
371                                                    *rContext->priv().caps());
372             }
373             return GrBicubicEffect::MakeSubset(std::move(view),
374                                                at,
375                                                m,
376                                                wmx,
377                                                wmy,
378                                                *subset,
379                                                sampling.cubic,
380                                                GrBicubicEffect::Direction::kXY,
381                                                *rContext->priv().caps());
382         }
383         return GrBicubicEffect::Make(std::move(view),
384                                      at,
385                                      m,
386                                      wmx,
387                                      wmy,
388                                      sampling.cubic,
389                                      GrBicubicEffect::Direction::kXY,
390                                      *rContext->priv().caps());
391     }
392     if (view.proxy()->asTextureProxy()->mipmapped() == GrMipmapped::kNo) {
393         sampling = SkSamplingOptions(sampling.filter);
394     }
395     GrSamplerState sampler(wmx, wmy, sampling.filter, sampling.mipmap);
396     if (subset) {
397         if (domain) {
398             return GrTextureEffect::MakeSubset(std::move(view),
399                                                at,
400                                                m,
401                                                sampler,
402                                                *subset,
403                                                *domain,
404                                                caps);
405         }
406         return GrTextureEffect::MakeSubset(std::move(view),
407                                            at,
408                                            m,
409                                            sampler,
410                                            *subset,
411                                            caps);
412     } else {
413         return GrTextureEffect::Make(std::move(view), at, m, sampler, caps);
414     }
415 }
416 
FindOrMakeCachedMipmappedView(GrRecordingContext * rContext,GrSurfaceProxyView view,uint32_t imageUniqueID)417 GrSurfaceProxyView SkImage_Base::FindOrMakeCachedMipmappedView(GrRecordingContext* rContext,
418                                                                GrSurfaceProxyView view,
419                                                                uint32_t imageUniqueID) {
420     SkASSERT(rContext);
421     SkASSERT(imageUniqueID != SK_InvalidUniqueID);
422 
423     if (!view || view.proxy()->asTextureProxy()->mipmapped() == GrMipmapped::kYes) {
424         return view;
425     }
426     GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
427 
428     GrUniqueKey baseKey;
429     GrMakeKeyFromImageID(&baseKey, imageUniqueID, SkIRect::MakeSize(view.dimensions()));
430     SkASSERT(baseKey.isValid());
431     GrUniqueKey mipmappedKey;
432     static const GrUniqueKey::Domain kMipmappedDomain = GrUniqueKey::GenerateDomain();
433     {  // No extra values beyond the domain are required. Must name the var to please
434        // clang-tidy.
435         GrUniqueKey::Builder b(&mipmappedKey, baseKey, kMipmappedDomain, 0);
436     }
437     SkASSERT(mipmappedKey.isValid());
438     if (sk_sp<GrTextureProxy> cachedMippedView =
439                 proxyProvider->findOrCreateProxyByUniqueKey(mipmappedKey)) {
440         return {std::move(cachedMippedView), view.origin(), view.swizzle()};
441     }
442 
443     auto copy = GrCopyBaseMipMapToView(rContext, view);
444     if (!copy) {
445         return view;
446     }
447     // TODO: If we move listeners up from SkImage_Lazy to SkImage_Base then add one here.
448     proxyProvider->assignUniqueKeyToProxy(mipmappedKey, copy.asTextureProxy());
449     return copy;
450 }
451 
452 #endif
453 
onGetBackendTexture(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const454 GrBackendTexture SkImage_Base::onGetBackendTexture(bool flushPendingGrContextIO,
455                                                    GrSurfaceOrigin* origin) const {
456     return GrBackendTexture(); // invalid
457 }
458 
directContext() const459 GrDirectContext* SkImage_Base::directContext() const {
460 #if SK_SUPPORT_GPU
461     return GrAsDirectContext(this->context());
462 #else
463     return nullptr;
464 #endif
465 }
466 
readPixels(GrDirectContext * dContext,const SkPixmap & pmap,int srcX,int srcY,CachingHint chint) const467 bool SkImage::readPixels(GrDirectContext* dContext, const SkPixmap& pmap, int srcX, int srcY,
468                          CachingHint chint) const {
469     return this->readPixels(dContext, pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX,
470                             srcY, chint);
471 }
472 
473 #ifndef SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API
readPixels(const SkPixmap & pmap,int srcX,int srcY,CachingHint chint) const474 bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const {
475     auto dContext = as_IB(this)->directContext();
476     return this->readPixels(dContext, pmap, srcX, srcY, chint);
477 }
478 #endif
479 
480 ///////////////////////////////////////////////////////////////////////////////////////////////////
481 
MakeFromBitmap(const SkBitmap & bm)482 sk_sp<SkImage> SkImage::MakeFromBitmap(const SkBitmap& bm) {
483     if (!bm.pixelRef()) {
484         return nullptr;
485     }
486 
487     return SkMakeImageFromRasterBitmap(bm, kIfMutable_SkCopyPixelsMode);
488 }
489 
asLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode) const490 bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode ) const {
491     // Context TODO: Elevate GrDirectContext requirement to public API.
492     auto dContext = as_IB(this)->directContext();
493     return as_IB(this)->onAsLegacyBitmap(dContext, bitmap);
494 }
495 
onAsLegacyBitmap(GrDirectContext * dContext,SkBitmap * bitmap) const496 bool SkImage_Base::onAsLegacyBitmap(GrDirectContext* dContext, SkBitmap* bitmap) const {
497     // As the base-class, all we can do is make a copy (regardless of mode).
498     // Subclasses that want to be more optimal should override.
499     SkImageInfo info = fInfo.makeColorType(kN32_SkColorType).makeColorSpace(nullptr);
500     if (!bitmap->tryAllocPixels(info)) {
501         return false;
502     }
503 
504     if (!this->readPixels(dContext, bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
505                           0, 0)) {
506         bitmap->reset();
507         return false;
508     }
509 
510     bitmap->setImmutable();
511     return true;
512 }
513 
MakeFromPicture(sk_sp<SkPicture> picture,const SkISize & dimensions,const SkMatrix * matrix,const SkPaint * paint,BitDepth bitDepth,sk_sp<SkColorSpace> colorSpace)514 sk_sp<SkImage> SkImage::MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions,
515                                         const SkMatrix* matrix, const SkPaint* paint,
516                                         BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace) {
517     return MakeFromGenerator(SkImageGenerator::MakeFromPicture(dimensions, std::move(picture),
518                                                                matrix, paint, bitDepth,
519                                                                std::move(colorSpace)));
520 }
521 
makeWithFilter(GrRecordingContext * rContext,const SkImageFilter * filter,const SkIRect & subset,const SkIRect & clipBounds,SkIRect * outSubset,SkIPoint * offset) const522 sk_sp<SkImage> SkImage::makeWithFilter(GrRecordingContext* rContext, const SkImageFilter* filter,
523                                        const SkIRect& subset, const SkIRect& clipBounds,
524                                        SkIRect* outSubset, SkIPoint* offset) const {
525 
526     if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) {
527         return nullptr;
528     }
529     sk_sp<SkSpecialImage> srcSpecialImage;
530 #if SK_SUPPORT_GPU
531     auto myContext = as_IB(this)->context();
532     if (myContext && !myContext->priv().matches(rContext)) {
533         return nullptr;
534     }
535     srcSpecialImage = SkSpecialImage::MakeFromImage(rContext, subset,
536                                                     sk_ref_sp(const_cast<SkImage*>(this)),
537                                                     SkSurfaceProps());
538 #else
539     srcSpecialImage = SkSpecialImage::MakeFromImage(nullptr, subset,
540                                                     sk_ref_sp(const_cast<SkImage*>(this)),
541                                                     SkSurfaceProps());
542 #endif
543     if (!srcSpecialImage) {
544         return nullptr;
545     }
546 
547     sk_sp<SkImageFilterCache> cache(
548         SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize));
549 
550     // The filters operate in the local space of the src image, where (0,0) corresponds to the
551     // subset's top left corner. But the clip bounds and any crop rects on the filters are in the
552     // original coordinate system, so configure the CTM to correct crop rects and explicitly adjust
553     // the clip bounds (since it is assumed to already be in image space).
554     SkImageFilter_Base::Context context(SkMatrix::Translate(-subset.x(), -subset.y()),
555                                         clipBounds.makeOffset(-subset.topLeft()),
556                                         cache.get(), fInfo.colorType(), fInfo.colorSpace(),
557                                         srcSpecialImage.get());
558 
559     sk_sp<SkSpecialImage> result = as_IFB(filter)->filterImage(context).imageAndOffset(offset);
560     if (!result) {
561         return nullptr;
562     }
563 
564     // The output image and offset are relative to the subset rectangle, so the offset needs to
565     // be shifted to put it in the correct spot with respect to the original coordinate system
566     offset->fX += subset.x();
567     offset->fY += subset.y();
568 
569     // Final clip against the exact clipBounds (the clip provided in the context gets adjusted
570     // to account for pixel-moving filters so doesn't always exactly match when finished). The
571     // clipBounds are translated into the clippedDstRect coordinate space, including the
572     // result->subset() ensures that the result's image pixel origin does not affect results.
573     SkIRect dstRect = result->subset();
574     SkIRect clippedDstRect = dstRect;
575     if (!clippedDstRect.intersect(clipBounds.makeOffset(result->subset().topLeft() - *offset))) {
576         return nullptr;
577     }
578 
579     // Adjust the geometric offset if the top-left corner moved as well
580     offset->fX += (clippedDstRect.x() - dstRect.x());
581     offset->fY += (clippedDstRect.y() - dstRect.y());
582     *outSubset = clippedDstRect;
583     return result->asImage();
584 }
585 
isLazyGenerated() const586 bool SkImage::isLazyGenerated() const {
587     return as_IB(this)->onIsLazyGenerated();
588 }
589 
isAlphaOnly() const590 bool SkImage::isAlphaOnly() const { return SkColorTypeIsAlphaOnly(fInfo.colorType()); }
591 
makeColorSpace(sk_sp<SkColorSpace> target,GrDirectContext * direct) const592 sk_sp<SkImage> SkImage::makeColorSpace(sk_sp<SkColorSpace> target, GrDirectContext* direct) const {
593     return this->makeColorTypeAndColorSpace(this->colorType(), std::move(target), direct);
594 }
595 
makeColorTypeAndColorSpace(SkColorType targetColorType,sk_sp<SkColorSpace> targetColorSpace,GrDirectContext * dContext) const596 sk_sp<SkImage> SkImage::makeColorTypeAndColorSpace(SkColorType targetColorType,
597                                                    sk_sp<SkColorSpace> targetColorSpace,
598                                                    GrDirectContext* dContext) const {
599     if (kUnknown_SkColorType == targetColorType || !targetColorSpace) {
600         return nullptr;
601     }
602 
603 #if SK_SUPPORT_GPU
604     auto myContext = as_IB(this)->context();
605     // This check is also performed in the subclass, but we do it here for the short-circuit below.
606     if (myContext && !myContext->priv().matches(dContext)) {
607         return nullptr;
608     }
609 #endif
610 
611     SkColorType colorType = this->colorType();
612     SkColorSpace* colorSpace = this->colorSpace();
613     if (!colorSpace) {
614         colorSpace = sk_srgb_singleton();
615     }
616     if (colorType == targetColorType &&
617         (SkColorSpace::Equals(colorSpace, targetColorSpace.get()) || this->isAlphaOnly())) {
618         return sk_ref_sp(const_cast<SkImage*>(this));
619     }
620 
621     return as_IB(this)->onMakeColorTypeAndColorSpace(targetColorType,
622                                                      std::move(targetColorSpace), dContext);
623 }
624 
reinterpretColorSpace(sk_sp<SkColorSpace> target) const625 sk_sp<SkImage> SkImage::reinterpretColorSpace(sk_sp<SkColorSpace> target) const {
626     if (!target) {
627         return nullptr;
628     }
629 
630     // No need to create a new image if:
631     // (1) The color spaces are equal.
632     // (2) The color type is kAlpha8.
633     SkColorSpace* colorSpace = this->colorSpace();
634     if (!colorSpace) {
635         colorSpace = sk_srgb_singleton();
636     }
637     if (SkColorSpace::Equals(colorSpace, target.get()) || this->isAlphaOnly()) {
638         return sk_ref_sp(const_cast<SkImage*>(this));
639     }
640 
641     return as_IB(this)->onReinterpretColorSpace(std::move(target));
642 }
643 
makeNonTextureImage() const644 sk_sp<SkImage> SkImage::makeNonTextureImage() const {
645     if (!this->isTextureBacked()) {
646         return sk_ref_sp(const_cast<SkImage*>(this));
647     }
648     return this->makeRasterImage();
649 }
650 
makeRasterImage(CachingHint chint) const651 sk_sp<SkImage> SkImage::makeRasterImage(CachingHint chint) const {
652     SkPixmap pm;
653     if (this->peekPixels(&pm)) {
654         return sk_ref_sp(const_cast<SkImage*>(this));
655     }
656 
657     const size_t rowBytes = fInfo.minRowBytes();
658     size_t size = fInfo.computeByteSize(rowBytes);
659     if (SkImageInfo::ByteSizeOverflowed(size)) {
660         return nullptr;
661     }
662 
663     // Context TODO: Elevate GrDirectContext requirement to public API.
664     auto dContext = as_IB(this)->directContext();
665     sk_sp<SkData> data = SkData::MakeUninitialized(size);
666     pm = {fInfo.makeColorSpace(nullptr), data->writable_data(), fInfo.minRowBytes()};
667     if (!this->readPixels(dContext, pm, 0, 0, chint)) {
668         return nullptr;
669     }
670 
671     return SkImage::MakeRasterData(fInfo, std::move(data), rowBytes);
672 }
673 
674 //////////////////////////////////////////////////////////////////////////////////////
675 
676 #if !SK_SUPPORT_GPU
677 
MakeFromTexture(GrRecordingContext *,const GrBackendTexture &,GrSurfaceOrigin,SkColorType,SkAlphaType,sk_sp<SkColorSpace>,TextureReleaseProc,ReleaseContext)678 sk_sp<SkImage> SkImage::MakeFromTexture(GrRecordingContext*,
679                                         const GrBackendTexture&, GrSurfaceOrigin,
680                                         SkColorType, SkAlphaType, sk_sp<SkColorSpace>,
681                                         TextureReleaseProc, ReleaseContext) {
682     return nullptr;
683 }
684 
MakeFromCompressedTexture(GrRecordingContext *,const GrBackendTexture &,GrSurfaceOrigin,SkAlphaType,sk_sp<SkColorSpace>,TextureReleaseProc,ReleaseContext)685 sk_sp<SkImage> SkImage::MakeFromCompressedTexture(GrRecordingContext*,
686                                                   const GrBackendTexture&,
687                                                   GrSurfaceOrigin,
688                                                   SkAlphaType,
689                                                   sk_sp<SkColorSpace>,
690                                                   TextureReleaseProc,
691                                                   ReleaseContext) {
692     return nullptr;
693 }
694 
MakeBackendTextureFromSkImage(GrDirectContext *,sk_sp<SkImage>,GrBackendTexture *,BackendTextureReleaseProc *)695 bool SkImage::MakeBackendTextureFromSkImage(GrDirectContext*,
696                                             sk_sp<SkImage>,
697                                             GrBackendTexture*,
698                                             BackendTextureReleaseProc*) {
699     return false;
700 }
701 
MakeFromAdoptedTexture(GrRecordingContext *,const GrBackendTexture &,GrSurfaceOrigin,SkColorType,SkAlphaType,sk_sp<SkColorSpace>)702 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrRecordingContext*,
703                                                const GrBackendTexture&, GrSurfaceOrigin,
704                                                SkColorType, SkAlphaType,
705                                                sk_sp<SkColorSpace>) {
706     return nullptr;
707 }
708 
MakeFromYUVAPixmaps(GrRecordingContext * context,const SkYUVAPixmaps & pixmaps,GrMipMapped buildMips,bool limitToMaxTextureSize,sk_sp<SkColorSpace> imageColorSpace)709 sk_sp<SkImage> SkImage::MakeFromYUVAPixmaps(GrRecordingContext* context,
710                                             const SkYUVAPixmaps& pixmaps,
711                                             GrMipMapped buildMips,
712                                             bool limitToMaxTextureSize,
713                                             sk_sp<SkColorSpace> imageColorSpace) {
714     return nullptr;
715 }
716 
makeTextureImage(GrDirectContext *,GrMipmapped,SkBudgeted) const717 sk_sp<SkImage> SkImage::makeTextureImage(GrDirectContext*, GrMipmapped, SkBudgeted) const {
718     return nullptr;
719 }
720 
MakePromiseTexture(sk_sp<GrContextThreadSafeProxy>,const GrBackendFormat &,SkISize,GrMipmapped,GrSurfaceOrigin,SkColorType,SkAlphaType,sk_sp<SkColorSpace>,PromiseImageTextureFulfillProc,PromiseImageTextureReleaseProc,PromiseImageTextureContext)721 sk_sp<SkImage> SkImage::MakePromiseTexture(sk_sp<GrContextThreadSafeProxy>,
722                                            const GrBackendFormat&,
723                                            SkISize,
724                                            GrMipmapped,
725                                            GrSurfaceOrigin,
726                                            SkColorType,
727                                            SkAlphaType,
728                                            sk_sp<SkColorSpace>,
729                                            PromiseImageTextureFulfillProc,
730                                            PromiseImageTextureReleaseProc,
731                                            PromiseImageTextureContext) {
732     return nullptr;
733 }
734 
MakePromiseYUVATexture(sk_sp<GrContextThreadSafeProxy>,const GrYUVABackendTextureInfo &,sk_sp<SkColorSpace>,PromiseImageTextureFulfillProc,PromiseImageTextureReleaseProc,PromiseImageTextureContext[])735 sk_sp<SkImage> SkImage::MakePromiseYUVATexture(sk_sp<GrContextThreadSafeProxy>,
736                                                const GrYUVABackendTextureInfo&,
737                                                sk_sp<SkColorSpace>,
738                                                PromiseImageTextureFulfillProc,
739                                                PromiseImageTextureReleaseProc,
740                                                PromiseImageTextureContext[]) {
741     return nullptr;
742 }
743 
744 #endif
745 
746 ///////////////////////////////////////////////////////////////////////////////////////////////////
747 
SkImage_pinAsTexture(const SkImage * image,GrRecordingContext * rContext)748 bool SkImage_pinAsTexture(const SkImage* image, GrRecordingContext* rContext) {
749     SkASSERT(image);
750     SkASSERT(rContext);
751     return as_IB(image)->onPinAsTexture(rContext);
752 }
753 
SkImage_unpinAsTexture(const SkImage * image,GrRecordingContext * rContext)754 void SkImage_unpinAsTexture(const SkImage* image, GrRecordingContext* rContext) {
755     SkASSERT(image);
756     SkASSERT(rContext);
757     as_IB(image)->onUnpinAsTexture(rContext);
758 }
759 
760 ///////////////////////////////////////////////////////////////////////////////////////////////////
761 
SkMipmapBuilder(const SkImageInfo & info)762 SkMipmapBuilder::SkMipmapBuilder(const SkImageInfo& info) {
763     fMM = sk_sp<SkMipmap>(SkMipmap::Build({info, nullptr, 0}, nullptr, false));
764 }
765 
~SkMipmapBuilder()766 SkMipmapBuilder::~SkMipmapBuilder() {}
767 
countLevels() const768 int SkMipmapBuilder::countLevels() const {
769     return fMM ? fMM->countLevels() : 0;
770 }
771 
level(int index) const772 SkPixmap SkMipmapBuilder::level(int index) const {
773     SkPixmap pm;
774 
775     SkMipmap::Level level;
776     if (fMM && fMM->getLevel(index, &level)) {
777         pm = level.fPixmap;
778     }
779     return pm;
780 }
781 
hasMipmaps() const782 bool SkImage::hasMipmaps() const { return as_IB(this)->onHasMipmaps(); }
783 
withMipmaps(sk_sp<SkMipmap> mips) const784 sk_sp<SkImage> SkImage::withMipmaps(sk_sp<SkMipmap> mips) const {
785     if (mips == nullptr || mips->validForRootLevel(this->imageInfo())) {
786         if (auto result = as_IB(this)->onMakeWithMipmaps(std::move(mips))) {
787             return result;
788         }
789     }
790     return sk_ref_sp((const_cast<SkImage*>(this)));
791 }
792 
withDefaultMipmaps() const793 sk_sp<SkImage> SkImage::withDefaultMipmaps() const {
794     return this->withMipmaps(nullptr);
795 }
796 
attachTo(const SkImage * src)797 sk_sp<SkImage> SkMipmapBuilder::attachTo(const SkImage* src) {
798     return src->withMipmaps(fMM);
799 }
800 
801 //////////////////////////////////////////////////////////////////////////////////////////////////
802 
803 #include "src/core/SkReadBuffer.h"
804 #include "src/core/SkSamplingPriv.h"
805 #include "src/core/SkWriteBuffer.h"
806 
SkSamplingOptions(SkFilterQuality fq,MediumBehavior behavior)807 SkSamplingOptions::SkSamplingOptions(SkFilterQuality fq, MediumBehavior behavior) {
808     switch (fq) {
809         case SkFilterQuality::kHigh_SkFilterQuality:
810             *this = SkSamplingOptions(SkCubicResampler{1/3.0f, 1/3.0f});
811             break;
812         case SkFilterQuality::kMedium_SkFilterQuality:
813             *this = SkSamplingOptions(SkFilterMode::kLinear,
814                                       behavior == kMedium_asMipmapNearest ? SkMipmapMode::kNearest
815                                                                           : SkMipmapMode::kLinear);
816             break;
817         case SkFilterQuality::kLow_SkFilterQuality:
818             *this = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
819             break;
820         case SkFilterQuality::kNone_SkFilterQuality:
821             *this = SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
822             break;
823     }
824 }
825 
Read(SkReadBuffer & buffer)826 SkSamplingOptions SkSamplingPriv::Read(SkReadBuffer& buffer) {
827     if (buffer.readBool()) {
828         SkScalar B = buffer.readScalar(),
829                  C = buffer.readScalar();
830         return SkSamplingOptions({B,C});
831     } else {
832         auto filter = buffer.read32LE<SkFilterMode>(SkFilterMode::kLinear);
833         auto mipmap = buffer.read32LE<SkMipmapMode>(SkMipmapMode::kLinear);
834         return SkSamplingOptions(filter, mipmap);
835     }
836 }
837 
Write(SkWriteBuffer & buffer,const SkSamplingOptions & sampling)838 void SkSamplingPriv::Write(SkWriteBuffer& buffer, const SkSamplingOptions& sampling) {
839     buffer.writeBool(sampling.useCubic);
840     if (sampling.useCubic) {
841         buffer.writeScalar(sampling.cubic.B);
842         buffer.writeScalar(sampling.cubic.C);
843     } else {
844         buffer.writeUInt((unsigned)sampling.filter);
845         buffer.writeUInt((unsigned)sampling.mipmap);
846     }
847 }
848