Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 COMPUTER, 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 #include "core/rendering/FilterEffectRenderer.h"
30
31 #include "core/dom/Document.h"
32 #include "core/fetch/DocumentResource.h"
33 #include "core/fetch/DocumentResourceReference.h"
34 #include "core/page/Page.h"
35 #include "core/rendering/RenderLayer.h"
36 #include "core/rendering/RenderView.h"
37 #include "core/rendering/svg/ReferenceFilterBuilder.h"
38 #include "core/svg/SVGElement.h"
39 #include "core/svg/SVGFilterPrimitiveStandardAttributes.h"
40 #include "platform/FloatConversion.h"
41 #include "platform/LengthFunctions.h"
42 #include "platform/graphics/ColorSpace.h"
43 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
44 #include "platform/graphics/filters/FEColorMatrix.h"
45 #include "platform/graphics/filters/FEComponentTransfer.h"
46 #include "platform/graphics/filters/FEDropShadow.h"
47 #include "platform/graphics/filters/FEGaussianBlur.h"
48 #include "wtf/MathExtras.h"
49 #include <algorithm>
50
51 namespace WebCore {
52
53 static inline void endMatrixRow(Vector<float>& parameters)
54 {
55     parameters.append(0);
56     parameters.append(0);
57 }
58
59 static inline void lastMatrixRow(Vector<float>& parameters)
60 {
61     parameters.append(0);
62     parameters.append(0);
63     parameters.append(0);
64     parameters.append(1);
65     parameters.append(0);
66 }
67
68 FilterEffectRenderer::FilterEffectRenderer()
69     : Filter(AffineTransform())
70     , m_graphicsBufferAttached(false)
71     , m_hasFilterThatMovesPixels(false)
72 {
73     m_sourceGraphic = SourceGraphic::create(this);
74 }
75
76 FilterEffectRenderer::~FilterEffectRenderer()
77 {
78 }
79
80 GraphicsContext* FilterEffectRenderer::inputContext()
81 {
82     return sourceImage() ? sourceImage()->context() : 0;
83 }
84
85 bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& operations)
86 {
87     m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels();
88
89     // Inverse zoom the pre-zoomed CSS shorthand filters, so that they are in the same zoom as the unzoomed reference filters.
90     const RenderStyle* style = renderer->style();
91 #ifdef BLINK_SCALE_FILTERS_AT_RECORD_TIME
92     float invZoom = 1.0f / ((style ? style->effectiveZoom() : 1.0f) * deviceScaleFactor(renderer->frame()));
93 #else
94     float invZoom = style ? 1.0f / style->effectiveZoom() : 1.0f;
95 #endif
96
97     RefPtr<FilterEffect> previousEffect = m_sourceGraphic;
98     for (size_t i = 0; i < operations.operations().size(); ++i) {
99         RefPtr<FilterEffect> effect;
100         FilterOperation* filterOperation = operations.operations().at(i).get();
101         switch (filterOperation->type()) {
102         case FilterOperation::REFERENCE: {
103             effect = ReferenceFilterBuilder::build(this, renderer, previousEffect.get(), toReferenceFilterOperation(filterOperation));
104             break;
105         }
106         case FilterOperation::GRAYSCALE: {
107             Vector<float> inputParameters;
108             double oneMinusAmount = clampTo(1 - toBasicColorMatrixFilterOperation(filterOperation)->amount(), 0.0, 1.0);
109
110             // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#grayscaleEquivalent
111             // for information on parameters.
112
113             inputParameters.append(narrowPrecisionToFloat(0.2126 + 0.7874 * oneMinusAmount));
114             inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount));
115             inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount));
116             endMatrixRow(inputParameters);
117
118             inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount));
119             inputParameters.append(narrowPrecisionToFloat(0.7152 + 0.2848 * oneMinusAmount));
120             inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount));
121             endMatrixRow(inputParameters);
122
123             inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount));
124             inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount));
125             inputParameters.append(narrowPrecisionToFloat(0.0722 + 0.9278 * oneMinusAmount));
126             endMatrixRow(inputParameters);
127
128             lastMatrixRow(inputParameters);
129
130             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters);
131             break;
132         }
133         case FilterOperation::SEPIA: {
134             Vector<float> inputParameters;
135             double oneMinusAmount = clampTo(1 - toBasicColorMatrixFilterOperation(filterOperation)->amount(), 0.0, 1.0);
136
137             // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#sepiaEquivalent
138             // for information on parameters.
139
140             inputParameters.append(narrowPrecisionToFloat(0.393 + 0.607 * oneMinusAmount));
141             inputParameters.append(narrowPrecisionToFloat(0.769 - 0.769 * oneMinusAmount));
142             inputParameters.append(narrowPrecisionToFloat(0.189 - 0.189 * oneMinusAmount));
143             endMatrixRow(inputParameters);
144
145             inputParameters.append(narrowPrecisionToFloat(0.349 - 0.349 * oneMinusAmount));
146             inputParameters.append(narrowPrecisionToFloat(0.686 + 0.314 * oneMinusAmount));
147             inputParameters.append(narrowPrecisionToFloat(0.168 - 0.168 * oneMinusAmount));
148             endMatrixRow(inputParameters);
149
150             inputParameters.append(narrowPrecisionToFloat(0.272 - 0.272 * oneMinusAmount));
151             inputParameters.append(narrowPrecisionToFloat(0.534 - 0.534 * oneMinusAmount));
152             inputParameters.append(narrowPrecisionToFloat(0.131 + 0.869 * oneMinusAmount));
153             endMatrixRow(inputParameters);
154
155             lastMatrixRow(inputParameters);
156
157             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters);
158             break;
159         }
160         case FilterOperation::SATURATE: {
161             Vector<float> inputParameters;
162             inputParameters.append(narrowPrecisionToFloat(toBasicColorMatrixFilterOperation(filterOperation)->amount()));
163             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_SATURATE, inputParameters);
164             break;
165         }
166         case FilterOperation::HUE_ROTATE: {
167             Vector<float> inputParameters;
168             inputParameters.append(narrowPrecisionToFloat(toBasicColorMatrixFilterOperation(filterOperation)->amount()));
169             effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_HUEROTATE, inputParameters);
170             break;
171         }
172         case FilterOperation::INVERT: {
173             BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(filterOperation);
174             ComponentTransferFunction transferFunction;
175             transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE;
176             Vector<float> transferParameters;
177             transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount()));
178             transferParameters.append(narrowPrecisionToFloat(1 - componentTransferOperation->amount()));
179             transferFunction.tableValues = transferParameters;
180
181             ComponentTransferFunction nullFunction;
182             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
183             break;
184         }
185         case FilterOperation::OPACITY: {
186             ComponentTransferFunction transferFunction;
187             transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE;
188             Vector<float> transferParameters;
189             transferParameters.append(0);
190             transferParameters.append(narrowPrecisionToFloat(toBasicComponentTransferFilterOperation(filterOperation)->amount()));
191             transferFunction.tableValues = transferParameters;
192
193             ComponentTransferFunction nullFunction;
194             effect = FEComponentTransfer::create(this, nullFunction, nullFunction, nullFunction, transferFunction);
195             break;
196         }
197         case FilterOperation::BRIGHTNESS: {
198             ComponentTransferFunction transferFunction;
199             transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
200             transferFunction.slope = narrowPrecisionToFloat(toBasicComponentTransferFilterOperation(filterOperation)->amount());
201             transferFunction.intercept = 0;
202
203             ComponentTransferFunction nullFunction;
204             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
205             break;
206         }
207         case FilterOperation::CONTRAST: {
208             ComponentTransferFunction transferFunction;
209             transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR;
210             float amount = narrowPrecisionToFloat(toBasicComponentTransferFilterOperation(filterOperation)->amount());
211             transferFunction.slope = amount;
212             transferFunction.intercept = -0.5 * amount + 0.5;
213
214             ComponentTransferFunction nullFunction;
215             effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction);
216             break;
217         }
218         case FilterOperation::BLUR: {
219             float stdDeviation = floatValueForLength(toBlurFilterOperation(filterOperation)->stdDeviation(), 0) * invZoom;
220             effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation);
221             break;
222         }
223         case FilterOperation::DROP_SHADOW: {
224             DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation);
225             float stdDeviation = dropShadowOperation->stdDeviation() * invZoom;
226             float x = dropShadowOperation->x() * invZoom;
227             float y = dropShadowOperation->y() * invZoom;
228             effect = FEDropShadow::create(this, stdDeviation, stdDeviation, x, y, dropShadowOperation->color(), 1);
229             break;
230         }
231         default:
232             break;
233         }
234
235         if (effect) {
236             if (filterOperation->type() != FilterOperation::REFERENCE) {
237                 // Unlike SVG, filters applied here should not clip to their primitive subregions.
238                 effect->setClipsToBounds(false);
239                 effect->setOperatingColorSpace(ColorSpaceDeviceRGB);
240                 effect->inputEffects().append(previousEffect);
241             }
242             previousEffect = effect.release();
243         }
244     }
245
246     // We need to keep the old effects alive until this point, so that SVG reference filters
247     // can share cached resources across frames.
248     m_lastEffect = previousEffect;
249
250     // If we didn't make any effects, tell our caller we are not valid
251     if (!m_lastEffect.get())
252         return false;
253
254     return true;
255 }
256
257 bool FilterEffectRenderer::updateBackingStoreRect(const FloatRect& floatFilterRect)
258 {
259     IntRect filterRect = enclosingIntRect(floatFilterRect);
260     if (!filterRect.isEmpty() && FilterEffect::isFilterSizeValid(filterRect)) {
261         FloatRect currentSourceRect = sourceImageRect();
262         if (filterRect != currentSourceRect) {
263             setSourceImageRect(filterRect);
264             return true;
265         }
266     }
267     return false;
268 }
269
270 void FilterEffectRenderer::allocateBackingStoreIfNeeded()
271 {
272     // At this point the effect chain has been built, and the
273     // source image sizes set. We just need to attach the graphic
274     // buffer if we have not yet done so.
275     if (!m_graphicsBufferAttached) {
276         IntSize logicalSize(m_sourceDrawingRegion.width(), m_sourceDrawingRegion.height());
277         if (!sourceImage() || sourceImage()->size() != logicalSize) {
278             OwnPtr<ImageBufferSurface> surface = adoptPtr(new UnacceleratedImageBufferSurface(logicalSize));
279             setSourceImage(ImageBuffer::create(surface.release()));
280         }
281         m_graphicsBufferAttached = true;
282     }
283 }
284
285 void FilterEffectRenderer::clearIntermediateResults()
286 {
287     if (m_lastEffect.get())
288         m_lastEffect->clearResultsRecursive();
289 }
290
291 void FilterEffectRenderer::apply()
292 {
293     RefPtr<FilterEffect> effect = lastEffect();
294     effect->apply();
295     effect->transformResultColorSpace(ColorSpaceDeviceRGB);
296 }
297
298 LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect)
299 {
300     // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect".
301     FloatRect rectForRepaint = dirtyRect;
302     float inf = std::numeric_limits<float>::infinity();
303     FloatRect clipRect = FloatRect(FloatPoint(-inf, -inf), FloatSize(inf, inf));
304     rectForRepaint = lastEffect()->getSourceRect(rectForRepaint, clipRect);
305     rectForRepaint.intersect(filterBoxRect);
306     return LayoutRect(rectForRepaint);
307 }
308
309 bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect)
310 {
311     ASSERT(m_haveFilterEffect && renderLayer->filterRenderer());
312     m_renderLayer = renderLayer;
313     m_repaintRect = dirtyRect;
314
315     // Get the zoom factor to scale the filterSourceRect input
316     const RenderLayerModelObject* renderer = renderLayer->renderer();
317     const RenderStyle* style = renderer ? renderer->style() : 0;
318     float zoom = style ? style->effectiveZoom() : 1.0f;
319
320     // Prepare a transformation that brings the coordinates into the space
321     // filter coordinates are defined in.
322     AffineTransform absoluteTransform;
323     // FIXME: Should these really be upconverted to doubles and not rounded? crbug.com/350474
324     absoluteTransform.translate(filterBoxRect.x().toDouble(), filterBoxRect.y().toDouble());
325     absoluteTransform.scale(zoom, zoom);
326
327     FilterEffectRenderer* filter = renderLayer->filterRenderer();
328     filter->setAbsoluteTransform(absoluteTransform);
329
330     IntRect filterSourceRect = pixelSnappedIntRect(filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect));
331
332     if (filterSourceRect.isEmpty()) {
333         // The dirty rect is not in view, just bail out.
334         m_haveFilterEffect = false;
335         return false;
336     }
337
338     filter->setFilterRegion(filter->mapAbsoluteRectToLocalRect(filterSourceRect));
339     filter->lastEffect()->determineFilterPrimitiveSubregion(MapRectForward);
340
341     bool hasUpdatedBackingStore = filter->updateBackingStoreRect(filterSourceRect);
342     if (filter->hasFilterThatMovesPixels()) {
343         if (hasUpdatedBackingStore)
344             m_repaintRect = filterSourceRect;
345         else {
346             m_repaintRect.unite(layerRepaintRect);
347             m_repaintRect.intersect(filterSourceRect);
348         }
349     }
350     return true;
351 }
352
353 GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(GraphicsContext* oldContext)
354 {
355     ASSERT(m_renderLayer);
356
357     FilterEffectRenderer* filter = m_renderLayer->filterRenderer();
358     filter->allocateBackingStoreIfNeeded();
359     // Paint into the context that represents the SourceGraphic of the filter.
360     GraphicsContext* sourceGraphicsContext = filter->inputContext();
361     if (!sourceGraphicsContext || !FilterEffect::isFilterSizeValid(filter->absoluteFilterRegion())) {
362         // Disable the filters and continue.
363         m_haveFilterEffect = false;
364         return oldContext;
365     }
366
367     m_savedGraphicsContext = oldContext;
368
369     // Translate the context so that the contents of the layer is captuterd in the offscreen memory buffer.
370     sourceGraphicsContext->save();
371     // FIXME: can we just use sourceImageRect for everything, and get rid of
372     // m_repaintRect?
373     FloatPoint offset = filter->sourceImageRect().location();
374     sourceGraphicsContext->translate(-offset.x(), -offset.y());
375     sourceGraphicsContext->clearRect(m_repaintRect);
376     sourceGraphicsContext->clip(m_repaintRect);
377
378     return sourceGraphicsContext;
379 }
380
381 GraphicsContext* FilterEffectRendererHelper::applyFilterEffect()
382 {
383     ASSERT(m_haveFilterEffect && m_renderLayer->filterRenderer());
384     FilterEffectRenderer* filter = m_renderLayer->filterRenderer();
385     filter->inputContext()->restore();
386
387     filter->apply();
388
389     // Get the filtered output and draw it in place.
390     m_savedGraphicsContext->drawImageBuffer(filter->output(), filter->outputRect());
391
392     filter->clearIntermediateResults();
393
394     return m_savedGraphicsContext;
395 }
396
397 } // namespace WebCore
398