[CSS Shaders] Make CSS Shaders compile on Chromium
[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 "Document.h"
33 #include "FEColorMatrix.h"
34 #include "FEComponentTransfer.h"
35 #include "FEDropShadow.h"
36 #include "FEGaussianBlur.h"
37 #include "FEMerge.h"
38 #include "FilterEffectObserver.h"
39 #include "FloatConversion.h"
40 #include "RenderLayer.h"
41
42 #include <algorithm>
43 #include <wtf/MathExtras.h>
44
45 #if ENABLE(CSS_SHADERS) && ENABLE(WEBGL)
46 #include "CustomFilterProgram.h"
47 #include "CustomFilterOperation.h"
48 #include "FECustomFilter.h"
49 #include "FrameView.h"
50 #include "Settings.h"
51 #endif
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     
71 #if ENABLE(CSS_SHADERS) && ENABLE(WEBGL)
72 static bool isCSSCustomFilterEnabled(Document* document)
73 {
74     // We only want to enable shaders if WebGL is also enabled on this platform.
75     Settings* settings = document->settings();
76     return settings && settings->isCSSCustomFilterEnabled() && settings->webGLEnabled();
77 }
78 #endif
79
80 FilterEffectRenderer::FilterEffectRenderer(FilterEffectObserver* observer)
81     : m_observer(observer)
82     , m_graphicsBufferAttached(false)
83 {
84     setFilterResolution(FloatSize(1, 1));
85     m_sourceGraphic = SourceGraphic::create(this);
86 }
87
88 FilterEffectRenderer::~FilterEffectRenderer()
89 {
90 #if ENABLE(CSS_SHADERS)
91     removeCustomFilterClients();
92 #endif
93 }
94
95 GraphicsContext* FilterEffectRenderer::inputContext()
96 {
97     return sourceImage() ? sourceImage()->context() : 0;
98 }
99
100 void FilterEffectRenderer::build(Document* document, const FilterOperations& operations)
101 {
102 #if !ENABLE(CSS_SHADERS) || !ENABLE(WEBGL)
103     UNUSED_PARAM(document);
104 #else
105     CustomFilterProgramList cachedCustomFilterPrograms;
106 #endif
107
108     m_effects.clear();
109
110     RefPtr<FilterEffect> previousEffect;
111     for (size_t i = 0; i < operations.operations().size(); ++i) {
112         RefPtr<FilterEffect> effect;
113         FilterOperation* filterOperation = operations.operations().at(i).get();
114         switch (filterOperation->getOperationType()) {
115         case FilterOperation::REFERENCE: {
116             // FIXME: Not yet implemented.
117             // https://bugs.webkit.org/show_bug.cgi?id=72443
118             break;
119         }
120         case FilterOperation::GRAYSCALE: {
121             BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation);
122             Vector<float> inputParameters;
123             double oneMinusAmount = clampTo(1 - colorMatrixOperation->amount(), 0.0, 1.0);
124
125             // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#grayscaleEquivalent
126             // for information on parameters.
127
128             inputParameters.append(narrowPrecisionToFloat(0.2126 + 0.7874 * oneMinusAmount));
129             inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount));
130             inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount));
131             endMatrixRow(inputParameters);
132
133             inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount));
134             inputParameters.append(narrowPrecisionToFloat(0.7152 + 0.2848 * oneMinusAmount));
135             inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount));
136             endMatrixRow(inputParameters);
137
138             inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount));
139             inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount));
140             inputParameters.append(narrowPrecisionToFloat(0.0722 + 0.9278 * oneMinusAmount));
141             endMatrixRow(inputParameters);
142
143             lastMatrixRow(inputParameters);
144
145             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters);
146             break;
147         }
148         case FilterOperation::SEPIA: {
149             BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation);
150             Vector<float> inputParameters;
151             double oneMinusAmount = clampTo(1 - colorMatrixOperation->amount(), 0.0, 1.0);
152
153             // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#sepiaEquivalent
154             // for information on parameters.
155
156             inputParameters.append(narrowPrecisionToFloat(0.393 + 0.607 * oneMinusAmount));
157             inputParameters.append(narrowPrecisionToFloat(0.769 - 0.769 * oneMinusAmount));
158             inputParameters.append(narrowPrecisionToFloat(0.189 - 0.189 * oneMinusAmount));
159             endMatrixRow(inputParameters);
160
161             inputParameters.append(narrowPrecisionToFloat(0.349 - 0.349 * oneMinusAmount));
162             inputParameters.append(narrowPrecisionToFloat(0.686 + 0.314 * oneMinusAmount));
163             inputParameters.append(narrowPrecisionToFloat(0.168 - 0.168 * oneMinusAmount));
164             endMatrixRow(inputParameters);
165
166             inputParameters.append(narrowPrecisionToFloat(0.272 - 0.272 * oneMinusAmount));
167             inputParameters.append(narrowPrecisionToFloat(0.534 - 0.534 * oneMinusAmount));
168             inputParameters.append(narrowPrecisionToFloat(0.131 + 0.869 * oneMinusAmount));
169             endMatrixRow(inputParameters);
170
171             lastMatrixRow(inputParameters);
172
173             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters);
174             break;
175         }
176         case FilterOperation::SATURATE: {
177             BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation);
178             Vector<float> inputParameters;
179             inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount()));
180             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_SATURATE, inputParameters);
181             break;
182         }
183         case FilterOperation::HUE_ROTATE: {
184             BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation);
185             Vector<float> inputParameters;
186             inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount()));
187             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_HUEROTATE, inputParameters);
188             break;
189         }
190         case FilterOperation::INVERT: {
191             BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation);
192             ComponentTransferFunction transferFunction;
193             transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE;
194             Vector<float> transferParameters;
195             transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount()));
196             transferParameters.append(narrowPrecisionToFloat(1 - componentTransferOperation->amount()));
197             transferFunction.tableValues = transferParameters;
198
199             ComponentTransferFunction nullFunction;
200             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
201             break;
202         }
203         case FilterOperation::OPACITY: {
204             BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation);
205             ComponentTransferFunction transferFunction;
206             transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE;
207             Vector<float> transferParameters;
208             transferParameters.append(0);
209             transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount()));
210             transferFunction.tableValues = transferParameters;
211
212             ComponentTransferFunction nullFunction;
213             effect = FEComponentTransfer::create(this, nullFunction, nullFunction, nullFunction, transferFunction);
214             break;
215         }
216         case FilterOperation::BRIGHTNESS: {
217             BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation);
218             ComponentTransferFunction transferFunction;
219             transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
220             transferFunction.slope = 1;
221             transferFunction.intercept = narrowPrecisionToFloat(componentTransferOperation->amount());
222
223             ComponentTransferFunction nullFunction;
224             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
225             break;
226         }
227         case FilterOperation::CONTRAST: {
228             BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation);
229             ComponentTransferFunction transferFunction;
230             transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
231             float amount = narrowPrecisionToFloat(componentTransferOperation->amount());
232             transferFunction.slope = amount;
233             transferFunction.intercept = -0.5 * amount + 0.5;
234             
235             ComponentTransferFunction nullFunction;
236             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
237             break;
238         }
239         case FilterOperation::BLUR: {
240             BlurFilterOperation* blurOperation = static_cast<BlurFilterOperation*>(filterOperation);
241             float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0);
242             effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation);
243             break;
244         }
245         case FilterOperation::DROP_SHADOW: {
246             DropShadowFilterOperation* dropShadowOperation = static_cast<DropShadowFilterOperation*>(filterOperation);
247             effect = FEDropShadow::create(this, dropShadowOperation->stdDeviation(), dropShadowOperation->stdDeviation(),
248                                                 dropShadowOperation->x(), dropShadowOperation->y(), dropShadowOperation->color(), 1);
249             break;
250         }
251 #if ENABLE(CSS_SHADERS)
252         case FilterOperation::CUSTOM: {
253 #if ENABLE(WEBGL)
254             if (!isCSSCustomFilterEnabled(document))
255                 continue;
256             
257             CustomFilterOperation* customFilterOperation = static_cast<CustomFilterOperation*>(filterOperation);
258             RefPtr<CustomFilterProgram> program = customFilterOperation->program();
259             cachedCustomFilterPrograms.append(program);
260             program->addClient(this);
261             if (program->isLoaded()) {
262                 effect = FECustomFilter::create(this, document->view()->root()->hostWindow(), program, customFilterOperation->parameters(),
263                                                 customFilterOperation->meshRows(), customFilterOperation->meshColumns(),
264                                                 customFilterOperation->meshBoxType(), customFilterOperation->meshType());
265             }
266 #endif
267             break;
268         }
269 #endif
270         default:
271             break;
272         }
273
274         if (effect) {
275             // Unlike SVG, filters applied here should not clip to their primitive subregions.
276             effect->setClipsToBounds(false);
277             
278             if (previousEffect)
279                 effect->inputEffects().append(previousEffect);
280             m_effects.append(effect);
281             previousEffect = effect.release();
282         }
283     }
284
285     // If we didn't make a real filter, create a null-op (FEMerge with one input).
286     if (!previousEffect)
287         m_effects.append(FEMerge::create(this));
288
289     m_effects.first()->inputEffects().append(m_sourceGraphic);
290     setMaxEffectRects(m_sourceDrawingRegion);
291     
292 #if ENABLE(CSS_SHADERS) && ENABLE(WEBGL)
293     removeCustomFilterClients();
294     m_cachedCustomFilterPrograms.swap(cachedCustomFilterPrograms);
295 #endif
296 }
297
298 void FilterEffectRenderer::updateBackingStore(const FloatRect& filterRect)
299 {
300     if (!filterRect.isZero()) {
301         FloatRect currentSourceRect = sourceImageRect();
302         if (filterRect != currentSourceRect)
303             setSourceImageRect(filterRect);
304     }
305 }
306
307 #if ENABLE(CSS_SHADERS)
308 void FilterEffectRenderer::notifyCustomFilterProgramLoaded(CustomFilterProgram*)
309 {
310     m_observer->filterNeedsRepaint();
311 }
312
313 void FilterEffectRenderer::removeCustomFilterClients()
314 {
315     for (CustomFilterProgramList::iterator iter = m_cachedCustomFilterPrograms.begin(), end = m_cachedCustomFilterPrograms.end(); iter != end; ++iter)
316         iter->get()->removeClient(this);
317 }
318 #endif
319
320 void FilterEffectRenderer::prepare()
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         setSourceImage(ImageBuffer::create(logicalSize, 1, ColorSpaceDeviceRGB, renderingMode()));
328         m_graphicsBufferAttached = true;
329     }
330     m_sourceGraphic->clearResult();
331     for (size_t i = 0; i < m_effects.size(); ++i)
332         m_effects[i]->clearResult();
333 }
334
335 void FilterEffectRenderer::apply()
336 {
337     lastEffect()->apply();
338 }
339
340
341 GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(RenderLayer* renderLayer, GraphicsContext* oldContext, const LayoutRect& filterRect)
342 {
343     ASSERT(m_haveFilterEffect && renderLayer->filter());
344     m_savedGraphicsContext = oldContext;
345     m_renderLayer = renderLayer;
346     m_paintOffset = filterRect.location();
347     
348     FloatRect filterSourceRect = filterRect;
349     filterSourceRect.setLocation(LayoutPoint());
350     
351     FilterEffectRenderer* filter = renderLayer->filter();
352     filter->updateBackingStore(filterSourceRect);
353     filter->prepare();
354     
355     // Paint into the context that represents the SourceGraphic of the filter.
356     GraphicsContext* sourceGraphicsContext = filter->inputContext();
357     if (!sourceGraphicsContext) {
358         // Could not allocate a new graphics context. Disable the filters and continue.
359         m_haveFilterEffect = false;
360         return m_savedGraphicsContext;
361     }
362     
363     sourceGraphicsContext->save();
364     sourceGraphicsContext->translate(-filterRect.x(), -filterRect.y());
365     sourceGraphicsContext->clearRect(filterRect);
366     
367     return sourceGraphicsContext;
368 }
369
370 GraphicsContext* FilterEffectRendererHelper::applyFilterEffect()
371 {
372     ASSERT(m_haveFilterEffect && m_renderLayer->filter());
373     FilterEffectRenderer* filter = m_renderLayer->filter();
374     filter->apply();
375     
376     filter->inputContext()->restore();
377     
378     // Get the filtered output and draw it in place.
379     IntRect destRect = filter->outputRect();
380     destRect.move(m_paintOffset.x(), m_paintOffset.y());
381     
382     m_savedGraphicsContext->drawImageBuffer(filter->output(), m_renderLayer->renderer()->style()->colorSpace(), destRect, CompositeSourceOver);
383     
384     return m_savedGraphicsContext;
385 }
386
387 } // namespace WebCore
388
389 #endif // ENABLE(CSS_FILTERS)