Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(625)

Side by Side Diff: Source/core/rendering/svg/RenderSVGEllipse.cpp

Issue 877553002: Fix ellipse hit testing in the non-circle case (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Lazily create the path Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2012 Google, Inc. 2 * Copyright (C) 2012 Google, Inc.
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 13 matching lines...) Expand all
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */ 25 */
26 26
27 #include "config.h" 27 #include "config.h"
28 28
29 #include "core/rendering/svg/RenderSVGEllipse.h" 29 #include "core/rendering/svg/RenderSVGEllipse.h"
30 30
31 #include "core/svg/SVGCircleElement.h" 31 #include "core/svg/SVGCircleElement.h"
32 #include "core/svg/SVGEllipseElement.h" 32 #include "core/svg/SVGEllipseElement.h"
33 33
34 #include <cmath>
35
34 namespace blink { 36 namespace blink {
35 37
36 RenderSVGEllipse::RenderSVGEllipse(SVGGraphicsElement* node) 38 RenderSVGEllipse::RenderSVGEllipse(SVGGraphicsElement* node)
37 : RenderSVGShape(node) 39 : RenderSVGShape(node)
38 , m_usePathFallback(false) 40 , m_usePathFallback(false)
39 { 41 {
40 } 42 }
41 43
42 RenderSVGEllipse::~RenderSVGEllipse() 44 RenderSVGEllipse::~RenderSVGEllipse()
43 { 45 {
(...skipping 10 matching lines...) Expand all
54 m_radii = FloatSize(); 56 m_radii = FloatSize();
55 m_usePathFallback = false; 57 m_usePathFallback = false;
56 58
57 calculateRadiiAndCenter(); 59 calculateRadiiAndCenter();
58 60
59 // Spec: "A negative value is an error. A value of zero disables rendering o f the element." 61 // Spec: "A negative value is an error. A value of zero disables rendering o f the element."
60 if (m_radii.width() < 0 || m_radii.height() < 0) 62 if (m_radii.width() < 0 || m_radii.height() < 0)
61 return; 63 return;
62 64
63 if (!m_radii.isEmpty()) { 65 if (!m_radii.isEmpty()) {
64 // Fallback to RenderSVGShape and path-based hit detection if the ellips e 66 // Fall back to RenderSVGShape and path-based hit detection if the ellip se
65 // has a non-scaling or discontinuous stroke. 67 // has a non-scaling or discontinuous stroke.
66 if (hasNonScalingStroke() || !hasContinuousStroke()) { 68 if (hasNonScalingStroke() || !hasContinuousStroke()) {
67 RenderSVGShape::updateShapeFromElement(); 69 RenderSVGShape::updateShapeFromElement();
68 m_usePathFallback = true; 70 m_usePathFallback = true;
69 return; 71 return;
70 } 72 }
71 } 73 }
72 74
75 clearPath();
76
73 m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height()); 77 m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height());
74 m_hitTestStrokeBoundingBox = m_fillBoundingBox; 78 m_hitTestStrokeBoundingBox = m_fillBoundingBox;
75 m_hitTestStrokeBoundingBox.inflate(strokeWidth() / 2); 79 m_hitTestStrokeBoundingBox.inflate(strokeWidth() / 2);
76 m_strokeBoundingBox = style()->svgStyle().hasStroke() ? m_hitTestStrokeBound ingBox : m_fillBoundingBox; 80 m_strokeBoundingBox = style()->svgStyle().hasStroke() ? m_hitTestStrokeBound ingBox : m_fillBoundingBox;
77 } 81 }
78 82
79 void RenderSVGEllipse::calculateRadiiAndCenter() 83 void RenderSVGEllipse::calculateRadiiAndCenter()
80 { 84 {
81 ASSERT(element()); 85 ASSERT(element());
82 if (isSVGCircleElement(*element())) { 86 if (isSVGCircleElement(*element())) {
83 SVGCircleElement& circle = toSVGCircleElement(*element()); 87 SVGCircleElement& circle = toSVGCircleElement(*element());
84 88
85 SVGLengthContext lengthContext(&circle); 89 SVGLengthContext lengthContext(&circle);
86 float radius = circle.r()->currentValue()->value(lengthContext); 90 float radius = circle.r()->currentValue()->value(lengthContext);
87 m_radii = FloatSize(radius, radius); 91 m_radii = FloatSize(radius, radius);
88 m_center = FloatPoint(circle.cx()->currentValue()->value(lengthContext), circle.cy()->currentValue()->value(lengthContext)); 92 m_center = FloatPoint(circle.cx()->currentValue()->value(lengthContext), circle.cy()->currentValue()->value(lengthContext));
89 return; 93 return;
90 } 94 }
91 95
92 SVGEllipseElement& ellipse = toSVGEllipseElement(*element()); 96 SVGEllipseElement& ellipse = toSVGEllipseElement(*element());
93 97
94 SVGLengthContext lengthContext(&ellipse); 98 SVGLengthContext lengthContext(&ellipse);
95 m_radii = FloatSize(ellipse.rx()->currentValue()->value(lengthContext), elli pse.ry()->currentValue()->value(lengthContext)); 99 m_radii = FloatSize(ellipse.rx()->currentValue()->value(lengthContext), elli pse.ry()->currentValue()->value(lengthContext));
96 m_center = FloatPoint(ellipse.cx()->currentValue()->value(lengthContext), el lipse.cy()->currentValue()->value(lengthContext)); 100 m_center = FloatPoint(ellipse.cx()->currentValue()->value(lengthContext), el lipse.cy()->currentValue()->value(lengthContext));
97 } 101 }
98 102
99 bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point) 103 bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point)
100 { 104 {
101 // The optimized code below does not support discontinuous strokes so we nee d 105 // The optimized check below for circles does not support non-scaling or
102 // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cas es. 106 // discontinuous strokes.
103 if (m_usePathFallback || !hasContinuousStroke()) { 107 if (m_usePathFallback
108 || !hasContinuousStroke()
109 || m_radii.width() != m_radii.height()) {
104 if (!hasPath()) 110 if (!hasPath())
105 RenderSVGShape::updateShapeFromElement(); 111 RenderSVGShape::updateShapeFromElement();
106 return RenderSVGShape::shapeDependentStrokeContains(point); 112 return RenderSVGShape::shapeDependentStrokeContains(point);
107 } 113 }
108 114
109 float halfStrokeWidth = strokeWidth() / 2; 115 const FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y());
110 FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - poin t.y()); 116 const float halfStrokeWidth = strokeWidth() / 2;
111 117 const float r = m_radii.width();
112 // This works by checking if the point satisfies the ellipse equation, 118 return std::abs(center.length() - r) <= halfStrokeWidth;
113 // (x/rX)^2 + (y/rY)^2 <= 1, for the outer but not the inner stroke.
114 float xrXOuter = center.x() / (m_radii.width() + halfStrokeWidth);
115 float yrYOuter = center.y() / (m_radii.height() + halfStrokeWidth);
116 if (xrXOuter * xrXOuter + yrYOuter * yrYOuter > 1.0)
117 return false;
118
119 float xrXInner = center.x() / (m_radii.width() - halfStrokeWidth);
120 float yrYInner = center.y() / (m_radii.height() - halfStrokeWidth);
121 return xrXInner * xrXInner + yrYInner * yrYInner >= 1.0;
122 } 119 }
123 120
124 bool RenderSVGEllipse::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const 121 bool RenderSVGEllipse::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
125 { 122 {
126 if (m_usePathFallback) 123 const FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y());
127 return RenderSVGShape::shapeDependentFillContains(point, fillRule);
128
129 FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - poin t.y());
130 124
131 // This works by checking if the point satisfies the ellipse equation. 125 // This works by checking if the point satisfies the ellipse equation.
132 // (x/rX)^2 + (y/rY)^2 <= 1 126 // (x/rX)^2 + (y/rY)^2 <= 1
133 float xrX = center.x() / m_radii.width(); 127 const float xrX = center.x() / m_radii.width();
134 float yrY = center.y() / m_radii.height(); 128 const float yrY = center.y() / m_radii.height();
135 return xrX * xrX + yrY * yrY <= 1.0; 129 return xrX * xrX + yrY * yrY <= 1.0;
136 } 130 }
137 131
138 bool RenderSVGEllipse::hasContinuousStroke() const 132 bool RenderSVGEllipse::hasContinuousStroke() const
139 { 133 {
140 const SVGRenderStyle& svgStyle = style()->svgStyle(); 134 const SVGRenderStyle& svgStyle = style()->svgStyle();
141 return svgStyle.strokeDashArray()->isEmpty(); 135 return svgStyle.strokeDashArray()->isEmpty();
142 } 136 }
143 137
144 } 138 }
OLDNEW
« no previous file with comments | « LayoutTests/svg/hittest/ellipse-hittest-expected.txt ('k') | Source/core/rendering/svg/RenderSVGShape.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698