• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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