Fix the issue that Web Audio test case fails on PR3.
[framework/web/webkit-efl.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 COMPUTER, 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 "Document.h"
33 #include "FEColorMatrix.h"
34 #include "FEComponentTransfer.h"
35 #include "FEDropShadow.h"
36 #include "FEGaussianBlur.h"
37 #include "FEMerge.h"
38 #include "FloatConversion.h"
39 #include "RenderLayer.h"
40
41 #include <algorithm>
42 #include <wtf/MathExtras.h>
43
44 #if ENABLE(CSS_SHADERS) && ENABLE(WEBGL)
45 #include "CustomFilterGlobalContext.h"
46 #include "CustomFilterProgram.h"
47 #include "CustomFilterOperation.h"
48 #include "FECustomFilter.h"
49 #include "RenderView.h"
50 #include "Settings.h"
51 #endif
52
53 #if ENABLE(SVG)
54 #include "CachedSVGDocument.h"
55 #include "SVGElement.h"
56 #include "SVGFilterPrimitiveStandardAttributes.h"
57 #include "SourceAlpha.h"
58 #endif
59
60 namespace WebCore {
61
62 static inline void endMatrixRow(Vector<float>& parameters)
63 {
64     parameters.append(0);
65     parameters.append(0);
66 }
67
68 static inline void lastMatrixRow(Vector<float>& parameters)
69 {
70     parameters.append(0);
71     parameters.append(0);
72     parameters.append(0);
73     parameters.append(1);
74     parameters.append(0);
75 }
76
77 inline bool isFilterSizeValid(FloatRect rect)
78 {
79     if (rect.width() < 0 || rect.width() > kMaxFilterSize
80         || rect.height() < 0 || rect.height() > kMaxFilterSize)
81         return false;
82     return true;
83 }
84
85 #if ENABLE(CSS_SHADERS) && ENABLE(WEBGL)
86 static bool isCSSCustomFilterEnabled(Document* document)
87 {
88     // We only want to enable shaders if WebGL is also enabled on this platform.
89     Settings* settings = document->settings();
90     return settings && settings->isCSSCustomFilterEnabled() && settings->webGLEnabled();
91 }
92 #endif
93
94 FilterEffectRenderer::FilterEffectRenderer()
95     : m_topOutset(0)
96     , m_rightOutset(0)
97     , m_bottomOutset(0)
98     , m_leftOutset(0)
99     , m_graphicsBufferAttached(false)
100     , m_hasFilterThatMovesPixels(false)
101 #if ENABLE(CSS_SHADERS)
102     , m_hasCustomShaderFilter(false)
103 #endif
104 {
105     setFilterResolution(FloatSize(1, 1));
106     m_sourceGraphic = SourceGraphic::create(this);
107 }
108
109 FilterEffectRenderer::~FilterEffectRenderer()
110 {
111 }
112
113 GraphicsContext* FilterEffectRenderer::inputContext()
114 {
115     return sourceImage() ? sourceImage()->context() : 0;
116 }
117
118 PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(Document* document, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation* op)
119 {
120 #if ENABLE(SVG)
121     CachedSVGDocument* cachedSVGDocument = static_cast<CachedSVGDocument*>(op->data());
122
123     // If we have an SVG document, this is an external reference. Otherwise
124     // we look up the referenced node in the current document.
125     if (cachedSVGDocument)
126         document = cachedSVGDocument->document();
127
128     if (!document)
129         return 0;
130
131     Element* filter = document->getElementById(op->fragment());
132     if (!filter)
133         return 0;
134
135     RefPtr<FilterEffect> effect;
136
137     // FIXME: Figure out what to do with SourceAlpha. Right now, we're
138     // using the alpha of the original input layer, which is obviously
139     // wrong. We should probably be extracting the alpha from the 
140     // previousEffect, but this requires some more processing.  
141     // This may need a spec clarification.
142     RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(previousEffect, SourceAlpha::create(this));
143
144     for (Node* node = filter->firstChild(); node; node = node->nextSibling()) {
145         if (!node->isSVGElement())
146             continue;
147
148         SVGElement* element = static_cast<SVGElement*>(node);
149         if (!element->isFilterEffect())
150             continue;
151
152         SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element);
153
154         effect = effectElement->build(builder.get(), this);
155         if (!effect)
156             continue;
157
158         effectElement->setStandardAttributes(effect.get());
159         builder->add(effectElement->result(), effect);
160         m_effects.append(effect);
161     }
162     return effect;
163 #else
164     UNUSED_PARAM(document);
165     UNUSED_PARAM(previousEffect);
166     UNUSED_PARAM(op);
167     return 0;
168 #endif
169 }
170
171 bool FilterEffectRenderer::build(Document* document, const FilterOperations& operations)
172 {
173 #if !ENABLE(CSS_SHADERS) || !ENABLE(WEBGL)
174     UNUSED_PARAM(document);
175 #endif
176
177 #if ENABLE(CSS_SHADERS)
178     m_hasCustomShaderFilter = false;
179 #endif
180     m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels();
181     if (m_hasFilterThatMovesPixels)
182         operations.getOutsets(m_topOutset, m_rightOutset, m_bottomOutset, m_leftOutset);
183     m_effects.clear();
184
185     RefPtr<FilterEffect> previousEffect = m_sourceGraphic;
186     for (size_t i = 0; i < operations.operations().size(); ++i) {
187         RefPtr<FilterEffect> effect;
188         FilterOperation* filterOperation = operations.operations().at(i).get();
189         switch (filterOperation->getOperationType()) {
190         case FilterOperation::REFERENCE: {
191             effect = buildReferenceFilter(document, previousEffect, static_cast<ReferenceFilterOperation*>(filterOperation));
192             break;
193         }
194         case FilterOperation::GRAYSCALE: {
195             BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation);
196             Vector<float> inputParameters;
197             double oneMinusAmount = clampTo(1 - colorMatrixOperation->amount(), 0.0, 1.0);
198
199             // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#grayscaleEquivalent
200             // for information on parameters.
201
202             inputParameters.append(narrowPrecisionToFloat(0.2126 + 0.7874 * oneMinusAmount));
203             inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount));
204             inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount));
205             endMatrixRow(inputParameters);
206
207             inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount));
208             inputParameters.append(narrowPrecisionToFloat(0.7152 + 0.2848 * oneMinusAmount));
209             inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount));
210             endMatrixRow(inputParameters);
211
212             inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount));
213             inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount));
214             inputParameters.append(narrowPrecisionToFloat(0.0722 + 0.9278 * oneMinusAmount));
215             endMatrixRow(inputParameters);
216
217             lastMatrixRow(inputParameters);
218
219             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters);
220             break;
221         }
222         case FilterOperation::SEPIA: {
223             BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation);
224             Vector<float> inputParameters;
225             double oneMinusAmount = clampTo(1 - colorMatrixOperation->amount(), 0.0, 1.0);
226
227             // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#sepiaEquivalent
228             // for information on parameters.
229
230             inputParameters.append(narrowPrecisionToFloat(0.393 + 0.607 * oneMinusAmount));
231             inputParameters.append(narrowPrecisionToFloat(0.769 - 0.769 * oneMinusAmount));
232             inputParameters.append(narrowPrecisionToFloat(0.189 - 0.189 * oneMinusAmount));
233             endMatrixRow(inputParameters);
234
235             inputParameters.append(narrowPrecisionToFloat(0.349 - 0.349 * oneMinusAmount));
236             inputParameters.append(narrowPrecisionToFloat(0.686 + 0.314 * oneMinusAmount));
237             inputParameters.append(narrowPrecisionToFloat(0.168 - 0.168 * oneMinusAmount));
238             endMatrixRow(inputParameters);
239
240             inputParameters.append(narrowPrecisionToFloat(0.272 - 0.272 * oneMinusAmount));
241             inputParameters.append(narrowPrecisionToFloat(0.534 - 0.534 * oneMinusAmount));
242             inputParameters.append(narrowPrecisionToFloat(0.131 + 0.869 * oneMinusAmount));
243             endMatrixRow(inputParameters);
244
245             lastMatrixRow(inputParameters);
246
247             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters);
248             break;
249         }
250         case FilterOperation::SATURATE: {
251             BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation);
252             Vector<float> inputParameters;
253             inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount()));
254             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_SATURATE, inputParameters);
255             break;
256         }
257         case FilterOperation::HUE_ROTATE: {
258             BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation);
259             Vector<float> inputParameters;
260             inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount()));
261             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_HUEROTATE, inputParameters);
262             break;
263         }
264         case FilterOperation::INVERT: {
265             BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation);
266             ComponentTransferFunction transferFunction;
267             transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE;
268             Vector<float> transferParameters;
269             transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount()));
270             transferParameters.append(narrowPrecisionToFloat(1 - componentTransferOperation->amount()));
271             transferFunction.tableValues = transferParameters;
272
273             ComponentTransferFunction nullFunction;
274             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
275             break;
276         }
277         case FilterOperation::OPACITY: {
278             BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation);
279             ComponentTransferFunction transferFunction;
280             transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE;
281             Vector<float> transferParameters;
282             transferParameters.append(0);
283             transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount()));
284             transferFunction.tableValues = transferParameters;
285
286             ComponentTransferFunction nullFunction;
287             effect = FEComponentTransfer::create(this, nullFunction, nullFunction, nullFunction, transferFunction);
288             break;
289         }
290         case FilterOperation::BRIGHTNESS: {
291             BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation);
292             ComponentTransferFunction transferFunction;
293             transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
294             transferFunction.slope = 1;
295             transferFunction.intercept = narrowPrecisionToFloat(componentTransferOperation->amount());
296
297             ComponentTransferFunction nullFunction;
298             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
299             break;
300         }
301         case FilterOperation::CONTRAST: {
302             BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation);
303             ComponentTransferFunction transferFunction;
304             transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
305             float amount = narrowPrecisionToFloat(componentTransferOperation->amount());
306             transferFunction.slope = amount;
307             transferFunction.intercept = -0.5 * amount + 0.5;
308             
309             ComponentTransferFunction nullFunction;
310             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
311             break;
312         }
313         case FilterOperation::BLUR: {
314             BlurFilterOperation* blurOperation = static_cast<BlurFilterOperation*>(filterOperation);
315             float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0);
316             effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation);
317             break;
318         }
319         case FilterOperation::DROP_SHADOW: {
320             DropShadowFilterOperation* dropShadowOperation = static_cast<DropShadowFilterOperation*>(filterOperation);
321             effect = FEDropShadow::create(this, dropShadowOperation->stdDeviation(), dropShadowOperation->stdDeviation(),
322                                                 dropShadowOperation->x(), dropShadowOperation->y(), dropShadowOperation->color(), 1);
323             break;
324         }
325 #if ENABLE(CSS_SHADERS)
326         case FilterOperation::CUSTOM: {
327 #if ENABLE(WEBGL)
328             if (!isCSSCustomFilterEnabled(document))
329                 continue;
330             
331             CustomFilterOperation* customFilterOperation = static_cast<CustomFilterOperation*>(filterOperation);
332             RefPtr<CustomFilterProgram> program = customFilterOperation->program();
333             if (program->isLoaded()) {
334                 CustomFilterGlobalContext* globalContext = document->renderView()->customFilterGlobalContext();
335                 globalContext->prepareContextIfNeeded(document->view()->hostWindow());
336                 effect = FECustomFilter::create(this, globalContext, program, customFilterOperation->parameters(),
337                                                 customFilterOperation->meshRows(), customFilterOperation->meshColumns(),
338                                                 customFilterOperation->meshBoxType(), customFilterOperation->meshType());
339                 m_hasCustomShaderFilter = true;
340             }
341 #endif
342             break;
343         }
344 #endif
345         default:
346             break;
347         }
348
349         if (effect) {
350             // Unlike SVG, filters applied here should not clip to their primitive subregions.
351             effect->setClipsToBounds(false);
352             
353             if (filterOperation->getOperationType() != FilterOperation::REFERENCE) {
354                 effect->inputEffects().append(previousEffect);
355                 m_effects.append(effect);
356             }
357             previousEffect = effect.release();
358         }
359     }
360
361     // If we didn't make any effects, tell our caller we are not valid
362     if (!m_effects.size())
363         return false;
364
365     setMaxEffectRects(m_sourceDrawingRegion);
366     
367     return true;
368 }
369
370 bool FilterEffectRenderer::updateBackingStoreRect(const FloatRect& filterRect)
371 {
372     if (!filterRect.isZero() && isFilterSizeValid(filterRect)) {
373         FloatRect currentSourceRect = sourceImageRect();
374         if (filterRect != currentSourceRect) {
375             setSourceImageRect(filterRect);
376             return true;
377         }
378     }
379     return false;
380 }
381
382 void FilterEffectRenderer::allocateBackingStoreIfNeeded()
383 {
384     // At this point the effect chain has been built, and the
385     // source image sizes set. We just need to attach the graphic
386     // buffer if we have not yet done so.
387     if (!m_graphicsBufferAttached) {
388         IntSize logicalSize(m_sourceDrawingRegion.width(), m_sourceDrawingRegion.height());
389         if (!sourceImage() || sourceImage()->logicalSize() != logicalSize)
390             setSourceImage(ImageBuffer::create(logicalSize, 1, ColorSpaceDeviceRGB, renderingMode()));
391         m_graphicsBufferAttached = true;
392     }
393 }
394
395 void FilterEffectRenderer::clearIntermediateResults()
396 {
397     m_sourceGraphic->clearResult();
398     for (size_t i = 0; i < m_effects.size(); ++i)
399         m_effects[i]->clearResult();
400 }
401
402 void FilterEffectRenderer::apply()
403 {
404     lastEffect()->apply();
405 }
406
407 LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect)
408 {
409 #if ENABLE(CSS_SHADERS)
410     if (hasCustomShaderFilter()) {
411         // When we have at least a custom shader in the chain, we need to compute the whole source image, because the shader can
412         // reference any pixel and we cannot control that.
413         return filterBoxRect;
414     }
415 #endif
416     // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect".
417     LayoutRect rectForRepaint = dirtyRect;
418     if (hasFilterThatMovesPixels()) {
419         // Note that the outsets are reversed here because we are going backwards -> we have the dirty rect and
420         // need to find out what is the rectangle that might influence the result inside that dirty rect.
421         rectForRepaint.move(-m_rightOutset, -m_bottomOutset);
422         rectForRepaint.expand(m_leftOutset + m_rightOutset, m_topOutset + m_bottomOutset);
423     }
424     rectForRepaint.intersect(filterBoxRect);
425     return rectForRepaint;
426 }
427
428 bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect)
429 {
430     ASSERT(m_haveFilterEffect && renderLayer->filterRenderer());
431     m_renderLayer = renderLayer;
432     m_repaintRect = dirtyRect;
433
434     FilterEffectRenderer* filter = renderLayer->filterRenderer();
435     LayoutRect filterSourceRect = filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect);
436     m_paintOffset = filterSourceRect.location();
437
438     if (filterSourceRect.isEmpty()) {
439         // The dirty rect is not in view, just bail out.
440         m_haveFilterEffect = false;
441         return false;
442     }
443     
444     bool hasUpdatedBackingStore = filter->updateBackingStoreRect(filterSourceRect);
445     if (filter->hasFilterThatMovesPixels()) {
446         if (hasUpdatedBackingStore)
447             m_repaintRect = filterSourceRect;
448         else {
449             m_repaintRect.unite(layerRepaintRect);
450             m_repaintRect.intersect(filterSourceRect);
451         }
452     }
453     return true;
454 }
455    
456 GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(GraphicsContext* oldContext)
457 {
458     ASSERT(m_renderLayer);
459     
460     FilterEffectRenderer* filter = m_renderLayer->filterRenderer();
461     filter->allocateBackingStoreIfNeeded();
462     // Paint into the context that represents the SourceGraphic of the filter.
463     GraphicsContext* sourceGraphicsContext = filter->inputContext();
464     if (!sourceGraphicsContext || !isFilterSizeValid(filter->filterRegion())) {
465         // Disable the filters and continue.
466         m_haveFilterEffect = false;
467         return oldContext;
468     }
469     
470     m_savedGraphicsContext = oldContext;
471     
472     // Translate the context so that the contents of the layer is captuterd in the offscreen memory buffer.
473     sourceGraphicsContext->save();
474     sourceGraphicsContext->translate(-m_paintOffset.x(), -m_paintOffset.y());
475     sourceGraphicsContext->clearRect(m_repaintRect);
476     sourceGraphicsContext->clip(m_repaintRect);
477     
478     return sourceGraphicsContext;
479 }
480
481 GraphicsContext* FilterEffectRendererHelper::applyFilterEffect()
482 {
483     ASSERT(m_haveFilterEffect && m_renderLayer->filterRenderer());
484     FilterEffectRenderer* filter = m_renderLayer->filterRenderer();
485     filter->inputContext()->restore();
486
487     filter->apply();
488     
489     // Get the filtered output and draw it in place.
490     LayoutRect destRect = filter->outputRect();
491     destRect.move(m_paintOffset.x(), m_paintOffset.y());
492     
493     m_savedGraphicsContext->drawImageBuffer(filter->output(), m_renderLayer->renderer()->style()->colorSpace(), pixelSnappedIntRect(destRect), CompositeSourceOver);
494     
495     filter->clearIntermediateResults();
496     
497     return m_savedGraphicsContext;
498 }
499
500 } // namespace WebCore
501
502 #endif // ENABLE(CSS_FILTERS)