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

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: Simplify 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
« no previous file with comments | « LayoutTests/svg/hittest/ellipse-hittest-expected.txt ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
68 m_usePathFallback = true; 69 m_usePathFallback = true;
69 return;
70 } 70 }
71 } 71 }
72 72
73 m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height()); 73 RenderSVGShape::updateShapeFromElement();
fs 2015/01/26 12:25:21 This code is still valid, no?
74 m_hitTestStrokeBoundingBox = m_fillBoundingBox;
75 m_hitTestStrokeBoundingBox.inflate(strokeWidth() / 2);
76 m_strokeBoundingBox = style()->svgStyle().hasStroke() ? m_hitTestStrokeBound ingBox : m_fillBoundingBox;
77 } 74 }
78 75
79 void RenderSVGEllipse::calculateRadiiAndCenter() 76 void RenderSVGEllipse::calculateRadiiAndCenter()
80 { 77 {
81 ASSERT(element()); 78 ASSERT(element());
82 if (isSVGCircleElement(*element())) { 79 if (isSVGCircleElement(*element())) {
83 SVGCircleElement& circle = toSVGCircleElement(*element()); 80 SVGCircleElement& circle = toSVGCircleElement(*element());
84 81
85 SVGLengthContext lengthContext(&circle); 82 SVGLengthContext lengthContext(&circle);
86 float radius = circle.r()->currentValue()->value(lengthContext); 83 float radius = circle.r()->currentValue()->value(lengthContext);
87 m_radii = FloatSize(radius, radius); 84 m_radii = FloatSize(radius, radius);
88 m_center = FloatPoint(circle.cx()->currentValue()->value(lengthContext), circle.cy()->currentValue()->value(lengthContext)); 85 m_center = FloatPoint(circle.cx()->currentValue()->value(lengthContext), circle.cy()->currentValue()->value(lengthContext));
89 return; 86 return;
90 } 87 }
91 88
92 SVGEllipseElement& ellipse = toSVGEllipseElement(*element()); 89 SVGEllipseElement& ellipse = toSVGEllipseElement(*element());
93 90
94 SVGLengthContext lengthContext(&ellipse); 91 SVGLengthContext lengthContext(&ellipse);
95 m_radii = FloatSize(ellipse.rx()->currentValue()->value(lengthContext), elli pse.ry()->currentValue()->value(lengthContext)); 92 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)); 93 m_center = FloatPoint(ellipse.cx()->currentValue()->value(lengthContext), el lipse.cy()->currentValue()->value(lengthContext));
97 } 94 }
98 95
99 bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point) 96 bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point)
100 { 97 {
101 // The optimized code below does not support discontinuous strokes so we nee d 98 // The optimized check below for circles does not support non-scaling or
102 // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cas es. 99 // discontinuous strokes.
103 if (m_usePathFallback || !hasContinuousStroke()) { 100 if (m_usePathFallback
104 if (!hasPath()) 101 || !hasContinuousStroke()
105 RenderSVGShape::updateShapeFromElement(); 102 || m_radii.width() != m_radii.height()) {
103 ASSERT(hasPath());
106 return RenderSVGShape::shapeDependentStrokeContains(point); 104 return RenderSVGShape::shapeDependentStrokeContains(point);
107 } 105 }
108 106
109 float halfStrokeWidth = strokeWidth() / 2; 107 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()); 108 const float halfStrokeWidth = strokeWidth() / 2;
111 109 const float r = m_radii.width();
112 // This works by checking if the point satisfies the ellipse equation, 110 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 } 111 }
123 112
124 bool RenderSVGEllipse::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const 113 bool RenderSVGEllipse::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
125 { 114 {
126 if (m_usePathFallback) 115 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 116
131 // This works by checking if the point satisfies the ellipse equation. 117 // This works by checking if the point satisfies the ellipse equation.
132 // (x/rX)^2 + (y/rY)^2 <= 1 118 // (x/rX)^2 + (y/rY)^2 <= 1
133 float xrX = center.x() / m_radii.width(); 119 const float xrX = center.x() / m_radii.width();
134 float yrY = center.y() / m_radii.height(); 120 const float yrY = center.y() / m_radii.height();
135 return xrX * xrX + yrY * yrY <= 1.0; 121 return xrX * xrX + yrY * yrY <= 1.0;
136 } 122 }
137 123
138 bool RenderSVGEllipse::hasContinuousStroke() const 124 bool RenderSVGEllipse::hasContinuousStroke() const
139 { 125 {
140 const SVGRenderStyle& svgStyle = style()->svgStyle(); 126 const SVGRenderStyle& svgStyle = style()->svgStyle();
141 return svgStyle.strokeDashArray()->isEmpty(); 127 return svgStyle.strokeDashArray()->isEmpty();
142 } 128 }
143 129
144 } 130 }
OLDNEW
« no previous file with comments | « LayoutTests/svg/hittest/ellipse-hittest-expected.txt ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698