Upstream version 5.34.104.0
[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/frame/Settings.h"
29 #include "core/rendering/svg/RenderSVGResourceFilterPrimitive.h"
30 #include "core/rendering/svg/SVGRenderingContext.h"
31 #include "core/svg/SVGFilterPrimitiveStandardAttributes.h"
32 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
33 #include "platform/graphics/filters/SkiaImageFilterBuilder.h"
34 #include "platform/graphics/filters/SourceAlpha.h"
35 #include "platform/graphics/filters/SourceGraphic.h"
36 #include "platform/graphics/gpu/AcceleratedImageBufferSurface.h"
37
38 using namespace std;
39
40 namespace WebCore {
41
42 const RenderSVGResourceType RenderSVGResourceFilter::s_resourceType = FilterResourceType;
43
44 RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement* node)
45     : RenderSVGResourceContainer(node)
46 {
47 }
48
49 RenderSVGResourceFilter::~RenderSVGResourceFilter()
50 {
51     m_filter.clear();
52 }
53
54 bool RenderSVGResourceFilter::isChildAllowed(RenderObject* child, RenderStyle*) const
55 {
56     return child->isSVGResourceFilterPrimitive();
57 }
58
59 void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation)
60 {
61     m_filter.clear();
62     markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
63 }
64
65 void RenderSVGResourceFilter::removeClientFromCache(RenderObject* client, bool markForInvalidation)
66 {
67     ASSERT(client);
68
69     if (FilterData* filterData = m_filter.get(client)) {
70         if (filterData->savedContext)
71             filterData->state = FilterData::MarkedForRemoval;
72         else
73             m_filter.remove(client);
74     }
75
76     markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
77 }
78
79 PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter)
80 {
81     SVGFilterElement* filterElement = toSVGFilterElement(element());
82     FloatRect targetBoundingBox = filter->targetBoundingBox();
83
84     // Add effects to the builder
85     RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(SourceGraphic::create(filter), SourceAlpha::create(filter));
86     for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) {
87         if (!node->isSVGElement())
88             continue;
89
90         SVGElement* element = toSVGElement(node);
91         if (!element->isFilterEffect() || !element->renderer())
92             continue;
93
94         SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element);
95         RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter);
96         if (!effect) {
97             builder->clearEffects();
98             return 0;
99         }
100         builder->appendEffectToEffectReferences(effect, effectElement->renderer());
101         effectElement->setStandardAttributes(effect.get());
102         effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnitsCurrentValue(), targetBoundingBox));
103         effect->setOperatingColorSpace(
104             effectElement->renderer()->style()->svgStyle()->colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB);
105         builder->add(AtomicString(effectElement->result()->currentValue()->value()), effect);
106     }
107     return builder.release();
108 }
109
110 bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, FloatSize& scale)
111 {
112     bool matchesFilterSize = true;
113     if (size.width() * scale.width() > kMaxFilterSize) {
114         scale.setWidth(kMaxFilterSize / size.width());
115         matchesFilterSize = false;
116     }
117     if (size.height() * scale.height() > kMaxFilterSize) {
118         scale.setHeight(kMaxFilterSize / size.height());
119         matchesFilterSize = false;
120     }
121
122     return matchesFilterSize;
123 }
124
125 static bool createImageBuffer(const Filter* filter, OwnPtr<ImageBuffer>& imageBuffer, bool accelerated)
126 {
127     IntRect paintRect = filter->sourceImageRect();
128     // Don't create empty ImageBuffers.
129     if (paintRect.isEmpty())
130         return false;
131
132     OwnPtr<ImageBufferSurface> surface;
133     if (accelerated)
134         surface = adoptPtr(new AcceleratedImageBufferSurface(paintRect.size()));
135     if (!accelerated || !surface->isValid())
136         surface = adoptPtr(new UnacceleratedImageBufferSurface(paintRect.size()));
137     if (!surface->isValid())
138         return false;
139     OwnPtr<ImageBuffer> image = ImageBuffer::create(surface.release());
140
141     GraphicsContext* imageContext = image->context();
142     ASSERT(imageContext);
143
144     imageContext->translate(-paintRect.x(), -paintRect.y());
145     imageContext->concatCTM(filter->absoluteTransform());
146     imageBuffer = image.release();
147     return true;
148 }
149
150 bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode)
151 {
152     ASSERT(object);
153     ASSERT(context);
154     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
155
156     clearInvalidationMask();
157
158     bool deferredFiltersEnabled = object->document().settings()->deferredFiltersEnabled();
159     if (deferredFiltersEnabled) {
160         if (m_objects.contains(object))
161             return false; // We're in a cycle.
162     } else if (m_filter.contains(object)) {
163         FilterData* filterData = m_filter.get(object);
164         if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying)
165             filterData->state = FilterData::CycleDetected;
166         return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now.
167     }
168
169     OwnPtr<FilterData> filterData(adoptPtr(new FilterData));
170     FloatRect targetBoundingBox = object->objectBoundingBox();
171
172     SVGFilterElement* filterElement = toSVGFilterElement(element());
173     filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnitsCurrentValue(), targetBoundingBox);
174     if (filterData->boundaries.isEmpty())
175         return false;
176
177     // Determine absolute transformation matrix for filter.
178     AffineTransform absoluteTransform;
179     SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
180     if (!absoluteTransform.isInvertible())
181         return false;
182
183     // Filters cannot handle a full transformation, only scales in each direction.
184     FloatSize filterScale;
185
186     // Calculate the scale factor for the filter.
187     // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
188     if (filterElement->hasAttribute(SVGNames::filterResAttr)) {
189         //  If resolution is specified, scale to match it.
190         filterScale = FloatSize(
191             filterElement->filterResX()->currentValue()->value() / filterData->boundaries.width(),
192             filterElement->filterResY()->currentValue()->value() / filterData->boundaries.height());
193     } else {
194         // Otherwise, use the scale of the absolute transform.
195         filterScale = FloatSize(absoluteTransform.xScale(), absoluteTransform.yScale());
196     }
197     // The size of the scaled filter boundaries shouldn't be bigger than kMaxFilterSize.
198     // Intermediate filters are limited by the filter boundaries so they can't be bigger than this.
199     fitsInMaximumImageSize(filterData->boundaries.size(), filterScale);
200
201     filterData->drawingRegion = object->strokeBoundingBox();
202     filterData->drawingRegion.intersect(filterData->boundaries);
203     FloatRect absoluteDrawingRegion = filterData->drawingRegion;
204     if (!deferredFiltersEnabled)
205         absoluteDrawingRegion.scale(filterScale.width(), filterScale.height());
206
207     IntRect intDrawingRegion = enclosingIntRect(absoluteDrawingRegion);
208
209     // Create the SVGFilter object.
210     bool primitiveBoundingBoxMode = filterElement->primitiveUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
211     filterData->shearFreeAbsoluteTransform = AffineTransform();
212     if (!deferredFiltersEnabled)
213         filterData->shearFreeAbsoluteTransform.scale(filterScale.width(), filterScale.height());
214     filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, intDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode);
215
216     // Create all relevant filter primitives.
217     filterData->builder = buildPrimitives(filterData->filter.get());
218     if (!filterData->builder)
219         return false;
220
221     FilterEffect* lastEffect = filterData->builder->lastEffect();
222     if (!lastEffect)
223         return false;
224
225     lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion);
226
227     if (deferredFiltersEnabled) {
228         SkiaImageFilterBuilder builder(context);
229         FloatRect oldBounds = context->getClipBounds();
230         m_objects.set(object, oldBounds);
231         RefPtr<ImageFilter> imageFilter = builder.build(lastEffect, ColorSpaceDeviceRGB);
232         FloatRect boundaries = enclosingIntRect(filterData->boundaries);
233         if (filterElement->hasAttribute(SVGNames::filterResAttr)) {
234             context->save();
235             // Get boundaries in device coords.
236             FloatSize size = context->getCTM().mapSize(boundaries.size());
237             // Compute the scale amount required so that the resulting offscreen is exactly filterResX by filterResY pixels.
238             FloatSize filterResScale(
239                 filterElement->filterResX()->currentValue()->value() / size.width(),
240                 filterElement->filterResY()->currentValue()->value() / size.height());
241             // Scale the CTM so the primitive is drawn to filterRes.
242             context->translate(boundaries.x(), boundaries.y());
243             context->scale(filterResScale);
244             context->translate(-boundaries.x(), -boundaries.y());
245             // Create a resize filter with the inverse scale.
246             imageFilter = builder.buildResize(1 / filterResScale.width(), 1 / filterResScale.height(), imageFilter.get());
247             // Clip the context so that the offscreen created in beginLayer()
248             // is clipped to filterResX by filerResY. Use Replace mode since
249             // this clip may be larger than the parent device.
250             context->clipRectReplace(boundaries);
251         }
252         context->beginLayer(1, CompositeSourceOver, &boundaries, ColorFilterNone, imageFilter.get());
253         return true;
254     }
255
256     // If the drawingRegion is empty, we have something like <g filter=".."/>.
257     // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource.
258     if (filterData->drawingRegion.isEmpty()) {
259         ASSERT(!m_filter.contains(object));
260         filterData->savedContext = context;
261         m_filter.set(object, filterData.release());
262         return false;
263     }
264
265     OwnPtr<ImageBuffer> sourceGraphic;
266     bool isAccelerated = object->document().settings()->acceleratedFiltersEnabled();
267     if (!createImageBuffer(filterData->filter.get(), sourceGraphic, isAccelerated)) {
268         ASSERT(!m_filter.contains(object));
269         filterData->savedContext = context;
270         m_filter.set(object, filterData.release());
271         return false;
272     }
273
274     // Set the rendering mode from the page's settings.
275     filterData->filter->setIsAccelerated(isAccelerated);
276
277     GraphicsContext* sourceGraphicContext = sourceGraphic->context();
278     ASSERT(sourceGraphicContext);
279
280     filterData->sourceGraphicBuffer = sourceGraphic.release();
281     filterData->savedContext = context;
282
283     context = sourceGraphicContext;
284
285     ASSERT(!m_filter.contains(object));
286     m_filter.set(object, filterData.release());
287
288     return true;
289 }
290
291 void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode, const Path*, const RenderSVGShape*)
292 {
293     ASSERT(object);
294     ASSERT(context);
295     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
296
297     if (object->document().settings()->deferredFiltersEnabled()) {
298         SVGFilterElement* filterElement = toSVGFilterElement(element());
299         if (filterElement->hasAttribute(SVGNames::filterResAttr)) {
300             // Restore the clip bounds before endLayer(), so the filtered
301             // image draw is clipped to the original device bounds, not the
302             // clip we set before the beginLayer() above.
303             FloatRect oldBounds = m_objects.get(object);
304             context->clipRectReplace(oldBounds);
305             context->endLayer();
306             context->restore();
307         } else {
308             context->endLayer();
309         }
310         m_objects.remove(object);
311         return;
312     }
313
314     FilterData* filterData = m_filter.get(object);
315     if (!filterData)
316         return;
317
318     switch (filterData->state) {
319     case FilterData::MarkedForRemoval:
320         m_filter.remove(object);
321         return;
322
323     case FilterData::CycleDetected:
324     case FilterData::Applying:
325         // We have a cycle if we are already applying the data.
326         // This can occur due to FeImage referencing a source that makes use of the FEImage itself.
327         // This is the first place we've hit the cycle, so set the state back to PaintingSource so the return stack
328         // will continue correctly.
329         filterData->state = FilterData::PaintingSource;
330         return;
331
332     case FilterData::PaintingSource:
333         if (!filterData->savedContext) {
334             removeClientFromCache(object);
335             return;
336         }
337
338         context = filterData->savedContext;
339         filterData->savedContext = 0;
340         break;
341
342     case FilterData::Built: { } // Empty
343     }
344
345     FilterEffect* lastEffect = filterData->builder->lastEffect();
346
347     if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) {
348         // This is the real filtering of the object. It just needs to be called on the
349         // initial filtering process. We just take the stored filter result on a
350         // second drawing.
351         if (filterData->state != FilterData::Built)
352             filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release());
353
354         // Always true if filterData is just built (filterData->state == FilterData::Built).
355         if (!lastEffect->hasResult()) {
356             filterData->state = FilterData::Applying;
357             lastEffect->apply();
358             lastEffect->correctFilterResultIfNeeded();
359             lastEffect->transformResultColorSpace(ColorSpaceDeviceRGB);
360         }
361         filterData->state = FilterData::Built;
362
363         ImageBuffer* resultImage = lastEffect->asImageBuffer();
364         if (resultImage) {
365             context->drawImageBuffer(resultImage, filterData->filter->mapAbsoluteRectToLocalRect(lastEffect->absolutePaintRect()));
366         }
367     }
368     filterData->sourceGraphicBuffer.clear();
369 }
370
371 FloatRect RenderSVGResourceFilter::resourceBoundingBox(const RenderObject* object)
372 {
373     if (SVGFilterElement* element = toSVGFilterElement(this->element()))
374         return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, element->filterUnitsCurrentValue(), object->objectBoundingBox());
375
376     return FloatRect();
377 }
378
379 void RenderSVGResourceFilter::primitiveAttributeChanged(RenderObject* object, const QualifiedName& attribute)
380 {
381     if (object->document().settings()->deferredFiltersEnabled()) {
382         markAllClientsForInvalidation(RepaintInvalidation);
383         markAllClientLayersForInvalidation();
384         return;
385     }
386
387     FilterMap::iterator it = m_filter.begin();
388     FilterMap::iterator end = m_filter.end();
389     SVGFilterPrimitiveStandardAttributes* primitve = static_cast<SVGFilterPrimitiveStandardAttributes*>(object->node());
390
391     for (; it != end; ++it) {
392         FilterData* filterData = it->value.get();
393         if (filterData->state != FilterData::Built)
394             continue;
395
396         SVGFilterBuilder* builder = filterData->builder.get();
397         FilterEffect* effect = builder->effectByRenderer(object);
398         if (!effect)
399             continue;
400         // Since all effects shares the same attribute value, all
401         // or none of them will be changed.
402         if (!primitve->setFilterEffectAttribute(effect, attribute))
403             return;
404         builder->clearResultsRecursive(effect);
405
406         // Repaint the image on the screen.
407         markClientForInvalidation(it->key, RepaintInvalidation);
408     }
409     markAllClientLayersForInvalidation();
410 }
411
412 FloatRect RenderSVGResourceFilter::drawingRegion(RenderObject* object) const
413 {
414     FilterData* filterData = m_filter.get(object);
415     return filterData ? filterData->drawingRegion : FloatRect();
416 }
417
418 }