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