blob: cce9a42299fd9e8b3a6beebd6c4020fe9999db99 [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"
Brian Salomond0924f32021-02-03 10:15:31 -050036#include "src/gpu/GrRecordingContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050037#include "src/image/SkImage_Gpu.h"
bsalomon55812362015-06-10 08:49:28 -070038#endif
Mike Kleinc0bd9f92019-04-23 12:05:21 -050039#include "include/gpu/GrBackendSurface.h"
Adlai Hollerc44e21f2021-02-22 14:08:07 -050040#include "include/gpu/GrContextThreadSafeProxy.h"
scroggo@google.com7def5e12013-05-31 14:00:10 +000041
Brian Salomon5ad6fd32019-03-21 15:30:08 -040042SkImage::SkImage(const SkImageInfo& info, uint32_t uniqueID)
43 : fInfo(info)
44 , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID) {
45 SkASSERT(info.width() > 0);
46 SkASSERT(info.height() > 0);
reed@google.comf6627b72012-07-27 18:02:50 +000047}
48
reed6ceeebd2016-03-09 14:26:26 -080049bool SkImage::peekPixels(SkPixmap* pm) const {
50 SkPixmap tmp;
51 if (!pm) {
52 pm = &tmp;
reed@google.com4f7c6152014-02-06 14:11:56 +000053 }
reed6ceeebd2016-03-09 14:26:26 -080054 return as_IB(this)->onPeekPixels(pm);
reed@google.com4f7c6152014-02-06 14:11:56 +000055}
56
Adlai Hollerbcfc5542020-08-27 12:44:07 -040057bool SkImage::readPixels(GrDirectContext* dContext, const SkImageInfo& dstInfo, void* dstPixels,
58 size_t dstRowBytes, int srcX, int srcY, CachingHint chint) const {
59 return as_IB(this)->onReadPixels(dContext, dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
reed09553032015-11-23 12:32:16 -080060}
61
Adlai Hollerbcfc5542020-08-27 12:44:07 -040062#ifndef SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API
63bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels,
64 size_t dstRowBytes, int srcX, int srcY, CachingHint chint) const {
65 auto dContext = as_IB(this)->directContext();
66 return this->readPixels(dContext, dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
67}
68#endif
69
Brian Salomon63a0a752020-06-26 13:32:09 -040070void SkImage::asyncRescaleAndReadPixels(const SkImageInfo& info,
71 const SkIRect& srcRect,
72 RescaleGamma rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -050073 RescaleMode rescaleMode,
Brian Salomon63a0a752020-06-26 13:32:09 -040074 ReadPixelsCallback callback,
75 ReadPixelsContext context) {
76 if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) ||
77 !SkImageInfoIsValid(info)) {
78 callback(context, nullptr);
79 return;
80 }
81 as_IB(this)->onAsyncRescaleAndReadPixels(
Mike Reed1efa14d2021-01-02 21:44:59 -050082 info, srcRect, rescaleGamma, rescaleMode, callback, context);
Brian Salomon63a0a752020-06-26 13:32:09 -040083}
84
85void SkImage::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
86 sk_sp<SkColorSpace> dstColorSpace,
87 const SkIRect& srcRect,
88 const SkISize& dstSize,
89 RescaleGamma rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -050090 RescaleMode rescaleMode,
Brian Salomon63a0a752020-06-26 13:32:09 -040091 ReadPixelsCallback callback,
92 ReadPixelsContext context) {
93 if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || dstSize.isZero() ||
94 (dstSize.width() & 0b1) || (dstSize.height() & 0b1)) {
95 callback(context, nullptr);
96 return;
97 }
98 as_IB(this)->onAsyncRescaleAndReadPixelsYUV420(yuvColorSpace,
99 std::move(dstColorSpace),
100 srcRect,
101 dstSize,
102 rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -0500103 rescaleMode,
Brian Salomon63a0a752020-06-26 13:32:09 -0400104 callback,
105 context);
106}
107
Mike Reedce0c8762020-11-23 17:41:35 -0500108bool SkImage::scalePixels(const SkPixmap& dst, const SkSamplingOptions& sampling,
109 CachingHint chint) const {
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400110 // Context TODO: Elevate GrDirectContext requirement to public API.
111 auto dContext = as_IB(this)->directContext();
reed6868c3f2015-11-24 11:44:47 -0800112 if (this->width() == dst.width() && this->height() == dst.height()) {
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400113 return this->readPixels(dContext, dst, 0, 0, chint);
reed6868c3f2015-11-24 11:44:47 -0800114 }
115
reed09553032015-11-23 12:32:16 -0800116 // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself
117 // can scale more efficiently) we should take advantage of it here.
118 //
119 SkBitmap bm;
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400120 if (as_IB(this)->getROPixels(dContext, &bm, chint)) {
reed09553032015-11-23 12:32:16 -0800121 SkPixmap pmap;
122 // Note: By calling the pixmap scaler, we never cache the final result, so the chint
123 // is (currently) only being applied to the getROPixels. If we get a request to
124 // also attempt to cache the final (scaled) result, we would add that logic here.
125 //
Mike Reedce0c8762020-11-23 17:41:35 -0500126 return bm.peekPixels(&pmap) && pmap.scalePixels(dst, sampling);
reed09553032015-11-23 12:32:16 -0800127 }
128 return false;
reed@google.com4f7c6152014-02-06 14:11:56 +0000129}
130
reed88d064d2015-10-12 11:30:02 -0700131///////////////////////////////////////////////////////////////////////////////////////////////////
132
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400133SkColorType SkImage::colorType() const { return fInfo.colorType(); }
Greg Daniel56008aa2018-03-14 15:33:42 -0400134
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400135SkAlphaType SkImage::alphaType() const { return fInfo.alphaType(); }
brianosman69c166d2016-08-17 14:01:05 -0700136
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400137SkColorSpace* SkImage::colorSpace() const { return fInfo.colorSpace(); }
Matt Sarett5b4599f2017-03-02 12:42:35 -0500138
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400139sk_sp<SkColorSpace> SkImage::refColorSpace() const { return fInfo.refColorSpace(); }
Matt Sarett5b4599f2017-03-02 12:42:35 -0500140
Mike Reed9290d012020-06-11 16:56:06 -0400141sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
Mike Reed74c51ac2020-11-20 10:23:58 -0500142 const SkSamplingOptions& sampling,
Mike Reedf8a6b5b2020-07-10 08:36:42 -0400143 const SkMatrix* localMatrix) const {
144 return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy,
Mike Reed225cdea2021-03-18 22:19:44 -0400145 sampling, localMatrix);
Mike Reedf8a6b5b2020-07-10 08:36:42 -0400146}
147
Mike Reed6409f842017-07-11 16:03:13 -0400148sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const {
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400149 // Context TODO: Elevate GrDirectContext requirement to public API.
150 auto dContext = as_IB(this)->directContext();
Leon Scroggins294c1c42016-11-08 14:29:46 +0000151 SkBitmap bm;
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400152 if (as_IB(this)->getROPixels(dContext, &bm)) {
Mike Reed25eef6b2017-12-08 16:20:58 -0500153 return SkEncodeBitmap(bm, type, quality);
Leon Scroggins294c1c42016-11-08 14:29:46 +0000154 }
155 return nullptr;
156}
157
Mike Reedef038482017-12-16 08:41:28 -0500158sk_sp<SkData> SkImage::encodeToData() const {
159 if (auto encoded = this->refEncodedData()) {
Mike Reed6409f842017-07-11 16:03:13 -0400160 return encoded;
fmalita2be71252015-09-03 07:17:25 -0700161 }
162
Brian Osmane50cdf02018-10-19 13:02:14 -0400163 return this->encodeToData(SkEncodedImageFormat::kPNG, 100);
fmalita2be71252015-09-03 07:17:25 -0700164}
165
Mike Reed6409f842017-07-11 16:03:13 -0400166sk_sp<SkData> SkImage::refEncodedData() const {
167 return sk_sp<SkData>(as_IB(this)->onRefEncoded());
reed871872f2015-06-22 12:48:26 -0700168}
169
Mike Reed564d49e2020-07-28 12:52:31 -0400170sk_sp<SkImage> SkImage::MakeFromEncoded(sk_sp<SkData> encoded) {
halcanary96fcdcc2015-08-27 07:41:13 -0700171 if (nullptr == encoded || 0 == encoded->size()) {
172 return nullptr;
reed5965c8a2015-01-07 18:04:45 -0800173 }
Mike Reed564d49e2020-07-28 12:52:31 -0400174 return SkImage::MakeFromGenerator(SkImageGenerator::MakeFromEncoded(std::move(encoded)));
reed5965c8a2015-01-07 18:04:45 -0800175}
176
Mike Reed6409f842017-07-11 16:03:13 -0400177///////////////////////////////////////////////////////////////////////////////////////////////////
178
Adlai Holler872a32c2020-07-10 14:33:22 -0400179sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset, GrDirectContext* direct) const {
reed7b6945b2015-09-24 00:50:58 -0700180 if (subset.isEmpty()) {
181 return nullptr;
182 }
183
184 const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
185 if (!bounds.contains(subset)) {
186 return nullptr;
187 }
188
Adlai Holler872a32c2020-07-10 14:33:22 -0400189#if SK_SUPPORT_GPU
190 auto myContext = as_IB(this)->context();
Adlai Holler3a220172020-07-15 10:37:50 -0400191 // 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 -0400192 if (myContext && !myContext->priv().matches(direct)) {
193 return nullptr;
194 }
195#endif
196
reed7b6945b2015-09-24 00:50:58 -0700197 // optimization : return self if the subset == our bounds
198 if (bounds == subset) {
reed7fb4f8b2016-03-11 04:33:52 -0800199 return sk_ref_sp(const_cast<SkImage*>(this));
reed7b6945b2015-09-24 00:50:58 -0700200 }
Robert Phillips6603a172019-03-05 12:35:44 -0500201
Adlai Holler872a32c2020-07-10 14:33:22 -0400202 return as_IB(this)->onMakeSubset(subset, direct);
reedf803da12015-01-23 05:58:07 -0800203}
204
bsalomon55812362015-06-10 08:49:28 -0700205#if SK_SUPPORT_GPU
206
Jim Van Verth21bd60d2018-10-12 15:00:20 -0400207bool SkImage::isTextureBacked() const { return as_IB(this)->onIsTextureBacked(); }
bsalomon55812362015-06-10 08:49:28 -0700208
Brian Salomon650dd082021-02-11 08:59:03 -0500209size_t SkImage::textureSize() const { return as_IB(this)->onTextureSize(); }
210
Robert Phillipsc5509952018-04-04 15:54:55 -0400211GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
212 GrSurfaceOrigin* origin) const {
213 return as_IB(this)->onGetBackendTexture(flushPendingGrContextIO, origin);
214}
Robert Phillipsc5509952018-04-04 15:54:55 -0400215
Adlai Holler01373552020-07-21 13:52:41 -0400216bool SkImage::isValid(GrRecordingContext* rContext) const {
217 if (rContext && rContext->abandoned()) {
Brian Osman5bbd0762017-05-08 11:07:42 -0400218 return false;
219 }
Adlai Holler01373552020-07-21 13:52:41 -0400220 return as_IB(this)->onIsValid(rContext);
Robert Phillips4a3ebc22020-07-10 11:27:43 -0400221}
222
Adlai Holler40ad5fd2020-07-22 10:22:12 -0400223GrSemaphoresSubmitted SkImage::flush(GrDirectContext* dContext, const GrFlushInfo& flushInfo) {
224 return as_IB(this)->onFlush(dContext, flushInfo);
225}
226
227void SkImage::flushAndSubmit(GrDirectContext* dContext) {
228 this->flush(dContext, {});
229 dContext->submit();
230}
231
bsalomon55812362015-06-10 08:49:28 -0700232#else
233
bsalomon55812362015-06-10 08:49:28 -0700234bool SkImage::isTextureBacked() const { return false; }
235
Robert Phillipsc5509952018-04-04 15:54:55 -0400236GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
237 GrSurfaceOrigin* origin) const {
238 return GrBackendTexture(); // invalid
239}
240
Adlai Holler01373552020-07-21 13:52:41 -0400241bool SkImage::isValid(GrRecordingContext* rContext) const {
242 if (rContext) {
Brian Osman5bbd0762017-05-08 11:07:42 -0400243 return false;
244 }
Robert Phillips4a3ebc22020-07-10 11:27:43 -0400245 return as_IB(this)->onIsValid(nullptr);
Brian Osman5bbd0762017-05-08 11:07:42 -0400246}
247
Adlai Holler40ad5fd2020-07-22 10:22:12 -0400248GrSemaphoresSubmitted SkImage::flush(GrDirectContext*, const GrFlushInfo&) {
249 return GrSemaphoresSubmitted::kNo;
250}
251
252void SkImage::flushAndSubmit(GrDirectContext*) {}
253
bsalomon55812362015-06-10 08:49:28 -0700254#endif
255
reed@google.com4f7c6152014-02-06 14:11:56 +0000256///////////////////////////////////////////////////////////////////////////////
257
Brian Salomon5ad6fd32019-03-21 15:30:08 -0400258SkImage_Base::SkImage_Base(const SkImageInfo& info, uint32_t uniqueID)
259 : INHERITED(info, uniqueID), fAddedToRasterCache(false) {}
fmalita3b0d5322015-09-18 08:07:31 -0700260
261SkImage_Base::~SkImage_Base() {
Mike Reed30301c42018-07-19 09:39:21 -0400262 if (fAddedToRasterCache.load()) {
fmalita3b0d5322015-09-18 08:07:31 -0700263 SkNotifyBitmapGenIDIsStale(this->uniqueID());
264 }
265}
266
Brian Salomon63a0a752020-06-26 13:32:09 -0400267void SkImage_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
268 const SkIRect& origSrcRect,
269 RescaleGamma rescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -0500270 RescaleMode rescaleMode,
Brian Salomon63a0a752020-06-26 13:32:09 -0400271 ReadPixelsCallback callback,
272 ReadPixelsContext context) {
273 SkBitmap src;
274 SkPixmap peek;
275 SkIRect srcRect;
276 if (this->peekPixels(&peek)) {
277 src.installPixels(peek);
278 srcRect = origSrcRect;
279 } else {
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400280 // Context TODO: Elevate GrDirectContext requirement to public API.
281 auto dContext = as_IB(this)->directContext();
Brian Salomon63a0a752020-06-26 13:32:09 -0400282 src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size()));
283 src.allocPixels();
Adlai Hollerbcfc5542020-08-27 12:44:07 -0400284 if (!this->readPixels(dContext, src.pixmap(), origSrcRect.x(), origSrcRect.y())) {
Brian Salomon63a0a752020-06-26 13:32:09 -0400285 callback(context, nullptr);
286 return;
287 }
288 srcRect = SkIRect::MakeSize(src.dimensions());
289 }
Mike Reed1efa14d2021-01-02 21:44:59 -0500290 return SkRescaleAndReadPixels(src, info, srcRect, rescaleGamma, rescaleMode, callback, context);
Brian Salomon63a0a752020-06-26 13:32:09 -0400291}
292
293void SkImage_Base::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace,
294 sk_sp<SkColorSpace> dstColorSpace,
295 const SkIRect& srcRect,
296 const SkISize& dstSize,
297 RescaleGamma,
Mike Reed1efa14d2021-01-02 21:44:59 -0500298 RescaleMode,
Brian Salomon63a0a752020-06-26 13:32:09 -0400299 ReadPixelsCallback callback,
300 ReadPixelsContext context) {
301 // TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and
302 // call client's callback.
303 callback(context, nullptr);
304}
305
Brian Salomond0924f32021-02-03 10:15:31 -0500306#if SK_SUPPORT_GPU
307std::tuple<GrSurfaceProxyView, GrColorType> SkImage_Base::asView(GrRecordingContext* context,
308 GrMipmapped mipmapped,
309 GrImageTexGenPolicy policy) const {
310 if (!context) {
311 return {};
312 }
313 if (!context->priv().caps()->mipmapSupport() || this->dimensions().area() <= 1) {
314 mipmapped = GrMipmapped::kNo;
315 }
316 return this->onAsView(context, mipmapped, policy);
317}
318#endif
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
Adlai Hollerc44e21f2021-02-22 14:08:07 -0500585sk_sp<SkImage> SkImage::MakePromiseTexture(sk_sp<GrContextThreadSafeProxy>,
586 const GrBackendFormat&,
587 SkISize,
588 GrMipmapped,
589 GrSurfaceOrigin,
590 SkColorType,
591 SkAlphaType,
592 sk_sp<SkColorSpace>,
593 PromiseImageTextureFulfillProc,
594 PromiseImageTextureReleaseProc,
595 PromiseImageTextureContext) {
596 return nullptr;
597}
598
599sk_sp<SkImage> SkImage::MakePromiseYUVATexture(sk_sp<GrContextThreadSafeProxy>,
600 const GrYUVABackendTextureInfo&,
601 sk_sp<SkColorSpace>,
602 PromiseImageTextureFulfillProc,
603 PromiseImageTextureReleaseProc,
604 PromiseImageTextureContext[]) {
605 return nullptr;
606}
607
reed7fb4f8b2016-03-11 04:33:52 -0800608#endif
609
610///////////////////////////////////////////////////////////////////////////////////////////////////
611
Adlai Holler29405382020-07-20 16:02:05 -0400612bool SkImage_pinAsTexture(const SkImage* image, GrRecordingContext* rContext) {
reed2d5b7142016-08-17 11:12:33 -0700613 SkASSERT(image);
Adlai Holler29405382020-07-20 16:02:05 -0400614 SkASSERT(rContext);
615 return as_IB(image)->onPinAsTexture(rContext);
reed2d5b7142016-08-17 11:12:33 -0700616}
617
Adlai Holler29405382020-07-20 16:02:05 -0400618void SkImage_unpinAsTexture(const SkImage* image, GrRecordingContext* rContext) {
reed2d5b7142016-08-17 11:12:33 -0700619 SkASSERT(image);
Adlai Holler29405382020-07-20 16:02:05 -0400620 SkASSERT(rContext);
621 as_IB(image)->onUnpinAsTexture(rContext);
reed2d5b7142016-08-17 11:12:33 -0700622}
Brian Osman0d4ff6c2017-01-17 16:10:07 -0500623
Mike Reed2fe15692020-07-14 11:29:38 -0400624///////////////////////////////////////////////////////////////////////////////////////////////////
625
626SkMipmapBuilder::SkMipmapBuilder(const SkImageInfo& info) {
Mike Reed13711eb2020-07-14 17:16:32 -0400627 fMM = sk_sp<SkMipmap>(SkMipmap::Build({info, nullptr, 0}, nullptr, false));
Mike Reed2fe15692020-07-14 11:29:38 -0400628}
629
630SkMipmapBuilder::~SkMipmapBuilder() {}
631
632int SkMipmapBuilder::countLevels() const {
633 return fMM ? fMM->countLevels() : 0;
634}
635
636SkPixmap SkMipmapBuilder::level(int index) const {
637 SkPixmap pm;
638
Mike Reed13711eb2020-07-14 17:16:32 -0400639 SkMipmap::Level level;
Mike Reed2fe15692020-07-14 11:29:38 -0400640 if (fMM && fMM->getLevel(index, &level)) {
641 pm = level.fPixmap;
642 }
643 return pm;
644}
645
Brian Salomon7d2757f2021-01-26 17:46:50 -0500646bool SkImage::hasMipmaps() const { return as_IB(this)->onHasMipmaps(); }
Mike Reed2fe15692020-07-14 11:29:38 -0400647
Mike Reed15292952020-07-25 12:47:14 -0400648sk_sp<SkImage> SkImage::withMipmaps(sk_sp<SkMipmap> mips) const {
649 if (mips == nullptr || mips->validForRootLevel(this->imageInfo())) {
650 if (auto result = as_IB(this)->onMakeWithMipmaps(std::move(mips))) {
651 return result;
652 }
Mike Reed2fe15692020-07-14 11:29:38 -0400653 }
Mike Reed15292952020-07-25 12:47:14 -0400654 return sk_ref_sp((const_cast<SkImage*>(this)));
Mike Reed2fe15692020-07-14 11:29:38 -0400655}
Mike Reed186866c2020-09-12 10:38:32 -0400656
657sk_sp<SkImage> SkImage::withDefaultMipmaps() const {
658 return this->withMipmaps(nullptr);
659}
Mike Reedb4aa6392020-09-17 13:58:26 -0400660
661sk_sp<SkImage> SkMipmapBuilder::attachTo(const SkImage* src) {
662 return src->withMipmaps(fMM);
663}
Mike Reedcae335d2020-11-13 14:32:04 -0500664
Mike Reed92236652021-02-01 13:07:32 -0500665//////////////////////////////////////////////////////////////////////////////////////////////////
666
667#include "src/core/SkReadBuffer.h"
668#include "src/core/SkSamplingPriv.h"
669#include "src/core/SkWriteBuffer.h"
670
Mike Reed9a275662020-12-26 21:48:57 -0500671SkSamplingOptions::SkSamplingOptions(SkFilterQuality fq, MediumBehavior behavior) {
Mike Reedcae335d2020-11-13 14:32:04 -0500672 switch (fq) {
Mike Reedcae335d2020-11-13 14:32:04 -0500673 case SkFilterQuality::kHigh_SkFilterQuality:
Mike Kleindcc89602020-12-02 15:06:15 -0600674 *this = SkSamplingOptions(SkCubicResampler{1/3.0f, 1/3.0f});
Mike Reeda03f8bf2020-11-20 18:45:36 -0500675 break;
676 case SkFilterQuality::kMedium_SkFilterQuality:
Mike Reed9a275662020-12-26 21:48:57 -0500677 *this = SkSamplingOptions(SkFilterMode::kLinear,
678 behavior == kMedium_asMipmapNearest ? SkMipmapMode::kNearest
679 : SkMipmapMode::kLinear);
Mike Reeda03f8bf2020-11-20 18:45:36 -0500680 break;
681 case SkFilterQuality::kLow_SkFilterQuality:
Mike Kleindcc89602020-12-02 15:06:15 -0600682 *this = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
Mike Reeda03f8bf2020-11-20 18:45:36 -0500683 break;
Mike Reedcae335d2020-11-13 14:32:04 -0500684 case SkFilterQuality::kNone_SkFilterQuality:
Mike Kleindcc89602020-12-02 15:06:15 -0600685 *this = SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
Mike Reeda03f8bf2020-11-20 18:45:36 -0500686 break;
Mike Reedcae335d2020-11-13 14:32:04 -0500687 }
Mike Reedcae335d2020-11-13 14:32:04 -0500688}
Mike Reed92236652021-02-01 13:07:32 -0500689
690SkSamplingOptions SkSamplingPriv::Read(SkReadBuffer& buffer) {
691 if (buffer.readBool()) {
692 SkScalar B = buffer.readScalar(),
693 C = buffer.readScalar();
694 return SkSamplingOptions({B,C});
695 } else {
696 auto filter = buffer.read32LE<SkFilterMode>(SkFilterMode::kLinear);
697 auto mipmap = buffer.read32LE<SkMipmapMode>(SkMipmapMode::kLinear);
698 return SkSamplingOptions(filter, mipmap);
699 }
700}
701
702void SkSamplingPriv::Write(SkWriteBuffer& buffer, const SkSamplingOptions& sampling) {
703 buffer.writeBool(sampling.useCubic);
704 if (sampling.useCubic) {
705 buffer.writeScalar(sampling.cubic.B);
706 buffer.writeScalar(sampling.cubic.C);
707 } else {
708 buffer.writeUInt((unsigned)sampling.filter);
709 buffer.writeUInt((unsigned)sampling.mipmap);
710 }
711}