Subpixel layout: remove roundedLayoutPoint/roundedLayoutSize functions.
[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 "LayoutRepainter.h"
36 #include "PointerEventsHitRules.h"
37 #include "RenderSVGResourceMarker.h"
38 #include "RenderSVGResourceSolidColor.h"
39 #include "SVGPathData.h"
40 #include "SVGRenderingContext.h"
41 #include "SVGResources.h"
42 #include "SVGResourcesCache.h"
43 #include "SVGTransformList.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     virtual 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, PassRef<RenderStyle> style)
67     : RenderSVGModelObject(element, WTF::move(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()
75 {
76 }
77
78 void RenderSVGShape::updateShapeFromElement()
79 {
80     m_path = std::make_unique<Path>();
81     ASSERT(RenderSVGShape::isEmpty());
82
83     updatePathFromGraphicsElement(&graphicsElement(), path());
84     processMarkerPositions();
85
86     m_fillBoundingBox = calculateObjectBoundingBox();
87     m_strokeBoundingBox = calculateStrokeBoundingBox();
88 }
89
90 bool RenderSVGShape::isEmpty() const
91 {
92     return path().isEmpty();
93 }
94
95 void RenderSVGShape::fillShape(GraphicsContext* context) const
96 {
97     context->fillPath(path());
98 }
99
100 void RenderSVGShape::strokeShape(GraphicsContext* context) const
101 {
102     ASSERT(m_path);
103     Path* usePath = m_path.get();
104
105     if (hasNonScalingStroke())
106         usePath = nonScalingStrokePath(usePath, nonScalingStrokeTransform());
107
108     context->strokePath(*usePath);
109 }
110
111 bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point)
112 {
113     ASSERT(m_path);
114     BoundingRectStrokeStyleApplier applier(*this);
115
116     if (hasNonScalingStroke()) {
117         AffineTransform nonScalingTransform = nonScalingStrokeTransform();
118         Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);
119
120         return usePath->strokeContains(&applier, nonScalingTransform.mapPoint(point));
121     }
122
123     return m_path->strokeContains(&applier, point);
124 }
125
126 bool RenderSVGShape::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
127 {
128     return path().contains(point, fillRule);
129 }
130
131 bool RenderSVGShape::fillContains(const FloatPoint& point, bool requiresFill, const WindRule fillRule)
132 {
133     if (!m_fillBoundingBox.contains(point))
134         return false;
135
136     Color fallbackColor;
137     if (requiresFill && !RenderSVGResource::fillPaintingResource(*this, style(), fallbackColor))
138         return false;
139
140     return shapeDependentFillContains(point, fillRule);
141 }
142
143 bool RenderSVGShape::strokeContains(const FloatPoint& point, bool requiresStroke)
144 {
145     if (!strokeBoundingBox().contains(point))
146         return false;
147
148     Color fallbackColor;
149     if (requiresStroke && !RenderSVGResource::strokePaintingResource(*this, style(), fallbackColor))
150         return false;
151
152     return shapeDependentStrokeContains(point);
153 }
154
155 void RenderSVGShape::layout()
156 {
157     StackStats::LayoutCheckPoint layoutCheckPoint;
158     LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(*this) && selfNeedsLayout());
159
160     bool updateCachedBoundariesInParents = false;
161
162     if (m_needsShapeUpdate || m_needsBoundariesUpdate) {
163         updateShapeFromElement();
164         m_needsShapeUpdate = false;
165         updateRepaintBoundingBox();
166         m_needsBoundariesUpdate = false;
167         updateCachedBoundariesInParents = true;
168     }
169
170     if (m_needsTransformUpdate) {
171         m_localTransform = graphicsElement().animatedLocalTransform();
172         m_needsTransformUpdate = false;
173         updateCachedBoundariesInParents = true;
174     }
175
176     // Invalidate all resources of this client if our layout changed.
177     if (everHadLayout() && selfNeedsLayout())
178         SVGResourcesCache::clientLayoutChanged(*this);
179
180     // If our bounds changed, notify the parents.
181     if (updateCachedBoundariesInParents)
182         RenderSVGModelObject::setNeedsBoundariesUpdate();
183
184     repainter.repaintAfterLayout();
185     clearNeedsLayout();
186 }
187
188 Path* RenderSVGShape::nonScalingStrokePath(const Path* path, const AffineTransform& strokeTransform) const
189 {
190     DEPRECATED_DEFINE_STATIC_LOCAL(Path, tempPath, ());
191
192     tempPath = *path;
193     tempPath.transform(strokeTransform);
194
195     return &tempPath;
196 }
197
198 bool RenderSVGShape::setupNonScalingStrokeContext(AffineTransform& strokeTransform, GraphicsContextStateSaver& stateSaver)
199 {
200     if (!strokeTransform.isInvertible())
201         return false;
202
203     stateSaver.save();
204     stateSaver.context()->concatCTM(strokeTransform.inverse());
205     return true;
206 }
207
208 AffineTransform RenderSVGShape::nonScalingStrokeTransform() const
209 {
210     return graphicsElement().getScreenCTM(SVGLocatable::DisallowStyleUpdate);
211 }
212
213 bool RenderSVGShape::shouldGenerateMarkerPositions() const
214 {
215     if (!style().svgStyle().hasMarkers())
216         return false;
217
218     if (!graphicsElement().supportsMarkers())
219         return false;
220
221     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this);
222     if (!resources)
223         return false;
224
225     return resources->markerStart() || resources->markerMid() || resources->markerEnd();
226 }
227
228 void RenderSVGShape::fillShape(const RenderStyle& style, GraphicsContext* context)
229 {
230     Color fallbackColor;
231     if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(*this, style, fallbackColor)) {
232         if (fillPaintingResource->applyResource(*this, style, context, ApplyToFillMode))
233             fillPaintingResource->postApplyResource(*this, context, ApplyToFillMode, 0, this);
234         else if (fallbackColor.isValid()) {
235             RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource();
236             fallbackResource->setColor(fallbackColor);
237             if (fallbackResource->applyResource(*this, style, context, ApplyToFillMode))
238                 fallbackResource->postApplyResource(*this, context, ApplyToFillMode, 0, this);
239         }
240     }
241 }
242
243 void RenderSVGShape::strokeShape(const RenderStyle& style, GraphicsContext* context)
244 {
245     Color fallbackColor;
246     if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(*this, style, fallbackColor)) {
247         if (strokePaintingResource->applyResource(*this, style, context, ApplyToStrokeMode))
248             strokePaintingResource->postApplyResource(*this, context, ApplyToStrokeMode, 0, this);
249         else if (fallbackColor.isValid()) {
250             RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource();
251             fallbackResource->setColor(fallbackColor);
252             if (fallbackResource->applyResource(*this, style, context, ApplyToStrokeMode))
253                 fallbackResource->postApplyResource(*this, context, ApplyToStrokeMode, 0, this);
254         }
255     }
256 }
257
258 void RenderSVGShape::strokeShape(GraphicsContext* context)
259 {
260     if (!style().svgStyle().hasVisibleStroke())
261         return;
262
263     GraphicsContextStateSaver stateSaver(*context, false);
264     if (hasNonScalingStroke()) {
265         AffineTransform nonScalingTransform = nonScalingStrokeTransform();
266         if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver))
267             return;
268     }
269     strokeShape(style(), context);
270 }
271
272 void RenderSVGShape::fillStrokeMarkers(PaintInfo& childPaintInfo)
273 {
274     Vector<PaintType> paintOrder = style().svgStyle().paintTypesForPaintOrder();
275     for (unsigned i = 0; i < paintOrder.size(); ++i) {
276         switch (paintOrder.at(i)) {
277         case PaintTypeFill:
278             fillShape(style(), childPaintInfo.context);
279             break;
280         case PaintTypeStroke:
281             strokeShape(childPaintInfo.context);
282             break;
283         case PaintTypeMarkers:
284             if (!m_markerPositions.isEmpty())
285                 drawMarkers(childPaintInfo);
286             break;
287         }
288     }
289 }
290
291 void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&)
292 {
293     if (paintInfo.context->paintingDisabled() || paintInfo.phase != PaintPhaseForeground
294         || style().visibility() == HIDDEN || isEmpty())
295         return;
296     FloatRect boundingBox = repaintRectInLocalCoordinates();
297     if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo))
298         return;
299
300     PaintInfo childPaintInfo(paintInfo);
301     GraphicsContextStateSaver stateSaver(*childPaintInfo.context);
302     childPaintInfo.applyTransform(m_localTransform);
303
304     if (childPaintInfo.phase == PaintPhaseForeground) {
305         SVGRenderingContext renderingContext(*this, childPaintInfo);
306
307         if (renderingContext.isRenderingPrepared()) {
308             const SVGRenderStyle& svgStyle = style().svgStyle();
309             if (svgStyle.shapeRendering() == SR_CRISPEDGES)
310                 childPaintInfo.context->setShouldAntialias(false);
311
312             fillStrokeMarkers(childPaintInfo);
313         }
314     }
315
316     if (style().outlineWidth())
317         paintOutline(childPaintInfo, IntRect(boundingBox));
318 }
319
320 // This method is called from inside paintOutline() since we call paintOutline()
321 // while transformed to our coord system, return local coords
322 void RenderSVGShape::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*)
323 {
324     IntRect rect = enclosingIntRect(repaintRectInLocalCoordinates());
325     if (!rect.isEmpty())
326         rects.append(rect);
327 }
328
329 bool RenderSVGShape::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
330 {
331     // We only draw in the forground phase, so we only hit-test then.
332     if (hitTestAction != HitTestForeground)
333         return false;
334
335     FloatPoint localPoint = m_localTransform.inverse().mapPoint(pointInParent);
336
337     if (!SVGRenderSupport::pointInClippingArea(*this, localPoint))
338         return false;
339
340     PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_PATH_HITTESTING, request, style().pointerEvents());
341     bool isVisible = (style().visibility() == VISIBLE);
342     if (isVisible || !hitRules.requireVisible) {
343         const SVGRenderStyle& svgStyle = style().svgStyle();
344         WindRule fillRule = svgStyle.fillRule();
345         if (request.svgClipContent())
346             fillRule = svgStyle.clipRule();
347         if ((hitRules.canHitStroke && (svgStyle.hasStroke() || !hitRules.requireStroke) && strokeContains(localPoint, hitRules.requireStroke))
348             || (hitRules.canHitFill && (svgStyle.hasFill() || !hitRules.requireFill) && fillContains(localPoint, hitRules.requireFill, fillRule))) {
349             updateHitTestResult(result, LayoutPoint(localPoint));
350             return true;
351         }
352     }
353     return false;
354 }
355
356 static inline RenderSVGResourceMarker* markerForType(SVGMarkerType type, RenderSVGResourceMarker* markerStart, RenderSVGResourceMarker* markerMid, RenderSVGResourceMarker* markerEnd)
357 {
358     switch (type) {
359     case StartMarker:
360         return markerStart;
361     case MidMarker:
362         return markerMid;
363     case EndMarker:
364         return markerEnd;
365     }
366
367     ASSERT_NOT_REACHED();
368     return 0;
369 }
370
371 FloatRect RenderSVGShape::markerRect(float strokeWidth) const
372 {
373     ASSERT(!m_markerPositions.isEmpty());
374
375     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this);
376     ASSERT(resources);
377
378     RenderSVGResourceMarker* markerStart = resources->markerStart();
379     RenderSVGResourceMarker* markerMid = resources->markerMid();
380     RenderSVGResourceMarker* markerEnd = resources->markerEnd();
381     ASSERT(markerStart || markerMid || markerEnd);
382
383     FloatRect boundaries;
384     unsigned size = m_markerPositions.size();
385     for (unsigned i = 0; i < size; ++i) {
386         if (RenderSVGResourceMarker* marker = markerForType(m_markerPositions[i].type, markerStart, markerMid, markerEnd))
387             boundaries.unite(marker->markerBoundaries(marker->markerTransformation(m_markerPositions[i].origin, m_markerPositions[i].angle, strokeWidth)));
388     }
389     return boundaries;
390 }
391
392 FloatRect RenderSVGShape::calculateObjectBoundingBox() const
393 {
394     return path().fastBoundingRect();
395 }
396
397 FloatRect RenderSVGShape::calculateStrokeBoundingBox() const
398 {
399     ASSERT(m_path);
400     FloatRect strokeBoundingBox = m_fillBoundingBox;
401
402     const SVGRenderStyle& svgStyle = style().svgStyle();
403     if (svgStyle.hasStroke()) {
404         BoundingRectStrokeStyleApplier strokeStyle(*this);
405         if (hasNonScalingStroke()) {
406             AffineTransform nonScalingTransform = nonScalingStrokeTransform();
407             if (nonScalingTransform.isInvertible()) {
408                 Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);
409                 FloatRect strokeBoundingRect = usePath->strokeBoundingRect(&strokeStyle);
410                 strokeBoundingRect = nonScalingTransform.inverse().mapRect(strokeBoundingRect);
411                 strokeBoundingBox.unite(strokeBoundingRect);
412             }
413         } else
414             strokeBoundingBox.unite(path().strokeBoundingRect(&strokeStyle));
415     }
416
417     if (!m_markerPositions.isEmpty())
418         strokeBoundingBox.unite(markerRect(strokeWidth()));
419
420     return strokeBoundingBox;
421 }
422
423 void RenderSVGShape::updateRepaintBoundingBox()
424 {
425     m_repaintBoundingBoxExcludingShadow = strokeBoundingBox();
426     SVGRenderSupport::intersectRepaintRectWithResources(*this, m_repaintBoundingBoxExcludingShadow);
427
428     m_repaintBoundingBox = m_repaintBoundingBoxExcludingShadow;
429     SVGRenderSupport::intersectRepaintRectWithShadows(*this, m_repaintBoundingBox);
430 }
431
432 float RenderSVGShape::strokeWidth() const
433 {
434     SVGLengthContext lengthContext(&graphicsElement());
435     return lengthContext.valueForLength(style().svgStyle().strokeWidth());
436 }
437
438 bool RenderSVGShape::hasSmoothStroke() const
439 {
440     const SVGRenderStyle& svgStyle = style().svgStyle();
441     return svgStyle.strokeDashArray().isEmpty()
442         && svgStyle.strokeMiterLimit() == svgStyle.initialStrokeMiterLimit()
443         && svgStyle.joinStyle() == svgStyle.initialJoinStyle()
444         && svgStyle.capStyle() == svgStyle.initialCapStyle();
445 }
446
447 void RenderSVGShape::drawMarkers(PaintInfo& paintInfo)
448 {
449     ASSERT(!m_markerPositions.isEmpty());
450
451     SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this);
452     if (!resources)
453         return;
454
455     RenderSVGResourceMarker* markerStart = resources->markerStart();
456     RenderSVGResourceMarker* markerMid = resources->markerMid();
457     RenderSVGResourceMarker* markerEnd = resources->markerEnd();
458     if (!markerStart && !markerMid && !markerEnd)
459         return;
460
461     float strokeWidth = this->strokeWidth();
462     unsigned size = m_markerPositions.size();
463     for (unsigned i = 0; i < size; ++i) {
464         if (RenderSVGResourceMarker* marker = markerForType(m_markerPositions[i].type, markerStart, markerMid, markerEnd))
465             marker->draw(paintInfo, marker->markerTransformation(m_markerPositions[i].origin, m_markerPositions[i].angle, strokeWidth));
466     }
467 }
468
469 void RenderSVGShape::processMarkerPositions()
470 {
471     m_markerPositions.clear();
472
473     if (!shouldGenerateMarkerPositions())
474         return;
475
476     ASSERT(m_path);
477
478     SVGMarkerData markerData(m_markerPositions);
479     m_path->apply(&markerData, SVGMarkerData::updateFromPathElement);
480     markerData.pathIsDone();
481 }
482
483 }