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

Side by Side Diff: Source/core/html/canvas/CanvasPathMethods.cpp

Issue 14298022: Add support for new canvas ellipse method. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Complete degenerateEllipse. Make canvas-ellipse-zero-lineto.html cover various degenerate edge case… Created 7 years, 5 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) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies) 3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2007 Alp Toker <alp@atoker.com> 4 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org> 5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
6 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org> 6 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
7 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. 7 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
8 * Copyright (C) 2012 Intel Corporation. All rights reserved. 8 * Copyright (C) 2012 Intel Corporation. All rights reserved.
9 * Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved. 9 * Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved.
10 * 10 *
(...skipping 19 matching lines...) Expand all
30 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
31 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35 #include "config.h" 35 #include "config.h"
36 #include "core/html/canvas/CanvasPathMethods.h" 36 #include "core/html/canvas/CanvasPathMethods.h"
37 37
38 #include "core/dom/ExceptionCode.h" 38 #include "core/dom/ExceptionCode.h"
39 #include "core/platform/graphics/FloatRect.h" 39 #include "core/platform/graphics/FloatRect.h"
40 #include "core/platform/graphics/transforms/AffineTransform.h"
40 #include <wtf/MathExtras.h> 41 #include <wtf/MathExtras.h>
41 42
42 namespace WebCore { 43 namespace WebCore {
43 44
44 void CanvasPathMethods::closePath() 45 void CanvasPathMethods::closePath()
45 { 46 {
46 if (m_path.isEmpty()) 47 if (m_path.isEmpty())
47 return; 48 return;
48 49
49 FloatRect boundRect = m_path.boundingRect(); 50 FloatRect boundRect = m_path.boundingRect();
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 m_path.moveTo(p1); 127 m_path.moveTo(p1);
127 else if (p1 == m_path.currentPoint() || p1 == p2 || !r) 128 else if (p1 == m_path.currentPoint() || p1 == p2 || !r)
128 lineTo(x1, y1); 129 lineTo(x1, y1);
129 else 130 else
130 m_path.addArcTo(p1, p2, r); 131 m_path.addArcTo(p1, p2, r);
131 } 132 }
132 133
133 static float adjustEndAngle(float startAngle, float endAngle, bool anticlockwise ) 134 static float adjustEndAngle(float startAngle, float endAngle, bool anticlockwise )
134 { 135 {
135 float twoPi = 2 * piFloat; 136 float twoPi = 2 * piFloat;
137 float newEndAngle = endAngle;
136 /* http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-el ement.html#dom-context-2d-arc 138 /* http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-el ement.html#dom-context-2d-arc
137 * If the anticlockwise argument is false and endAngle-startAngle is equal t o or greater than 2π, or, 139 * If the anticlockwise argument is false and endAngle-startAngle is equal t o or greater than 2π, or,
138 * if the anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2π, 140 * if the anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2π,
139 * then the arc is the whole circumference of this ellipse. 141 * then the arc is the whole circumference of this ellipse.
140 */ 142 */
141 if (!anticlockwise && endAngle - startAngle >= twoPi) 143 if (!anticlockwise && endAngle - startAngle >= twoPi)
142 return startAngle + twoPi + fmodf(endAngle - startAngle, twoPi); 144 newEndAngle = startAngle + twoPi + fmodf(endAngle - startAngle, twoPi);
143 if (anticlockwise && startAngle - endAngle >= twoPi) 145 else if (anticlockwise && startAngle - endAngle >= twoPi)
144 return startAngle - twoPi - fmodf(startAngle - endAngle, twoPi); 146 newEndAngle = startAngle - twoPi - fmodf(startAngle - endAngle, twoPi);
145 147
146 /* 148 /*
147 * Otherwise, the arc is the path along the circumference of this ellipse fr om the start point to the end point, 149 * Otherwise, the arc is the path along the circumference of this ellipse fr om the start point to the end point,
148 * going anti-clockwise if the anticlockwise argument is true, and clockwise otherwise. 150 * going anti-clockwise if the anticlockwise argument is true, and clockwise otherwise.
149 * Since the points are on the ellipse, as opposed to being simply angles fr om zero, 151 * Since the points are on the ellipse, as opposed to being simply angles fr om zero,
150 * the arc can never cover an angle greater than 2π radians. 152 * the arc can never cover an angle greater than 2π radians.
151 */ 153 */
152 if (!anticlockwise && startAngle > endAngle) 154 else if (!anticlockwise && startAngle > endAngle)
153 return startAngle + (twoPi - fmodf(startAngle - endAngle, twoPi)); 155 newEndAngle = startAngle + (twoPi - fmodf(startAngle - endAngle, twoPi)) ;
154 if (anticlockwise && startAngle < endAngle) 156 else if (anticlockwise && startAngle < endAngle)
155 return startAngle - (twoPi - fmodf(endAngle - startAngle, twoPi)); 157 newEndAngle = startAngle - (twoPi - fmodf(endAngle - startAngle, twoPi)) ;
156 158
157 return endAngle; 159 ASSERT(std::abs(newEndAngle - startAngle) < 4 * piFloat);
160 return newEndAngle;
158 } 161 }
159 162
160 void CanvasPathMethods::arc(float x, float y, float radius, float startAngle, fl oat endAngle, bool anticlockwise, ExceptionCode& ec) 163 void CanvasPathMethods::arc(float x, float y, float radius, float startAngle, fl oat endAngle, bool anticlockwise, ExceptionCode& ec)
161 { 164 {
162 ec = 0; 165 ec = 0;
163 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(radius) || !std ::isfinite(startAngle) || !std::isfinite(endAngle)) 166 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(radius) || !std ::isfinite(startAngle) || !std::isfinite(endAngle))
164 return; 167 return;
165 168
166 if (radius < 0) { 169 if (radius < 0) {
167 ec = IndexSizeError; 170 ec = IndexSizeError;
168 return; 171 return;
169 } 172 }
170 173
171 if (!isTransformInvertible()) 174 if (!isTransformInvertible())
172 return; 175 return;
173 176
174 if (!radius || startAngle == endAngle) { 177 if (!radius || startAngle == endAngle) {
175 // The arc is empty but we still need to draw the connecting line. 178 // The arc is empty but we still need to draw the connecting line.
176 lineTo(x + radius * cosf(startAngle), y + radius * sinf(startAngle)); 179 lineTo(x + radius * cosf(startAngle), y + radius * sinf(startAngle));
177 return; 180 return;
178 } 181 }
179 182
180 float adjustedEndAngle = adjustEndAngle(startAngle, endAngle, anticlockwise) ; 183 float adjustedEndAngle = adjustEndAngle(startAngle, endAngle, anticlockwise) ;
181 m_path.addArc(FloatPoint(x, y), radius, startAngle, adjustedEndAngle, anticl ockwise); 184 m_path.addArc(FloatPoint(x, y), radius, startAngle, adjustedEndAngle, anticl ockwise);
182 } 185 }
183 186
187 inline static void lineToFloatPoint(CanvasPathMethods* path, const FloatPoint& p )
188 {
189 path->lineTo(p.x(), p.y());
190 }
191
192 inline static FloatPoint getPointOnEllipse(float radiusX, float radiusY, float t heta)
193 {
194 return FloatPoint(radiusX * cosf(theta), radiusY * sinf(theta));
195 }
196
197 inline static void canonicalizeAngle(float* startAngle, float* endAngle)
198 {
199 // Make 0 <= startAngle < 2*PI
200 float twoPi = 2 * piFloat;
201 float newStartAngle = *startAngle;
202 if (newStartAngle < 0)
203 newStartAngle = twoPi + fmodf(newStartAngle, -twoPi);
204 else
205 newStartAngle = fmodf(newStartAngle, twoPi);
206
207 float delta = newStartAngle - *startAngle;
208 *startAngle = newStartAngle;
209 *endAngle = *endAngle + delta;
210 }
211
212 static void degenerateEllipse(CanvasPathMethods* path, float x, float y, float r adiusX, float radiusY, float rotation, float startAngle, float endAngle, bool an ticlockwise)
213 {
214 ASSERT(std::abs(endAngle - startAngle) < 4 * piFloat);
215
216 FloatPoint center(x, y);
217 AffineTransform rotationMatrix;
218 rotationMatrix.rotate(rad2deg(rotation));
219 lineToFloatPoint(path, center + rotationMatrix.mapPoint(getPointOnEllipse(ra diusX, radiusY, startAngle)));
220 if ((!radiusX && !radiusY) || startAngle == endAngle)
221 return;
222
223 canonicalizeAngle(&startAngle, &endAngle);
alph 2013/07/10 13:38:04 It seems that canonicalizeAngle should depend on a
dshwang 2013/07/10 14:19:57 canonicalizeAngle() is independent from whether an
alph 2013/07/10 15:22:30 Sorry, missed that.
224 ASSERT(std::abs(endAngle - startAngle) < 4 * piFloat);
225
226 float halfPiFloat = piFloat * 0.5;
227 if (!anticlockwise) {
228 for (float angle = startAngle - fmodf(startAngle, halfPiFloat) + halfPiF loat; angle < endAngle; angle += halfPiFloat)
229 lineToFloatPoint(path, center + rotationMatrix.mapPoint(getPointOnEl lipse(radiusX, radiusY, angle)));
230 } else {
231 for (float angle = startAngle - fmodf(startAngle, halfPiFloat); angle > endAngle; angle -= halfPiFloat)
232 lineToFloatPoint(path, center + rotationMatrix.mapPoint(getPointOnEl lipse(radiusX, radiusY, angle)));
233 }
234
235 lineToFloatPoint(path, center + rotationMatrix.mapPoint(getPointOnEllipse(ra diusX, radiusY, endAngle)));
236 }
237
238 void CanvasPathMethods::ellipse(float x, float y, float radiusX, float radiusY, float rotation, float startAngle, float endAngle, bool anticlockwise, ExceptionC ode& ec)
239 {
240 ec = 0;
241 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(radiusX) || !st d::isfinite(radiusY) || !std::isfinite(rotation) || !std::isfinite(startAngle) | | !std::isfinite(endAngle))
242 return;
243
244 if (radiusX < 0 || radiusY < 0) {
245 ec = IndexSizeError;
246 return;
247 }
248
249 if (!isTransformInvertible())
250 return;
251
252 float adjustedEndAngle = adjustEndAngle(startAngle, endAngle, anticlockwise) ;
253 if (!radiusX || !radiusY || startAngle == adjustedEndAngle) {
254 // The ellipse is empty but we still need to draw the connecting line to start point.
255 degenerateEllipse(this, x, y, radiusX, radiusY, rotation, startAngle, ad justedEndAngle, anticlockwise);
256 return;
257 }
258
259 m_path.addEllipse(FloatPoint(x, y), radiusX, radiusY, rotation, startAngle, adjustedEndAngle, anticlockwise);
260 }
261
184 void CanvasPathMethods::rect(float x, float y, float width, float height) 262 void CanvasPathMethods::rect(float x, float y, float width, float height)
185 { 263 {
186 if (!isTransformInvertible()) 264 if (!isTransformInvertible())
187 return; 265 return;
188 266
189 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(width) || !std: :isfinite(height)) 267 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(width) || !std: :isfinite(height))
190 return; 268 return;
191 269
192 if (!width && !height) { 270 if (!width && !height) {
193 m_path.moveTo(FloatPoint(x, y)); 271 m_path.moveTo(FloatPoint(x, y));
194 return; 272 return;
195 } 273 }
196 274
197 m_path.addRect(FloatRect(x, y, width, height)); 275 m_path.addRect(FloatRect(x, y, width, height));
198 } 276 }
199 } 277 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698