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 "SkXfermodeImageFilter.h"
9 #include "SkArithmeticImageFilter.h"
10 #include "SkArithmeticModePriv.h"
11 #include "SkCanvas.h"
12 #include "SkColorPriv.h"
13 #include "SkReadBuffer.h"
14 #include "SkSpecialImage.h"
15 #include "SkSpecialSurface.h"
16 #include "SkWriteBuffer.h"
17 #if SK_SUPPORT_GPU
18 #include "GrClip.h"
19 #include "GrContext.h"
20 #include "GrRenderTargetContext.h"
21 #include "GrTextureProxy.h"
22 
23 #include "effects/GrConstColorProcessor.h"
24 #include "effects/GrTextureDomain.h"
25 #include "effects/GrSimpleTextureEffect.h"
26 #include "SkGr.h"
27 #endif
28 #include "SkClipOpPriv.h"
29 
30 class SkXfermodeImageFilter_Base : public SkImageFilter {
31 public:
32     SkXfermodeImageFilter_Base(SkBlendMode mode, sk_sp<SkImageFilter> inputs[2],
33                                const CropRect* cropRect);
34 
35     SK_TO_STRING_OVERRIDE()
36     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkXfermodeImageFilter_Base)
37 
38 protected:
39     sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
40                                         SkIPoint* offset) const override;
41 
42 #if SK_SUPPORT_GPU
43     sk_sp<SkSpecialImage> filterImageGPU(SkSpecialImage* source,
44                                          sk_sp<SkSpecialImage> background,
45                                          const SkIPoint& backgroundOffset,
46                                          sk_sp<SkSpecialImage> foreground,
47                                          const SkIPoint& foregroundOffset,
48                                          const SkIRect& bounds,
49                                          const OutputProperties& outputProperties) const;
50 #endif
51 
52     void flatten(SkWriteBuffer&) const override;
53 
54     void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const;
55 #if SK_SUPPORT_GPU
56     sk_sp<GrFragmentProcessor> makeFGFrag(sk_sp<GrFragmentProcessor> bgFP) const;
57 #endif
58 
59 private:
60     static sk_sp<SkFlattenable> LegacyArithmeticCreateProc(SkReadBuffer& buffer);
61 
62     SkBlendMode fMode;
63 
64     friend class SkXfermodeImageFilter;
65 
66     typedef SkImageFilter INHERITED;
67 };
68 
69 ///////////////////////////////////////////////////////////////////////////////
70 
Make(SkBlendMode mode,sk_sp<SkImageFilter> background,sk_sp<SkImageFilter> foreground,const SkImageFilter::CropRect * cropRect)71 sk_sp<SkImageFilter> SkXfermodeImageFilter::Make(SkBlendMode mode,
72                                                  sk_sp<SkImageFilter> background,
73                                                  sk_sp<SkImageFilter> foreground,
74                                                  const SkImageFilter::CropRect* cropRect) {
75     sk_sp<SkImageFilter> inputs[2] = { std::move(background), std::move(foreground) };
76     return sk_sp<SkImageFilter>(new SkXfermodeImageFilter_Base(mode, inputs, cropRect));
77 }
78 
SkXfermodeImageFilter_Base(SkBlendMode mode,sk_sp<SkImageFilter> inputs[2],const CropRect * cropRect)79 SkXfermodeImageFilter_Base::SkXfermodeImageFilter_Base(SkBlendMode mode,
80                                                        sk_sp<SkImageFilter> inputs[2],
81                                                        const CropRect* cropRect)
82     : INHERITED(inputs, 2, cropRect)
83     , fMode(mode)
84 {}
85 
unflatten_blendmode(SkReadBuffer & buffer,SkArithmeticParams * arith)86 static int unflatten_blendmode(SkReadBuffer& buffer, SkArithmeticParams* arith) {
87     if (buffer.isVersionLT(SkReadBuffer::kXfermodeToBlendMode_Version)) {
88         sk_sp<SkXfermode> xfer = buffer.readXfermode();
89         if (xfer) {
90             if (xfer->isArithmetic(arith)) {
91                 return -1;
92             }
93             return (int)xfer->blend();
94         } else {
95             return (int)SkBlendMode::kSrcOver;
96         }
97     } else {
98         uint32_t mode = buffer.read32();
99         (void)buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode);
100         return mode;
101     }
102 }
103 
CreateProc(SkReadBuffer & buffer)104 sk_sp<SkFlattenable> SkXfermodeImageFilter_Base::CreateProc(SkReadBuffer& buffer) {
105     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
106     SkArithmeticParams arith;
107     int mode = unflatten_blendmode(buffer, &arith);
108     if (mode >= 0) {
109         return SkXfermodeImageFilter::Make((SkBlendMode)mode, common.getInput(0),
110                                            common.getInput(1), &common.cropRect());
111     } else {
112         return SkArithmeticImageFilter::Make(arith.fK[0], arith.fK[1], arith.fK[2], arith.fK[3],
113                                              arith.fEnforcePMColor, common.getInput(0),
114                                              common.getInput(1), &common.cropRect());
115     }
116 }
117 
flatten(SkWriteBuffer & buffer) const118 void SkXfermodeImageFilter_Base::flatten(SkWriteBuffer& buffer) const {
119     this->INHERITED::flatten(buffer);
120     buffer.write32((unsigned)fMode);
121 }
122 
onFilterImage(SkSpecialImage * source,const Context & ctx,SkIPoint * offset) const123 sk_sp<SkSpecialImage> SkXfermodeImageFilter_Base::onFilterImage(SkSpecialImage* source,
124                                                            const Context& ctx,
125                                                            SkIPoint* offset) const {
126     SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
127     sk_sp<SkSpecialImage> background(this->filterInput(0, source, ctx, &backgroundOffset));
128 
129     SkIPoint foregroundOffset = SkIPoint::Make(0, 0);
130     sk_sp<SkSpecialImage> foreground(this->filterInput(1, source, ctx, &foregroundOffset));
131 
132     SkIRect foregroundBounds = SkIRect::EmptyIRect();
133     if (foreground) {
134         foregroundBounds = SkIRect::MakeXYWH(foregroundOffset.x(), foregroundOffset.y(),
135                                              foreground->width(), foreground->height());
136     }
137 
138     SkIRect srcBounds = SkIRect::EmptyIRect();
139     if (background) {
140         srcBounds = SkIRect::MakeXYWH(backgroundOffset.x(), backgroundOffset.y(),
141                                        background->width(), background->height());
142     }
143 
144     srcBounds.join(foregroundBounds);
145     if (srcBounds.isEmpty()) {
146         return nullptr;
147     }
148 
149     SkIRect bounds;
150     if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
151         return nullptr;
152     }
153 
154     offset->fX = bounds.left();
155     offset->fY = bounds.top();
156 
157 #if SK_SUPPORT_GPU
158     if (source->isTextureBacked()) {
159         return this->filterImageGPU(source,
160                                     background, backgroundOffset,
161                                     foreground, foregroundOffset,
162                                     bounds, ctx.outputProperties());
163     }
164 #endif
165 
166     sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
167     if (!surf) {
168         return nullptr;
169     }
170 
171     SkCanvas* canvas = surf->getCanvas();
172     SkASSERT(canvas);
173 
174     canvas->clear(0x0); // can't count on background to fully clear the background
175     canvas->translate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
176 
177     if (background) {
178         SkPaint paint;
179         paint.setBlendMode(SkBlendMode::kSrc);
180         background->draw(canvas,
181                          SkIntToScalar(backgroundOffset.fX), SkIntToScalar(backgroundOffset.fY),
182                          &paint);
183     }
184 
185     this->drawForeground(canvas, foreground.get(), foregroundBounds);
186 
187     return surf->makeImageSnapshot();
188 }
189 
drawForeground(SkCanvas * canvas,SkSpecialImage * img,const SkIRect & fgBounds) const190 void SkXfermodeImageFilter_Base::drawForeground(SkCanvas* canvas, SkSpecialImage* img,
191                                                 const SkIRect& fgBounds) const {
192     SkPaint paint;
193     paint.setBlendMode(fMode);
194     if (img) {
195         img->draw(canvas, SkIntToScalar(fgBounds.fLeft), SkIntToScalar(fgBounds.fTop), &paint);
196     }
197 
198     SkAutoCanvasRestore acr(canvas, true);
199     canvas->clipRect(SkRect::Make(fgBounds), kDifference_SkClipOp);
200     paint.setColor(0);
201     canvas->drawPaint(paint);
202 }
203 
204 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const205 void SkXfermodeImageFilter_Base::toString(SkString* str) const {
206     str->appendf("SkXfermodeImageFilter: (");
207     str->appendf("blendmode: (%d)", (int)fMode);
208     if (this->getInput(0)) {
209         str->appendf("foreground: (");
210         this->getInput(0)->toString(str);
211         str->appendf(")");
212     }
213     if (this->getInput(1)) {
214         str->appendf("background: (");
215         this->getInput(1)->toString(str);
216         str->appendf(")");
217     }
218     str->append(")");
219 }
220 #endif
221 
222 #if SK_SUPPORT_GPU
223 
224 #include "SkXfermode_proccoeff.h"
225 
filterImageGPU(SkSpecialImage * source,sk_sp<SkSpecialImage> background,const SkIPoint & backgroundOffset,sk_sp<SkSpecialImage> foreground,const SkIPoint & foregroundOffset,const SkIRect & bounds,const OutputProperties & outputProperties) const226 sk_sp<SkSpecialImage> SkXfermodeImageFilter_Base::filterImageGPU(
227                                                    SkSpecialImage* source,
228                                                    sk_sp<SkSpecialImage> background,
229                                                    const SkIPoint& backgroundOffset,
230                                                    sk_sp<SkSpecialImage> foreground,
231                                                    const SkIPoint& foregroundOffset,
232                                                    const SkIRect& bounds,
233                                                    const OutputProperties& outputProperties) const {
234     SkASSERT(source->isTextureBacked());
235 
236     GrContext* context = source->getContext();
237 
238     sk_sp<GrTextureProxy> backgroundProxy, foregroundProxy;
239 
240     if (background) {
241         backgroundProxy = background->asTextureProxyRef(context);
242     }
243 
244     if (foreground) {
245         foregroundProxy = foreground->asTextureProxyRef(context);
246     }
247 
248     GrPaint paint;
249     sk_sp<GrFragmentProcessor> bgFP;
250 
251     if (backgroundProxy) {
252         SkMatrix bgMatrix = SkMatrix::MakeTrans(-SkIntToScalar(backgroundOffset.fX),
253                                                 -SkIntToScalar(backgroundOffset.fY));
254         sk_sp<GrColorSpaceXform> bgXform = GrColorSpaceXform::Make(background->getColorSpace(),
255                                                                    outputProperties.colorSpace());
256         bgFP = GrTextureDomainEffect::Make(
257                             context->resourceProvider(), std::move(backgroundProxy),
258                             std::move(bgXform), bgMatrix,
259                             GrTextureDomain::MakeTexelDomain(background->subset()),
260                             GrTextureDomain::kDecal_Mode,
261                             GrSamplerParams::kNone_FilterMode);
262     } else {
263         bgFP = GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
264                                            GrConstColorProcessor::kIgnore_InputMode);
265     }
266 
267     if (foregroundProxy) {
268         SkMatrix fgMatrix = SkMatrix::MakeTrans(-SkIntToScalar(foregroundOffset.fX),
269                                                 -SkIntToScalar(foregroundOffset.fY));
270         sk_sp<GrColorSpaceXform> fgXform = GrColorSpaceXform::Make(foreground->getColorSpace(),
271                                                                    outputProperties.colorSpace());
272         sk_sp<GrFragmentProcessor> foregroundFP;
273 
274         foregroundFP = GrTextureDomainEffect::Make(
275                             context->resourceProvider(), std::move(foregroundProxy),
276                             std::move(fgXform), fgMatrix,
277                             GrTextureDomain::MakeTexelDomain(foreground->subset()),
278                             GrTextureDomain::kDecal_Mode,
279                             GrSamplerParams::kNone_FilterMode);
280 
281         paint.addColorFragmentProcessor(std::move(foregroundFP));
282 
283         sk_sp<GrFragmentProcessor> xferFP = this->makeFGFrag(bgFP);
284 
285         // A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed
286         if (xferFP) {
287             paint.addColorFragmentProcessor(std::move(xferFP));
288         }
289     } else {
290         paint.addColorFragmentProcessor(std::move(bgFP));
291     }
292 
293     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
294 
295     sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext(
296                                     SkBackingFit::kApprox, bounds.width(), bounds.height(),
297                                     GrRenderableConfigForColorSpace(outputProperties.colorSpace()),
298                                     sk_ref_sp(outputProperties.colorSpace())));
299     if (!renderTargetContext) {
300         return nullptr;
301     }
302     paint.setGammaCorrect(renderTargetContext->isGammaCorrect());
303 
304     SkMatrix matrix;
305     matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
306     renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix,
307                                   SkRect::Make(bounds));
308 
309     return SkSpecialImage::MakeDeferredFromGpu(context,
310                                                SkIRect::MakeWH(bounds.width(), bounds.height()),
311                                                kNeedNewImageUniqueID_SpecialImage,
312                                                renderTargetContext->asTextureProxyRef(),
313                                                renderTargetContext->refColorSpace());
314 }
315 
316 sk_sp<GrFragmentProcessor>
makeFGFrag(sk_sp<GrFragmentProcessor> bgFP) const317 SkXfermodeImageFilter_Base::makeFGFrag(sk_sp<GrFragmentProcessor> bgFP) const {
318     // A null fMode is interpreted to mean kSrcOver_Mode (to match raster).
319     SkXfermode* xfer = SkXfermode::Peek(fMode);
320     sk_sp<SkXfermode> srcover;
321     if (!xfer) {
322         // It would be awesome to use SkXfermode::Create here but it knows better
323         // than us and won't return a kSrcOver_Mode SkXfermode. That means we
324         // have to get one the hard way.
325         struct ProcCoeff rec;
326         rec.fProc = SkXfermode::GetProc(SkBlendMode::kSrcOver);
327         SkXfermode::ModeAsCoeff(SkBlendMode::kSrcOver, &rec.fSC, &rec.fDC);
328 
329         srcover.reset(new SkProcCoeffXfermode(rec, SkBlendMode::kSrcOver));
330         xfer = srcover.get();
331 
332     }
333     return xfer->makeFragmentProcessorForImageFilter(std::move(bgFP));
334 }
335 
336 #endif
337 ///////////////////////////////////////////////////////////////////////////////////////////////////
338 
LegacyArithmeticCreateProc(SkReadBuffer & buffer)339 sk_sp<SkFlattenable> SkXfermodeImageFilter_Base::LegacyArithmeticCreateProc(SkReadBuffer& buffer) {
340     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
341     // skip the unused mode (srcover) field
342     SkDEBUGCODE(int mode =) unflatten_blendmode(buffer, nullptr);
343     if (!buffer.isValid()) {
344         return nullptr;
345     }
346     SkASSERT(SkBlendMode::kSrcOver == (SkBlendMode)mode);
347     float k[4];
348     for (int i = 0; i < 4; ++i) {
349         k[i] = buffer.readScalar();
350     }
351     const bool enforcePMColor = buffer.readBool();
352     return SkArithmeticImageFilter::Make(k[0], k[1], k[2], k[3], enforcePMColor, common.getInput(0),
353                                          common.getInput(1), &common.cropRect());
354 }
355 
356 ///////////////////////////////////////////////////////////////////////////////////////////////////
357 
358 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermodeImageFilter)
359     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkXfermodeImageFilter_Base)
360     // manually register the legacy serialized name "SkXfermodeImageFilter"
361     SkFlattenable::Register("SkXfermodeImageFilter", SkXfermodeImageFilter_Base::CreateProc,
362                             SkFlattenable::kSkImageFilter_Type);
363     // manually register the legacy serialized name "SkArithmeticImageFilter" from when that filter
364     // was implemented as a xfermode image filter.
365     SkFlattenable::Register("SkArithmeticImageFilter",
366                             SkXfermodeImageFilter_Base::LegacyArithmeticCreateProc,
367                             SkFlattenable::kSkImageFilter_Type);
368 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
369