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