blob: 6539104a305659fa88d666ca9bdb5e5c736294eb [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"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
robertphillipsfef28602016-04-11 11:08:52 -070012#include "SkSpecialImage.h"
13#include "SkSpecialSurface.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000014#include "SkWriteBuffer.h"
senorblanco@chromium.org53333002013-12-12 23:28:52 +000015#include "SkValidationUtils.h"
16
robertphillips225db442016-04-17 14:27:05 -070017sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture) {
18 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture)));
19}
20
21sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture,
22 const SkRect& cropRect) {
23 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture),
24 cropRect,
25 kDeviceSpace_PictureResolution,
26 kLow_SkFilterQuality));
27}
28
29sk_sp<SkImageFilter> SkPictureImageFilter::MakeForLocalSpace(sk_sp<SkPicture> picture,
30 const SkRect& cropRect,
31 SkFilterQuality filterQuality) {
32 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture),
33 cropRect,
34 kLocalSpace_PictureResolution,
35 filterQuality));
36}
37
robertphillips5ff17b12016-03-28 13:13:42 -070038SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture)
robertphillips372177e2016-03-30 07:32:28 -070039 : INHERITED(nullptr, 0, nullptr)
robertphillips5ff17b12016-03-28 13:13:42 -070040 , fPicture(std::move(picture))
41 , fCropRect(fPicture ? fPicture->cullRect() : SkRect::MakeEmpty())
halcanary9d524f22016-03-29 09:03:52 -070042 , fPictureResolution(kDeviceSpace_PictureResolution)
reed93a12152015-03-16 10:08:34 -070043 , fFilterQuality(kLow_SkFilterQuality) {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000044}
45
robertphillips5ff17b12016-03-28 13:13:42 -070046SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cropRect,
senorblanco24e06d52015-03-18 12:11:33 -070047 PictureResolution pictureResolution,
reed93a12152015-03-16 10:08:34 -070048 SkFilterQuality filterQuality)
robertphillips372177e2016-03-30 07:32:28 -070049 : INHERITED(nullptr, 0, nullptr)
robertphillips5ff17b12016-03-28 13:13:42 -070050 , fPicture(std::move(picture))
Justin Novosad52340752014-12-02 14:50:56 -050051 , fCropRect(cropRect)
junovf3c78cc2014-12-09 13:07:22 -080052 , fPictureResolution(pictureResolution)
reed93a12152015-03-16 10:08:34 -070053 , fFilterQuality(filterQuality) {
senorblanco@chromium.org53333002013-12-12 23:28:52 +000054}
55
reed60c9b582016-04-03 09:11:13 -070056sk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
reedca2622b2016-03-18 07:25:55 -070057 sk_sp<SkPicture> picture;
reed9fa60da2014-08-21 07:59:51 -070058 SkRect cropRect;
59
hendrikw446ee672015-06-16 09:28:37 -070060 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
robertphillipsc4bd39c2015-01-06 09:17:02 -080061 buffer.validate(!buffer.readBool());
hendrikw446ee672015-06-16 09:28:37 -070062 } else {
reed9fa60da2014-08-21 07:59:51 -070063 if (buffer.readBool()) {
reedca2622b2016-03-18 07:25:55 -070064 picture = SkPicture::MakeFromBuffer(buffer);
reed9fa60da2014-08-21 07:59:51 -070065 }
reed9fa60da2014-08-21 07:59:51 -070066 }
67 buffer.readRect(&cropRect);
Justin Novosad52340752014-12-02 14:50:56 -050068 PictureResolution pictureResolution;
69 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) {
70 pictureResolution = kDeviceSpace_PictureResolution;
71 } else {
72 pictureResolution = (PictureResolution)buffer.readInt();
halcanary9d524f22016-03-29 09:03:52 -070073 }
reed9fa60da2014-08-21 07:59:51 -070074
junovf3c78cc2014-12-09 13:07:22 -080075 if (kLocalSpace_PictureResolution == pictureResolution) {
76 //filterLevel is only serialized if pictureResolution is LocalSpace
reed93a12152015-03-16 10:08:34 -070077 SkFilterQuality filterQuality;
junovf3c78cc2014-12-09 13:07:22 -080078 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterLevel_Version)) {
reed93a12152015-03-16 10:08:34 -070079 filterQuality = kLow_SkFilterQuality;
junovf3c78cc2014-12-09 13:07:22 -080080 } else {
reed93a12152015-03-16 10:08:34 -070081 filterQuality = (SkFilterQuality)buffer.readInt();
junovf3c78cc2014-12-09 13:07:22 -080082 }
reed60c9b582016-04-03 09:11:13 -070083 return MakeForLocalSpace(picture, cropRect, filterQuality);
Justin Novosad52340752014-12-02 14:50:56 -050084 }
reed60c9b582016-04-03 09:11:13 -070085 return Make(picture, cropRect);
reed9fa60da2014-08-21 07:59:51 -070086}
senorblanco@chromium.org53333002013-12-12 23:28:52 +000087
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000088void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
hendrikw446ee672015-06-16 09:28:37 -070089 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
robertphillipsc4bd39c2015-01-06 09:17:02 -080090 buffer.writeBool(false);
hendrikw446ee672015-06-16 09:28:37 -070091 } else {
halcanary96fcdcc2015-08-27 07:41:13 -070092 bool hasPicture = (fPicture != nullptr);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000093 buffer.writeBool(hasPicture);
94 if (hasPicture) {
95 fPicture->flatten(buffer);
96 }
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +000097 }
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +000098 buffer.writeRect(fCropRect);
Justin Novosad52340752014-12-02 14:50:56 -050099 buffer.writeInt(fPictureResolution);
junovf3c78cc2014-12-09 13:07:22 -0800100 if (kLocalSpace_PictureResolution == fPictureResolution) {
reed93a12152015-03-16 10:08:34 -0700101 buffer.writeInt(fFilterQuality);
junovf3c78cc2014-12-09 13:07:22 -0800102 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000103}
104
robertphillipsfef28602016-04-11 11:08:52 -0700105sk_sp<SkSpecialImage> SkPictureImageFilter::onFilterImage(SkSpecialImage* source,
106 const Context& ctx,
107 SkIPoint* offset) const {
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000108 if (!fPicture) {
robertphillipsfef28602016-04-11 11:08:52 -0700109 return nullptr;
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000110 }
111
112 SkRect floatBounds;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000113 ctx.ctm().mapRect(&floatBounds, fCropRect);
reedb07a94f2014-11-19 05:03:18 -0800114 SkIRect bounds = floatBounds.roundOut();
senorblanco3d822c22014-07-30 14:49:31 -0700115 if (!bounds.intersect(ctx.clipBounds())) {
robertphillipsfef28602016-04-11 11:08:52 -0700116 return nullptr;
senorblanco3d822c22014-07-30 14:49:31 -0700117 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000118
robertphillipsfef28602016-04-11 11:08:52 -0700119 SkASSERT(!bounds.isEmpty());
120
brianosmaneed6b0e2016-09-23 13:04:05 -0700121 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
robertphillipsfef28602016-04-11 11:08:52 -0700122 if (!surf) {
123 return nullptr;
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000124 }
125
robertphillipsfef28602016-04-11 11:08:52 -0700126 SkCanvas* canvas = surf->getCanvas();
127 SkASSERT(canvas);
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000128
robertphillipsfef28602016-04-11 11:08:52 -0700129 canvas->clear(0x0);
130
robertphillips0b7e5a12016-04-13 07:18:41 -0700131 if (kDeviceSpace_PictureResolution == fPictureResolution ||
junovf3c78cc2014-12-09 13:07:22 -0800132 0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
robertphillips0b7e5a12016-04-13 07:18:41 -0700133 this->drawPictureAtDeviceResolution(canvas, bounds, ctx);
Justin Novosad52340752014-12-02 14:50:56 -0500134 } else {
robertphillipsfef28602016-04-11 11:08:52 -0700135 this->drawPictureAtLocalResolution(source, canvas, bounds, ctx);
Justin Novosad52340752014-12-02 14:50:56 -0500136 }
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000137
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000138 offset->fX = bounds.fLeft;
139 offset->fY = bounds.fTop;
robertphillipsfef28602016-04-11 11:08:52 -0700140 return surf->makeImageSnapshot();
senorblanco@chromium.org53333002013-12-12 23:28:52 +0000141}
Justin Novosad52340752014-12-02 14:50:56 -0500142
robertphillipsfef28602016-04-11 11:08:52 -0700143void SkPictureImageFilter::drawPictureAtDeviceResolution(SkCanvas* canvas,
Justin Novosad52340752014-12-02 14:50:56 -0500144 const SkIRect& deviceBounds,
145 const Context& ctx) const {
robertphillipsfef28602016-04-11 11:08:52 -0700146 canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
147 canvas->concat(ctx.ctm());
148 canvas->drawPicture(fPicture);
Justin Novosad52340752014-12-02 14:50:56 -0500149}
150
robertphillipsfef28602016-04-11 11:08:52 -0700151void SkPictureImageFilter::drawPictureAtLocalResolution(SkSpecialImage* source,
152 SkCanvas* canvas,
Justin Novosad52340752014-12-02 14:50:56 -0500153 const SkIRect& deviceBounds,
154 const Context& ctx) const {
155 SkMatrix inverseCtm;
robertphillipsefbffed2015-06-22 12:06:08 -0700156 if (!ctx.ctm().invert(&inverseCtm)) {
Justin Novosad52340752014-12-02 14:50:56 -0500157 return;
robertphillipsefbffed2015-06-22 12:06:08 -0700158 }
159
Justin Novosad52340752014-12-02 14:50:56 -0500160 SkRect localBounds = SkRect::Make(ctx.clipBounds());
161 inverseCtm.mapRect(&localBounds);
robertphillipsefbffed2015-06-22 12:06:08 -0700162 if (!localBounds.intersect(fCropRect)) {
Justin Novosad52340752014-12-02 14:50:56 -0500163 return;
robertphillipsefbffed2015-06-22 12:06:08 -0700164 }
Justin Novosad52340752014-12-02 14:50:56 -0500165 SkIRect localIBounds = localBounds.roundOut();
Justin Novosad52340752014-12-02 14:50:56 -0500166
robertphillipsfef28602016-04-11 11:08:52 -0700167 sk_sp<SkSpecialImage> localImg;
168 {
brianosmaneed6b0e2016-09-23 13:04:05 -0700169 sk_sp<SkSpecialSurface> localSurface(source->makeSurface(ctx.outputProperties(),
170 localIBounds.size()));
robertphillipsfef28602016-04-11 11:08:52 -0700171 if (!localSurface) {
172 return;
173 }
Justin Novosad52340752014-12-02 14:50:56 -0500174
robertphillipsfef28602016-04-11 11:08:52 -0700175 SkCanvas* localCanvas = localSurface->getCanvas();
176 SkASSERT(localCanvas);
ericrka31312c2016-05-12 09:06:44 -0700177
178 localCanvas->clear(0x0);
robertphillipsfef28602016-04-11 11:08:52 -0700179
180 localCanvas->translate(-SkIntToScalar(localIBounds.fLeft),
181 -SkIntToScalar(localIBounds.fTop));
182 localCanvas->drawPicture(fPicture);
183
184 localImg = localSurface->makeImageSnapshot();
185 SkASSERT(localImg);
186 }
187
188 {
189 canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
190 canvas->concat(ctx.ctm());
191 SkPaint paint;
192 paint.setFilterQuality(fFilterQuality);
193
194 localImg->draw(canvas,
195 SkIntToScalar(localIBounds.fLeft),
196 SkIntToScalar(localIBounds.fTop),
197 &paint);
198 }
Justin Novosad52340752014-12-02 14:50:56 -0500199}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800200
201#ifndef SK_IGNORE_TO_STRING
202void SkPictureImageFilter::toString(SkString* str) const {
203 str->appendf("SkPictureImageFilter: (");
halcanary9d524f22016-03-29 09:03:52 -0700204 str->appendf("crop: (%f,%f,%f,%f) ",
robertphillipsf3f5bad2014-12-19 13:49:15 -0800205 fCropRect.fLeft, fCropRect.fTop, fCropRect.fRight, fCropRect.fBottom);
206 if (fPicture) {
207 str->appendf("picture: (%f,%f,%f,%f)",
208 fPicture->cullRect().fLeft, fPicture->cullRect().fTop,
209 fPicture->cullRect().fRight, fPicture->cullRect().fBottom);
210 }
211 str->append(")");
212}
213#endif