Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/rendering/svg/RenderSVGShape.h"
30
31 #include "core/paint/SVGShapePainter.h"
32 #include "core/rendering/HitTestRequest.h"
33 #include "core/rendering/PointerEventsHitRules.h"
34 #include "core/rendering/svg/SVGPathData.h"
35 #include "core/rendering/svg/SVGRenderSupport.h"
36 #include "core/rendering/svg/SVGResources.h"
37 #include "core/rendering/svg/SVGResourcesCache.h"
38 #include "core/svg/SVGGraphicsElement.h"
39 #include "platform/geometry/FloatPoint.h"
40 #include "platform/graphics/StrokeData.h"
41 #include "wtf/MathExtras.h"
42
43 namespace blink {
44
45 RenderSVGShape::RenderSVGShape(SVGGraphicsElement* node)
46     : RenderSVGModelObject(node)
47     , m_needsBoundariesUpdate(false) // Default is false, the cached rects are empty from the beginning.
48     , m_needsShapeUpdate(true) // Default is true, so we grab a Path object once from SVGGraphicsElement.
49     , m_needsTransformUpdate(true) // Default is true, so we grab a AffineTransform object once from SVGGraphicsElement.
50 {
51 }
52
53 RenderSVGShape::~RenderSVGShape()
54 {
55 }
56
57 void RenderSVGShape::updateShapeFromElement()
58 {
59     m_path.clear();
60     m_path = adoptPtr(new Path);
61     ASSERT(RenderSVGShape::isShapeEmpty());
62
63     updatePathFromGraphicsElement(toSVGGraphicsElement(element()), path());
64     processMarkerPositions();
65
66     m_fillBoundingBox = calculateObjectBoundingBox();
67     m_strokeBoundingBox = calculateStrokeBoundingBox();
68 }
69
70 bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point)
71 {
72     ASSERT(m_path);
73     StrokeData strokeData;
74     SVGRenderSupport::applyStrokeStyleToStrokeData(&strokeData, style(), this);
75
76     if (hasNonScalingStroke()) {
77         AffineTransform nonScalingTransform = nonScalingStrokeTransform();
78         Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);
79
80         return usePath->strokeContains(nonScalingTransform.mapPoint(point), strokeData);
81     }
82
83     return m_path->strokeContains(point, strokeData);
84 }
85
86 bool RenderSVGShape::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
87 {
88     return path().contains(point, fillRule);
89 }
90
91 bool RenderSVGShape::fillContains(const FloatPoint& point, bool requiresFill, const WindRule fillRule)
92 {
93     if (!m_fillBoundingBox.contains(point))
94         return false;
95
96     if (requiresFill && !SVGPaintServer::existsForRenderer(*this, style(), ApplyToFillMode))
97         return false;
98
99     return shapeDependentFillContains(point, fillRule);
100 }
101
102 bool RenderSVGShape::strokeContains(const FloatPoint& point, bool requiresStroke)
103 {
104     if (!strokeBoundingBox().contains(point))
105         return false;
106
107     if (requiresStroke && !SVGPaintServer::existsForRenderer(*this, style(), ApplyToStrokeMode))
108         return false;
109
110     return shapeDependentStrokeContains(point);
111 }
112
113 void RenderSVGShape::layout()
114 {
115     bool updateCachedBoundariesInParents = false;
116
117     if (m_needsShapeUpdate || m_needsBoundariesUpdate) {
118         updateShapeFromElement();
119         m_needsShapeUpdate = false;
120         updatePaintInvalidationBoundingBox();
121         m_needsBoundariesUpdate = false;
122         updateCachedBoundariesInParents = true;
123     }
124
125     if (m_needsTransformUpdate) {
126         m_localTransform =  toSVGGraphicsElement(element())->calculateAnimatedLocalTransform();
127         m_needsTransformUpdate = false;
128         updateCachedBoundariesInParents = true;
129     }
130
131     // Invalidate all resources of this client if our layout changed.
132     if (everHadLayout() && selfNeedsLayout())
133         SVGResourcesCache::clientLayoutChanged(this);
134
135     // If our bounds changed, notify the parents.
136     if (updateCachedBoundariesInParents)
137         RenderSVGModelObject::setNeedsBoundariesUpdate();
138
139     clearNeedsLayout();
140 }
141
142 Path* RenderSVGShape::nonScalingStrokePath(const Path* path, const AffineTransform& strokeTransform) const
143 {
144     DEFINE_STATIC_LOCAL(Path, tempPath, ());
145
146     tempPath = *path;
147     tempPath.transform(strokeTransform);
148
149     return &tempPath;
150 }
151
152 AffineTransform RenderSVGShape::nonScalingStrokeTransform() const
153 {
154     return toSVGGraphicsElement(element())->getScreenCTM(SVGGraphicsElement::DisallowStyleUpdate);
155 }
156
157 void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&)
158 {
159     SVGShapePainter(*this).paint(paintInfo);
160 }
161
162 // This method is called from inside paintOutline() since we call paintOutline()
163 // while transformed to our coord system, return local coords
164 void RenderSVGShape::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) const
165 {
166     LayoutRect rect = LayoutRect(paintInvalidationRectInLocalCoordinates());
167     if (!rect.isEmpty())
168         rects.append(rect);
169 }
170
171 bool RenderSVGShape::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
172 {
173     // We only draw in the foreground phase, so we only hit-test then.
174     if (hitTestAction != HitTestForeground)
175         return false;
176
177     FloatPoint localPoint;
178     if (!SVGRenderSupport::transformToUserSpaceAndCheckClipping(this, m_localTransform, pointInParent, localPoint))
179         return false;
180
181     PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_GEOMETRY_HITTESTING, request, style()->pointerEvents());
182     if (nodeAtFloatPointInternal(request, localPoint, hitRules)) {
183         updateHitTestResult(result, roundedLayoutPoint(localPoint));
184         return true;
185     }
186
187     return false;
188 }
189
190 bool RenderSVGShape::nodeAtFloatPointInternal(const HitTestRequest& request, const FloatPoint& localPoint, PointerEventsHitRules hitRules)
191 {
192     bool isVisible = (style()->visibility() == VISIBLE);
193     if (isVisible || !hitRules.requireVisible) {
194         const SVGRenderStyle& svgStyle = style()->svgStyle();
195         WindRule fillRule = svgStyle.fillRule();
196         if (request.svgClipContent())
197             fillRule = svgStyle.clipRule();
198         if ((hitRules.canHitBoundingBox && objectBoundingBox().contains(localPoint))
199             || (hitRules.canHitStroke && (svgStyle.hasStroke() || !hitRules.requireStroke) && strokeContains(localPoint, hitRules.requireStroke))
200             || (hitRules.canHitFill && (svgStyle.hasFill() || !hitRules.requireFill) && fillContains(localPoint, hitRules.requireFill, fillRule)))
201             return true;
202     }
203     return false;
204 }
205
206 FloatRect RenderSVGShape::calculateObjectBoundingBox() const
207 {
208     return path().boundingRect();
209 }
210
211 FloatRect RenderSVGShape::calculateStrokeBoundingBox() const
212 {
213     ASSERT(m_path);
214     FloatRect strokeBoundingBox = m_fillBoundingBox;
215
216     if (style()->svgStyle().hasStroke()) {
217         StrokeData strokeData;
218         SVGRenderSupport::applyStrokeStyleToStrokeData(&strokeData, style(), this);
219         if (hasNonScalingStroke()) {
220             AffineTransform nonScalingTransform = nonScalingStrokeTransform();
221             if (nonScalingTransform.isInvertible()) {
222                 Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);
223                 FloatRect strokeBoundingRect = usePath->strokeBoundingRect(strokeData);
224                 strokeBoundingRect = nonScalingTransform.inverse().mapRect(strokeBoundingRect);
225                 strokeBoundingBox.unite(strokeBoundingRect);
226             }
227         } else {
228             strokeBoundingBox.unite(path().strokeBoundingRect(strokeData));
229         }
230     }
231
232     return strokeBoundingBox;
233 }
234
235 void RenderSVGShape::updatePaintInvalidationBoundingBox()
236 {
237     m_paintInvalidationBoundingBox = strokeBoundingBox();
238     if (strokeWidth() < 1.0f && !m_paintInvalidationBoundingBox.isEmpty())
239         m_paintInvalidationBoundingBox.inflate(1);
240     SVGRenderSupport::intersectPaintInvalidationRectWithResources(this, m_paintInvalidationBoundingBox);
241 }
242
243 float RenderSVGShape::strokeWidth() const
244 {
245     SVGLengthContext lengthContext(element());
246     return style()->svgStyle().strokeWidth()->value(lengthContext);
247 }
248
249 bool RenderSVGShape::hasSmoothStroke() const
250 {
251     const SVGRenderStyle& svgStyle = style()->svgStyle();
252     return svgStyle.strokeDashArray()->isEmpty()
253         && svgStyle.strokeMiterLimit() == SVGRenderStyle::initialStrokeMiterLimit()
254         && svgStyle.joinStyle() == SVGRenderStyle::initialJoinStyle()
255         && svgStyle.capStyle() == SVGRenderStyle::initialCapStyle();
256 }
257
258 }