48dde9c80e2910c5335ffca08d503adabadfd601
[WebKit-https.git] / Source / WebCore / rendering / FilterEffectRenderer.cpp
1 /*
2  * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2013 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28 #include "FilterEffectRenderer.h"
29
30 #include "CachedSVGDocument.h"
31 #include "CachedSVGDocumentReference.h"
32 #include "ElementIterator.h"
33 #include "FEColorMatrix.h"
34 #include "FEComponentTransfer.h"
35 #include "FEDropShadow.h"
36 #include "FEGaussianBlur.h"
37 #include "FEMerge.h"
38 #include "RenderLayer.h"
39 #include "SVGElement.h"
40 #include "SVGFilterBuilder.h"
41 #include "SVGFilterPrimitiveStandardAttributes.h"
42 #include "SourceGraphic.h"
43 #include <algorithm>
44 #include <wtf/MathExtras.h>
45
46 #if USE(DIRECT2D)
47 #include <d2d1.h>
48 #endif
49
50 namespace WebCore {
51
52 static inline void endMatrixRow(Vector<float>& parameters)
53 {
54     parameters.append(0);
55     parameters.append(0);
56 }
57
58 static inline void lastMatrixRow(Vector<float>& parameters)
59 {
60     parameters.append(0);
61     parameters.append(0);
62     parameters.append(0);
63     parameters.append(1);
64     parameters.append(0);
65 }
66
67 inline FilterEffectRenderer::FilterEffectRenderer()
68     : Filter(FloatSize { 1, 1 })
69     , m_sourceGraphic(SourceGraphic::create(*this))
70 {
71 }
72
73 Ref<FilterEffectRenderer> FilterEffectRenderer::create()
74 {
75     return adoptRef(*new FilterEffectRenderer);
76 }
77
78 FilterEffectRenderer::~FilterEffectRenderer() = default;
79
80 GraphicsContext* FilterEffectRenderer::inputContext()
81 {
82     return sourceImage() ? &sourceImage()->context() : nullptr;
83 }
84
85 RefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(RenderElement& renderer, FilterEffect& previousEffect, ReferenceFilterOperation& filterOperation)
86 {
87     auto* cachedSVGDocumentReference = filterOperation.cachedSVGDocumentReference();
88     auto* cachedSVGDocument = cachedSVGDocumentReference ? cachedSVGDocumentReference->document() : nullptr;
89
90     // If we have an SVG document, this is an external reference. Otherwise
91     // we look up the referenced node in the current document.
92     Document* document;
93     if (!cachedSVGDocument)
94         document = &renderer.document();
95     else {
96         document = cachedSVGDocument->document();
97         if (!document)
98             return nullptr;
99     }
100
101     auto* filter = document->getElementById(filterOperation.fragment());
102     if (!filter) {
103         // Although we did not find the referenced filter, it might exist later in the document.
104         // FIXME: This skips anonymous RenderObjects. <https://webkit.org/b/131085>
105         if (auto* element = renderer.element())
106             document->accessSVGExtensions().addPendingResource(filterOperation.fragment(), element);
107         return nullptr;
108     }
109
110     RefPtr<FilterEffect> effect;
111
112     auto builder = std::make_unique<SVGFilterBuilder>(&previousEffect);
113
114     for (auto& effectElement : childrenOfType<SVGFilterPrimitiveStandardAttributes>(*filter)) {
115         effect = effectElement.build(builder.get(), *this);
116         if (!effect)
117             continue;
118
119         effectElement.setStandardAttributes(effect.get());
120         builder->add(effectElement.result(), effect);
121         m_effects.append(*effect);
122     }
123     return effect;
124 }
125
126 bool FilterEffectRenderer::build(RenderElement& renderer, const FilterOperations& operations, FilterConsumer consumer)
127 {
128     m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels();
129     m_hasFilterThatShouldBeRestrictedBySecurityOrigin = operations.hasFilterThatShouldBeRestrictedBySecurityOrigin();
130     if (m_hasFilterThatMovesPixels)
131         m_outsets = operations.outsets();
132
133     m_effects.clear();
134
135     RefPtr<FilterEffect> previousEffect = m_sourceGraphic.ptr();
136     for (auto& operation : operations.operations()) {
137         RefPtr<FilterEffect> effect;
138         auto& filterOperation = *operation;
139         switch (filterOperation.type()) {
140         case FilterOperation::REFERENCE: {
141             auto& referenceOperation = downcast<ReferenceFilterOperation>(filterOperation);
142             effect = buildReferenceFilter(renderer, *previousEffect, referenceOperation);
143             referenceOperation.setFilterEffect(effect.copyRef());
144             break;
145         }
146         case FilterOperation::GRAYSCALE: {
147             auto& colorMatrixOperation = downcast<BasicColorMatrixFilterOperation>(filterOperation);
148             Vector<float> inputParameters;
149             double oneMinusAmount = clampTo(1 - colorMatrixOperation.amount(), 0.0, 1.0);
150
151             // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#grayscaleEquivalent
152             // for information on parameters.
153
154             inputParameters.append(narrowPrecisionToFloat(0.2126 + 0.7874 * oneMinusAmount));
155             inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount));
156             inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount));
157             endMatrixRow(inputParameters);
158
159             inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount));
160             inputParameters.append(narrowPrecisionToFloat(0.7152 + 0.2848 * oneMinusAmount));
161             inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount));
162             endMatrixRow(inputParameters);
163
164             inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount));
165             inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount));
166             inputParameters.append(narrowPrecisionToFloat(0.0722 + 0.9278 * oneMinusAmount));
167             endMatrixRow(inputParameters);
168
169             lastMatrixRow(inputParameters);
170
171             effect = FEColorMatrix::create(*this, FECOLORMATRIX_TYPE_MATRIX, inputParameters);
172             break;
173         }
174         case FilterOperation::SEPIA: {
175             auto& colorMatrixOperation = downcast<BasicColorMatrixFilterOperation>(filterOperation);
176             Vector<float> inputParameters;
177             double oneMinusAmount = clampTo(1 - colorMatrixOperation.amount(), 0.0, 1.0);
178
179             // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#sepiaEquivalent
180             // for information on parameters.
181
182             inputParameters.append(narrowPrecisionToFloat(0.393 + 0.607 * oneMinusAmount));
183             inputParameters.append(narrowPrecisionToFloat(0.769 - 0.769 * oneMinusAmount));
184             inputParameters.append(narrowPrecisionToFloat(0.189 - 0.189 * oneMinusAmount));
185             endMatrixRow(inputParameters);
186
187             inputParameters.append(narrowPrecisionToFloat(0.349 - 0.349 * oneMinusAmount));
188             inputParameters.append(narrowPrecisionToFloat(0.686 + 0.314 * oneMinusAmount));
189             inputParameters.append(narrowPrecisionToFloat(0.168 - 0.168 * oneMinusAmount));
190             endMatrixRow(inputParameters);
191
192             inputParameters.append(narrowPrecisionToFloat(0.272 - 0.272 * oneMinusAmount));
193             inputParameters.append(narrowPrecisionToFloat(0.534 - 0.534 * oneMinusAmount));
194             inputParameters.append(narrowPrecisionToFloat(0.131 + 0.869 * oneMinusAmount));
195             endMatrixRow(inputParameters);
196
197             lastMatrixRow(inputParameters);
198
199             effect = FEColorMatrix::create(*this, FECOLORMATRIX_TYPE_MATRIX, inputParameters);
200             break;
201         }
202         case FilterOperation::SATURATE: {
203             auto& colorMatrixOperation = downcast<BasicColorMatrixFilterOperation>(filterOperation);
204             Vector<float> inputParameters;
205             inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation.amount()));
206             effect = FEColorMatrix::create(*this, FECOLORMATRIX_TYPE_SATURATE, inputParameters);
207             break;
208         }
209         case FilterOperation::HUE_ROTATE: {
210             auto& colorMatrixOperation = downcast<BasicColorMatrixFilterOperation>(filterOperation);
211             Vector<float> inputParameters;
212             inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation.amount()));
213             effect = FEColorMatrix::create(*this, FECOLORMATRIX_TYPE_HUEROTATE, inputParameters);
214             break;
215         }
216         case FilterOperation::INVERT: {
217             auto& componentTransferOperation = downcast<BasicComponentTransferFilterOperation>(filterOperation);
218             ComponentTransferFunction transferFunction;
219             transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE;
220             Vector<float> transferParameters;
221             transferParameters.append(narrowPrecisionToFloat(componentTransferOperation.amount()));
222             transferParameters.append(narrowPrecisionToFloat(1 - componentTransferOperation.amount()));
223             transferFunction.tableValues = transferParameters;
224
225             ComponentTransferFunction nullFunction;
226             effect = FEComponentTransfer::create(*this, transferFunction, transferFunction, transferFunction, nullFunction);
227             break;
228         }
229         case FilterOperation::OPACITY: {
230             auto& componentTransferOperation = downcast<BasicComponentTransferFilterOperation>(filterOperation);
231             ComponentTransferFunction transferFunction;
232             transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE;
233             Vector<float> transferParameters;
234             transferParameters.append(0);
235             transferParameters.append(narrowPrecisionToFloat(componentTransferOperation.amount()));
236             transferFunction.tableValues = transferParameters;
237
238             ComponentTransferFunction nullFunction;
239             effect = FEComponentTransfer::create(*this, nullFunction, nullFunction, nullFunction, transferFunction);
240             break;
241         }
242         case FilterOperation::BRIGHTNESS: {
243             auto& componentTransferOperation = downcast<BasicComponentTransferFilterOperation>(filterOperation);
244             ComponentTransferFunction transferFunction;
245             transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
246             transferFunction.slope = narrowPrecisionToFloat(componentTransferOperation.amount());
247             transferFunction.intercept = 0;
248
249             ComponentTransferFunction nullFunction;
250             effect = FEComponentTransfer::create(*this, transferFunction, transferFunction, transferFunction, nullFunction);
251             break;
252         }
253         case FilterOperation::CONTRAST: {
254             auto& componentTransferOperation = downcast<BasicComponentTransferFilterOperation>(filterOperation);
255             ComponentTransferFunction transferFunction;
256             transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
257             float amount = narrowPrecisionToFloat(componentTransferOperation.amount());
258             transferFunction.slope = amount;
259             transferFunction.intercept = -0.5 * amount + 0.5;
260             
261             ComponentTransferFunction nullFunction;
262             effect = FEComponentTransfer::create(*this, transferFunction, transferFunction, transferFunction, nullFunction);
263             break;
264         }
265         case FilterOperation::BLUR: {
266             auto& blurOperation = downcast<BlurFilterOperation>(filterOperation);
267             float stdDeviation = floatValueForLength(blurOperation.stdDeviation(), 0);
268             effect = FEGaussianBlur::create(*this, stdDeviation, stdDeviation, consumer == FilterProperty ? EDGEMODE_NONE : EDGEMODE_DUPLICATE);
269             break;
270         }
271         case FilterOperation::DROP_SHADOW: {
272             auto& dropShadowOperation = downcast<DropShadowFilterOperation>(filterOperation);
273             effect = FEDropShadow::create(*this, dropShadowOperation.stdDeviation(), dropShadowOperation.stdDeviation(),
274                 dropShadowOperation.x(), dropShadowOperation.y(), dropShadowOperation.color(), 1);
275             break;
276         }
277         default:
278             break;
279         }
280
281         if (effect) {
282             // Unlike SVG Filters and CSSFilterImages, filter functions on the filter
283             // property applied here should not clip to their primitive subregions.
284             effect->setClipsToBounds(consumer == FilterFunction);
285             effect->setOperatingColorSpace(ColorSpaceSRGB);
286             
287             if (filterOperation.type() != FilterOperation::REFERENCE) {
288                 effect->inputEffects().append(WTFMove(previousEffect));
289                 m_effects.append(*effect);
290             }
291             previousEffect = WTFMove(effect);
292         }
293     }
294
295     // If we didn't make any effects, tell our caller we are not valid.
296     if (m_effects.isEmpty())
297         return false;
298
299     setMaxEffectRects(m_sourceDrawingRegion);
300     return true;
301 }
302
303 bool FilterEffectRenderer::updateBackingStoreRect(const FloatRect& filterRect)
304 {
305     if (filterRect.isEmpty() || ImageBuffer::sizeNeedsClamping(filterRect.size()))
306         return false;
307
308     if (filterRect == sourceImageRect())
309         return false;
310
311     setSourceImageRect(filterRect);
312     return true;
313 }
314
315 void FilterEffectRenderer::allocateBackingStoreIfNeeded(const GraphicsContext& targetContext)
316 {
317     // At this point the effect chain has been built, and the
318     // source image sizes set. We just need to attach the graphic
319     // buffer if we have not yet done so.
320
321     if (m_graphicsBufferAttached)
322         return;
323
324     IntSize logicalSize { m_sourceDrawingRegion.size() };
325     if (!sourceImage() || sourceImage()->logicalSize() != logicalSize) {
326 #if USE(DIRECT2D)
327         setSourceImage(ImageBuffer::create(logicalSize, renderingMode(), &targetContext, filterScale()));
328 #else
329         UNUSED_PARAM(targetContext);
330         setSourceImage(ImageBuffer::create(logicalSize, renderingMode(), filterScale()));
331 #endif
332     }
333     m_graphicsBufferAttached = true;
334 }
335
336 void FilterEffectRenderer::clearIntermediateResults()
337 {
338     m_sourceGraphic->clearResult();
339     for (auto& effect : m_effects)
340         effect->clearResult();
341 }
342
343 void FilterEffectRenderer::apply()
344 {
345     auto& effect = m_effects.last().get();
346     effect.apply();
347     effect.transformResultColorSpace(ColorSpaceSRGB);
348 }
349
350 LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect)
351 {
352     // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect".
353     auto rectForRepaint = dirtyRect;
354     if (hasFilterThatMovesPixels()) {
355         // Note that the outsets are reversed here because we are going backwards -> we have the dirty rect and
356         // need to find out what is the rectangle that might influence the result inside that dirty rect.
357         rectForRepaint.move(-m_outsets.right(), -m_outsets.bottom());
358         rectForRepaint.expand(m_outsets.left() + m_outsets.right(), m_outsets.top() + m_outsets.bottom());
359     }
360     rectForRepaint.intersect(filterBoxRect);
361     return rectForRepaint;
362 }
363
364 ImageBuffer* FilterEffectRenderer::output() const
365 {
366     return m_effects.last()->imageBufferResult();
367 }
368
369 void FilterEffectRenderer::setMaxEffectRects(const FloatRect& effectRect)
370 {
371     for (auto& effect : m_effects)
372         effect->setMaxEffectRect(effectRect);
373 }
374
375 IntRect FilterEffectRenderer::outputRect() const
376 {
377     auto& lastEffect = m_effects.last().get();
378     if (!lastEffect.hasResult())
379         return { };
380     return lastEffect.requestedRegionOfInputImageData(IntRect { m_filterRegion });
381 }
382
383 bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer& layer, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect)
384 {
385     ASSERT(m_haveFilterEffect);
386     ASSERT(layer.filterRenderer());
387
388     auto& filter = *layer.filterRenderer();
389     auto filterSourceRect = filter.computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect);
390
391     if (filterSourceRect.isEmpty()) {
392         // The dirty rect is not in view, just bail out.
393         m_haveFilterEffect = false;
394         return false;
395     }
396
397     bool hasUpdatedBackingStore = filter.updateBackingStoreRect(filterSourceRect);
398
399     m_renderLayer = &layer;
400     if (!filter.hasFilterThatMovesPixels())
401         m_repaintRect = dirtyRect;
402     else {
403         if (hasUpdatedBackingStore)
404             m_repaintRect = filterSourceRect;
405         else {
406             m_repaintRect = dirtyRect;
407             m_repaintRect.unite(layerRepaintRect);
408             m_repaintRect.intersect(filterSourceRect);
409         }
410     }
411     m_paintOffset = filterSourceRect.location();
412
413     return true;
414 }
415
416 GraphicsContext* FilterEffectRendererHelper::filterContext() const
417 {
418     if (!m_haveFilterEffect)
419         return nullptr;
420     return m_renderLayer->filterRenderer()->inputContext();
421 }
422
423 bool FilterEffectRendererHelper::beginFilterEffect()
424 {
425     ASSERT(m_renderLayer);
426     ASSERT(m_renderLayer->filterRenderer());
427
428     auto& filter = *m_renderLayer->filterRenderer();
429     filter.allocateBackingStoreIfNeeded(m_targetContext);
430     // Paint into the context that represents the SourceGraphic of the filter.
431     auto* sourceGraphicsContext = filter.inputContext();
432     if (!sourceGraphicsContext || filter.filterRegion().isEmpty() || ImageBuffer::sizeNeedsClamping(filter.filterRegion().size())) {
433         // Disable the filters and continue.
434         m_haveFilterEffect = false;
435         return false;
436     }
437
438     // Translate the context so that the contents of the layer is captured in the offscreen memory buffer.
439     sourceGraphicsContext->save();
440     sourceGraphicsContext->translate(-m_paintOffset);
441     sourceGraphicsContext->clearRect(m_repaintRect);
442     sourceGraphicsContext->clip(m_repaintRect);
443
444     m_startedFilterEffect = true;
445     return true;
446 }
447
448 void FilterEffectRendererHelper::applyFilterEffect(GraphicsContext& destinationContext)
449 {
450     ASSERT(m_haveFilterEffect);
451     ASSERT(m_renderLayer);
452     ASSERT(m_renderLayer->filterRenderer());
453     ASSERT(m_renderLayer->filterRenderer()->inputContext());
454
455     auto& filter = *m_renderLayer->filterRenderer();
456     filter.inputContext()->restore();
457
458     filter.apply();
459
460     // Get the filtered output and draw it in place.
461     LayoutRect destRect = filter.outputRect();
462     destRect.move(m_paintOffset.x(), m_paintOffset.y());
463
464     if (auto* outputBuffer = filter.output())
465         destinationContext.drawImageBuffer(*outputBuffer, snapRectToDevicePixels(destRect, m_renderLayer->renderer().document().deviceScaleFactor()));
466
467     filter.clearIntermediateResults();
468 }
469
470 } // namespace WebCore