• 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/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