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