1 /*
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"
9
10 #include "SkCanvas.h"
11 #include "SkReadBuffer.h"
12 #include "SkSpecialImage.h"
13 #include "SkSpecialSurface.h"
14 #include "SkWriteBuffer.h"
15 #include "SkValidationUtils.h"
16
Make(sk_sp<SkPicture> picture)17 sk_sp<SkImageFilter> SkPictureImageFilter::Make(sk_sp<SkPicture> picture) {
18 return sk_sp<SkImageFilter>(new SkPictureImageFilter(std::move(picture)));
19 }
20
Make(sk_sp<SkPicture> picture,const SkRect & cropRect)21 sk_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
MakeForLocalSpace(sk_sp<SkPicture> picture,const SkRect & cropRect,SkFilterQuality filterQuality)29 sk_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
SkPictureImageFilter(sk_sp<SkPicture> picture)38 SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture)
39 : INHERITED(nullptr, 0, nullptr)
40 , fPicture(std::move(picture))
41 , fCropRect(fPicture ? fPicture->cullRect() : SkRect::MakeEmpty())
42 , fPictureResolution(kDeviceSpace_PictureResolution)
43 , fFilterQuality(kLow_SkFilterQuality) {
44 }
45
SkPictureImageFilter(sk_sp<SkPicture> picture,const SkRect & cropRect,PictureResolution pictureResolution,SkFilterQuality filterQuality)46 SkPictureImageFilter::SkPictureImageFilter(sk_sp<SkPicture> picture, const SkRect& cropRect,
47 PictureResolution pictureResolution,
48 SkFilterQuality filterQuality)
49 : INHERITED(nullptr, 0, nullptr)
50 , fPicture(std::move(picture))
51 , fCropRect(cropRect)
52 , fPictureResolution(pictureResolution)
53 , fFilterQuality(filterQuality) {
54 }
55
CreateProc(SkReadBuffer & buffer)56 sk_sp<SkFlattenable> SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) {
57 sk_sp<SkPicture> picture;
58 SkRect cropRect;
59
60 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
61 buffer.validate(!buffer.readBool());
62 } else {
63 if (buffer.readBool()) {
64 picture = SkPicture::MakeFromBuffer(buffer);
65 }
66 }
67 buffer.readRect(&cropRect);
68 PictureResolution pictureResolution;
69 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) {
70 pictureResolution = kDeviceSpace_PictureResolution;
71 } else {
72 pictureResolution = (PictureResolution)buffer.readInt();
73 }
74
75 if (kLocalSpace_PictureResolution == pictureResolution) {
76 //filterLevel is only serialized if pictureResolution is LocalSpace
77 SkFilterQuality filterQuality;
78 if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterLevel_Version)) {
79 filterQuality = kLow_SkFilterQuality;
80 } else {
81 filterQuality = (SkFilterQuality)buffer.readInt();
82 }
83 return MakeForLocalSpace(picture, cropRect, filterQuality);
84 }
85 return Make(picture, cropRect);
86 }
87
flatten(SkWriteBuffer & buffer) const88 void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const {
89 if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) {
90 buffer.writeBool(false);
91 } else {
92 bool hasPicture = (fPicture != nullptr);
93 buffer.writeBool(hasPicture);
94 if (hasPicture) {
95 fPicture->flatten(buffer);
96 }
97 }
98 buffer.writeRect(fCropRect);
99 buffer.writeInt(fPictureResolution);
100 if (kLocalSpace_PictureResolution == fPictureResolution) {
101 buffer.writeInt(fFilterQuality);
102 }
103 }
104
onFilterImage(SkSpecialImage * source,const Context & ctx,SkIPoint * offset) const105 sk_sp<SkSpecialImage> SkPictureImageFilter::onFilterImage(SkSpecialImage* source,
106 const Context& ctx,
107 SkIPoint* offset) const {
108 if (!fPicture) {
109 return nullptr;
110 }
111
112 SkRect floatBounds;
113 ctx.ctm().mapRect(&floatBounds, fCropRect);
114 SkIRect bounds = floatBounds.roundOut();
115 if (!bounds.intersect(ctx.clipBounds())) {
116 return nullptr;
117 }
118
119 SkASSERT(!bounds.isEmpty());
120
121 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
122 if (!surf) {
123 return nullptr;
124 }
125
126 SkCanvas* canvas = surf->getCanvas();
127 SkASSERT(canvas);
128
129 canvas->clear(0x0);
130
131 if (kDeviceSpace_PictureResolution == fPictureResolution ||
132 0 == (ctx.ctm().getType() & ~SkMatrix::kTranslate_Mask)) {
133 this->drawPictureAtDeviceResolution(canvas, bounds, ctx);
134 } else {
135 this->drawPictureAtLocalResolution(source, canvas, bounds, ctx);
136 }
137
138 offset->fX = bounds.fLeft;
139 offset->fY = bounds.fTop;
140 return surf->makeImageSnapshot();
141 }
142
drawPictureAtDeviceResolution(SkCanvas * canvas,const SkIRect & deviceBounds,const Context & ctx) const143 void SkPictureImageFilter::drawPictureAtDeviceResolution(SkCanvas* canvas,
144 const SkIRect& deviceBounds,
145 const Context& ctx) const {
146 canvas->translate(-SkIntToScalar(deviceBounds.fLeft), -SkIntToScalar(deviceBounds.fTop));
147 canvas->concat(ctx.ctm());
148 canvas->drawPicture(fPicture);
149 }
150
drawPictureAtLocalResolution(SkSpecialImage * source,SkCanvas * canvas,const SkIRect & deviceBounds,const Context & ctx) const151 void SkPictureImageFilter::drawPictureAtLocalResolution(SkSpecialImage* source,
152 SkCanvas* canvas,
153 const SkIRect& deviceBounds,
154 const Context& ctx) const {
155 SkMatrix inverseCtm;
156 if (!ctx.ctm().invert(&inverseCtm)) {
157 return;
158 }
159
160 SkRect localBounds = SkRect::Make(ctx.clipBounds());
161 inverseCtm.mapRect(&localBounds);
162 if (!localBounds.intersect(fCropRect)) {
163 return;
164 }
165 SkIRect localIBounds = localBounds.roundOut();
166
167 sk_sp<SkSpecialImage> localImg;
168 {
169 sk_sp<SkSpecialSurface> localSurface(source->makeSurface(ctx.outputProperties(),
170 localIBounds.size()));
171 if (!localSurface) {
172 return;
173 }
174
175 SkCanvas* localCanvas = localSurface->getCanvas();
176 SkASSERT(localCanvas);
177
178 localCanvas->clear(0x0);
179
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 }
199 }
200
201 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const202 void SkPictureImageFilter::toString(SkString* str) const {
203 str->appendf("SkPictureImageFilter: (");
204 str->appendf("crop: (%f,%f,%f,%f) ",
205 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
214