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