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

Side by Side Diff: third_party/WebKit/Source/core/svg/SVGPathParser.cpp

Issue 1472853005: Expose the SVG path normalizer in SVGPathParser.h (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Use regular raw ptr. Created 5 years, 1 month 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 | « third_party/WebKit/Source/core/svg/SVGPathParser.h ('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) 2002, 2003 The Karbon Developers 2 * Copyright (C) 2002, 2003 The Karbon Developers
3 * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> 3 * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org>
4 * Copyright (C) 2006, 2007 Rob Buis <buis@kde.org> 4 * Copyright (C) 2006, 2007 Rob Buis <buis@kde.org>
5 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. 5 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public 9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 53
54 if (!m_consumer->continueConsuming()) 54 if (!m_consumer->continueConsuming())
55 return true; 55 return true;
56 56
57 if (m_source->hasMoreData()) 57 if (m_source->hasMoreData())
58 m_consumer->incrementPathSegmentCount(); 58 m_consumer->incrementPathSegmentCount();
59 } 59 }
60 return true; 60 return true;
61 } 61 }
62 62
63 class NormalizingConsumer {
64 STACK_ALLOCATED();
65 public:
66 NormalizingConsumer(SVGPathConsumer* consumer)
67 : m_consumer(consumer)
68 , m_lastCommand(PathSegUnknown)
69 {
70 ASSERT(m_consumer);
71 }
72
73 void emitSegment(PathSegmentData&);
74
75 private:
76 bool decomposeArcToCubic(const FloatPoint& currentPoint, const PathSegmentDa ta&);
77
78 SVGPathConsumer* m_consumer;
79 FloatPoint m_controlPoint;
80 FloatPoint m_currentPoint;
81 FloatPoint m_subPathPoint;
82 SVGPathSegType m_lastCommand;
83 };
84
85 static FloatPoint reflectedPoint(const FloatPoint& reflectIn, const FloatPoint& pointToReflect) 63 static FloatPoint reflectedPoint(const FloatPoint& reflectIn, const FloatPoint& pointToReflect)
86 { 64 {
87 return FloatPoint(2 * reflectIn.x() - pointToReflect.x(), 2 * reflectIn.y() - pointToReflect.y()); 65 return FloatPoint(2 * reflectIn.x() - pointToReflect.x(), 2 * reflectIn.y() - pointToReflect.y());
88 } 66 }
89 67
90 // Blend the points with a ratio (1/3):(2/3). 68 // Blend the points with a ratio (1/3):(2/3).
91 static FloatPoint blendPoints(const FloatPoint& p1, const FloatPoint& p2) 69 static FloatPoint blendPoints(const FloatPoint& p1, const FloatPoint& p2)
92 { 70 {
93 const float oneOverThree = 1 / 3.f; 71 const float oneOverThree = 1 / 3.f;
94 return FloatPoint((p1.x() + 2 * p2.x()) * oneOverThree, (p1.y() + 2 * p2.y() ) * oneOverThree); 72 return FloatPoint((p1.x() + 2 * p2.x()) * oneOverThree, (p1.y() + 2 * p2.y() ) * oneOverThree);
95 } 73 }
96 74
97 static inline bool isCubicCommand(SVGPathSegType command) 75 static inline bool isCubicCommand(SVGPathSegType command)
98 { 76 {
99 return command == PathSegCurveToCubicAbs 77 return command == PathSegCurveToCubicAbs
100 || command == PathSegCurveToCubicRel 78 || command == PathSegCurveToCubicRel
101 || command == PathSegCurveToCubicSmoothAbs 79 || command == PathSegCurveToCubicSmoothAbs
102 || command == PathSegCurveToCubicSmoothRel; 80 || command == PathSegCurveToCubicSmoothRel;
103 } 81 }
104 82
105 static inline bool isQuadraticCommand(SVGPathSegType command) 83 static inline bool isQuadraticCommand(SVGPathSegType command)
106 { 84 {
107 return command == PathSegCurveToQuadraticAbs 85 return command == PathSegCurveToQuadraticAbs
108 || command == PathSegCurveToQuadraticRel 86 || command == PathSegCurveToQuadraticRel
109 || command == PathSegCurveToQuadraticSmoothAbs 87 || command == PathSegCurveToQuadraticSmoothAbs
110 || command == PathSegCurveToQuadraticSmoothRel; 88 || command == PathSegCurveToQuadraticSmoothRel;
111 } 89 }
112 90
113 void NormalizingConsumer::emitSegment(PathSegmentData& segment) 91 void SVGPathNormalizer::emitSegment(const PathSegmentData& segment)
114 { 92 {
115 SVGPathSegType originalCommand = segment.command; 93 PathSegmentData normSeg = segment;
116 94
117 // Convert relative points to absolute points. 95 // Convert relative points to absolute points.
118 switch (segment.command) { 96 switch (segment.command) {
119 case PathSegCurveToQuadraticRel: 97 case PathSegCurveToQuadraticRel:
120 segment.point1 += m_currentPoint; 98 normSeg.point1 += m_currentPoint;
121 segment.targetPoint += m_currentPoint; 99 normSeg.targetPoint += m_currentPoint;
122 break; 100 break;
123 case PathSegCurveToCubicRel: 101 case PathSegCurveToCubicRel:
124 segment.point1 += m_currentPoint; 102 normSeg.point1 += m_currentPoint;
125 /* fall through */ 103 /* fall through */
126 case PathSegCurveToCubicSmoothRel: 104 case PathSegCurveToCubicSmoothRel:
127 segment.point2 += m_currentPoint; 105 normSeg.point2 += m_currentPoint;
128 /* fall through */ 106 /* fall through */
129 case PathSegMoveToRel: 107 case PathSegMoveToRel:
130 case PathSegLineToRel: 108 case PathSegLineToRel:
131 case PathSegLineToHorizontalRel: 109 case PathSegLineToHorizontalRel:
132 case PathSegLineToVerticalRel: 110 case PathSegLineToVerticalRel:
133 case PathSegCurveToQuadraticSmoothRel: 111 case PathSegCurveToQuadraticSmoothRel:
134 case PathSegArcRel: 112 case PathSegArcRel:
135 segment.targetPoint += m_currentPoint; 113 normSeg.targetPoint += m_currentPoint;
136 break; 114 break;
137 case PathSegLineToHorizontalAbs: 115 case PathSegLineToHorizontalAbs:
138 segment.targetPoint.setY(m_currentPoint.y()); 116 normSeg.targetPoint.setY(m_currentPoint.y());
139 break; 117 break;
140 case PathSegLineToVerticalAbs: 118 case PathSegLineToVerticalAbs:
141 segment.targetPoint.setX(m_currentPoint.x()); 119 normSeg.targetPoint.setX(m_currentPoint.x());
142 break; 120 break;
143 case PathSegClosePath: 121 case PathSegClosePath:
144 // Reset m_currentPoint for the next path. 122 // Reset m_currentPoint for the next path.
145 segment.targetPoint = m_subPathPoint; 123 normSeg.targetPoint = m_subPathPoint;
146 break; 124 break;
147 default: 125 default:
148 break; 126 break;
149 } 127 }
150 128
151 // Update command verb, handle smooth segments and convert quadratic curve 129 // Update command verb, handle smooth segments and convert quadratic curve
152 // segments to cubics. 130 // segments to cubics.
153 switch (segment.command) { 131 switch (segment.command) {
154 case PathSegMoveToRel: 132 case PathSegMoveToRel:
155 case PathSegMoveToAbs: 133 case PathSegMoveToAbs:
156 m_subPathPoint = segment.targetPoint; 134 m_subPathPoint = normSeg.targetPoint;
157 segment.command = PathSegMoveToAbs; 135 normSeg.command = PathSegMoveToAbs;
158 break; 136 break;
159 case PathSegLineToRel: 137 case PathSegLineToRel:
160 case PathSegLineToAbs: 138 case PathSegLineToAbs:
161 case PathSegLineToHorizontalRel: 139 case PathSegLineToHorizontalRel:
162 case PathSegLineToHorizontalAbs: 140 case PathSegLineToHorizontalAbs:
163 case PathSegLineToVerticalRel: 141 case PathSegLineToVerticalRel:
164 case PathSegLineToVerticalAbs: 142 case PathSegLineToVerticalAbs:
165 segment.command = PathSegLineToAbs; 143 normSeg.command = PathSegLineToAbs;
166 break; 144 break;
167 case PathSegClosePath: 145 case PathSegClosePath:
146 normSeg.command = PathSegClosePath;
168 break; 147 break;
169 case PathSegCurveToCubicSmoothRel: 148 case PathSegCurveToCubicSmoothRel:
170 case PathSegCurveToCubicSmoothAbs: 149 case PathSegCurveToCubicSmoothAbs:
171 if (!isCubicCommand(m_lastCommand)) 150 if (!isCubicCommand(m_lastCommand))
172 segment.point1 = m_currentPoint; 151 normSeg.point1 = m_currentPoint;
173 else 152 else
174 segment.point1 = reflectedPoint(m_currentPoint, m_controlPoint); 153 normSeg.point1 = reflectedPoint(m_currentPoint, m_controlPoint);
175 /* fall through */ 154 /* fall through */
176 case PathSegCurveToCubicRel: 155 case PathSegCurveToCubicRel:
177 case PathSegCurveToCubicAbs: 156 case PathSegCurveToCubicAbs:
178 m_controlPoint = segment.point2; 157 m_controlPoint = normSeg.point2;
179 segment.command = PathSegCurveToCubicAbs; 158 normSeg.command = PathSegCurveToCubicAbs;
180 break; 159 break;
181 case PathSegCurveToQuadraticSmoothRel: 160 case PathSegCurveToQuadraticSmoothRel:
182 case PathSegCurveToQuadraticSmoothAbs: 161 case PathSegCurveToQuadraticSmoothAbs:
183 if (!isQuadraticCommand(m_lastCommand)) 162 if (!isQuadraticCommand(m_lastCommand))
184 segment.point1 = m_currentPoint; 163 normSeg.point1 = m_currentPoint;
185 else 164 else
186 segment.point1 = reflectedPoint(m_currentPoint, m_controlPoint); 165 normSeg.point1 = reflectedPoint(m_currentPoint, m_controlPoint);
187 /* fall through */ 166 /* fall through */
188 case PathSegCurveToQuadraticRel: 167 case PathSegCurveToQuadraticRel:
189 case PathSegCurveToQuadraticAbs: 168 case PathSegCurveToQuadraticAbs:
190 // Save the unmodified control point. 169 // Save the unmodified control point.
191 m_controlPoint = segment.point1; 170 m_controlPoint = normSeg.point1;
192 segment.point1 = blendPoints(m_currentPoint, m_controlPoint); 171 normSeg.point1 = blendPoints(m_currentPoint, m_controlPoint);
193 segment.point2 = blendPoints(segment.targetPoint, m_controlPoint); 172 normSeg.point2 = blendPoints(normSeg.targetPoint, m_controlPoint);
194 segment.command = PathSegCurveToCubicAbs; 173 normSeg.command = PathSegCurveToCubicAbs;
195 break; 174 break;
196 case PathSegArcRel: 175 case PathSegArcRel:
197 case PathSegArcAbs: 176 case PathSegArcAbs:
198 if (!decomposeArcToCubic(m_currentPoint, segment)) { 177 if (!decomposeArcToCubic(m_currentPoint, normSeg)) {
199 // On failure, emit a line segment to the target point. 178 // On failure, emit a line segment to the target point.
200 segment.command = PathSegLineToAbs; 179 normSeg.command = PathSegLineToAbs;
201 } else { 180 } else {
202 // decomposeArcToCubic() has already emitted the normalized 181 // decomposeArcToCubic() has already emitted the normalized
203 // segments, so set command to PathSegArcAbs, to skip any further 182 // segments, so set command to PathSegArcAbs, to skip any further
204 // emit. 183 // emit.
205 segment.command = PathSegArcAbs; 184 normSeg.command = PathSegArcAbs;
206 } 185 }
207 break; 186 break;
208 default: 187 default:
209 ASSERT_NOT_REACHED(); 188 ASSERT_NOT_REACHED();
210 } 189 }
211 190
212 if (segment.command != PathSegArcAbs) 191 if (normSeg.command != PathSegArcAbs)
213 m_consumer->emitSegment(segment); 192 m_consumer->emitSegment(normSeg);
214 193
215 m_currentPoint = segment.targetPoint; 194 m_currentPoint = normSeg.targetPoint;
216 195
217 if (!isCubicCommand(originalCommand) && !isQuadraticCommand(originalCommand) ) 196 if (!isCubicCommand(segment.command) && !isQuadraticCommand(segment.command) )
218 m_controlPoint = m_currentPoint; 197 m_controlPoint = m_currentPoint;
219 198
220 m_lastCommand = originalCommand; 199 m_lastCommand = segment.command;
221 } 200 }
222 201
223 // This works by converting the SVG arc to "simple" beziers. 202 // This works by converting the SVG arc to "simple" beziers.
224 // Partly adapted from Niko's code in kdelibs/kdecore/svgicons. 203 // Partly adapted from Niko's code in kdelibs/kdecore/svgicons.
225 // See also SVG implementation notes: http://www.w3.org/TR/SVG/implnote.html#Arc ConversionEndpointToCenter 204 // See also SVG implementation notes: http://www.w3.org/TR/SVG/implnote.html#Arc ConversionEndpointToCenter
226 bool NormalizingConsumer::decomposeArcToCubic(const FloatPoint& currentPoint, co nst PathSegmentData& arcSegment) 205 bool SVGPathNormalizer::decomposeArcToCubic(const FloatPoint& currentPoint, cons t PathSegmentData& arcSegment)
227 { 206 {
228 // If rx = 0 or ry = 0 then this arc is treated as a straight line segment ( a "lineto") joining the endpoints. 207 // If rx = 0 or ry = 0 then this arc is treated as a straight line segment ( a "lineto") joining the endpoints.
229 // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters 208 // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
230 float rx = fabsf(arcSegment.arcRadii().x()); 209 float rx = fabsf(arcSegment.arcRadii().x());
231 float ry = fabsf(arcSegment.arcRadii().y()); 210 float ry = fabsf(arcSegment.arcRadii().y());
232 if (!rx || !ry) 211 if (!rx || !ry)
233 return false; 212 return false;
234 213
235 // If the current point and target point for the arc are identical, it shoul d be treated as a zero length 214 // If the current point and target point for the arc are identical, it shoul d be treated as a zero length
236 // path. This ensures continuity in animations. 215 // path. This ensures continuity in animations.
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 cubicSegment.point2 = pointTransform.mapPoint(point2); 299 cubicSegment.point2 = pointTransform.mapPoint(point2);
321 cubicSegment.targetPoint = pointTransform.mapPoint(targetPoint); 300 cubicSegment.targetPoint = pointTransform.mapPoint(targetPoint);
322 301
323 m_consumer->emitSegment(cubicSegment); 302 m_consumer->emitSegment(cubicSegment);
324 } 303 }
325 return true; 304 return true;
326 } 305 }
327 306
328 bool SVGPathParser::parseAndNormalizePath() 307 bool SVGPathParser::parseAndNormalizePath()
329 { 308 {
330 NormalizingConsumer normalizer(m_consumer); 309 SVGPathNormalizer normalizer(m_consumer);
331 310
332 while (m_source->hasMoreData()) { 311 while (m_source->hasMoreData()) {
333 PathSegmentData segment = m_source->parseSegment(); 312 PathSegmentData segment = m_source->parseSegment();
334 if (segment.command == PathSegUnknown) 313 if (segment.command == PathSegUnknown)
335 return false; 314 return false;
336 315
337 normalizer.emitSegment(segment); 316 normalizer.emitSegment(segment);
338 317
339 if (!m_consumer->continueConsuming()) 318 if (!m_consumer->continueConsuming())
340 return true; 319 return true;
341 320
342 if (m_source->hasMoreData()) 321 if (m_source->hasMoreData())
343 m_consumer->incrementPathSegmentCount(); 322 m_consumer->incrementPathSegmentCount();
344 } 323 }
345 return true; 324 return true;
346 } 325 }
347 326
348 } 327 }
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/svg/SVGPathParser.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698