blob: 5611900e7eb7bb0cbbea6ba6f4d8efe6f64b1b33 [file] [log] [blame]
senorblanco@chromium.org53333002013-12-12 23:28:52 +00001/*
2 * Copyright 2013 The Android Open Source Project
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 "SkPictureImageFilter.h"
robertphillipsfef28602016-04-11 11:08:52 -07009
senorblanco@chromium.org53333002013-12-12 23:28:52 +000010#include "SkCanvas.h"
Matt Sarette22a6a22017-04-12 16:26:21 -040011#include "SkColorSpaceXformCanvas.h"
12#include "SkColorSpaceXformer.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkReadBuffer.h"
robertphillipsfef28602016-04-11 11:08:52 -070014#include "SkSpecialImage.h"
15#include "SkSpecialSurface.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000016#include "SkWriteBuffer.h"
senorblanco@chromium.org53333002013-12-12 23:28:52 +000017#include "SkValidationUtils.h"
18
robertphillips225db442016-04-17 14:27:05 -070019sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture) {
20 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture)));
21}
22
23sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture,
24 const SkRect& cropRect) {
Ben Wagner63fd7602017-10-09 15:45:33 -040025 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture),
robertphillips225db442016-04-17 14:27:05 -070026 cropRect,
27 kDeviceSpace_PictureResolution,
Matt Sarette22a6a22017-04-12 16:26:21 -040028 kLow_SkFilterQuality,
29 nullptr));
robertphillips225db442016-04-17 14:27:05 -070030}
31
robertphillips5ff17b12016-03-28 13:13:42 -070032SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture)
robertphillips372177e2016-03-30 07:32:28 -070033 : INHERITED(nullptr, 0, nullptr)
robertphillips5ff17b12016-03-28 13:13:42 -070034 , fPicture(std::move(picture))
35 , fCropRect(fPicture ? fPicture->cullRect() : SkRect::MakeEmpty())
halcanary9d524f22016-03-29 09:03:52 -070036 , fPictureResolution(kDeviceSpace_PictureResolution)
reed93a12152015-03-16 10:08:34 -070037 , fFilterQuality(kLow_SkFilterQuality) {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000038}
39
robertphillips5ff17b12016-03-28 13:13:42 -070040SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cropRect,
senorblanco24e06d52015-03-18 12:11:33 -070041 PictureResolution pictureResolution,
Matt Sarette22a6a22017-04-12 16:26:21 -040042 SkFilterQuality filterQuality,
43 sk_sp<SkColorSpace> colorSpace)
robertphillips372177e2016-03-30 07:32:28 -070044 : INHERITED(nullptr, 0, nullptr)
robertphillips5ff17b12016-03-28 13:13:42 -070045 , fPicture(std::move(picture))
Justin Novosad52340752014-12-02 14:50:56 -050046 , fCropRect(cropRect)
junovf3c78cc2014-12-09 13:07:22 -080047 , fPictureResolution(pictureResolution)
Matt Sarette22a6a22017-04-12 16:26:21 -040048 , fFilterQuality(filterQuality)
49 , fColorSpace(std::move(colorSpace)) {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000050}
51
reed60c9b582016-04-03 09:11:13 -070052sk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
reedca2622b2016-03-18 07:25:55 -070053 sk_sp<SkPicture> picture;
reed9fa60da2014-08-21 07:59:51 -070054 SkRect cropRect;
55
hendrikw446ee672015-06-16 09:28:37 -070056 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
robertphillipsc4bd39c2015-01-06 09:17:02 -080057 buffer.validate(!buffer.readBool());
hendrikw446ee672015-06-16 09:28:37 -070058 } else {
reed9fa60da2014-08-21 07:59:51 -070059 if (buffer.readBool()) {
reedca2622b2016-03-18 07:25:55 -070060 picture = SkPicture::MakeFromBuffer(buffer);
reed9fa60da2014-08-21 07:59:51 -070061 }
reed9fa60da2014-08-21 07:59:51 -070062 }
63 buffer.readRect(&cropRect);
64
Mike Reed77e487d2017-11-09 21:50:20 +000065 // NOTE: these two fields can be removed from the class once we have out-lived the need
66 // to load pictures older than SkReadBuffer::kRemovePictureImageFilterLocalSpace
67 //
68 PictureResolution pictureResolution = kDeviceSpace_PictureResolution;
69 SkFilterQuality filterQuality = kNone_SkFilterQuality;
70
71 if (buffer.isVersionLT(SkReadBuffer::kRemovePictureImageFilterLocalSpace)) {
72 pictureResolution = (PictureResolution)buffer.readInt();
73 if (kLocalSpace_PictureResolution == pictureResolution) {
74 //filterLevel is only serialized if pictureResolution is LocalSpace
75 filterQuality = (SkFilterQuality)buffer.readInt();
76 }
Justin Novosad52340752014-12-02 14:50:56 -050077 }
Mike Reed77e487d2017-11-09 21:50:20 +000078 return sk_sp<SkImageFilter>(new SkPictureImageFilter(picture,
79 cropRect,
80 pictureResolution,
81 filterQuality,
82 nullptr));
reed9fa60da2014-08-21 07:59:51 -070083}
senorblanco@chromium.org53333002013-12-12 23:28:52 +000084
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000085void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
hendrikw446ee672015-06-16 09:28:37 -070086 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
robertphillipsc4bd39c2015-01-06 09:17:02 -080087 buffer.writeBool(false);
hendrikw446ee672015-06-16 09:28:37 -070088 } else {
halcanary96fcdcc2015-08-27 07:41:13 -070089 bool hasPicture = (fPicture != nullptr);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000090 buffer.writeBool(hasPicture);
91 if (hasPicture) {
92 fPicture->flatten(buffer);
93 }
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +000094 }
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +000095 buffer.writeRect(fCropRect);
senorblanco@chromium.org53333002013-12-12 23:28:52 +000096}
97
robertphillipsfef28602016-04-11 11:08:52 -070098sk_sp<SkSpecialImage> SkPictureImageFilter::onFilterImage(SkSpecialImage* source,
99 const Context& ctx,
100 SkIPoint* offset) const {
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000101 if (!fPicture) {
robertphillipsfef28602016-04-11 11:08:52 -0700102 return nullptr;
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000103 }
104
105 SkRect floatBounds;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000106 ctx.ctm().mapRect(&floatBounds, fCropRect);
reedb07a94f2014-11-19 05:03:18 -0800107 SkIRect bounds = floatBounds.roundOut();
senorblanco3d822c22014-07-30 14:49:31 -0700108 if (!bounds.intersect(ctx.clipBounds())) {
robertphillipsfef28602016-04-11 11:08:52 -0700109 return nullptr;
senorblanco3d822c22014-07-30 14:49:31 -0700110 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000111
robertphillipsfef28602016-04-11 11:08:52 -0700112 SkASSERT(!bounds.isEmpty());
113
brianosmaneed6b0e2016-09-23 13:04:05 -0700114 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
robertphillipsfef28602016-04-11 11:08:52 -0700115 if (!surf) {
116 return nullptr;
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000117 }
118
robertphillipsfef28602016-04-11 11:08:52 -0700119 SkCanvas* canvas = surf->getCanvas();
120 SkASSERT(canvas);
robertphillipsfef28602016-04-11 11:08:52 -0700121 canvas->clear(0x0);
122
robertphillips0b7e5a12016-04-13 07:18:41 -0700123 if (kDeviceSpace_PictureResolution == fPictureResolution ||
junovf3c78cc2014-12-09 13:07:22 -0800124 0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
robertphillips0b7e5a12016-04-13 07:18:41 -0700125 this->drawPictureAtDeviceResolution(canvas, bounds, ctx);
Justin Novosad52340752014-12-02 14:50:56 -0500126 } else {
robertphillipsfef28602016-04-11 11:08:52 -0700127 this->drawPictureAtLocalResolution(source, canvas, bounds, ctx);
Justin Novosad52340752014-12-02 14:50:56 -0500128 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000129
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000130 offset->fX = bounds.fLeft;
131 offset->fY = bounds.fTop;
robertphillipsfef28602016-04-11 11:08:52 -0700132 return surf->makeImageSnapshot();
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000133}
Justin Novosad52340752014-12-02 14:50:56 -0500134
Matt Sarette22a6a22017-04-12 16:26:21 -0400135sk_sp<SkImageFilter> SkPictureImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
Florin Malitaa252c662017-07-10 12:27:52 -0400136 sk_sp<SkColorSpace> dstCS = xformer->dst();
Florin Malita604f0d52017-07-13 14:29:12 -0400137 if (SkColorSpace::Equals(dstCS.get(), fColorSpace.get())) {
Florin Malitaa252c662017-07-10 12:27:52 -0400138 return this->refMe();
139 }
140
Matt Sarette22a6a22017-04-12 16:26:21 -0400141 return sk_sp<SkImageFilter>(new SkPictureImageFilter(fPicture, fCropRect, fPictureResolution,
Florin Malitaa252c662017-07-10 12:27:52 -0400142 fFilterQuality, std::move(dstCS)));
Matt Sarette22a6a22017-04-12 16:26:21 -0400143}
144
robertphillipsfef28602016-04-11 11:08:52 -0700145void SkPictureImageFilter::drawPictureAtDeviceResolution(SkCanvas* canvas,
Justin Novosad52340752014-12-02 14:50:56 -0500146 const SkIRect& deviceBounds,
147 const Context& ctx) const {
Christopher Cameroneb0e60f2017-05-31 13:47:09 -0700148 std::unique_ptr<SkCanvas> xformCanvas = nullptr;
149 if (fColorSpace) {
150 // Only non-null in the case where onMakeColorSpace() was called. This instructs
151 // us to do the color space xform on playback.
152 xformCanvas = SkCreateColorSpaceXformCanvas(canvas, fColorSpace);
153 canvas = xformCanvas.get();
154 }
robertphillipsfef28602016-04-11 11:08:52 -0700155 canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
156 canvas->concat(ctx.ctm());
157 canvas->drawPicture(fPicture);
Justin Novosad52340752014-12-02 14:50:56 -0500158}
159
robertphillipsfef28602016-04-11 11:08:52 -0700160void SkPictureImageFilter::drawPictureAtLocalResolution(SkSpecialImage* source,
161 SkCanvas* canvas,
Justin Novosad52340752014-12-02 14:50:56 -0500162 const SkIRect& deviceBounds,
163 const Context& ctx) const {
164 SkMatrix inverseCtm;
robertphillipsefbffed2015-06-22 12:06:08 -0700165 if (!ctx.ctm().invert(&inverseCtm)) {
Justin Novosad52340752014-12-02 14:50:56 -0500166 return;
robertphillipsefbffed2015-06-22 12:06:08 -0700167 }
168
Justin Novosad52340752014-12-02 14:50:56 -0500169 SkRect localBounds = SkRect::Make(ctx.clipBounds());
170 inverseCtm.mapRect(&localBounds);
robertphillipsefbffed2015-06-22 12:06:08 -0700171 if (!localBounds.intersect(fCropRect)) {
Justin Novosad52340752014-12-02 14:50:56 -0500172 return;
robertphillipsefbffed2015-06-22 12:06:08 -0700173 }
Justin Novosad52340752014-12-02 14:50:56 -0500174 SkIRect localIBounds = localBounds.roundOut();
Justin Novosad52340752014-12-02 14:50:56 -0500175
robertphillipsfef28602016-04-11 11:08:52 -0700176 sk_sp<SkSpecialImage> localImg;
Ben Wagner63fd7602017-10-09 15:45:33 -0400177 {
brianosmaneed6b0e2016-09-23 13:04:05 -0700178 sk_sp<SkSpecialSurface> localSurface(source->makeSurface(ctx.outputProperties(),
179 localIBounds.size()));
robertphillipsfef28602016-04-11 11:08:52 -0700180 if (!localSurface) {
181 return;
182 }
Justin Novosad52340752014-12-02 14:50:56 -0500183
robertphillipsfef28602016-04-11 11:08:52 -0700184 SkCanvas* localCanvas = localSurface->getCanvas();
185 SkASSERT(localCanvas);
Christopher Cameron92eaad62017-05-22 23:12:01 -0700186 std::unique_ptr<SkCanvas> xformCanvas = nullptr;
187 if (fColorSpace) {
188 // Only non-null in the case where onMakeColorSpace() was called. This instructs
189 // us to do the color space xform on playback.
190 xformCanvas = SkCreateColorSpaceXformCanvas(localCanvas, fColorSpace);
191 localCanvas = xformCanvas.get();
192 }
193
ericrka31312c2016-05-12 09:06:44 -0700194 localCanvas->clear(0x0);
robertphillipsfef28602016-04-11 11:08:52 -0700195
196 localCanvas->translate(-SkIntToScalar(localIBounds.fLeft),
197 -SkIntToScalar(localIBounds.fTop));
198 localCanvas->drawPicture(fPicture);
199
200 localImg = localSurface->makeImageSnapshot();
201 SkASSERT(localImg);
202 }
203
204 {
205 canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
206 canvas->concat(ctx.ctm());
207 SkPaint paint;
208 paint.setFilterQuality(fFilterQuality);
209
210 localImg->draw(canvas,
211 SkIntToScalar(localIBounds.fLeft),
212 SkIntToScalar(localIBounds.fTop),
213 &paint);
214 }
Justin Novosad52340752014-12-02 14:50:56 -0500215}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800216
217#ifndef SK_IGNORE_TO_STRING
218void SkPictureImageFilter::toString(SkString* str) const {
219 str->appendf("SkPictureImageFilter: (");
halcanary9d524f22016-03-29 09:03:52 -0700220 str->appendf("crop: (%f,%f,%f,%f) ",
robertphillipsf3f5bad2014-12-19 13:49:15 -0800221 fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
222 if (fPicture) {
223 str->appendf("picture: (%f,%f,%f,%f)",
224 fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
225 fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
226 }
227 str->append(")");
228}
229#endif