blob: ed3cc928848f85cffbd720fc57d7276d4c166e18 [file] [log] [blame]
reed@google.com6997ebb2012-07-30 19:50:31 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#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"
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040021#include "src/core/SkImageFilter_Base.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/core/SkImagePriv.h"
Mike Reed13711eb2020-07-14 17:16:32 -040023#include "src/core/SkMipmap.h"
Mike Reed6affa2c2020-11-30 13:09:24 -050024#include "src/core/SkMipmapBuilder.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/core/SkNextID.h"
26#include "src/core/SkSpecialImage.h"
27#include "src/image/SkImage_Base.h"
28#include "src/image/SkReadPixelsRec.h"
Brian Salomon63a0a752020-06-26 13:32:09 -040029#include "src/image/SkRescaleAndReadPixels.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050030#include "src/shaders/SkImageShader.h"
reed56179002015-07-07 06:11:19 -070031
bsalomon55812362015-06-10 08:49:28 -070032#if SK_SUPPORT_GPU
Robert Phillips4a3ebc22020-07-10 11:27:43 -040033#include "include/gpu/GrDirectContext.h"
Adlai Hollera0693042020-10-14 11:23:11 -040034#include "src/gpu/GrDirectContextPriv.h"
Adlai Holler302e8fb2020-09-14 11:58:06 -040035#include "src/gpu/GrImageContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050036#include "src/image/SkImage_Gpu.h"
bsalomon55812362015-06-10 08:49:28 -070037#endif
Mike Kleinc0bd9f92019-04-23 12:05:21 -050038#include "include/gpu/GrBackendSurface.h"
scroggo@google.com7def5e12013-05-31 14:00:10 +000039
Brian Salomon5ad6fd32019-03-21 15:30:08 -040040SkImage::SkImage(const SkImageInfo& info, uint32_t uniqueID)
41 : fInfo(info)
42 , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID) {
43 SkASSERT(info.width() > 0);
44 SkASSERT(info.height() > 0);
reed@google.comf6627b72012-07-27 18:02:50 +000045}
46
reed6ceeebd2016-03-09 14:26:26 -080047bool SkImage::peekPixels(SkPixmap* pm) const {
48 SkPixmap tmp;
49 if (!pm) {
50 pm = &tmp;
reed@google.com4f7c6152014-02-06 14:11:56 +000051 }
reed6ceeebd2016-03-09 14:26:26 -080052 return as_IB(this)->onPeekPixels(pm);
reed@google.com4f7c6152014-02-06 14:11:56 +000053}
54
Adlai Hollerbcfc5542020-08-27 12:44:07 -040055bool SkImage::readPixels(GrDirectContext* dContext, const SkImageInfo& dstInfo, void* dstPixels,
56 size_t dstRowBytes, int srcX, int srcY, CachingHint chint) const {
57 return as_IB(this)->onReadPixels(dContext, dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
reed09553032015-11-23 12:32:16 -080058}
59
Adlai Hollerbcfc5542020-08-27 12:44:07 -040060#ifndef SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API
61bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels,
62 size_t dstRowBytes, int srcX, int srcY, CachingHint chint) const {
63 auto dContext = as_IB(this)->directContext();
64 return this->readPixels(dContext, dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
65}
66#endif
67
Brian Salomon63a0a752020-06-26 13:32:09 -040068void SkImage::asyncRescaleAndReadPixels(const SkImageInfo& info,
69 const SkIRect& srcRect,
70 RescaleGamma rescaleGamma,
71 SkFilterQuality rescaleQuality,
72 ReadPixelsCallback callback,
73 ReadPixelsContext context) {
74 if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) ||
75 !SkImageInfoIsValid(info)) {
76 callback(context, nullptr);
77 return;
78 }
79 as_IB(this)->onAsyncRescaleAndReadPixels(
80 info, srcRect, rescaleGamma, rescaleQuality, callback, context);
81}
82
83void SkImage::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
84 sk_sp<SkColorSpace> dstColorSpace,
85 const SkIRect& srcRect,
86 const SkISize& dstSize,
87 RescaleGamma rescaleGamma,
88 SkFilterQuality rescaleQuality,
89 ReadPixelsCallback callback,
90 ReadPixelsContext context) {
91 if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || dstSize.isZero() ||
92 (dstSize.width() & 0b1) || (dstSize.height() & 0b1)) {
93 callback(context, nullptr);
94 return;
95 }
96 as_IB(this)->onAsyncRescaleAndReadPixelsYUV420(yuvColorSpace,
97 std::move(dstColorSpace),
98 srcRect,
99 dstSize,
100 rescaleGamma,
101 rescaleQuality,
102 callback,
103 context);
104}
105
Mike Reedce0c8762020-11-23 17:41:35 -0500106bool SkImage::scalePixels(const SkPixmap& dst, const SkSamplingOptions& sampling,
107 CachingHint chint) const {
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400108 // Context TODO: Elevate GrDirectContext requirement to public API.
109 auto dContext = as_IB(this)->directContext();
reed6868c3f2015-11-24 11:44:47 -0800110 if (this->width() == dst.width() && this->height() == dst.height()) {
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400111 return this->readPixels(dContext, dst, 0, 0, chint);
reed6868c3f2015-11-24 11:44:47 -0800112 }
113
reed09553032015-11-23 12:32:16 -0800114 // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself
115 // can scale more efficiently) we should take advantage of it here.
116 //
117 SkBitmap bm;
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400118 if (as_IB(this)->getROPixels(dContext, &bm, chint)) {
reed09553032015-11-23 12:32:16 -0800119 SkPixmap pmap;
120 // Note: By calling the pixmap scaler, we never cache the final result, so the chint
121 // is (currently) only being applied to the getROPixels. If we get a request to
122 // also attempt to cache the final (scaled) result, we would add that logic here.
123 //
Mike Reedce0c8762020-11-23 17:41:35 -0500124 return bm.peekPixels(&pmap) && pmap.scalePixels(dst, sampling);
reed09553032015-11-23 12:32:16 -0800125 }
126 return false;
reed@google.com4f7c6152014-02-06 14:11:56 +0000127}
128
reed88d064d2015-10-12 11:30:02 -0700129///////////////////////////////////////////////////////////////////////////////////////////////////
130
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400131SkColorType SkImage::colorType() const { return fInfo.colorType(); }
Greg Daniel56008aa2018-03-14 15:33:42 -0400132
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400133SkAlphaType SkImage::alphaType() const { return fInfo.alphaType(); }
brianosman69c166d2016-08-17 14:01:05 -0700134
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400135SkColorSpace* SkImage::colorSpace() const { return fInfo.colorSpace(); }
Matt Sarett5b4599f2017-03-02 12:42:35 -0500136
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400137sk_sp<SkColorSpace> SkImage::refColorSpace() const { return fInfo.refColorSpace(); }
Matt Sarett5b4599f2017-03-02 12:42:35 -0500138
Mike Reed99c94462020-12-08 13:16:56 -0500139#ifdef SK_SUPPORT_LEGACY_IMPLICIT_FILTERQUALITY
Mike Reede25b4472019-04-02 17:49:12 -0400140sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
reed5671c5b2016-03-09 14:47:34 -0800141 const SkMatrix* localMatrix) const {
Mike Reed74c51ac2020-11-20 10:23:58 -0500142 const SkSamplingOptions* inherit_from_paint = nullptr;
143 return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy, inherit_from_paint,
144 localMatrix);
Mike Reed9290d012020-06-11 16:56:06 -0400145}
Mike Reed99c94462020-12-08 13:16:56 -0500146#endif
Mike Reed9290d012020-06-11 16:56:06 -0400147
Mike Reedb86cd3d2020-12-10 14:55:43 -0500148sk_sp<SkShader> SkImage_makeShaderImplicitFilterQuality(const SkImage* image,
149 SkTileMode tmx, SkTileMode tmy,
150 const SkMatrix* localMatrix) {
151 const SkSamplingOptions* inherit_from_paint = nullptr;
152 return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(image)), tmx, tmy, inherit_from_paint,
153 localMatrix);
154}
155
Mike Reed9290d012020-06-11 16:56:06 -0400156sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
Mike Reed74c51ac2020-11-20 10:23:58 -0500157 const SkSamplingOptions& sampling,
Mike Reedf8a6b5b2020-07-10 08:36:42 -0400158 const SkMatrix* localMatrix) const {
159 return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy,
Mike Reed74c51ac2020-11-20 10:23:58 -0500160 &sampling, localMatrix);
Mike Reedf8a6b5b2020-07-10 08:36:42 -0400161}
162
Mike Reed6409f842017-07-11 16:03:13 -0400163sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const {
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400164 // Context TODO: Elevate GrDirectContext requirement to public API.
165 auto dContext = as_IB(this)->directContext();
Leon Scroggins294c1c42016-11-08 14:29:46 +0000166 SkBitmap bm;
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400167 if (as_IB(this)->getROPixels(dContext, &bm)) {
Mike Reed25eef6b2017-12-08 16:20:58 -0500168 return SkEncodeBitmap(bm, type, quality);
Leon Scroggins294c1c42016-11-08 14:29:46 +0000169 }
170 return nullptr;
171}
172
Mike Reedef038482017-12-16 08:41:28 -0500173sk_sp<SkData> SkImage::encodeToData() const {
174 if (auto encoded = this->refEncodedData()) {
Mike Reed6409f842017-07-11 16:03:13 -0400175 return encoded;
fmalita2be71252015-09-03 07:17:25 -0700176 }
177
Brian Osmane50cdf02018-10-19 13:02:14 -0400178 return this->encodeToData(SkEncodedImageFormat::kPNG, 100);
fmalita2be71252015-09-03 07:17:25 -0700179}
180
Mike Reed6409f842017-07-11 16:03:13 -0400181sk_sp<SkData> SkImage::refEncodedData() const {
182 return sk_sp<SkData>(as_IB(this)->onRefEncoded());
reed871872f2015-06-22 12:48:26 -0700183}
184
Mike Reed564d49e2020-07-28 12:52:31 -0400185sk_sp<SkImage> SkImage::MakeFromEncoded(sk_sp<SkData> encoded) {
halcanary96fcdcc2015-08-27 07:41:13 -0700186 if (nullptr == encoded || 0 == encoded->size()) {
187 return nullptr;
reed5965c8a2015-01-07 18:04:45 -0800188 }
Mike Reed564d49e2020-07-28 12:52:31 -0400189 return SkImage::MakeFromGenerator(SkImageGenerator::MakeFromEncoded(std::move(encoded)));
reed5965c8a2015-01-07 18:04:45 -0800190}
191
Mike Reed6409f842017-07-11 16:03:13 -0400192///////////////////////////////////////////////////////////////////////////////////////////////////
193
Adlai Holler872a32c2020-07-10 14:33:22 -0400194sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset, GrDirectContext* direct) const {
reed7b6945b2015-09-24 00:50:58 -0700195 if (subset.isEmpty()) {
196 return nullptr;
197 }
198
199 const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
200 if (!bounds.contains(subset)) {
201 return nullptr;
202 }
203
Adlai Holler872a32c2020-07-10 14:33:22 -0400204#if SK_SUPPORT_GPU
205 auto myContext = as_IB(this)->context();
Adlai Holler3a220172020-07-15 10:37:50 -0400206 // This check is also performed in the subclass, but we do it here for the short-circuit below.
Adlai Holler872a32c2020-07-10 14:33:22 -0400207 if (myContext && !myContext->priv().matches(direct)) {
208 return nullptr;
209 }
210#endif
211
reed7b6945b2015-09-24 00:50:58 -0700212 // optimization : return self if the subset == our bounds
213 if (bounds == subset) {
reed7fb4f8b2016-03-11 04:33:52 -0800214 return sk_ref_sp(const_cast<SkImage*>(this));
reed7b6945b2015-09-24 00:50:58 -0700215 }
Robert Phillips6603a172019-03-05 12:35:44 -0500216
Adlai Holler872a32c2020-07-10 14:33:22 -0400217 return as_IB(this)->onMakeSubset(subset, direct);
reedf803da12015-01-23 05:58:07 -0800218}
219
bsalomon55812362015-06-10 08:49:28 -0700220#if SK_SUPPORT_GPU
221
Jim Van Verth21bd60d2018-10-12 15:00:20 -0400222bool SkImage::isTextureBacked() const { return as_IB(this)->onIsTextureBacked(); }
bsalomon55812362015-06-10 08:49:28 -0700223
Robert Phillipsc5509952018-04-04 15:54:55 -0400224GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
225 GrSurfaceOrigin* origin) const {
226 return as_IB(this)->onGetBackendTexture(flushPendingGrContextIO, origin);
227}
Robert Phillipsc5509952018-04-04 15:54:55 -0400228
Adlai Holler01373552020-07-21 13:52:41 -0400229bool SkImage::isValid(GrRecordingContext* rContext) const {
230 if (rContext && rContext->abandoned()) {
Brian Osman5bbd0762017-05-08 11:07:42 -0400231 return false;
232 }
Adlai Holler01373552020-07-21 13:52:41 -0400233 return as_IB(this)->onIsValid(rContext);
Robert Phillips4a3ebc22020-07-10 11:27:43 -0400234}
235
Adlai Holler40ad5fd2020-07-22 10:22:12 -0400236GrSemaphoresSubmitted SkImage::flush(GrDirectContext* dContext, const GrFlushInfo& flushInfo) {
237 return as_IB(this)->onFlush(dContext, flushInfo);
238}
239
240void SkImage::flushAndSubmit(GrDirectContext* dContext) {
241 this->flush(dContext, {});
242 dContext->submit();
243}
244
bsalomon55812362015-06-10 08:49:28 -0700245#else
246
bsalomon55812362015-06-10 08:49:28 -0700247bool SkImage::isTextureBacked() const { return false; }
248
Robert Phillipsc5509952018-04-04 15:54:55 -0400249GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
250 GrSurfaceOrigin* origin) const {
251 return GrBackendTexture(); // invalid
252}
253
Adlai Holler01373552020-07-21 13:52:41 -0400254bool SkImage::isValid(GrRecordingContext* rContext) const {
255 if (rContext) {
Brian Osman5bbd0762017-05-08 11:07:42 -0400256 return false;
257 }
Robert Phillips4a3ebc22020-07-10 11:27:43 -0400258 return as_IB(this)->onIsValid(nullptr);
Brian Osman5bbd0762017-05-08 11:07:42 -0400259}
260
Adlai Holler40ad5fd2020-07-22 10:22:12 -0400261GrSemaphoresSubmitted SkImage::flush(GrDirectContext*, const GrFlushInfo&) {
262 return GrSemaphoresSubmitted::kNo;
263}
264
265void SkImage::flushAndSubmit(GrDirectContext*) {}
266
bsalomon55812362015-06-10 08:49:28 -0700267#endif
268
reed@google.com4f7c6152014-02-06 14:11:56 +0000269///////////////////////////////////////////////////////////////////////////////
270
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400271SkImage_Base::SkImage_Base(const SkImageInfo& info, uint32_t uniqueID)
272 : INHERITED(info, uniqueID), fAddedToRasterCache(false) {}
fmalita3b0d5322015-09-18 08:07:31 -0700273
274SkImage_Base::~SkImage_Base() {
Mike Reed30301c42018-07-19 09:39:21 -0400275 if (fAddedToRasterCache.load()) {
fmalita3b0d5322015-09-18 08:07:31 -0700276 SkNotifyBitmapGenIDIsStale(this->uniqueID());
277 }
278}
279
Brian Salomon63a0a752020-06-26 13:32:09 -0400280void SkImage_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
281 const SkIRect& origSrcRect,
282 RescaleGamma rescaleGamma,
283 SkFilterQuality rescaleQuality,
284 ReadPixelsCallback callback,
285 ReadPixelsContext context) {
286 SkBitmap src;
287 SkPixmap peek;
288 SkIRect srcRect;
289 if (this->peekPixels(&peek)) {
290 src.installPixels(peek);
291 srcRect = origSrcRect;
292 } else {
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400293 // Context TODO: Elevate GrDirectContext requirement to public API.
294 auto dContext = as_IB(this)->directContext();
Brian Salomon63a0a752020-06-26 13:32:09 -0400295 src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size()));
296 src.allocPixels();
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400297 if (!this->readPixels(dContext, src.pixmap(), origSrcRect.x(), origSrcRect.y())) {
Brian Salomon63a0a752020-06-26 13:32:09 -0400298 callback(context, nullptr);
299 return;
300 }
301 srcRect = SkIRect::MakeSize(src.dimensions());
302 }
303 return SkRescaleAndReadPixels(
304 src, info, srcRect, rescaleGamma, rescaleQuality, callback, context);
305}
306
307void SkImage_Base::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace,
308 sk_sp<SkColorSpace> dstColorSpace,
309 const SkIRect& srcRect,
310 const SkISize& dstSize,
311 RescaleGamma,
312 SkFilterQuality,
313 ReadPixelsCallback callback,
314 ReadPixelsContext context) {
315 // TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and
316 // call client's callback.
317 callback(context, nullptr);
318}
319
Robert Phillips8caf85f2018-04-05 09:30:38 -0400320GrBackendTexture SkImage_Base::onGetBackendTexture(bool flushPendingGrContextIO,
321 GrSurfaceOrigin* origin) const {
322 return GrBackendTexture(); // invalid
323}
324
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400325GrDirectContext* SkImage_Base::directContext() const {
326#if SK_SUPPORT_GPU
327 return GrAsDirectContext(this->context());
328#else
329 return nullptr;
330#endif
reed871872f2015-06-22 12:48:26 -0700331}
332
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400333bool SkImage::readPixels(GrDirectContext* dContext, const SkPixmap& pmap, int srcX, int srcY,
334 CachingHint chint) const {
335 return this->readPixels(dContext, pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX,
336 srcY, chint);
337}
338
339#ifndef SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API
340bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const {
341 auto dContext = as_IB(this)->directContext();
342 return this->readPixels(dContext, pmap, srcX, srcY, chint);
343}
344#endif
345
reed871872f2015-06-22 12:48:26 -0700346///////////////////////////////////////////////////////////////////////////////////////////////////
reedf803da12015-01-23 05:58:07 -0800347
reed7fb4f8b2016-03-11 04:33:52 -0800348sk_sp<SkImage> SkImage::MakeFromBitmap(const SkBitmap& bm) {
Brian Osman41ba8262018-10-19 14:56:26 -0400349 if (!bm.pixelRef()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700350 return nullptr;
reed56179002015-07-07 06:11:19 -0700351 }
352
reed1ec04d92016-08-05 12:07:41 -0700353 return SkMakeImageFromRasterBitmap(bm, kIfMutable_SkCopyPixelsMode);
reed56179002015-07-07 06:11:19 -0700354}
355
Cary Clark4f5a79c2018-02-07 15:51:00 -0500356bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode ) const {
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400357 // Context TODO: Elevate GrDirectContext requirement to public API.
358 auto dContext = as_IB(this)->directContext();
359 return as_IB(this)->onAsLegacyBitmap(dContext, bitmap);
reed3c065112015-07-08 12:46:22 -0700360}
361
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400362bool SkImage_Base::onAsLegacyBitmap(GrDirectContext* dContext, SkBitmap* bitmap) const {
reed3c065112015-07-08 12:46:22 -0700363 // As the base-class, all we can do is make a copy (regardless of mode).
364 // Subclasses that want to be more optimal should override.
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400365 SkImageInfo info = fInfo.makeColorType(kN32_SkColorType).makeColorSpace(nullptr);
reed3c065112015-07-08 12:46:22 -0700366 if (!bitmap->tryAllocPixels(info)) {
367 return false;
368 }
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400369
370 if (!this->readPixels(dContext, bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
371 0, 0)) {
reed3c065112015-07-08 12:46:22 -0700372 bitmap->reset();
373 return false;
374 }
375
Cary Clark4f5a79c2018-02-07 15:51:00 -0500376 bitmap->setImmutable();
reed3c065112015-07-08 12:46:22 -0700377 return true;
378}
379
Brian Osman138ea972016-12-16 11:55:18 -0500380sk_sp<SkImage> SkImage::MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions,
Matt Sarette94255d2017-01-09 12:38:59 -0500381 const SkMatrix* matrix, const SkPaint* paint,
382 BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace) {
Mike Reed185130c2017-02-15 15:14:16 -0500383 return MakeFromGenerator(SkImageGenerator::MakeFromPicture(dimensions, std::move(picture),
384 matrix, paint, bitDepth,
385 std::move(colorSpace)));
Matt Sarette94255d2017-01-09 12:38:59 -0500386}
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500387
Adlai Holler247835b2020-07-21 16:50:06 -0400388sk_sp<SkImage> SkImage::makeWithFilter(GrRecordingContext* rContext, const SkImageFilter* filter,
389 const SkIRect& subset, const SkIRect& clipBounds,
390 SkIRect* outSubset, SkIPoint* offset) const {
Robert Phillips27467652019-01-10 16:34:22 -0500391
brianosman04a44d02016-09-21 09:46:57 -0700392 if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) {
393 return nullptr;
394 }
Adlai Holler247835b2020-07-21 16:50:06 -0400395 sk_sp<SkSpecialImage> srcSpecialImage;
Robert Phillipsbc429442019-02-20 08:26:03 -0500396#if SK_SUPPORT_GPU
Adlai Holler247835b2020-07-21 16:50:06 -0400397 auto myContext = as_IB(this)->context();
398 if (myContext && !myContext->priv().matches(rContext)) {
399 return nullptr;
400 }
401 srcSpecialImage = SkSpecialImage::MakeFromImage(rContext, subset,
402 sk_ref_sp(const_cast<SkImage*>(this)));
Robert Phillipsbc429442019-02-20 08:26:03 -0500403#else
Adlai Holler247835b2020-07-21 16:50:06 -0400404 srcSpecialImage = SkSpecialImage::MakeFromImage(nullptr, subset,
405 sk_ref_sp(const_cast<SkImage*>(this)));
Robert Phillipsbc429442019-02-20 08:26:03 -0500406#endif
brianosman04a44d02016-09-21 09:46:57 -0700407 if (!srcSpecialImage) {
408 return nullptr;
409 }
senorblanco5878dbd2016-05-19 14:50:29 -0700410
Hal Canary67b39de2016-11-07 11:47:44 -0500411 sk_sp<SkImageFilterCache> cache(
brianosman04a44d02016-09-21 09:46:57 -0700412 SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize));
Michael Ludwigb4580352019-06-21 16:01:42 -0400413
414 // The filters operate in the local space of the src image, where (0,0) corresponds to the
415 // subset's top left corner. But the clip bounds and any crop rects on the filters are in the
416 // original coordinate system, so configure the CTM to correct crop rects and explicitly adjust
417 // the clip bounds (since it is assumed to already be in image space).
Mike Reed1f607332020-05-21 12:11:27 -0400418 SkImageFilter_Base::Context context(SkMatrix::Translate(-subset.x(), -subset.y()),
Brian Salomon9bd947d2019-10-03 14:57:07 -0400419 clipBounds.makeOffset(-subset.topLeft()),
Michael Ludwige30a4852019-08-14 14:35:42 -0400420 cache.get(), fInfo.colorType(), fInfo.colorSpace(),
421 srcSpecialImage.get());
brianosman2a75e5d2016-09-22 07:15:37 -0700422
Michael Ludwigea071232019-08-26 10:52:15 -0400423 sk_sp<SkSpecialImage> result = as_IFB(filter)->filterImage(context).imageAndOffset(offset);
brianosman04a44d02016-09-21 09:46:57 -0700424 if (!result) {
425 return nullptr;
426 }
senorblanco5878dbd2016-05-19 14:50:29 -0700427
Michael Ludwigb4580352019-06-21 16:01:42 -0400428 // The output image and offset are relative to the subset rectangle, so the offset needs to
429 // be shifted to put it in the correct spot with respect to the original coordinate system
430 offset->fX += subset.x();
431 offset->fY += subset.y();
432
433 // Final clip against the exact clipBounds (the clip provided in the context gets adjusted
434 // to account for pixel-moving filters so doesn't always exactly match when finished). The
435 // clipBounds are translated into the clippedDstRect coordinate space, including the
436 // result->subset() ensures that the result's image pixel origin does not affect results.
437 SkIRect dstRect = result->subset();
438 SkIRect clippedDstRect = dstRect;
Brian Salomon9bd947d2019-10-03 14:57:07 -0400439 if (!clippedDstRect.intersect(clipBounds.makeOffset(result->subset().topLeft() - *offset))) {
brianosman04a44d02016-09-21 09:46:57 -0700440 return nullptr;
441 }
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500442
Michael Ludwigb4580352019-06-21 16:01:42 -0400443 // Adjust the geometric offset if the top-left corner moved as well
444 offset->fX += (clippedDstRect.x() - dstRect.x());
445 offset->fY += (clippedDstRect.y() - dstRect.y());
446 *outSubset = clippedDstRect;
Robert Phillipsa5fdc972017-02-18 16:58:09 -0500447 return result->asImage();
senorblanco5878dbd2016-05-19 14:50:29 -0700448}
449
fmalitaddbbdda2015-08-20 08:47:26 -0700450bool SkImage::isLazyGenerated() const {
451 return as_IB(this)->onIsLazyGenerated();
452}
453
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400454bool SkImage::isAlphaOnly() const { return SkColorTypeIsAlphaOnly(fInfo.colorType()); }
reed9e2ed832016-10-31 05:27:28 -0700455
Adlai Holler3a220172020-07-15 10:37:50 -0400456sk_sp<SkImage> SkImage::makeColorSpace(sk_sp<SkColorSpace> target, GrDirectContext* direct) const {
457 return this->makeColorTypeAndColorSpace(this->colorType(), std::move(target), direct);
Brian Osmanf48c9962019-01-14 11:15:50 -0500458}
459
460sk_sp<SkImage> SkImage::makeColorTypeAndColorSpace(SkColorType targetColorType,
Adlai Holler3a220172020-07-15 10:37:50 -0400461 sk_sp<SkColorSpace> targetColorSpace,
Adlai Holler356bcb62020-08-14 11:09:30 -0400462 GrDirectContext* dContext) const {
Brian Osmanf48c9962019-01-14 11:15:50 -0500463 if (kUnknown_SkColorType == targetColorType || !targetColorSpace) {
464 return nullptr;
465 }
466
Adlai Holler3a220172020-07-15 10:37:50 -0400467#if SK_SUPPORT_GPU
468 auto myContext = as_IB(this)->context();
Adlai Holler3a220172020-07-15 10:37:50 -0400469 // This check is also performed in the subclass, but we do it here for the short-circuit below.
Adlai Holler356bcb62020-08-14 11:09:30 -0400470 if (myContext && !myContext->priv().matches(dContext)) {
Adlai Holler3a220172020-07-15 10:37:50 -0400471 return nullptr;
472 }
473#endif
474
Brian Osmanf48c9962019-01-14 11:15:50 -0500475 SkColorType colorType = this->colorType();
476 SkColorSpace* colorSpace = this->colorSpace();
477 if (!colorSpace) {
478 colorSpace = sk_srgb_singleton();
479 }
480 if (colorType == targetColorType &&
481 (SkColorSpace::Equals(colorSpace, targetColorSpace.get()) || this->isAlphaOnly())) {
482 return sk_ref_sp(const_cast<SkImage*>(this));
483 }
484
Adlai Holler3a220172020-07-15 10:37:50 -0400485 return as_IB(this)->onMakeColorTypeAndColorSpace(targetColorType,
Adlai Holler356bcb62020-08-14 11:09:30 -0400486 std::move(targetColorSpace), dContext);
Matt Sarett6de13102017-03-14 14:10:48 -0400487}
488
Brian Osmand5148372019-08-14 16:14:51 -0400489sk_sp<SkImage> SkImage::reinterpretColorSpace(sk_sp<SkColorSpace> target) const {
490 if (!target) {
491 return nullptr;
492 }
493
494 // No need to create a new image if:
495 // (1) The color spaces are equal.
496 // (2) The color type is kAlpha8.
497 SkColorSpace* colorSpace = this->colorSpace();
498 if (!colorSpace) {
499 colorSpace = sk_srgb_singleton();
500 }
501 if (SkColorSpace::Equals(colorSpace, target.get()) || this->isAlphaOnly()) {
502 return sk_ref_sp(const_cast<SkImage*>(this));
503 }
504
505 return as_IB(this)->onReinterpretColorSpace(std::move(target));
506}
507
Mike Reedb950b592018-01-02 10:16:12 -0500508sk_sp<SkImage> SkImage::makeNonTextureImage() const {
509 if (!this->isTextureBacked()) {
510 return sk_ref_sp(const_cast<SkImage*>(this));
511 }
512 return this->makeRasterImage();
513}
514
Brian Osmana88cab12020-01-09 10:21:44 -0500515sk_sp<SkImage> SkImage::makeRasterImage(CachingHint chint) const {
Mike Reedf7ee95c2017-12-04 14:27:01 -0500516 SkPixmap pm;
517 if (this->peekPixels(&pm)) {
518 return sk_ref_sp(const_cast<SkImage*>(this));
519 }
520
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400521 const size_t rowBytes = fInfo.minRowBytes();
522 size_t size = fInfo.computeByteSize(rowBytes);
Mike Reedf7ee95c2017-12-04 14:27:01 -0500523 if (SkImageInfo::ByteSizeOverflowed(size)) {
524 return nullptr;
525 }
526
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400527 // Context TODO: Elevate GrDirectContext requirement to public API.
528 auto dContext = as_IB(this)->directContext();
Mike Reedf7ee95c2017-12-04 14:27:01 -0500529 sk_sp<SkData> data = SkData::MakeUninitialized(size);
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400530 pm = {fInfo.makeColorSpace(nullptr), data->writable_data(), fInfo.minRowBytes()};
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400531 if (!this->readPixels(dContext, pm, 0, 0, chint)) {
Mike Reedf7ee95c2017-12-04 14:27:01 -0500532 return nullptr;
533 }
534
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400535 return SkImage::MakeRasterData(fInfo, std::move(data), rowBytes);
Mike Reedf7ee95c2017-12-04 14:27:01 -0500536}
537
reed56179002015-07-07 06:11:19 -0700538//////////////////////////////////////////////////////////////////////////////////////
539
reed8b26b992015-05-07 15:36:17 -0700540#if !SK_SUPPORT_GPU
541
Adlai Holler14dc7912020-08-11 15:48:49 +0000542sk_sp<SkImage> SkImage::MakeFromTexture(GrRecordingContext*,
543 const GrBackendTexture&, GrSurfaceOrigin,
544 SkColorType, SkAlphaType, sk_sp<SkColorSpace>,
545 TextureReleaseProc, ReleaseContext) {
Greg Daniel94403452017-04-18 15:52:36 -0400546 return nullptr;
547}
548
Adlai Holler14dc7912020-08-11 15:48:49 +0000549sk_sp<SkImage> SkImage::MakeFromCompressedTexture(GrRecordingContext*,
550 const GrBackendTexture&,
551 GrSurfaceOrigin,
552 SkAlphaType,
553 sk_sp<SkColorSpace>,
554 TextureReleaseProc,
555 ReleaseContext) {
Robert Phillipsb915c942019-12-17 14:44:37 -0500556 return nullptr;
557}
558
Adlai Hollerb2705682020-10-20 10:11:53 -0400559bool SkImage::MakeBackendTextureFromSkImage(GrDirectContext*,
Eric Karl914a36b2017-10-12 12:44:50 -0700560 sk_sp<SkImage>,
561 GrBackendTexture*,
562 BackendTextureReleaseProc*) {
563 return false;
564}
565
Adlai Hollerf7129fc2020-08-04 14:07:40 -0400566sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrRecordingContext*,
Adlai Hollere34b2822020-07-29 12:50:56 -0400567 const GrBackendTexture&, GrSurfaceOrigin,
568 SkColorType, SkAlphaType,
569 sk_sp<SkColorSpace>) {
Greg Danielf5d87582017-12-18 14:48:15 -0500570 return nullptr;
571}
572
Brian Salomonc2a9a972020-09-15 11:24:28 -0400573sk_sp<SkImage> SkImage::MakeFromYUVAPixmaps(GrRecordingContext* context,
574 const SkYUVAPixmaps& pixmaps,
575 GrMipMapped buildMips,
576 bool limitToMaxTextureSize,
577 sk_sp<SkColorSpace> imageColorSpace) {
578 return nullptr;
579}
580
Brian Salomon7e67dca2020-07-21 09:27:25 -0400581sk_sp<SkImage> SkImage::makeTextureImage(GrDirectContext*, GrMipmapped, SkBudgeted) const {
Adlai Holler4caa9352020-07-16 10:58:58 -0400582 return nullptr;
583}
Adlai Hollerc0ca8562020-07-28 10:23:33 -0400584
reed7fb4f8b2016-03-11 04:33:52 -0800585#endif
586
587///////////////////////////////////////////////////////////////////////////////////////////////////
588
Adlai Holler29405382020-07-20 16:02:05 -0400589bool SkImage_pinAsTexture(const SkImage* image, GrRecordingContext* rContext) {
reed2d5b7142016-08-17 11:12:33 -0700590 SkASSERT(image);
Adlai Holler29405382020-07-20 16:02:05 -0400591 SkASSERT(rContext);
592 return as_IB(image)->onPinAsTexture(rContext);
reed2d5b7142016-08-17 11:12:33 -0700593}
594
Adlai Holler29405382020-07-20 16:02:05 -0400595void SkImage_unpinAsTexture(const SkImage* image, GrRecordingContext* rContext) {
reed2d5b7142016-08-17 11:12:33 -0700596 SkASSERT(image);
Adlai Holler29405382020-07-20 16:02:05 -0400597 SkASSERT(rContext);
598 as_IB(image)->onUnpinAsTexture(rContext);
reed2d5b7142016-08-17 11:12:33 -0700599}
Brian Osman0d4ff6c2017-01-17 16:10:07 -0500600
Mike Reed2fe15692020-07-14 11:29:38 -0400601///////////////////////////////////////////////////////////////////////////////////////////////////
602
603SkMipmapBuilder::SkMipmapBuilder(const SkImageInfo& info) {
Mike Reed13711eb2020-07-14 17:16:32 -0400604 fMM = sk_sp<SkMipmap>(SkMipmap::Build({info, nullptr, 0}, nullptr, false));
Mike Reed2fe15692020-07-14 11:29:38 -0400605}
606
607SkMipmapBuilder::~SkMipmapBuilder() {}
608
609int SkMipmapBuilder::countLevels() const {
610 return fMM ? fMM->countLevels() : 0;
611}
612
613SkPixmap SkMipmapBuilder::level(int index) const {
614 SkPixmap pm;
615
Mike Reed13711eb2020-07-14 17:16:32 -0400616 SkMipmap::Level level;
Mike Reed2fe15692020-07-14 11:29:38 -0400617 if (fMM && fMM->getLevel(index, &level)) {
618 pm = level.fPixmap;
619 }
620 return pm;
621}
622
Mike Reed2fe15692020-07-14 11:29:38 -0400623bool SkImage::hasMipmaps() const {
624 return as_IB(this)->onPeekMips() != nullptr;
625}
626
Mike Reed15292952020-07-25 12:47:14 -0400627sk_sp<SkImage> SkImage::withMipmaps(sk_sp<SkMipmap> mips) const {
628 if (mips == nullptr || mips->validForRootLevel(this->imageInfo())) {
629 if (auto result = as_IB(this)->onMakeWithMipmaps(std::move(mips))) {
630 return result;
631 }
Mike Reed2fe15692020-07-14 11:29:38 -0400632 }
Mike Reed15292952020-07-25 12:47:14 -0400633 return sk_ref_sp((const_cast<SkImage*>(this)));
Mike Reed2fe15692020-07-14 11:29:38 -0400634}
Mike Reed186866c2020-09-12 10:38:32 -0400635
636sk_sp<SkImage> SkImage::withDefaultMipmaps() const {
637 return this->withMipmaps(nullptr);
638}
Mike Reedb4aa6392020-09-17 13:58:26 -0400639
640sk_sp<SkImage> SkMipmapBuilder::attachTo(const SkImage* src) {
641 return src->withMipmaps(fMM);
642}
Mike Reedcae335d2020-11-13 14:32:04 -0500643
Mike Reed9a275662020-12-26 21:48:57 -0500644SkSamplingOptions::SkSamplingOptions(SkFilterQuality fq, MediumBehavior behavior) {
Mike Reedcae335d2020-11-13 14:32:04 -0500645 switch (fq) {
Mike Reedcae335d2020-11-13 14:32:04 -0500646 case SkFilterQuality::kHigh_SkFilterQuality:
Mike Kleindcc89602020-12-02 15:06:15 -0600647 *this = SkSamplingOptions(SkCubicResampler{1/3.0f, 1/3.0f});
Mike Reeda03f8bf2020-11-20 18:45:36 -0500648 break;
649 case SkFilterQuality::kMedium_SkFilterQuality:
Mike Reed9a275662020-12-26 21:48:57 -0500650 *this = SkSamplingOptions(SkFilterMode::kLinear,
651 behavior == kMedium_asMipmapNearest ? SkMipmapMode::kNearest
652 : SkMipmapMode::kLinear);
Mike Reeda03f8bf2020-11-20 18:45:36 -0500653 break;
654 case SkFilterQuality::kLow_SkFilterQuality:
Mike Kleindcc89602020-12-02 15:06:15 -0600655 *this = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
Mike Reeda03f8bf2020-11-20 18:45:36 -0500656 break;
Mike Reedcae335d2020-11-13 14:32:04 -0500657 case SkFilterQuality::kNone_SkFilterQuality:
Mike Kleindcc89602020-12-02 15:06:15 -0600658 *this = SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
Mike Reeda03f8bf2020-11-20 18:45:36 -0500659 break;
Mike Reedcae335d2020-11-13 14:32:04 -0500660 }
Mike Reedcae335d2020-11-13 14:32:04 -0500661}