blob: 80361aaaed82c44a34884adf0221ab104e96f44c [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) {
25 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture),
26 cropRect,
27 kDeviceSpace_PictureResolution,
Matt Sarette22a6a22017-04-12 16:26:21 -040028 kLow_SkFilterQuality,
29 nullptr));
robertphillips225db442016-04-17 14:27:05 -070030}
31
32sk_sp<SkImageFilter> SkPictureImageFilter::MakeForLocalSpace(sk_sp<SkPicture> picture,
33 const SkRect& cropRect,
34 SkFilterQuality filterQuality) {
35 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture),
36 cropRect,
37 kLocalSpace_PictureResolution,
Matt Sarette22a6a22017-04-12 16:26:21 -040038 filterQuality,
39 nullptr));
robertphillips225db442016-04-17 14:27:05 -070040}
41
robertphillips5ff17b12016-03-28 13:13:42 -070042SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture)
robertphillips372177e2016-03-30 07:32:28 -070043 : INHERITED(nullptr, 0, nullptr)
robertphillips5ff17b12016-03-28 13:13:42 -070044 , fPicture(std::move(picture))
45 , fCropRect(fPicture ? fPicture->cullRect() : SkRect::MakeEmpty())
halcanary9d524f22016-03-29 09:03:52 -070046 , fPictureResolution(kDeviceSpace_PictureResolution)
reed93a12152015-03-16 10:08:34 -070047 , fFilterQuality(kLow_SkFilterQuality) {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000048}
49
robertphillips5ff17b12016-03-28 13:13:42 -070050SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cropRect,
senorblanco24e06d52015-03-18 12:11:33 -070051 PictureResolution pictureResolution,
Matt Sarette22a6a22017-04-12 16:26:21 -040052 SkFilterQuality filterQuality,
53 sk_sp<SkColorSpace> colorSpace)
robertphillips372177e2016-03-30 07:32:28 -070054 : INHERITED(nullptr, 0, nullptr)
robertphillips5ff17b12016-03-28 13:13:42 -070055 , fPicture(std::move(picture))
Justin Novosad52340752014-12-02 14:50:56 -050056 , fCropRect(cropRect)
junovf3c78cc2014-12-09 13:07:22 -080057 , fPictureResolution(pictureResolution)
Matt Sarette22a6a22017-04-12 16:26:21 -040058 , fFilterQuality(filterQuality)
59 , fColorSpace(std::move(colorSpace)) {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000060}
61
reed60c9b582016-04-03 09:11:13 -070062sk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
reedca2622b2016-03-18 07:25:55 -070063 sk_sp<SkPicture> picture;
reed9fa60da2014-08-21 07:59:51 -070064 SkRect cropRect;
65
hendrikw446ee672015-06-16 09:28:37 -070066 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
robertphillipsc4bd39c2015-01-06 09:17:02 -080067 buffer.validate(!buffer.readBool());
hendrikw446ee672015-06-16 09:28:37 -070068 } else {
reed9fa60da2014-08-21 07:59:51 -070069 if (buffer.readBool()) {
reedca2622b2016-03-18 07:25:55 -070070 picture = SkPicture::MakeFromBuffer(buffer);
reed9fa60da2014-08-21 07:59:51 -070071 }
reed9fa60da2014-08-21 07:59:51 -070072 }
73 buffer.readRect(&cropRect);
Mike Reed70bc94f2017-06-08 12:45:52 -040074 PictureResolution pictureResolution = (PictureResolution)buffer.readInt();
reed9fa60da2014-08-21 07:59:51 -070075
junovf3c78cc2014-12-09 13:07:22 -080076 if (kLocalSpace_PictureResolution == pictureResolution) {
77 //filterLevel is only serialized if pictureResolution is LocalSpace
Mike Reed70bc94f2017-06-08 12:45:52 -040078 SkFilterQuality filterQuality = (SkFilterQuality)buffer.readInt();
reed60c9b582016-04-03 09:11:13 -070079 return MakeForLocalSpace(picture, cropRect, filterQuality);
Justin Novosad52340752014-12-02 14:50:56 -050080 }
reed60c9b582016-04-03 09:11:13 -070081 return Make(picture, cropRect);
reed9fa60da2014-08-21 07:59:51 -070082}
senorblanco@chromium.org53333002013-12-12 23:28:52 +000083
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000084void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
hendrikw446ee672015-06-16 09:28:37 -070085 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
robertphillipsc4bd39c2015-01-06 09:17:02 -080086 buffer.writeBool(false);
hendrikw446ee672015-06-16 09:28:37 -070087 } else {
halcanary96fcdcc2015-08-27 07:41:13 -070088 bool hasPicture = (fPicture != nullptr);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000089 buffer.writeBool(hasPicture);
90 if (hasPicture) {
91 fPicture->flatten(buffer);
92 }
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +000093 }
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +000094 buffer.writeRect(fCropRect);
Justin Novosad52340752014-12-02 14:50:56 -050095 buffer.writeInt(fPictureResolution);
junovf3c78cc2014-12-09 13:07:22 -080096 if (kLocalSpace_PictureResolution == fPictureResolution) {
reed93a12152015-03-16 10:08:34 -070097 buffer.writeInt(fFilterQuality);
junovf3c78cc2014-12-09 13:07:22 -080098 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +000099}
100
robertphillipsfef28602016-04-11 11:08:52 -0700101sk_sp<SkSpecialImage> SkPictureImageFilter::onFilterImage(SkSpecialImage* source,
102 const Context& ctx,
103 SkIPoint* offset) const {
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000104 if (!fPicture) {
robertphillipsfef28602016-04-11 11:08:52 -0700105 return nullptr;
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000106 }
107
108 SkRect floatBounds;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000109 ctx.ctm().mapRect(&floatBounds, fCropRect);
reedb07a94f2014-11-19 05:03:18 -0800110 SkIRect bounds = floatBounds.roundOut();
senorblanco3d822c22014-07-30 14:49:31 -0700111 if (!bounds.intersect(ctx.clipBounds())) {
robertphillipsfef28602016-04-11 11:08:52 -0700112 return nullptr;
senorblanco3d822c22014-07-30 14:49:31 -0700113 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000114
robertphillipsfef28602016-04-11 11:08:52 -0700115 SkASSERT(!bounds.isEmpty());
116
brianosmaneed6b0e2016-09-23 13:04:05 -0700117 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
robertphillipsfef28602016-04-11 11:08:52 -0700118 if (!surf) {
119 return nullptr;
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000120 }
121
robertphillipsfef28602016-04-11 11:08:52 -0700122 SkCanvas* canvas = surf->getCanvas();
123 SkASSERT(canvas);
robertphillipsfef28602016-04-11 11:08:52 -0700124 canvas->clear(0x0);
125
robertphillips0b7e5a12016-04-13 07:18:41 -0700126 if (kDeviceSpace_PictureResolution == fPictureResolution ||
junovf3c78cc2014-12-09 13:07:22 -0800127 0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
robertphillips0b7e5a12016-04-13 07:18:41 -0700128 this->drawPictureAtDeviceResolution(canvas, bounds, ctx);
Justin Novosad52340752014-12-02 14:50:56 -0500129 } else {
robertphillipsfef28602016-04-11 11:08:52 -0700130 this->drawPictureAtLocalResolution(source, canvas, bounds, ctx);
Justin Novosad52340752014-12-02 14:50:56 -0500131 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000132
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000133 offset->fX = bounds.fLeft;
134 offset->fY = bounds.fTop;
robertphillipsfef28602016-04-11 11:08:52 -0700135 return surf->makeImageSnapshot();
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000136}
Justin Novosad52340752014-12-02 14:50:56 -0500137
Matt Sarette22a6a22017-04-12 16:26:21 -0400138sk_sp<SkImageFilter> SkPictureImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
Florin Malitaa252c662017-07-10 12:27:52 -0400139 sk_sp<SkColorSpace> dstCS = xformer->dst();
140 if (dstCS == fColorSpace) {
141 return this->refMe();
142 }
143
Matt Sarette22a6a22017-04-12 16:26:21 -0400144 return sk_sp<SkImageFilter>(new SkPictureImageFilter(fPicture, fCropRect, fPictureResolution,
Florin Malitaa252c662017-07-10 12:27:52 -0400145 fFilterQuality, std::move(dstCS)));
Matt Sarette22a6a22017-04-12 16:26:21 -0400146}
147
robertphillipsfef28602016-04-11 11:08:52 -0700148void SkPictureImageFilter::drawPictureAtDeviceResolution(SkCanvas* canvas,
Justin Novosad52340752014-12-02 14:50:56 -0500149 const SkIRect& deviceBounds,
150 const Context& ctx) const {
Christopher Cameroneb0e60f2017-05-31 13:47:09 -0700151 std::unique_ptr<SkCanvas> xformCanvas = nullptr;
152 if (fColorSpace) {
153 // Only non-null in the case where onMakeColorSpace() was called. This instructs
154 // us to do the color space xform on playback.
155 xformCanvas = SkCreateColorSpaceXformCanvas(canvas, fColorSpace);
156 canvas = xformCanvas.get();
157 }
robertphillipsfef28602016-04-11 11:08:52 -0700158 canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
159 canvas->concat(ctx.ctm());
160 canvas->drawPicture(fPicture);
Justin Novosad52340752014-12-02 14:50:56 -0500161}
162
robertphillipsfef28602016-04-11 11:08:52 -0700163void SkPictureImageFilter::drawPictureAtLocalResolution(SkSpecialImage* source,
164 SkCanvas* canvas,
Justin Novosad52340752014-12-02 14:50:56 -0500165 const SkIRect& deviceBounds,
166 const Context& ctx) const {
167 SkMatrix inverseCtm;
robertphillipsefbffed2015-06-22 12:06:08 -0700168 if (!ctx.ctm().invert(&inverseCtm)) {
Justin Novosad52340752014-12-02 14:50:56 -0500169 return;
robertphillipsefbffed2015-06-22 12:06:08 -0700170 }
171
Justin Novosad52340752014-12-02 14:50:56 -0500172 SkRect localBounds = SkRect::Make(ctx.clipBounds());
173 inverseCtm.mapRect(&localBounds);
robertphillipsefbffed2015-06-22 12:06:08 -0700174 if (!localBounds.intersect(fCropRect)) {
Justin Novosad52340752014-12-02 14:50:56 -0500175 return;
robertphillipsefbffed2015-06-22 12:06:08 -0700176 }
Justin Novosad52340752014-12-02 14:50:56 -0500177 SkIRect localIBounds = localBounds.roundOut();
Justin Novosad52340752014-12-02 14:50:56 -0500178
robertphillipsfef28602016-04-11 11:08:52 -0700179 sk_sp<SkSpecialImage> localImg;
180 {
brianosmaneed6b0e2016-09-23 13:04:05 -0700181 sk_sp<SkSpecialSurface> localSurface(source->makeSurface(ctx.outputProperties(),
182 localIBounds.size()));
robertphillipsfef28602016-04-11 11:08:52 -0700183 if (!localSurface) {
184 return;
185 }
Justin Novosad52340752014-12-02 14:50:56 -0500186
robertphillipsfef28602016-04-11 11:08:52 -0700187 SkCanvas* localCanvas = localSurface->getCanvas();
188 SkASSERT(localCanvas);
Christopher Cameron92eaad62017-05-22 23:12:01 -0700189 std::unique_ptr<SkCanvas> xformCanvas = nullptr;
190 if (fColorSpace) {
191 // Only non-null in the case where onMakeColorSpace() was called. This instructs
192 // us to do the color space xform on playback.
193 xformCanvas = SkCreateColorSpaceXformCanvas(localCanvas, fColorSpace);
194 localCanvas = xformCanvas.get();
195 }
196
ericrka31312c2016-05-12 09:06:44 -0700197 localCanvas->clear(0x0);
robertphillipsfef28602016-04-11 11:08:52 -0700198
199 localCanvas->translate(-SkIntToScalar(localIBounds.fLeft),
200 -SkIntToScalar(localIBounds.fTop));
201 localCanvas->drawPicture(fPicture);
202
203 localImg = localSurface->makeImageSnapshot();
204 SkASSERT(localImg);
205 }
206
207 {
208 canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
209 canvas->concat(ctx.ctm());
210 SkPaint paint;
211 paint.setFilterQuality(fFilterQuality);
212
213 localImg->draw(canvas,
214 SkIntToScalar(localIBounds.fLeft),
215 SkIntToScalar(localIBounds.fTop),
216 &paint);
217 }
Justin Novosad52340752014-12-02 14:50:56 -0500218}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800219
220#ifndef SK_IGNORE_TO_STRING
221void SkPictureImageFilter::toString(SkString* str) const {
222 str->appendf("SkPictureImageFilter: (");
halcanary9d524f22016-03-29 09:03:52 -0700223 str->appendf("crop: (%f,%f,%f,%f) ",
robertphillipsf3f5bad2014-12-19 13:49:15 -0800224 fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
225 if (fPicture) {
226 str->appendf("picture: (%f,%f,%f,%f)",
227 fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
228 fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
229 }
230 str->append(")");
231}
232#endif