Replace PassRef with Ref/Ref&& across the board.
[WebKit-https.git] / Source / WebCore / 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 #include "RenderSVGResourceFilter.h"
26
27 #include "ElementChildIterator.h"
28 #include "FilterEffect.h"
29 #include "FloatPoint.h"
30 #include "Frame.h"
31 #include "GraphicsContext.h"
32 #include "Image.h"
33 #include "ImageData.h"
34 #include "IntRect.h"
35 #include "Page.h"
36 #include "RenderSVGResourceFilterPrimitive.h"
37 #include "RenderView.h"
38 #include "SVGFilterPrimitiveStandardAttributes.h"
39 #include "SVGNames.h"
40 #include "SVGRenderingContext.h"
41 #include "Settings.h"
42 #include "SourceAlpha.h"
43 #include "SourceGraphic.h"
44
45 namespace WebCore {
46
47 RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement& element, Ref<RenderStyle>&& style)
48     : RenderSVGResourceContainer(element, WTF::move(style))
49 {
50 }
51
52 RenderSVGResourceFilter::~RenderSVGResourceFilter()
53 {
54 }
55
56 void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation)
57 {
58     m_filter.clear();
59
60     markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
61 }
62
63 void RenderSVGResourceFilter::removeClientFromCache(RenderElement& client, bool markForInvalidation)
64 {
65     if (FilterData* filterData = m_filter.get(&client)) {
66         if (filterData->savedContext)
67             filterData->state = FilterData::MarkedForRemoval;
68         else
69             m_filter.remove(&client);
70     }
71
72     markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
73 }
74
75 std::unique_ptr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter) const
76 {
77     static const unsigned maxCountChildNodes = 200;
78     if (filterElement().countChildNodes() > maxCountChildNodes)
79         return nullptr;
80
81     FloatRect targetBoundingBox = filter->targetBoundingBox();
82
83     // Add effects to the builder
84     auto builder = std::make_unique<SVGFilterBuilder>(SourceGraphic::create(filter), SourceAlpha::create(filter));
85     for (auto& element : childrenOfType<SVGFilterPrimitiveStandardAttributes>(filterElement())) {
86         RefPtr<FilterEffect> effect = element.build(builder.get(), filter);
87         if (!effect) {
88             builder->clearEffects();
89             return nullptr;
90         }
91         builder->appendEffectToEffectReferences(effect, element.renderer());
92         element.setStandardAttributes(effect.get());
93         effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(&element, filterElement().primitiveUnits(), targetBoundingBox));
94         effect->setOperatingColorSpace(element.renderer()->style().svgStyle().colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB);
95         builder->add(element.result(), effect.release());
96     }
97     return builder;
98 }
99
100 bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, FloatSize& scale)
101 {
102     FloatSize scaledSize(size);
103     scaledSize.scale(scale.width(), scale.height());
104     float scaledArea = scaledSize.width() * scaledSize.height();
105
106     if (scaledArea <= FilterEffect::maxFilterArea())
107         return true;
108
109     // If area of scaled size is bigger than the upper limit, adjust the scale
110     // to fit.
111     scale.scale(sqrt(FilterEffect::maxFilterArea() / scaledArea));
112     return false;
113 }
114
115 bool RenderSVGResourceFilter::applyResource(RenderElement& renderer, const RenderStyle&, GraphicsContext*& context, unsigned short resourceMode)
116 {
117     ASSERT(context);
118     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
119
120     if (m_filter.contains(&renderer)) {
121         FilterData* filterData = m_filter.get(&renderer);
122         if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying)
123             filterData->state = FilterData::CycleDetected;
124         return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now.
125     }
126
127     auto filterData = std::make_unique<FilterData>();
128     FloatRect targetBoundingBox = renderer.objectBoundingBox();
129
130     filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(&filterElement(), filterElement().filterUnits(), targetBoundingBox);
131     if (filterData->boundaries.isEmpty())
132         return false;
133
134     // Determine absolute transformation matrix for filter. 
135     AffineTransform absoluteTransform;
136     SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer, absoluteTransform);
137     if (!absoluteTransform.isInvertible())
138         return false;
139
140     // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile.
141     filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), 0, 0);
142
143     // Determine absolute boundaries of the filter and the drawing region.
144     FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries);
145     filterData->drawingRegion = renderer.strokeBoundingBox();
146     filterData->drawingRegion.intersect(filterData->boundaries);
147     FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(filterData->drawingRegion);
148
149     // Create the SVGFilter object.
150     bool primitiveBoundingBoxMode = filterElement().primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
151     filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode);
152
153     // Create all relevant filter primitives.
154     filterData->builder = buildPrimitives(filterData->filter.get());
155     if (!filterData->builder)
156         return false;
157
158     // Calculate the scale factor for the use of filterRes.
159     // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
160     FloatSize scale(1, 1);
161     if (filterElement().hasAttribute(SVGNames::filterResAttr)) {
162         scale.setWidth(filterElement().filterResX() / absoluteFilterBoundaries.width());
163         scale.setHeight(filterElement().filterResY() / absoluteFilterBoundaries.height());
164     }
165
166     if (scale.isEmpty())
167         return false;
168
169     // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize.
170     FloatRect tempSourceRect = absoluteDrawingRegion;
171     tempSourceRect.scale(scale.width(), scale.height());
172     fitsInMaximumImageSize(tempSourceRect.size(), scale);
173
174     // Set the scale level in SVGFilter.
175     filterData->filter->setFilterResolution(scale);
176
177     static const unsigned maxTotalOfEffectInputs = 100;
178     FilterEffect* lastEffect = filterData->builder->lastEffect();
179     if (!lastEffect || lastEffect->totalNumberOfEffectInputs() > maxTotalOfEffectInputs)
180         return false;
181
182     RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(*lastEffect);
183     FloatRect subRegion = lastEffect->maxEffectRect();
184     // At least one FilterEffect has a too big image size,
185     // recalculate the effect sizes with new scale factors.
186     if (!fitsInMaximumImageSize(subRegion.size(), scale)) {
187         filterData->filter->setFilterResolution(scale);
188         RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(*lastEffect);
189     }
190
191     // If the drawingRegion is empty, we have something like <g filter=".."/>.
192     // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource.
193     if (filterData->drawingRegion.isEmpty()) {
194         ASSERT(!m_filter.contains(&renderer));
195         filterData->savedContext = context;
196         m_filter.set(&renderer, WTF::move(filterData));
197         return false;
198     }
199
200     // Change the coordinate transformation applied to the filtered element to reflect the resolution of the filter.
201     AffineTransform effectiveTransform;
202     effectiveTransform.scale(scale.width(), scale.height());
203     effectiveTransform.multiply(filterData->shearFreeAbsoluteTransform);
204
205     std::unique_ptr<ImageBuffer> sourceGraphic;
206     RenderingMode renderingMode = renderer.frame().settings().acceleratedFiltersEnabled() ? Accelerated : Unaccelerated;
207     if (!SVGRenderingContext::createImageBuffer(filterData->drawingRegion, effectiveTransform, sourceGraphic, ColorSpaceLinearRGB, renderingMode)) {
208         ASSERT(!m_filter.contains(&renderer));
209         filterData->savedContext = context;
210         m_filter.set(&renderer, WTF::move(filterData));
211         return false;
212     }
213     
214     // Set the rendering mode from the page's settings.
215     filterData->filter->setRenderingMode(renderingMode);
216
217     GraphicsContext* sourceGraphicContext = sourceGraphic->context();
218     ASSERT(sourceGraphicContext);
219   
220     filterData->sourceGraphicBuffer = WTF::move(sourceGraphic);
221     filterData->savedContext = context;
222
223     context = sourceGraphicContext;
224
225     ASSERT(!m_filter.contains(&renderer));
226     m_filter.set(&renderer, WTF::move(filterData));
227
228     return true;
229 }
230
231 void RenderSVGResourceFilter::postApplyResource(RenderElement& renderer, GraphicsContext*& context, unsigned short resourceMode, const Path*, const RenderSVGShape*)
232 {
233     ASSERT(context);
234     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
235
236     FilterData* filterData = m_filter.get(&renderer);
237     if (!filterData)
238         return;
239
240     switch (filterData->state) {
241     case FilterData::MarkedForRemoval:
242         m_filter.remove(&renderer);
243         return;
244
245     case FilterData::CycleDetected:
246     case FilterData::Applying:
247         // We have a cycle if we are already applying the data.
248         // This can occur due to FeImage referencing a source that makes use of the FEImage itself.
249         // This is the first place we've hit the cycle, so set the state back to PaintingSource so the return stack
250         // will continue correctly.
251         filterData->state = FilterData::PaintingSource;
252         return;
253
254     case FilterData::PaintingSource:
255         if (!filterData->savedContext) {
256             removeClientFromCache(renderer);
257             return;
258         }
259
260         context = filterData->savedContext;
261         filterData->savedContext = 0;
262         break;
263
264     case FilterData::Built: { } // Empty
265     }
266
267     FilterEffect* lastEffect = filterData->builder->lastEffect();
268
269     if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) {
270         // This is the real filtering of the object. It just needs to be called on the
271         // initial filtering process. We just take the stored filter result on a
272         // second drawing.
273         if (filterData->state != FilterData::Built)
274             filterData->filter->setSourceImage(WTF::move(filterData->sourceGraphicBuffer));
275
276         // Always true if filterData is just built (filterData->state == FilterData::Built).
277         if (!lastEffect->hasResult()) {
278             filterData->state = FilterData::Applying;
279             lastEffect->applyAll();
280             lastEffect->correctFilterResultIfNeeded();
281             lastEffect->transformResultColorSpace(ColorSpaceDeviceRGB);
282         }
283         filterData->state = FilterData::Built;
284
285         ImageBuffer* resultImage = lastEffect->asImageBuffer();
286         if (resultImage) {
287             context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse());
288
289             context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height()));
290             context->drawImageBuffer(resultImage, renderer.style().colorSpace(), lastEffect->absolutePaintRect());
291             context->scale(filterData->filter->filterResolution());
292
293             context->concatCTM(filterData->shearFreeAbsoluteTransform);
294         }
295     }
296     filterData->sourceGraphicBuffer.reset();
297 }
298
299 FloatRect RenderSVGResourceFilter::resourceBoundingBox(const RenderObject& object)
300 {
301     return SVGLengthContext::resolveRectangle<SVGFilterElement>(&filterElement(), filterElement().filterUnits(), object.objectBoundingBox());
302 }
303
304 void RenderSVGResourceFilter::primitiveAttributeChanged(RenderObject* object, const QualifiedName& attribute)
305 {
306     SVGFilterPrimitiveStandardAttributes* primitve = static_cast<SVGFilterPrimitiveStandardAttributes*>(object->node());
307
308     for (const auto& objectFilterDataPair : m_filter) {
309         const auto& filterData = objectFilterDataPair.value;
310         if (filterData->state != FilterData::Built)
311             continue;
312
313         SVGFilterBuilder* builder = filterData->builder.get();
314         FilterEffect* effect = builder->effectByRenderer(object);
315         if (!effect)
316             continue;
317         // Since all effects shares the same attribute value, all
318         // or none of them will be changed.
319         if (!primitve->setFilterEffectAttribute(effect, attribute))
320             return;
321         builder->clearResultsRecursive(effect);
322
323         // Repaint the image on the screen.
324         markClientForInvalidation(*objectFilterDataPair.key, RepaintInvalidation);
325     }
326     markAllClientLayersForInvalidation();
327 }
328
329 FloatRect RenderSVGResourceFilter::drawingRegion(RenderObject* object) const
330 {
331     FilterData* filterData = m_filter.get(object);
332     return filterData ? filterData->drawingRegion : FloatRect();
333 }
334
335 }