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