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