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