Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / rendering / svg / RenderSVGShape.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2008 Rob Buis <buis@kde.org>
4  * Copyright (C) 2005, 2007 Eric Seidel <eric@webkit.org>
5  * Copyright (C) 2009 Google, Inc.
6  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
7  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
8  * Copyright (C) 2009 Jeff Schiller <codedread@gmail.com>
9  * Copyright (C) 2011 Renata Hodovan <reni@webkit.org>
10  * Copyright (C) 2011 University of Szeged
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "RenderSVGShape.h"
30
31 #include "FloatPoint.h"
32 #include "FloatQuad.h"
33 #include "GraphicsContext.h"
34 #include "HitTestRequest.h"
35 #include "HitTestResult.h"
36 #include "LayoutRepainter.h"
37 #include "PointerEventsHitRules.h"
38 #include "RenderSVGResourceMarker.h"
39 #include "RenderSVGResourceSolidColor.h"
40 #include "SVGPathData.h"
41 #include "SVGRenderingContext.h"
42 #include "SVGResources.h"
43 #include "SVGResourcesCache.h"
44 #include "SVGURIReference.h"
45 #include "StrokeStyleApplier.h"
46 #include <wtf/StackStats.h>
47
48 namespace WebCore {
49
50 class BoundingRectStrokeStyleApplier final : public StrokeStyleApplier {
51 public:
52     BoundingRectStrokeStyleApplier(const RenderSVGShape& renderer)
53         : m_renderer(renderer)
54     {
55     }
56
57     void strokeStyle(GraphicsContext* context) override
58     {
59         SVGRenderSupport::applyStrokeStyleToContext(context, m_renderer.style(), m_renderer);
60     }
61
62 private:
63     const RenderSVGShape& m_renderer;
64 };
65
66 RenderSVGShape::RenderSVGShape(SVGGraphicsElement& element, RenderStyle&& style)
67     : RenderSVGModelObject(element, WTFMove(style))
68     , m_needsBoundariesUpdate(false) // Default is false, the cached rects are empty from the beginning.
69     , m_needsShapeUpdate(true) // Default is true, so we grab a Path object once from SVGGraphicsElement.
70     , m_needsTransformUpdate(true) // Default is true, so we grab a AffineTransform object once from SVGGraphicsElement.
71 {
72 }
73
74 RenderSVGShape::~RenderSVGShape() = default;
75
76 void RenderSVGShape::updateShapeFromElement()
77 {
78     m_path = std::make_unique<Path>();
79     ASSERT(RenderSVGShape::isEmpty());
80
81     updatePathFromGraphicsElement(&graphicsElement(), path());
82     processMarkerPositions();
83
84     m_fillBoundingBox = calculateObjectBoundingBox();
85     m_strokeBoundingBox = calculateStrokeBoundingBox();
86 }
87
88 bool RenderSVGShape::isEmpty() const
89 {
90     // This function should never be called before assigning a new Path to m_path.
91     // But this bug can happen if this renderer was created and its layout was not
92     // done before painting. Assert this did not happen but do not crash.
93     ASSERT(hasPath());
94     return !hasPath() || path().isEmpty();
95 }
96
97 void RenderSVGShape::fillShape(GraphicsContext& context) const
98 {
99     context.fillPath(path());
100 }
101
102 void RenderSVGShape::strokeShape(GraphicsContext& context) const
103 {
104     ASSERT(m_path);
105     Path* usePath = m_path.get();
106
107     if (hasNonScalingStroke())
108         usePath = nonScalingStrokePath(usePath, nonScalingStrokeTransform());
109
110     context.strokePath(*usePath);
111 }
112
113 bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point)
114 {
115     ASSERT(m_path);
116     BoundingRectStrokeStyleApplier applier(*this);
117
118     if (hasNonScalingStroke()) {
119         AffineTransform nonScalingTransform = nonScalingStrokeTransform();
120         Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);
121
122         return usePath->strokeContains(&applier, nonScalingTransform.mapPoint(point));
123     }
124
125     return m_path->strokeContains(&applier, point);
126 }
127
128 bool RenderSVGShape::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
129 {
130     return path().contains(point, fillRule);
131 }
132
133 bool RenderSVGShape::fillContains(const FloatPoint& point, bool requiresFill, const WindRule fillRule)
134 {
135     if (!m_fillBoundingBox.contains(point))
136         return false;
137
138     Color fallbackColor;
139     if (requiresFill && !RenderSVGResource::fillPaintingResource(*this, style(), fallbackColor))
140         return false;
141
142     return shapeDependentFillContains(point, fillRule);
143 }
144
145 bool RenderSVGShape::strokeContains(const FloatPoint& point, bool requiresStroke)
146 {
147     if (!strokeBoundingBox().contains(point))
148         return false;
149
150     Color fallbackColor;
151     if (requiresStroke && !RenderSVGResource::strokePaintingResource(*this, style(), fallbackColor))
152         return false;
153
154     return shapeDependentStrokeContains(point);
155 }
156
157 void RenderSVGShape::layout()
158 {
159     StackStats::LayoutCheckPoint layoutCheckPoint;
160     LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(*this) && selfNeedsLayout());
161
162     bool updateCachedBoundariesInParents = false;
163
164     if (m_needsShapeUpdate || m_needsBoundariesUpdate) {
165         updateShapeFromElement();
166         m_needsShapeUpdate = false;
167         updateRepaintBoundingBox();
168         m_needsBoundariesUpdate = false;
169         updateCachedBoundariesInParents = true;
170     }
171
172     if (m_needsTransformUpdate) {
173         m_localTransform = graphicsElement().animatedLocalTransform();
174         m_needsTransformUpdate = false;
175         updateCachedBoundariesInParents = true;
176     }
177
178     // Invalidate all resources of this client if our layout changed.
179     if (everHadLayout() && selfNeedsLayout())
180         SVGResourcesCache::clientLayoutChanged(*this);
181
182     // If our bounds changed, notify the parents.
183     if (updateCachedBoundariesInParents)
184         RenderSVGModelObject::setNeedsBoundariesUpdate();
185
186     repainter.repaintAfterLayout();
187     clearNeedsLayout();
188 }
189
190 Path* RenderSVGShape::nonScalingStrokePath(const Path* path, const AffineTransform& strokeTransform) const
191 {
192     static NeverDestroyed<Path> tempPath;
193
194     tempPath.get() = *path;
195     tempPath.get().transform(strokeTransform);
196
197     return &tempPath.get();
198 }
199
200 bool RenderSVGShape::setupNonScalingStrokeContext(AffineTransform& strokeTransform, GraphicsContextStateSaver& stateSaver)
201 {
202     std::optional<AffineTransform> inverse = strokeTransform.inverse();
203     if (!inverse)
204         return false;
205
206     stateSaver.save();
207     stateSaver.context()->concatCTM(inverse.value());
208     return true;
209 }
210
211 AffineTransform RenderSVGShape::nonScalingStrokeTransform() const
212 {
213     return graphicsElement().getScreenCTM(SVGLocatable::DisallowStyleUpdate);
214 }
215
216 bool RenderSVGShape::shouldGenerateMarkerPositions() const
217 {
218     if (!style().svgStyle().hasMarkers())
219         return false;
220
221     if (!graphicsElement().supportsMarkers())
222         return false;
223
224     auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this);
225     if (!resources)
226         return false;
227
228     return resources->markerStart() || resources->markerMid() || resources->markerEnd();
229 }
230
231 void RenderSVGShape::fillShape(const RenderStyle& style, GraphicsContext& originalContext)
232 {
233     GraphicsContext* context = &originalContext;
234     Color fallbackColor;
235     if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(*this, style, fallbackColor)) {
236         if (fillPaintingResource->applyResource(*this, style, context, RenderSVGResourceMode::ApplyToFill))
237             fillPaintingResource->postApplyResource(*this, context, RenderSVGResourceMode::ApplyToFill, nullptr, this);
238         else if (fallbackColor.isValid()) {
239             RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource();
240             fallbackResource->setColor(fallbackColor);
241             if (fallbackResource->applyResource(*this, style, context, RenderSVGResourceMode::ApplyToFill))
242                 fallbackResource->postApplyResource(*this, context, RenderSVGResourceMode::ApplyToFill, nullptr, this);
243         }
244     }
245 }
246
247 void RenderSVGShape::strokeShape(const RenderStyle& style, GraphicsContext& originalContext)
248 {
249     GraphicsContext* context = &originalContext;
250     Color fallbackColor;
251     if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(*this, style, fallbackColor)) {
252         if (strokePaintingResource->applyResource(*this, style, context, RenderSVGResourceMode::ApplyToStroke))
253             strokePaintingResource->postApplyResource(*this, context, RenderSVGResourceMode::ApplyToStroke, nullptr, this);
254         else if (fallbackColor.isValid()) {
255             RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource();
256             fallbackResource->setColor(fallbackColor);
257             if (fallbackResource->applyResource(*this, style, context, RenderSVGResourceMode::ApplyToStroke))
258                 fallbackResource->postApplyResource(*this, context, RenderSVGResourceMode::ApplyToStroke, nullptr, this);
259         }
260     }
261 }
262
263 void RenderSVGShape::strokeShape(GraphicsContext& context)
264 {
265     if (!style().hasVisibleStroke())
266         return;
267
268     GraphicsContextStateSaver stateSaver(context, false);
269     if (hasNonScalingStroke()) {
270         AffineTransform nonScalingTransform = nonScalingStrokeTransform();
271         if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver))
272             return;
273     }
274     strokeShape(style(), context);
275 }
276
277 void RenderSVGShape::fillStrokeMarkers(PaintInfo& childPaintInfo)
278 {
279     auto paintOrder = RenderStyle::paintTypesForPaintOrder(style().paintOrder());
280     for (unsigned i = 0; i < paintOrder.size(); ++i) {
281         switch (paintOrder.at(i)) {
282         case PaintType::Fill:
283             fillShape(style(), childPaintInfo.context());
284             break;
285         case PaintType::Stroke:
286             strokeShape(childPaintInfo.context());
287             break;
288         case PaintType::Markers:
289             if (!m_markerPositions.isEmpty())
290                 drawMarkers(childPaintInfo);
291             break;
292         }
293     }
294 }
295
296 void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&)
297 {
298     if (paintInfo.context().paintingDisabled() || paintInfo.phase != PaintPhaseForeground
299         || style().visibility() == HIDDEN || isEmpty())
300         return;
301     FloatRect boundingBox = repaintRectInLocalCoordinates();
302     if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo))
303         return;
304
305     PaintInfo childPaintInfo(paintInfo);
306     GraphicsContextStateSaver stateSaver(childPaintInfo.context());
307     childPaintInfo.applyTransform(m_localTransform);
308
309     if (childPaintInfo.phase == PaintPhaseForeground) {
310         SVGRenderingContext renderingContext(*this, childPaintInfo);
311
312         if (renderingContext.isRenderingPrepared()) {
313             const SVGRenderStyle& svgStyle = style().svgStyle();
314             if (svgStyle.shapeRendering() == SR_CRISPEDGES)
315                 childPaintInfo.context().setShouldAntialias(false);
316
317             fillStrokeMarkers(childPaintInfo);
318         }
319     }
320
321     if (style().outlineWidth())
322         paintOutline(childPaintInfo, IntRect(boundingBox));
323 }
324
325 // This method is called from inside paintOutline() since we call paintOutline()
326 // while transformed to our coord system, return local coords
327 void RenderSVGShape::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&, const RenderLayerModelObject*)
328 {
329     LayoutRect rect = LayoutRect(repaintRectInLocalCoordinates());
330     if (!rect.isEmpty())
331         rects.append(rect);
332 }
333
334 bool RenderSVGShape::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
335 {
336     // We only draw in the forground phase, so we only hit-test then.
337     if (hitTestAction != HitTestForeground)
338         return false;
339
340     FloatPoint localPoint = m_localTransform.inverse().value_or(AffineTransform()).mapPoint(pointInParent);
341
342     if (!SVGRenderSupport::pointInClippingArea(*this, localPoint))
343         return false;
344
345     PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_PATH_HITTESTING, request, style().pointerEvents());
346     bool isVisible = (style().visibility() == VISIBLE);
347     if (isVisible || !hitRules.requireVisible) {
348         const SVGRenderStyle& svgStyle = style().svgStyle();
349         WindRule fillRule = svgStyle.fillRule();
350         if (request.svgClipContent())
351             fillRule = svgStyle.clipRule();
352         if ((hitRules.canHitStroke && (svgStyle.hasStroke() || !hitRules.requireStroke) && strokeContains(localPoint, hitRules.requireStroke))
353             || (hitRules.canHitFill && (svgStyle.hasFill() || !hitRules.requireFill) && fillContains(localPoint, hitRules.requireFill, fillRule))) {
354             updateHitTestResult(result, LayoutPoint(localPoint));
355             if (result.addNodeToListBasedTestResult(&graphicsElement(), request, localPoint) == HitTestProgress::Stop)
356                 return true;
357         }
358     }
359     return false;
360 }
361
362 static inline RenderSVGResourceMarker* markerForType(SVGMarkerType type, RenderSVGResourceMarker* markerStart, RenderSVGResourceMarker* markerMid, RenderSVGResourceMarker* markerEnd)
363 {
364     switch (type) {
365     case StartMarker:
366         return markerStart;
367     case MidMarker:
368         return markerMid;
369     case EndMarker:
370         return markerEnd;
371     }
372
373     ASSERT_NOT_REACHED();
374     return 0;
375 }
376
377 FloatRect RenderSVGShape::markerRect(float strokeWidth) const
378 {
379     ASSERT(!m_markerPositions.isEmpty());
380
381     auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this);
382     ASSERT(resources);
383
384     RenderSVGResourceMarker* markerStart = resources->markerStart();
385     RenderSVGResourceMarker* markerMid = resources->markerMid();
386     RenderSVGResourceMarker* markerEnd = resources->markerEnd();
387     ASSERT(markerStart || markerMid || markerEnd);
388
389     FloatRect boundaries;
390     unsigned size = m_markerPositions.size();
391     for (unsigned i = 0; i < size; ++i) {
392         if (RenderSVGResourceMarker* marker = markerForType(m_markerPositions[i].type, markerStart, markerMid, markerEnd))
393             boundaries.unite(marker->markerBoundaries(marker->markerTransformation(m_markerPositions[i].origin, m_markerPositions[i].angle, strokeWidth)));
394     }
395     return boundaries;
396 }
397
398 FloatRect RenderSVGShape::calculateObjectBoundingBox() const
399 {
400     return path().boundingRect();
401 }
402
403 FloatRect RenderSVGShape::calculateStrokeBoundingBox() const
404 {
405     ASSERT(m_path);
406     FloatRect strokeBoundingBox = m_fillBoundingBox;
407
408     const SVGRenderStyle& svgStyle = style().svgStyle();
409     if (svgStyle.hasStroke()) {
410         BoundingRectStrokeStyleApplier strokeStyle(*this);
411         if (hasNonScalingStroke()) {
412             AffineTransform nonScalingTransform = nonScalingStrokeTransform();
413             if (std::optional<AffineTransform> inverse = nonScalingTransform.inverse()) {
414                 Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);
415                 FloatRect strokeBoundingRect = usePath->strokeBoundingRect(&strokeStyle);
416                 strokeBoundingRect = inverse.value().mapRect(strokeBoundingRect);
417                 strokeBoundingBox.unite(strokeBoundingRect);
418             }
419         } else
420             strokeBoundingBox.unite(path().strokeBoundingRect(&strokeStyle));
421     }
422
423     if (!m_markerPositions.isEmpty())
424         strokeBoundingBox.unite(markerRect(strokeWidth()));
425
426     return strokeBoundingBox;
427 }
428
429 void RenderSVGShape::updateRepaintBoundingBox()
430 {
431     m_repaintBoundingBoxExcludingShadow = strokeBoundingBox();
432     SVGRenderSupport::intersectRepaintRectWithResources(*this, m_repaintBoundingBoxExcludingShadow);
433
434     m_repaintBoundingBox = m_repaintBoundingBoxExcludingShadow;
435     SVGRenderSupport::intersectRepaintRectWithShadows(*this, m_repaintBoundingBox);
436 }
437
438 float RenderSVGShape::strokeWidth() const
439 {
440     SVGLengthContext lengthContext(&graphicsElement());
441     return lengthContext.valueForLength(style().strokeWidth());
442 }
443
444 bool RenderSVGShape::hasSmoothStroke() const
445 {
446     const SVGRenderStyle& svgStyle = style().svgStyle();
447     return svgStyle.strokeDashArray().isEmpty()
448         && style().strokeMiterLimit() == style().initialStrokeMiterLimit()
449         && style().joinStyle() == style().initialJoinStyle()
450         && style().capStyle() == style().initialCapStyle();
451 }
452
453 void RenderSVGShape::drawMarkers(PaintInfo& paintInfo)
454 {
455     ASSERT(!m_markerPositions.isEmpty());
456
457     auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this);
458     if (!resources)
459         return;
460
461     RenderSVGResourceMarker* markerStart = resources->markerStart();
462     RenderSVGResourceMarker* markerMid = resources->markerMid();
463     RenderSVGResourceMarker* markerEnd = resources->markerEnd();
464     if (!markerStart && !markerMid && !markerEnd)
465         return;
466
467     float strokeWidth = this->strokeWidth();
468     unsigned size = m_markerPositions.size();
469     for (unsigned i = 0; i < size; ++i) {
470         if (RenderSVGResourceMarker* marker = markerForType(m_markerPositions[i].type, markerStart, markerMid, markerEnd))
471             marker->draw(paintInfo, marker->markerTransformation(m_markerPositions[i].origin, m_markerPositions[i].angle, strokeWidth));
472     }
473 }
474
475 void RenderSVGShape::processMarkerPositions()
476 {
477     m_markerPositions.clear();
478
479     if (!shouldGenerateMarkerPositions())
480         return;
481
482     ASSERT(m_path);
483
484     SVGMarkerData markerData(m_markerPositions, SVGResourcesCache::cachedResourcesForRenderer(*this)->markerReverseStart());
485     m_path->apply([&markerData](const PathElement& pathElement) {
486         SVGMarkerData::updateFromPathElement(markerData, pathElement);
487     });
488     markerData.pathIsDone();
489 }
490
491 }