- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / svg / RenderSVGResourceFilter.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
4  * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
5  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
6  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #include "config.h"
25
26 #include "core/rendering/svg/RenderSVGResourceFilter.h"
27
28 #include "core/page/Settings.h"
29 #include "core/platform/graphics/filters/SourceAlpha.h"
30 #include "core/platform/graphics/filters/SourceGraphic.h"
31 #include "core/rendering/svg/RenderSVGResourceFilterPrimitive.h"
32 #include "core/rendering/svg/SVGRenderingContext.h"
33 #include "core/svg/SVGFilterPrimitiveStandardAttributes.h"
34
35 using namespace std;
36
37 namespace WebCore {
38
39 const RenderSVGResourceType RenderSVGResourceFilter::s_resourceType = FilterResourceType;
40
41 RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement* node)
42     : RenderSVGResourceContainer(node)
43 {
44 }
45
46 RenderSVGResourceFilter::~RenderSVGResourceFilter()
47 {
48     m_filter.clear();
49 }
50
51 void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation)
52 {
53     m_filter.clear();
54     markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
55 }
56
57 void RenderSVGResourceFilter::removeClientFromCache(RenderObject* client, bool markForInvalidation)
58 {
59     ASSERT(client);
60
61     if (FilterData* filterData = m_filter.get(client)) {
62         if (filterData->savedContext)
63             filterData->state = FilterData::MarkedForRemoval;
64         else
65             m_filter.remove(client);
66     }
67
68     markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
69 }
70
71 PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter)
72 {
73     SVGFilterElement* filterElement = toSVGFilterElement(element());
74     FloatRect targetBoundingBox = filter->targetBoundingBox();
75
76     // Add effects to the builder
77     RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(SourceGraphic::create(filter), SourceAlpha::create(filter));
78     for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) {
79         if (!node->isSVGElement())
80             continue;
81
82         SVGElement* element = toSVGElement(node);
83         if (!element->isFilterEffect() || !element->renderer())
84             continue;
85
86         SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element);
87         RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter);
88         if (!effect) {
89             builder->clearEffects();
90             return 0;
91         }
92         builder->appendEffectToEffectReferences(effect, effectElement->renderer());
93         effectElement->setStandardAttributes(effect.get());
94         effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnitsCurrentValue(), targetBoundingBox));
95         effect->setOperatingColorSpace(
96             effectElement->renderer()->style()->svgStyle()->colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB);
97         builder->add(effectElement->resultCurrentValue(), effect);
98     }
99     return builder.release();
100 }
101
102 bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, FloatSize& scale)
103 {
104     bool matchesFilterSize = true;
105     if (size.width() > kMaxFilterSize) {
106         scale.setWidth(scale.width() * kMaxFilterSize / size.width());
107         matchesFilterSize = false;
108     }
109     if (size.height() > kMaxFilterSize) {
110         scale.setHeight(scale.height() * kMaxFilterSize / size.height());
111         matchesFilterSize = false;
112     }
113
114     return matchesFilterSize;
115 }
116
117 static bool createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform,
118     OwnPtr<ImageBuffer>& imageBuffer, RenderingMode renderingMode)
119 {
120     IntRect paintRect = SVGRenderingContext::calculateImageBufferRect(targetRect, absoluteTransform);
121     // Don't create empty ImageBuffers.
122     if (paintRect.isEmpty())
123         return false;
124
125     OwnPtr<ImageBuffer> image = ImageBuffer::create(paintRect.size(), 1, renderingMode);
126     if (!image)
127         return false;
128
129     GraphicsContext* imageContext = image->context();
130     ASSERT(imageContext);
131
132     imageContext->translate(-paintRect.x(), -paintRect.y());
133     imageContext->concatCTM(absoluteTransform);
134
135     imageBuffer = image.release();
136     return true;
137 }
138
139 bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode)
140 {
141     ASSERT(object);
142     ASSERT(context);
143     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
144
145     if (m_filter.contains(object)) {
146         FilterData* filterData = m_filter.get(object);
147         if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying)
148             filterData->state = FilterData::CycleDetected;
149         return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now.
150     }
151
152     OwnPtr<FilterData> filterData(adoptPtr(new FilterData));
153     FloatRect targetBoundingBox = object->objectBoundingBox();
154
155     SVGFilterElement* filterElement = toSVGFilterElement(element());
156     filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnitsCurrentValue(), targetBoundingBox);
157     if (filterData->boundaries.isEmpty())
158         return false;
159
160     // Determine absolute transformation matrix for filter.
161     AffineTransform absoluteTransform;
162     SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
163     if (!absoluteTransform.isInvertible())
164         return false;
165
166     // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile.
167     filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), 0, 0);
168
169     // Determine absolute boundaries of the filter and the drawing region.
170     FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries);
171     filterData->drawingRegion = object->strokeBoundingBox();
172     filterData->drawingRegion.intersect(filterData->boundaries);
173     FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(filterData->drawingRegion);
174
175     // Create the SVGFilter object.
176     bool primitiveBoundingBoxMode = filterElement->primitiveUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
177     filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode);
178
179     // Create all relevant filter primitives.
180     filterData->builder = buildPrimitives(filterData->filter.get());
181     if (!filterData->builder)
182         return false;
183
184     // Calculate the scale factor for the use of filterRes.
185     // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
186     FloatSize scale(1, 1);
187     if (filterElement->hasAttribute(SVGNames::filterResAttr)) {
188         scale.setWidth(filterElement->filterResXCurrentValue() / absoluteFilterBoundaries.width());
189         scale.setHeight(filterElement->filterResYCurrentValue() / absoluteFilterBoundaries.height());
190     }
191
192     if (scale.isEmpty())
193         return false;
194
195     // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize.
196     FloatRect tempSourceRect = absoluteDrawingRegion;
197     tempSourceRect.scale(scale.width(), scale.height());
198     fitsInMaximumImageSize(tempSourceRect.size(), scale);
199
200     // Set the scale level in SVGFilter.
201     filterData->filter->setFilterResolution(scale);
202
203     FilterEffect* lastEffect = filterData->builder->lastEffect();
204     if (!lastEffect)
205         return false;
206
207     RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect);
208     FloatRect subRegion = lastEffect->maxEffectRect();
209     // At least one FilterEffect has a too big image size,
210     // recalculate the effect sizes with new scale factors.
211     if (!fitsInMaximumImageSize(subRegion.size(), scale)) {
212         filterData->filter->setFilterResolution(scale);
213         RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect);
214     }
215
216     // If the drawingRegion is empty, we have something like <g filter=".."/>.
217     // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource.
218     if (filterData->drawingRegion.isEmpty()) {
219         ASSERT(!m_filter.contains(object));
220         filterData->savedContext = context;
221         m_filter.set(object, filterData.release());
222         return false;
223     }
224
225     // Change the coordinate transformation applied to the filtered element to reflect the resolution of the filter.
226     AffineTransform effectiveTransform;
227     effectiveTransform.scale(scale.width(), scale.height());
228     effectiveTransform.multiply(filterData->shearFreeAbsoluteTransform);
229
230     OwnPtr<ImageBuffer> sourceGraphic;
231     RenderingMode renderingMode = object->document().settings()->acceleratedFiltersEnabled() ? Accelerated : Unaccelerated;
232     if (!createImageBuffer(filterData->drawingRegion, effectiveTransform, sourceGraphic, renderingMode)) {
233         ASSERT(!m_filter.contains(object));
234         filterData->savedContext = context;
235         m_filter.set(object, filterData.release());
236         return false;
237     }
238
239     // Set the rendering mode from the page's settings.
240     filterData->filter->setRenderingMode(renderingMode);
241
242     GraphicsContext* sourceGraphicContext = sourceGraphic->context();
243     ASSERT(sourceGraphicContext);
244
245     filterData->sourceGraphicBuffer = sourceGraphic.release();
246     filterData->savedContext = context;
247
248     context = sourceGraphicContext;
249
250     ASSERT(!m_filter.contains(object));
251     m_filter.set(object, filterData.release());
252
253     return true;
254 }
255
256 void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode, const Path*, const RenderSVGShape*)
257 {
258     ASSERT(object);
259     ASSERT(context);
260     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
261
262     FilterData* filterData = m_filter.get(object);
263     if (!filterData)
264         return;
265
266     switch (filterData->state) {
267     case FilterData::MarkedForRemoval:
268         m_filter.remove(object);
269         return;
270
271     case FilterData::CycleDetected:
272     case FilterData::Applying:
273         // We have a cycle if we are already applying the data.
274         // This can occur due to FeImage referencing a source that makes use of the FEImage itself.
275         // This is the first place we've hit the cycle, so set the state back to PaintingSource so the return stack
276         // will continue correctly.
277         filterData->state = FilterData::PaintingSource;
278         return;
279
280     case FilterData::PaintingSource:
281         if (!filterData->savedContext) {
282             removeClientFromCache(object);
283             return;
284         }
285
286         context = filterData->savedContext;
287         filterData->savedContext = 0;
288         break;
289
290     case FilterData::Built: { } // Empty
291     }
292
293     FilterEffect* lastEffect = filterData->builder->lastEffect();
294
295     if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) {
296         // This is the real filtering of the object. It just needs to be called on the
297         // initial filtering process. We just take the stored filter result on a
298         // second drawing.
299         if (filterData->state != FilterData::Built)
300             filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release());
301
302         // Always true if filterData is just built (filterData->state == FilterData::Built).
303         if (!lastEffect->hasResult()) {
304             filterData->state = FilterData::Applying;
305             lastEffect->apply();
306             lastEffect->correctFilterResultIfNeeded();
307             lastEffect->transformResultColorSpace(ColorSpaceDeviceRGB);
308         }
309         filterData->state = FilterData::Built;
310
311         ImageBuffer* resultImage = lastEffect->asImageBuffer();
312         if (resultImage) {
313             context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse());
314
315             context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height()));
316             context->drawImageBuffer(resultImage, lastEffect->absolutePaintRect());
317             context->scale(filterData->filter->filterResolution());
318
319             context->concatCTM(filterData->shearFreeAbsoluteTransform);
320         }
321     }
322     filterData->sourceGraphicBuffer.clear();
323 }
324
325 FloatRect RenderSVGResourceFilter::resourceBoundingBox(RenderObject* object)
326 {
327     if (SVGFilterElement* element = toSVGFilterElement(this->element()))
328         return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, element->filterUnitsCurrentValue(), object->objectBoundingBox());
329
330     return FloatRect();
331 }
332
333 void RenderSVGResourceFilter::primitiveAttributeChanged(RenderObject* object, const QualifiedName& attribute)
334 {
335     FilterMap::iterator it = m_filter.begin();
336     FilterMap::iterator end = m_filter.end();
337     SVGFilterPrimitiveStandardAttributes* primitve = static_cast<SVGFilterPrimitiveStandardAttributes*>(object->node());
338
339     for (; it != end; ++it) {
340         FilterData* filterData = it->value.get();
341         if (filterData->state != FilterData::Built)
342             continue;
343
344         SVGFilterBuilder* builder = filterData->builder.get();
345         FilterEffect* effect = builder->effectByRenderer(object);
346         if (!effect)
347             continue;
348         // Since all effects shares the same attribute value, all
349         // or none of them will be changed.
350         if (!primitve->setFilterEffectAttribute(effect, attribute))
351             return;
352         builder->clearResultsRecursive(effect);
353
354         // Repaint the image on the screen.
355         markClientForInvalidation(it->key, RepaintInvalidation);
356     }
357     markAllClientLayersForInvalidation();
358 }
359
360 FloatRect RenderSVGResourceFilter::drawingRegion(RenderObject* object) const
361 {
362     FilterData* filterData = m_filter.get(object);
363     return filterData ? filterData->drawingRegion : FloatRect();
364 }
365
366 }