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