Assertion failure under FEImage::determineAbsolutePaintRect()
[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 #if ENABLE(CSS_FILTERS)
30
31 #include "FilterEffectRenderer.h"
32
33 #include "CachedSVGDocument.h"
34 #include "CachedSVGDocumentReference.h"
35 #include "ColorSpace.h"
36 #include "Document.h"
37 #include "ElementIterator.h"
38 #include "FEColorMatrix.h"
39 #include "FEComponentTransfer.h"
40 #include "FEDropShadow.h"
41 #include "FEGaussianBlur.h"
42 #include "FEMerge.h"
43 #include "FloatConversion.h"
44 #include "Frame.h"
45 #include "RenderLayer.h"
46 #include "SVGElement.h"
47 #include "SVGFilterPrimitiveStandardAttributes.h"
48 #include "Settings.h"
49 #include "SourceAlpha.h"
50
51 #include <algorithm>
52 #include <wtf/MathExtras.h>
53
54 namespace WebCore {
55
56 static inline void endMatrixRow(Vector<float>& parameters)
57 {
58     parameters.append(0);
59     parameters.append(0);
60 }
61
62 static inline void lastMatrixRow(Vector<float>& parameters)
63 {
64     parameters.append(0);
65     parameters.append(0);
66     parameters.append(0);
67     parameters.append(1);
68     parameters.append(0);
69 }
70
71 FilterEffectRenderer::FilterEffectRenderer()
72     : Filter(AffineTransform())
73     , m_graphicsBufferAttached(false)
74     , m_hasFilterThatMovesPixels(false)
75 {
76     setFilterResolution(FloatSize(1, 1));
77     m_sourceGraphic = SourceGraphic::create(this);
78 }
79
80 FilterEffectRenderer::~FilterEffectRenderer()
81 {
82 }
83
84 GraphicsContext* FilterEffectRenderer::inputContext()
85 {
86     return sourceImage() ? sourceImage()->context() : 0;
87 }
88
89 PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(RenderElement* renderer, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation* filterOperation)
90 {
91     if (!renderer)
92         return 0;
93
94     Document* document = &renderer->document();
95
96     CachedSVGDocumentReference* cachedSVGDocumentReference = filterOperation->cachedSVGDocumentReference();
97     CachedSVGDocument* cachedSVGDocument = cachedSVGDocumentReference ? cachedSVGDocumentReference->document() : 0;
98
99     // If we have an SVG document, this is an external reference. Otherwise
100     // we look up the referenced node in the current document.
101     if (cachedSVGDocument)
102         document = cachedSVGDocument->document();
103
104     if (!document)
105         return 0;
106
107     Element* filter = document->getElementById(filterOperation->fragment());
108     if (!filter) {
109         // Although we did not find the referenced filter, it might exist later in the document.
110         // FIXME: This skips anonymous RenderObjects. <https://webkit.org/b/131085>
111         if (Element* element = renderer->element())
112             document->accessSVGExtensions()->addPendingResource(filterOperation->fragment(), element);
113         return 0;
114     }
115
116     RefPtr<FilterEffect> effect;
117
118     // FIXME: Figure out what to do with SourceAlpha. Right now, we're
119     // using the alpha of the original input layer, which is obviously
120     // wrong. We should probably be extracting the alpha from the 
121     // previousEffect, but this requires some more processing.  
122     // This may need a spec clarification.
123     auto builder = std::make_unique<SVGFilterBuilder>(previousEffect, SourceAlpha::create(this));
124
125     for (auto& effectElement : childrenOfType<SVGFilterPrimitiveStandardAttributes>(*filter)) {
126         effect = effectElement.build(builder.get(), this);
127         if (!effect)
128             continue;
129
130         effectElement.setStandardAttributes(effect.get());
131         builder->add(effectElement.result(), effect);
132         m_effects.append(effect);
133     }
134     return effect;
135 }
136
137 bool FilterEffectRenderer::build(RenderElement* renderer, const FilterOperations& operations, FilterConsumer consumer)
138 {
139     m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels();
140     if (m_hasFilterThatMovesPixels)
141         m_outsets = operations.outsets();
142
143     m_effects.clear();
144
145     RefPtr<FilterEffect> previousEffect = m_sourceGraphic;
146     for (size_t i = 0; i < operations.operations().size(); ++i) {
147         RefPtr<FilterEffect> effect;
148         FilterOperation* filterOperation = operations.operations().at(i).get();
149         switch (filterOperation->type()) {
150         case FilterOperation::REFERENCE: {
151             ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation);
152             effect = buildReferenceFilter(renderer, previousEffect, referenceOperation);
153             referenceOperation->setFilterEffect(effect);
154             break;
155         }
156         case FilterOperation::GRAYSCALE: {
157             BasicColorMatrixFilterOperation* colorMatrixOperation = toBasicColorMatrixFilterOperation(filterOperation);
158             Vector<float> inputParameters;
159             double oneMinusAmount = clampTo(1 - colorMatrixOperation->amount(), 0.0, 1.0);
160
161             // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#grayscaleEquivalent
162             // for information on parameters.
163
164             inputParameters.append(narrowPrecisionToFloat(0.2126 + 0.7874 * oneMinusAmount));
165             inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount));
166             inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount));
167             endMatrixRow(inputParameters);
168
169             inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount));
170             inputParameters.append(narrowPrecisionToFloat(0.7152 + 0.2848 * oneMinusAmount));
171             inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount));
172             endMatrixRow(inputParameters);
173
174             inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount));
175             inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount));
176             inputParameters.append(narrowPrecisionToFloat(0.0722 + 0.9278 * oneMinusAmount));
177             endMatrixRow(inputParameters);
178
179             lastMatrixRow(inputParameters);
180
181             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters);
182             break;
183         }
184         case FilterOperation::SEPIA: {
185             BasicColorMatrixFilterOperation* colorMatrixOperation = toBasicColorMatrixFilterOperation(filterOperation);
186             Vector<float> inputParameters;
187             double oneMinusAmount = clampTo(1 - colorMatrixOperation->amount(), 0.0, 1.0);
188
189             // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#sepiaEquivalent
190             // for information on parameters.
191
192             inputParameters.append(narrowPrecisionToFloat(0.393 + 0.607 * oneMinusAmount));
193             inputParameters.append(narrowPrecisionToFloat(0.769 - 0.769 * oneMinusAmount));
194             inputParameters.append(narrowPrecisionToFloat(0.189 - 0.189 * oneMinusAmount));
195             endMatrixRow(inputParameters);
196
197             inputParameters.append(narrowPrecisionToFloat(0.349 - 0.349 * oneMinusAmount));
198             inputParameters.append(narrowPrecisionToFloat(0.686 + 0.314 * oneMinusAmount));
199             inputParameters.append(narrowPrecisionToFloat(0.168 - 0.168 * oneMinusAmount));
200             endMatrixRow(inputParameters);
201
202             inputParameters.append(narrowPrecisionToFloat(0.272 - 0.272 * oneMinusAmount));
203             inputParameters.append(narrowPrecisionToFloat(0.534 - 0.534 * oneMinusAmount));
204             inputParameters.append(narrowPrecisionToFloat(0.131 + 0.869 * oneMinusAmount));
205             endMatrixRow(inputParameters);
206
207             lastMatrixRow(inputParameters);
208
209             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters);
210             break;
211         }
212         case FilterOperation::SATURATE: {
213             BasicColorMatrixFilterOperation* colorMatrixOperation = toBasicColorMatrixFilterOperation(filterOperation);
214             Vector<float> inputParameters;
215             inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount()));
216             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_SATURATE, inputParameters);
217             break;
218         }
219         case FilterOperation::HUE_ROTATE: {
220             BasicColorMatrixFilterOperation* colorMatrixOperation = toBasicColorMatrixFilterOperation(filterOperation);
221             Vector<float> inputParameters;
222             inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount()));
223             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_HUEROTATE, inputParameters);
224             break;
225         }
226         case FilterOperation::INVERT: {
227             BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(filterOperation);
228             ComponentTransferFunction transferFunction;
229             transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE;
230             Vector<float> transferParameters;
231             transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount()));
232             transferParameters.append(narrowPrecisionToFloat(1 - componentTransferOperation->amount()));
233             transferFunction.tableValues = transferParameters;
234
235             ComponentTransferFunction nullFunction;
236             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
237             break;
238         }
239         case FilterOperation::OPACITY: {
240             BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(filterOperation);
241             ComponentTransferFunction transferFunction;
242             transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE;
243             Vector<float> transferParameters;
244             transferParameters.append(0);
245             transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount()));
246             transferFunction.tableValues = transferParameters;
247
248             ComponentTransferFunction nullFunction;
249             effect = FEComponentTransfer::create(this, nullFunction, nullFunction, nullFunction, transferFunction);
250             break;
251         }
252         case FilterOperation::BRIGHTNESS: {
253             BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(filterOperation);
254             ComponentTransferFunction transferFunction;
255             transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
256             transferFunction.slope = narrowPrecisionToFloat(componentTransferOperation->amount());
257             transferFunction.intercept = 0;
258
259             ComponentTransferFunction nullFunction;
260             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
261             break;
262         }
263         case FilterOperation::CONTRAST: {
264             BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(filterOperation);
265             ComponentTransferFunction transferFunction;
266             transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
267             float amount = narrowPrecisionToFloat(componentTransferOperation->amount());
268             transferFunction.slope = amount;
269             transferFunction.intercept = -0.5 * amount + 0.5;
270             
271             ComponentTransferFunction nullFunction;
272             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
273             break;
274         }
275         case FilterOperation::BLUR: {
276             BlurFilterOperation* blurOperation = toBlurFilterOperation(filterOperation);
277             float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0);
278             effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation, consumer == FilterProperty ? EDGEMODE_NONE : EDGEMODE_DUPLICATE);
279             break;
280         }
281         case FilterOperation::DROP_SHADOW: {
282             DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation);
283             effect = FEDropShadow::create(this, dropShadowOperation->stdDeviation(), dropShadowOperation->stdDeviation(),
284                                                 dropShadowOperation->x(), dropShadowOperation->y(), dropShadowOperation->color(), 1);
285             break;
286         }
287         default:
288             break;
289         }
290
291         if (effect) {
292             // Unlike SVG Filters and CSSFilterImages, filter functions on the filter
293             // property applied here should not clip to their primitive subregions.
294             effect->setClipsToBounds(consumer == FilterFunction);
295             effect->setOperatingColorSpace(ColorSpaceDeviceRGB);
296             
297             if (filterOperation->type() != FilterOperation::REFERENCE) {
298                 effect->inputEffects().append(previousEffect);
299                 m_effects.append(effect);
300             }
301             previousEffect = effect.release();
302         }
303     }
304
305     // If we didn't make any effects, tell our caller we are not valid
306     if (!m_effects.size())
307         return false;
308
309     setMaxEffectRects(m_sourceDrawingRegion);
310     
311     return true;
312 }
313
314 bool FilterEffectRenderer::updateBackingStoreRect(const FloatRect& filterRect)
315 {
316     if (!filterRect.isZero() && FilterEffect::isFilterSizeValid(filterRect)) {
317         FloatRect currentSourceRect = sourceImageRect();
318         if (filterRect != currentSourceRect) {
319             setSourceImageRect(filterRect);
320             return true;
321         }
322     }
323     return false;
324 }
325
326 void FilterEffectRenderer::allocateBackingStoreIfNeeded()
327 {
328     // At this point the effect chain has been built, and the
329     // source image sizes set. We just need to attach the graphic
330     // buffer if we have not yet done so.
331     if (!m_graphicsBufferAttached) {
332         IntSize logicalSize(m_sourceDrawingRegion.width(), m_sourceDrawingRegion.height());
333         if (!sourceImage() || sourceImage()->logicalSize() != logicalSize)
334             setSourceImage(ImageBuffer::create(logicalSize, 1, ColorSpaceDeviceRGB, renderingMode()));
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(ColorSpaceDeviceRGB);
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 0;
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();
410     // Paint into the context that represents the SourceGraphic of the filter.
411     GraphicsContext* sourceGraphicsContext = filter->inputContext();
412     if (!sourceGraphicsContext || !FilterEffect::isFilterSizeValid(filter->filterRegion())) {
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 captuterd 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     destinationContext->drawImageBuffer(filter->output(), m_renderLayer->renderer().style().colorSpace(),
441         pixelSnappedForPainting(destRect, m_renderLayer->renderer().document().deviceScaleFactor()), CompositeSourceOver);
442
443     filter->clearIntermediateResults();
444 }
445
446 } // namespace WebCore
447
448 #endif // ENABLE(CSS_FILTERS)