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