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