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/SkNextID.h"
24 #include "src/core/SkSpecialImage.h"
25 #include "src/image/SkImage_Base.h"
26 #include "src/image/SkReadPixelsRec.h"
27 #include "src/shaders/SkImageShader.h"
28 
29 #if SK_SUPPORT_GPU
30 #include "include/gpu/GrContext.h"
31 #include "include/gpu/GrTexture.h"
32 #include "src/image/SkImage_Gpu.h"
33 #endif
34 #include "include/gpu/GrBackendSurface.h"
35 
SkImage(const SkImageInfo & info,uint32_t uniqueID)36 SkImage::SkImage(const SkImageInfo& info, uint32_t uniqueID)
37         : fInfo(info)
38         , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID) {
39     SkASSERT(info.width() > 0);
40     SkASSERT(info.height() > 0);
41 }
42 
peekPixels(SkPixmap * pm) const43 bool SkImage::peekPixels(SkPixmap* pm) const {
44     SkPixmap tmp;
45     if (!pm) {
46         pm = &tmp;
47     }
48     return as_IB(this)->onPeekPixels(pm);
49 }
50 
readPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint chint) const51 bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX,
52                          int srcY, CachingHint chint) const {
53     return as_IB(this)->onReadPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
54 }
55 
scalePixels(const SkPixmap & dst,SkFilterQuality quality,CachingHint chint) const56 bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingHint chint) const {
57     if (this->width() == dst.width() && this->height() == dst.height()) {
58         return this->readPixels(dst, 0, 0, chint);
59     }
60 
61     // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself
62     //       can scale more efficiently) we should take advantage of it here.
63     //
64     SkBitmap bm;
65     if (as_IB(this)->getROPixels(&bm, chint)) {
66         SkPixmap pmap;
67         // Note: By calling the pixmap scaler, we never cache the final result, so the chint
68         //       is (currently) only being applied to the getROPixels. If we get a request to
69         //       also attempt to cache the final (scaled) result, we would add that logic here.
70         //
71         return bm.peekPixels(&pmap) && pmap.scalePixels(dst, quality);
72     }
73     return false;
74 }
75 
76 ///////////////////////////////////////////////////////////////////////////////////////////////////
77 
colorType() const78 SkColorType SkImage::colorType() const { return fInfo.colorType(); }
79 
alphaType() const80 SkAlphaType SkImage::alphaType() const { return fInfo.alphaType(); }
81 
colorSpace() const82 SkColorSpace* SkImage::colorSpace() const { return fInfo.colorSpace(); }
83 
refColorSpace() const84 sk_sp<SkColorSpace> SkImage::refColorSpace() const { return fInfo.refColorSpace(); }
85 
makeShader(SkTileMode tmx,SkTileMode tmy,const SkMatrix * localMatrix) const86 sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
87                                     const SkMatrix* localMatrix) const {
88     return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy, localMatrix);
89 }
90 
encodeToData(SkEncodedImageFormat type,int quality) const91 sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const {
92     SkBitmap bm;
93     if (as_IB(this)->getROPixels(&bm)) {
94         return SkEncodeBitmap(bm, type, quality);
95     }
96     return nullptr;
97 }
98 
encodeToData() const99 sk_sp<SkData> SkImage::encodeToData() const {
100     if (auto encoded = this->refEncodedData()) {
101         return encoded;
102     }
103 
104     return this->encodeToData(SkEncodedImageFormat::kPNG, 100);
105 }
106 
refEncodedData() const107 sk_sp<SkData> SkImage::refEncodedData() const {
108     return sk_sp<SkData>(as_IB(this)->onRefEncoded());
109 }
110 
MakeFromEncoded(sk_sp<SkData> encoded,const SkIRect * subset)111 sk_sp<SkImage> SkImage::MakeFromEncoded(sk_sp<SkData> encoded, const SkIRect* subset) {
112     if (nullptr == encoded || 0 == encoded->size()) {
113         return nullptr;
114     }
115     return SkImage::MakeFromGenerator(SkImageGenerator::MakeFromEncoded(std::move(encoded)),
116                                       subset);
117 }
118 
119 ///////////////////////////////////////////////////////////////////////////////////////////////////
120 
makeSubset(const SkIRect & subset) const121 sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset) const {
122     if (subset.isEmpty()) {
123         return nullptr;
124     }
125 
126     const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
127     if (!bounds.contains(subset)) {
128         return nullptr;
129     }
130 
131     // optimization : return self if the subset == our bounds
132     if (bounds == subset) {
133         return sk_ref_sp(const_cast<SkImage*>(this));
134     }
135 
136     // CONTEXT TODO: propagate the context parameter to the top-level API
137 #if SK_SUPPORT_GPU
138     return as_IB(this)->onMakeSubset(as_IB(this)->context(), subset);
139 #else
140     return as_IB(this)->onMakeSubset(nullptr, subset);
141 #endif
142 }
143 
144 #if SK_SUPPORT_GPU
145 
getTexture() const146 GrTexture* SkImage::getTexture() const {
147     return as_IB(this)->onGetTexture();
148 }
149 
isTextureBacked() const150 bool SkImage::isTextureBacked() const { return as_IB(this)->onIsTextureBacked(); }
151 
getBackendTexture(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const152 GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
153                                             GrSurfaceOrigin* origin) const {
154     return as_IB(this)->onGetBackendTexture(flushPendingGrContextIO, origin);
155 }
156 
isValid(GrContext * context) const157 bool SkImage::isValid(GrContext* context) const {
158     if (context && context->abandoned()) {
159         return false;
160     }
161     return as_IB(this)->onIsValid(context);
162 }
163 
flush(GrContext * context,const GrFlushInfo & flushInfo)164 GrSemaphoresSubmitted SkImage::flush(GrContext* context, const GrFlushInfo& flushInfo) {
165     return as_IB(this)->onFlush(context, flushInfo);
166 }
167 
flush(GrContext * context)168 void SkImage::flush(GrContext* context) { as_IB(this)->onFlush(context, {}); }
169 
170 #else
171 
getTexture() const172 GrTexture* SkImage::getTexture() const { return nullptr; }
173 
isTextureBacked() const174 bool SkImage::isTextureBacked() const { return false; }
175 
getBackendTexture(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const176 GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
177                                             GrSurfaceOrigin* origin) const {
178     return GrBackendTexture(); // invalid
179 }
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 
flush(GrContext *,const GrFlushInfo &)188 GrSemaphoresSubmitted SkImage::flush(GrContext*, const GrFlushInfo&) {
189     return GrSemaphoresSubmitted::kNo;
190 }
191 
flush(GrContext *)192 void SkImage::flush(GrContext*) {}
193 
194 #endif
195 
196 ///////////////////////////////////////////////////////////////////////////////
197 
SkImage_Base(const SkImageInfo & info,uint32_t uniqueID)198 SkImage_Base::SkImage_Base(const SkImageInfo& info, uint32_t uniqueID)
199         : INHERITED(info, uniqueID), fAddedToRasterCache(false) {}
200 
~SkImage_Base()201 SkImage_Base::~SkImage_Base() {
202     if (fAddedToRasterCache.load()) {
203         SkNotifyBitmapGenIDIsStale(this->uniqueID());
204     }
205 }
206 
onGetBackendTexture(bool flushPendingGrContextIO,GrSurfaceOrigin * origin) const207 GrBackendTexture SkImage_Base::onGetBackendTexture(bool flushPendingGrContextIO,
208                                                    GrSurfaceOrigin* origin) const {
209     return GrBackendTexture(); // invalid
210 }
211 
readPixels(const SkPixmap & pmap,int srcX,int srcY,CachingHint chint) const212 bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const {
213     return this->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX, srcY, chint);
214 }
215 
216 ///////////////////////////////////////////////////////////////////////////////////////////////////
217 
MakeFromBitmap(const SkBitmap & bm)218 sk_sp<SkImage> SkImage::MakeFromBitmap(const SkBitmap& bm) {
219     if (!bm.pixelRef()) {
220         return nullptr;
221     }
222 
223     return SkMakeImageFromRasterBitmap(bm, kIfMutable_SkCopyPixelsMode);
224 }
225 
asLegacyBitmap(SkBitmap * bitmap,LegacyBitmapMode) const226 bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode ) const {
227     return as_IB(this)->onAsLegacyBitmap(bitmap);
228 }
229 
getPlanes(SkYUVASizeInfo *,SkYUVAIndex[4],SkYUVColorSpace *,const void * [4])230 sk_sp<SkCachedData> SkImage_Base::getPlanes(SkYUVASizeInfo*, SkYUVAIndex[4],
231                                             SkYUVColorSpace*, const void*[4]) {
232     return nullptr;
233 }
234 
onAsLegacyBitmap(SkBitmap * bitmap) const235 bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap) const {
236     // As the base-class, all we can do is make a copy (regardless of mode).
237     // Subclasses that want to be more optimal should override.
238     SkImageInfo info = fInfo.makeColorType(kN32_SkColorType).makeColorSpace(nullptr);
239     if (!bitmap->tryAllocPixels(info)) {
240         return false;
241     }
242     if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
243         bitmap->reset();
244         return false;
245     }
246 
247     bitmap->setImmutable();
248     return true;
249 }
250 
MakeFromPicture(sk_sp<SkPicture> picture,const SkISize & dimensions,const SkMatrix * matrix,const SkPaint * paint,BitDepth bitDepth,sk_sp<SkColorSpace> colorSpace)251 sk_sp<SkImage> SkImage::MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions,
252                                         const SkMatrix* matrix, const SkPaint* paint,
253                                         BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace) {
254     return MakeFromGenerator(SkImageGenerator::MakeFromPicture(dimensions, std::move(picture),
255                                                                matrix, paint, bitDepth,
256                                                                std::move(colorSpace)));
257 }
258 
makeWithFilter(const SkImageFilter * filter,const SkIRect & subset,const SkIRect & clipBounds,SkIRect * outSubset,SkIPoint * offset) const259 sk_sp<SkImage> SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRect& subset,
260                                        const SkIRect& clipBounds, SkIRect* outSubset,
261                                        SkIPoint* offset) const {
262     GrContext* context = as_IB(this)->context();
263 
264     return this->makeWithFilter(context, filter, subset, clipBounds, outSubset, offset);
265 }
266 
makeWithFilter(GrContext * grContext,const SkImageFilter * filter,const SkIRect & subset,const SkIRect & clipBounds,SkIRect * outSubset,SkIPoint * offset) const267 sk_sp<SkImage> SkImage::makeWithFilter(GrContext* grContext,
268                                        const SkImageFilter* filter, const SkIRect& subset,
269                                        const SkIRect& clipBounds, SkIRect* outSubset,
270                                        SkIPoint* offset) const {
271     if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) {
272         return nullptr;
273     }
274     sk_sp<SkSpecialImage> srcSpecialImage =
275 #if SK_SUPPORT_GPU
276         SkSpecialImage::MakeFromImage(grContext, subset, sk_ref_sp(const_cast<SkImage*>(this)));
277 #else
278         SkSpecialImage::MakeFromImage(nullptr, subset, sk_ref_sp(const_cast<SkImage*>(this)));
279 #endif
280     if (!srcSpecialImage) {
281         return nullptr;
282     }
283 
284     sk_sp<SkImageFilterCache> cache(
285         SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize));
286 
287     // The filters operate in the local space of the src image, where (0,0) corresponds to the
288     // subset's top left corner. But the clip bounds and any crop rects on the filters are in the
289     // original coordinate system, so configure the CTM to correct crop rects and explicitly adjust
290     // the clip bounds (since it is assumed to already be in image space).
291     SkImageFilter_Base::Context context(SkMatrix::MakeTrans(-subset.x(), -subset.y()),
292                                         clipBounds.makeOffset(-subset.topLeft()),
293                                         cache.get(), fInfo.colorType(), fInfo.colorSpace(),
294                                         srcSpecialImage.get());
295 
296     sk_sp<SkSpecialImage> result = as_IFB(filter)->filterImage(context).imageAndOffset(offset);
297     if (!result) {
298         return nullptr;
299     }
300 
301     // The output image and offset are relative to the subset rectangle, so the offset needs to
302     // be shifted to put it in the correct spot with respect to the original coordinate system
303     offset->fX += subset.x();
304     offset->fY += subset.y();
305 
306     // Final clip against the exact clipBounds (the clip provided in the context gets adjusted
307     // to account for pixel-moving filters so doesn't always exactly match when finished). The
308     // clipBounds are translated into the clippedDstRect coordinate space, including the
309     // result->subset() ensures that the result's image pixel origin does not affect results.
310     SkIRect dstRect = result->subset();
311     SkIRect clippedDstRect = dstRect;
312     if (!clippedDstRect.intersect(clipBounds.makeOffset(result->subset().topLeft() - *offset))) {
313         return nullptr;
314     }
315 
316     // Adjust the geometric offset if the top-left corner moved as well
317     offset->fX += (clippedDstRect.x() - dstRect.x());
318     offset->fY += (clippedDstRect.y() - dstRect.y());
319     *outSubset = clippedDstRect;
320     return result->asImage();
321 }
322 
isLazyGenerated() const323 bool SkImage::isLazyGenerated() const {
324     return as_IB(this)->onIsLazyGenerated();
325 }
326 
isAlphaOnly() const327 bool SkImage::isAlphaOnly() const { return SkColorTypeIsAlphaOnly(fInfo.colorType()); }
328 
makeColorSpace(sk_sp<SkColorSpace> target) const329 sk_sp<SkImage> SkImage::makeColorSpace(sk_sp<SkColorSpace> target) const {
330     if (!target) {
331         return nullptr;
332     }
333 
334     // No need to create a new image if:
335     // (1) The color spaces are equal.
336     // (2) The color type is kAlpha8.
337     SkColorSpace* colorSpace = this->colorSpace();
338     if (!colorSpace) {
339         colorSpace = sk_srgb_singleton();
340     }
341     if (SkColorSpace::Equals(colorSpace, target.get()) || this->isAlphaOnly()) {
342         return sk_ref_sp(const_cast<SkImage*>(this));
343     }
344 
345     // CONTEXT TODO: propagate the context parameter to the top-level API
346 #if SK_SUPPORT_GPU
347     return as_IB(this)->onMakeColorTypeAndColorSpace(as_IB(this)->context(),
348 #else
349     return as_IB(this)->onMakeColorTypeAndColorSpace(nullptr,
350 #endif
351                                                      this->colorType(), std::move(target));
352 }
353 
makeColorTypeAndColorSpace(SkColorType targetColorType,sk_sp<SkColorSpace> targetColorSpace) const354 sk_sp<SkImage> SkImage::makeColorTypeAndColorSpace(SkColorType targetColorType,
355                                                    sk_sp<SkColorSpace> targetColorSpace) const {
356     if (kUnknown_SkColorType == targetColorType || !targetColorSpace) {
357         return nullptr;
358     }
359 
360     SkColorType colorType = this->colorType();
361     SkColorSpace* colorSpace = this->colorSpace();
362     if (!colorSpace) {
363         colorSpace = sk_srgb_singleton();
364     }
365     if (colorType == targetColorType &&
366         (SkColorSpace::Equals(colorSpace, targetColorSpace.get()) || this->isAlphaOnly())) {
367         return sk_ref_sp(const_cast<SkImage*>(this));
368     }
369 
370     // CONTEXT TODO: propagate the context parameter to the top-level API
371 #if SK_SUPPORT_GPU
372     return as_IB(this)->onMakeColorTypeAndColorSpace(as_IB(this)->context(),
373 #else
374     return as_IB(this)->onMakeColorTypeAndColorSpace(nullptr,
375 #endif
376                                                      targetColorType, std::move(targetColorSpace));
377 }
378 
reinterpretColorSpace(sk_sp<SkColorSpace> target) const379 sk_sp<SkImage> SkImage::reinterpretColorSpace(sk_sp<SkColorSpace> target) const {
380     if (!target) {
381         return nullptr;
382     }
383 
384     // No need to create a new image if:
385     // (1) The color spaces are equal.
386     // (2) The color type is kAlpha8.
387     SkColorSpace* colorSpace = this->colorSpace();
388     if (!colorSpace) {
389         colorSpace = sk_srgb_singleton();
390     }
391     if (SkColorSpace::Equals(colorSpace, target.get()) || this->isAlphaOnly()) {
392         return sk_ref_sp(const_cast<SkImage*>(this));
393     }
394 
395     return as_IB(this)->onReinterpretColorSpace(std::move(target));
396 }
397 
makeNonTextureImage() const398 sk_sp<SkImage> SkImage::makeNonTextureImage() const {
399     if (!this->isTextureBacked()) {
400         return sk_ref_sp(const_cast<SkImage*>(this));
401     }
402     return this->makeRasterImage();
403 }
404 
makeRasterImage() const405 sk_sp<SkImage> SkImage::makeRasterImage() const {
406     SkPixmap pm;
407     if (this->peekPixels(&pm)) {
408         return sk_ref_sp(const_cast<SkImage*>(this));
409     }
410 
411     const size_t rowBytes = fInfo.minRowBytes();
412     size_t size = fInfo.computeByteSize(rowBytes);
413     if (SkImageInfo::ByteSizeOverflowed(size)) {
414         return nullptr;
415     }
416 
417     sk_sp<SkData> data = SkData::MakeUninitialized(size);
418     pm = {fInfo.makeColorSpace(nullptr), data->writable_data(), fInfo.minRowBytes()};
419     if (!this->readPixels(pm, 0, 0)) {
420         return nullptr;
421     }
422 
423     return SkImage::MakeRasterData(fInfo, std::move(data), rowBytes);
424 }
425 
426 //////////////////////////////////////////////////////////////////////////////////////
427 
428 #if !SK_SUPPORT_GPU
429 
DecodeToTexture(GrContext *,const void *,size_t,const SkIRect *)430 sk_sp<SkImage> SkImage::DecodeToTexture(GrContext*, const void*, size_t, const SkIRect*) {
431     return nullptr;
432 }
433 
MakeFromTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)434 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
435                                         const GrBackendTexture& tex, GrSurfaceOrigin origin,
436                                         SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
437                                         TextureReleaseProc releaseP, ReleaseContext releaseC) {
438     return nullptr;
439 }
440 
MakeBackendTextureFromSkImage(GrContext *,sk_sp<SkImage>,GrBackendTexture *,BackendTextureReleaseProc *)441 bool SkImage::MakeBackendTextureFromSkImage(GrContext*,
442                                             sk_sp<SkImage>,
443                                             GrBackendTexture*,
444                                             BackendTextureReleaseProc*) {
445     return false;
446 }
447 
MakeFromAdoptedTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs)448 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
449                                                const GrBackendTexture& tex, GrSurfaceOrigin origin,
450                                                SkColorType ct, SkAlphaType at,
451                                                sk_sp<SkColorSpace> cs) {
452     return nullptr;
453 }
454 
MakeFromYUVATexturesCopy(GrContext * context,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvaTextures[],const SkYUVAIndex yuvaIndices[4],SkISize imageSize,GrSurfaceOrigin imageOrigin,sk_sp<SkColorSpace> imageColorSpace)455 sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopy(GrContext* context,
456                                                  SkYUVColorSpace yuvColorSpace,
457                                                  const GrBackendTexture yuvaTextures[],
458                                                  const SkYUVAIndex yuvaIndices[4],
459                                                  SkISize imageSize,
460                                                  GrSurfaceOrigin imageOrigin,
461                                                  sk_sp<SkColorSpace> imageColorSpace) {
462     return nullptr;
463 }
464 
MakeFromYUVATexturesCopyWithExternalBackend(GrContext * context,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvaTextures[],const SkYUVAIndex yuvaIndices[4],SkISize imageSize,GrSurfaceOrigin imageOrigin,const GrBackendTexture & backendTexture,sk_sp<SkColorSpace> imageColorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)465 sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopyWithExternalBackend(
466         GrContext* context,
467         SkYUVColorSpace yuvColorSpace,
468         const GrBackendTexture yuvaTextures[],
469         const SkYUVAIndex yuvaIndices[4],
470         SkISize imageSize,
471         GrSurfaceOrigin imageOrigin,
472         const GrBackendTexture& backendTexture,
473         sk_sp<SkColorSpace> imageColorSpace,
474         TextureReleaseProc textureReleaseProc,
475         ReleaseContext releaseContext) {
476     return nullptr;
477 }
478 
MakeFromYUVTexturesCopy(GrContext * ctx,SkYUVColorSpace space,const GrBackendTexture[3],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)479 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace space,
480                                                 const GrBackendTexture[3],
481                                                 GrSurfaceOrigin origin,
482                                                 sk_sp<SkColorSpace> imageColorSpace) {
483     return nullptr;
484 }
485 
MakeFromYUVTexturesCopyWithExternalBackend(GrContext * context,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvTextures[3],GrSurfaceOrigin surfaceOrigin,const GrBackendTexture & backendTexture,sk_sp<SkColorSpace> colorSpace)486 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopyWithExternalBackend(
487         GrContext* context, SkYUVColorSpace yuvColorSpace, const GrBackendTexture yuvTextures[3],
488         GrSurfaceOrigin surfaceOrigin, const GrBackendTexture& backendTexture,
489         sk_sp<SkColorSpace> colorSpace) {
490     return nullptr;
491 }
492 
MakeFromNV12TexturesCopy(GrContext * ctx,SkYUVColorSpace space,const GrBackendTexture[2],GrSurfaceOrigin origin,sk_sp<SkColorSpace> imageColorSpace)493 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace space,
494                                                 const GrBackendTexture[2],
495                                                 GrSurfaceOrigin origin,
496                                                 sk_sp<SkColorSpace> imageColorSpace) {
497     return nullptr;
498 }
499 
makeTextureImage(GrContext *,GrMipMapped mipMapped) const500 sk_sp<SkImage> SkImage::makeTextureImage(GrContext*, GrMipMapped mipMapped) const {
501     return nullptr;
502 }
503 
MakeFromNV12TexturesCopyWithExternalBackend(GrContext * context,SkYUVColorSpace yuvColorSpace,const GrBackendTexture nv12Textures[2],GrSurfaceOrigin imageOrigin,const GrBackendTexture & backendTexture,sk_sp<SkColorSpace> imageColorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)504 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopyWithExternalBackend(
505                                                            GrContext* context,
506                                                            SkYUVColorSpace yuvColorSpace,
507                                                            const GrBackendTexture nv12Textures[2],
508                                                            GrSurfaceOrigin imageOrigin,
509                                                            const GrBackendTexture& backendTexture,
510                                                            sk_sp<SkColorSpace> imageColorSpace,
511                                                            TextureReleaseProc textureReleaseProc,
512                                                            ReleaseContext releaseContext) {
513     return nullptr;
514 }
515 
516 #endif
517 
518 ///////////////////////////////////////////////////////////////////////////////////////////////////
519 
SkImage_pinAsTexture(const SkImage * image,GrContext * ctx)520 bool SkImage_pinAsTexture(const SkImage* image, GrContext* ctx) {
521     SkASSERT(image);
522     SkASSERT(ctx);
523     return as_IB(image)->onPinAsTexture(ctx);
524 }
525 
SkImage_unpinAsTexture(const SkImage * image,GrContext * ctx)526 void SkImage_unpinAsTexture(const SkImage* image, GrContext* ctx) {
527     SkASSERT(image);
528     SkASSERT(ctx);
529     as_IB(image)->onUnpinAsTexture(ctx);
530 }
531 
SkImage_getSubset(const SkImage * image)532 SkIRect SkImage_getSubset(const SkImage* image) {
533     SkASSERT(image);
534     return as_IB(image)->onGetSubset();
535 }
536