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 "include/core/SkCanvas.h"
9 #include "include/effects/SkImageFilters.h"
10 #include "include/private/SkColorData.h"
11 #include "src/core/SkBlendModePriv.h"
12 #include "src/core/SkBlenderBase.h"
13 #include "src/core/SkImageFilter_Base.h"
14 #include "src/core/SkMatrixProvider.h"
15 #include "src/core/SkReadBuffer.h"
16 #include "src/core/SkSpecialImage.h"
17 #include "src/core/SkSpecialSurface.h"
18 #include "src/core/SkWriteBuffer.h"
19
20 #if SK_SUPPORT_GPU
21 #include "include/gpu/GrRecordingContext.h"
22 #include "src/gpu/GrCaps.h"
23 #include "src/gpu/GrColorSpaceXform.h"
24 #include "src/gpu/GrRecordingContextPriv.h"
25 #include "src/gpu/GrTextureProxy.h"
26 #include "src/gpu/SkGr.h"
27 #include "src/gpu/SurfaceFillContext.h"
28 #include "src/gpu/effects/GrTextureEffect.h"
29 #endif
30
31 namespace {
32
33 class SkBlendImageFilter : public SkImageFilter_Base {
34 public:
SkBlendImageFilter(sk_sp<SkBlender> blender,sk_sp<SkImageFilter> inputs[2],const SkRect * cropRect)35 SkBlendImageFilter(sk_sp<SkBlender> blender, sk_sp<SkImageFilter> inputs[2],
36 const SkRect* cropRect)
37 : INHERITED(inputs, 2, cropRect)
38 , fBlender(std::move(blender))
39 {
40 SkASSERT(fBlender);
41 }
42
43 protected:
44 sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
45
46 SkIRect onFilterBounds(const SkIRect&, const SkMatrix& ctm,
47 MapDirection, const SkIRect* inputRect) const override;
48
49 #if SK_SUPPORT_GPU
50 sk_sp<SkSpecialImage> filterImageGPU(const Context& ctx,
51 sk_sp<SkSpecialImage> background,
52 const SkIPoint& backgroundOffset,
53 sk_sp<SkSpecialImage> foreground,
54 const SkIPoint& foregroundOffset,
55 const SkIRect& bounds) const;
56 #endif
57
58 void flatten(SkWriteBuffer&) const override;
59
60 void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const;
61
62 private:
63 friend void ::SkRegisterBlendImageFilterFlattenable();
64 SK_FLATTENABLE_HOOKS(SkBlendImageFilter)
65
66 sk_sp<SkBlender> fBlender;
67
68 using INHERITED = SkImageFilter_Base;
69 };
70
71 } // end namespace
72
Blend(SkBlendMode mode,sk_sp<SkImageFilter> background,sk_sp<SkImageFilter> foreground,const CropRect & cropRect)73 sk_sp<SkImageFilter> SkImageFilters::Blend(SkBlendMode mode,
74 sk_sp<SkImageFilter> background,
75 sk_sp<SkImageFilter> foreground,
76 const CropRect& cropRect) {
77 sk_sp<SkImageFilter> inputs[2] = { std::move(background), std::move(foreground) };
78 return sk_sp<SkImageFilter>(new SkBlendImageFilter(SkBlender::Mode(mode), inputs, cropRect));
79 }
80
Blend(sk_sp<SkBlender> blender,sk_sp<SkImageFilter> background,sk_sp<SkImageFilter> foreground,const CropRect & cropRect)81 sk_sp<SkImageFilter> SkImageFilters::Blend(sk_sp<SkBlender> blender,
82 sk_sp<SkImageFilter> background,
83 sk_sp<SkImageFilter> foreground,
84 const CropRect& cropRect) {
85 if (!blender) {
86 blender = SkBlender::Mode(SkBlendMode::kSrcOver);
87 }
88 sk_sp<SkImageFilter> inputs[2] = { std::move(background), std::move(foreground) };
89 return sk_sp<SkImageFilter>(new SkBlendImageFilter(blender, inputs, cropRect));
90 }
91
SkRegisterBlendImageFilterFlattenable()92 void SkRegisterBlendImageFilterFlattenable() {
93 SK_REGISTER_FLATTENABLE(SkBlendImageFilter);
94 // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
95 SkFlattenable::Register("SkXfermodeImageFilter_Base", SkBlendImageFilter::CreateProc);
96 SkFlattenable::Register("SkXfermodeImageFilterImpl", SkBlendImageFilter::CreateProc);
97 }
98
CreateProc(SkReadBuffer & buffer)99 sk_sp<SkFlattenable> SkBlendImageFilter::CreateProc(SkReadBuffer& buffer) {
100 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
101
102 sk_sp<SkBlender> blender;
103 const uint32_t mode = buffer.read32();
104 if (mode == kCustom_SkBlendMode) {
105 blender = buffer.readBlender();
106 } else {
107 if (mode > (unsigned)SkBlendMode::kLastMode) {
108 buffer.validate(false);
109 return nullptr;
110 }
111 blender = SkBlender::Mode((SkBlendMode)mode);
112 }
113 return SkImageFilters::Blend(std::move(blender), common.getInput(0), common.getInput(1),
114 common.cropRect());
115 }
116
flatten(SkWriteBuffer & buffer) const117 void SkBlendImageFilter::flatten(SkWriteBuffer& buffer) const {
118 this->INHERITED::flatten(buffer);
119 if (auto bm = as_BB(fBlender)->asBlendMode()) {
120 buffer.write32((unsigned)bm.value());
121 } else {
122 buffer.write32(kCustom_SkBlendMode);
123 buffer.writeFlattenable(fBlender.get());
124 }
125 }
126
127 ///////////////////////////////////////////////////////////////////////////////////////////////////
128
onFilterImage(const Context & ctx,SkIPoint * offset) const129 sk_sp<SkSpecialImage> SkBlendImageFilter::onFilterImage(const Context& ctx,
130 SkIPoint* offset) const {
131 SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
132 sk_sp<SkSpecialImage> background(this->filterInput(0, ctx, &backgroundOffset));
133
134 SkIPoint foregroundOffset = SkIPoint::Make(0, 0);
135 sk_sp<SkSpecialImage> foreground(this->filterInput(1, ctx, &foregroundOffset));
136
137 SkIRect foregroundBounds = SkIRect::MakeEmpty();
138 if (foreground) {
139 foregroundBounds = SkIRect::MakeXYWH(foregroundOffset.x(), foregroundOffset.y(),
140 foreground->width(), foreground->height());
141 }
142
143 SkIRect srcBounds = SkIRect::MakeEmpty();
144 if (background) {
145 srcBounds = SkIRect::MakeXYWH(backgroundOffset.x(), backgroundOffset.y(),
146 background->width(), background->height());
147 }
148
149 srcBounds.join(foregroundBounds);
150 if (srcBounds.isEmpty()) {
151 return nullptr;
152 }
153
154 SkIRect bounds;
155 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
156 return nullptr;
157 }
158
159 offset->fX = bounds.left();
160 offset->fY = bounds.top();
161
162 #if SK_SUPPORT_GPU
163 if (ctx.gpuBacked()) {
164 return this->filterImageGPU(ctx, background, backgroundOffset,
165 foreground, foregroundOffset, bounds);
166 }
167 #endif
168
169 sk_sp<SkSpecialSurface> surf(ctx.makeSurface(bounds.size()));
170 if (!surf) {
171 return nullptr;
172 }
173
174 SkCanvas* canvas = surf->getCanvas();
175 SkASSERT(canvas);
176
177 canvas->clear(0x0); // can't count on background to fully clear the background
178 canvas->translate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
179
180 if (background) {
181 SkPaint paint;
182 paint.setBlendMode(SkBlendMode::kSrc);
183 background->draw(canvas,
184 SkIntToScalar(backgroundOffset.fX), SkIntToScalar(backgroundOffset.fY),
185 SkSamplingOptions(), &paint);
186 }
187
188 this->drawForeground(canvas, foreground.get(), foregroundBounds);
189
190 return surf->makeImageSnapshot();
191 }
192
onFilterBounds(const SkIRect & src,const SkMatrix & ctm,MapDirection dir,const SkIRect * inputRect) const193 SkIRect SkBlendImageFilter::onFilterBounds(const SkIRect& src,
194 const SkMatrix& ctm,
195 MapDirection dir,
196 const SkIRect* inputRect) const {
197 if (kReverse_MapDirection == dir) {
198 return INHERITED::onFilterBounds(src, ctm, dir, inputRect);
199 }
200
201 SkASSERT(!inputRect);
202 SkASSERT(2 == this->countInputs());
203 auto getBackground = [&]() {
204 return this->getInput(0) ? this->getInput(0)->filterBounds(src, ctm, dir, inputRect) : src;
205 };
206 auto getForeground = [&]() {
207 return this->getInput(1) ? this->getInput(1)->filterBounds(src, ctm, dir, inputRect) : src;
208 };
209 if (auto bm = as_BB(fBlender)->asBlendMode()) {
210 switch (bm.value()) {
211 case SkBlendMode::kClear:
212 return SkIRect::MakeEmpty();
213
214 case SkBlendMode::kSrc:
215 case SkBlendMode::kDstATop:
216 return getForeground();
217
218 case SkBlendMode::kDst:
219 case SkBlendMode::kSrcATop:
220 return getBackground();
221
222 case SkBlendMode::kSrcIn:
223 case SkBlendMode::kDstIn: {
224 auto result = getBackground();
225 if (!result.intersect(getForeground())) {
226 return SkIRect::MakeEmpty();
227 }
228 return result;
229 }
230 default: break;
231 }
232 }
233 auto result = getBackground();
234 result.join(getForeground());
235 return result;
236 }
237
drawForeground(SkCanvas * canvas,SkSpecialImage * img,const SkIRect & fgBounds) const238 void SkBlendImageFilter::drawForeground(SkCanvas* canvas, SkSpecialImage* img,
239 const SkIRect& fgBounds) const {
240 SkPaint paint;
241 paint.setBlender(fBlender);
242 if (img) {
243 img->draw(canvas, SkIntToScalar(fgBounds.fLeft), SkIntToScalar(fgBounds.fTop),
244 SkSamplingOptions(), &paint);
245 }
246
247 SkAutoCanvasRestore acr(canvas, true);
248 canvas->clipRect(SkRect::Make(fgBounds), SkClipOp::kDifference);
249 paint.setColor(0);
250 canvas->drawPaint(paint);
251 }
252
253 #if SK_SUPPORT_GPU
254
255 #include "src/gpu/effects/GrBlendFragmentProcessor.h"
256
filterImageGPU(const Context & ctx,sk_sp<SkSpecialImage> background,const SkIPoint & backgroundOffset,sk_sp<SkSpecialImage> foreground,const SkIPoint & foregroundOffset,const SkIRect & bounds) const257 sk_sp<SkSpecialImage> SkBlendImageFilter::filterImageGPU(const Context& ctx,
258 sk_sp<SkSpecialImage> background,
259 const SkIPoint& backgroundOffset,
260 sk_sp<SkSpecialImage> foreground,
261 const SkIPoint& foregroundOffset,
262 const SkIRect& bounds) const {
263 SkASSERT(ctx.gpuBacked());
264
265 auto rContext = ctx.getContext();
266
267 GrSurfaceProxyView backgroundView, foregroundView;
268
269 if (background) {
270 backgroundView = background->view(rContext);
271 }
272
273 if (foreground) {
274 foregroundView = foreground->view(rContext);
275 }
276
277 std::unique_ptr<GrFragmentProcessor> fp;
278 const auto& caps = *ctx.getContext()->priv().caps();
279 GrSamplerState sampler(GrSamplerState::WrapMode::kClampToBorder,
280 GrSamplerState::Filter::kNearest);
281
282 if (backgroundView.asTextureProxy()) {
283 SkRect bgSubset = SkRect::Make(background->subset());
284 SkMatrix bgMatrix = SkMatrix::Translate(
285 SkIntToScalar(bgSubset.left() - backgroundOffset.fX),
286 SkIntToScalar(bgSubset.top() - backgroundOffset.fY));
287 fp = GrTextureEffect::MakeSubset(std::move(backgroundView), background->alphaType(),
288 bgMatrix, sampler, bgSubset, caps);
289 fp = GrColorSpaceXformEffect::Make(std::move(fp), background->getColorSpace(),
290 background->alphaType(), ctx.colorSpace(),
291 kPremul_SkAlphaType);
292 } else {
293 fp = GrFragmentProcessor::MakeColor(SK_PMColor4fTRANSPARENT);
294 }
295
296 GrImageInfo info(ctx.grColorType(), kPremul_SkAlphaType, ctx.refColorSpace(), bounds.size());
297
298 if (foregroundView.asTextureProxy()) {
299 SkRect fgSubset = SkRect::Make(foreground->subset());
300 SkMatrix fgMatrix = SkMatrix::Translate(
301 SkIntToScalar(fgSubset.left() - foregroundOffset.fX),
302 SkIntToScalar(fgSubset.top() - foregroundOffset.fY));
303 auto fgFP = GrTextureEffect::MakeSubset(std::move(foregroundView), foreground->alphaType(),
304 fgMatrix, sampler, fgSubset, caps);
305 fgFP = GrColorSpaceXformEffect::Make(std::move(fgFP), foreground->getColorSpace(),
306 foreground->alphaType(), ctx.colorSpace(),
307 kPremul_SkAlphaType);
308
309 GrFPArgs args(rContext, SkSimpleMatrixProvider(SkMatrix::I()), &info.colorInfo());
310
311 fp = as_BB(fBlender)->asFragmentProcessor(std::move(fgFP), std::move(fp), args);
312 }
313
314 auto sfc = rContext->priv().makeSFC(info, SkBackingFit::kApprox);
315 if (!sfc) {
316 return nullptr;
317 }
318
319 sfc->fillRectToRectWithFP(bounds, SkIRect::MakeSize(bounds.size()), std::move(fp));
320
321 return SkSpecialImage::MakeDeferredFromGpu(rContext,
322 SkIRect::MakeWH(bounds.width(), bounds.height()),
323 kNeedNewImageUniqueID_SpecialImage,
324 sfc->readSurfaceView(),
325 sfc->colorInfo().colorType(),
326 sfc->colorInfo().refColorSpace(),
327 ctx.surfaceProps());
328 }
329
330 #endif
331