Chromium Code Reviews| Index: Source/core/html/canvas/CanvasPathMethods.cpp | 
| diff --git a/Source/core/html/canvas/CanvasPathMethods.cpp b/Source/core/html/canvas/CanvasPathMethods.cpp | 
| index 0226af21d52095cce66cdd6c9ba0d00b2dd05aa8..7d4cd1c3db98eb98f5bf2fc6789af64320602f44 100644 | 
| --- a/Source/core/html/canvas/CanvasPathMethods.cpp | 
| +++ b/Source/core/html/canvas/CanvasPathMethods.cpp | 
| @@ -130,37 +130,97 @@ void CanvasPathMethods::arcTo(float x1, float y1, float x2, float y2, float r, E | 
| m_path.addArcTo(p1, p2, r); | 
| } | 
| -void CanvasPathMethods::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec) | 
| +static float adjustEndAngle(float startAngle, float endAngle, bool anticlockwise) | 
| +{ | 
| + // If 'startAngle' and 'endAngle' differ by more than 2Pi, just add a circle starting/ending at 'startAngle'. | 
| + if (anticlockwise && startAngle - endAngle >= 2 * piFloat) | 
| + return startAngle - 2 * piFloat; | 
| + if (!anticlockwise && endAngle - startAngle >= 2 * piFloat) | 
| + return startAngle + 2 * piFloat; | 
| + return endAngle; | 
| +} | 
| + | 
| +void CanvasPathMethods::arc(float x, float y, float radius, float startAngle, float endAngle, bool anticlockwise, ExceptionCode& ec) | 
| { | 
| ec = 0; | 
| - if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(r) || !std::isfinite(sa) || !std::isfinite(ea)) | 
| + if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(radius) || !std::isfinite(startAngle) || !std::isfinite(endAngle)) | 
| return; | 
| - if (r < 0) { | 
| + if (radius < 0) { | 
| ec = INDEX_SIZE_ERR; | 
| return; | 
| } | 
| - if (!r || sa == ea) { | 
| + if (!radius || startAngle == endAngle) { | 
| // The arc is empty but we still need to draw the connecting line. | 
| - lineTo(x + r * cosf(sa), y + r * sinf(sa)); | 
| + lineTo(x + radius * cosf(startAngle), y + radius * sinf(startAngle)); | 
| return; | 
| } | 
| if (!isTransformInvertible()) | 
| return; | 
| - // If 'sa' and 'ea' differ by more than 2Pi, just add a circle starting/ending at 'sa'. | 
| - if (anticlockwise && sa - ea >= 2 * piFloat) { | 
| - m_path.addArc(FloatPoint(x, y), r, sa, sa - 2 * piFloat, anticlockwise); | 
| + float adjustedEndAngle = adjustEndAngle(startAngle, endAngle, anticlockwise); | 
| + m_path.addArc(FloatPoint(x, y), radius, startAngle, adjustedEndAngle, anticlockwise); | 
| +} | 
| + | 
| +static void degenerateEllipse(CanvasPathMethods* path, float x, float y, float radiusX, float radiusY, float rotation, float startAngle, float endAngle, bool anticlockwise) | 
| +{ | 
| + ASSERT((radiusX || radiusY) && startAngle != endAngle); | 
| + float sweep = endAngle - startAngle; | 
| + if (anticlockwise) | 
| + sweep = startAngle - endAngle; | 
| + | 
| + if (sweep < 0) | 
| + sweep = std::fmod(-sweep, piFloat * 2); | 
| + | 
| + if (sweep <= piFloat * 0.5) { | 
| + path->lineTo(x + radiusX * cosf(endAngle + rotation), y + radiusY * sinf(endAngle + rotation)); | 
| 
 
alph
2013/07/09 16:21:23
Here's a counter example:
rotation = x = y = 0;
st
 
 | 
| + } else if (sweep <= piFloat) { | 
| + path->lineTo(x + radiusX * cosf(piFloat * 0.5), y + radiusY * sinf(piFloat * 0.5)); | 
| + path->lineTo(x + radiusX * cosf(endAngle + rotation), y + radiusY * sinf(endAngle + rotation)); | 
| + } else if (sweep <= piFloat * 1.5) { | 
| + path->lineTo(x + radiusX * cosf(piFloat * 0.5), y + radiusY * sinf(piFloat * 0.5)); | 
| + path->lineTo(x + radiusX * cosf(piFloat), y + radiusY * sinf(piFloat)); | 
| + path->lineTo(x + radiusX * cosf(endAngle + rotation), y + radiusY * sinf(endAngle + rotation)); | 
| + } else if (sweep <= piFloat * 2) { | 
| + path->lineTo(x + radiusX * cosf(piFloat * 0.5), y + radiusY * sinf(piFloat * 0.5)); | 
| + path->lineTo(x + radiusX * cosf(piFloat), y + radiusY * sinf(piFloat)); | 
| + path->lineTo(x + radiusX * cosf(piFloat * 1.5), y + radiusY * sinf(piFloat * 1.5)); | 
| + path->lineTo(x + radiusX * cosf(endAngle + rotation), y + radiusY * sinf(endAngle + rotation)); | 
| + } else { // sweep > piFloat * 2 | 
| + path->lineTo(x + radiusX * cosf(piFloat * 0.5), y + radiusY * sinf(piFloat * 0.5)); | 
| + path->lineTo(x + radiusX * cosf(piFloat), y + radiusY * sinf(piFloat)); | 
| + path->lineTo(x + radiusX * cosf(piFloat * 1.5), y + radiusY * sinf(piFloat * 1.5)); | 
| + path->lineTo(x + radiusX * cosf(piFloat * 2), y + radiusY * sinf(piFloat * 2)); | 
| + path->lineTo(x + radiusX * cosf(endAngle + rotation), y + radiusY * sinf(endAngle + rotation)); | 
| + } | 
| +} | 
| + | 
| +void CanvasPathMethods::ellipse(float x, float y, float radiusX, float radiusY, float rotation, float startAngle, float endAngle, bool anticlockwise, ExceptionCode& ec) | 
| +{ | 
| + ec = 0; | 
| + if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(radiusX) || !std::isfinite(radiusY) || !std::isfinite(rotation) || !std::isfinite(startAngle) || !std::isfinite(endAngle)) | 
| + return; | 
| + | 
| + if (radiusX < 0 || radiusY < 0) { | 
| + ec = INDEX_SIZE_ERR; | 
| return; | 
| } | 
| - if (!anticlockwise && ea - sa >= 2 * piFloat) { | 
| - m_path.addArc(FloatPoint(x, y), r, sa, sa + 2 * piFloat, anticlockwise); | 
| + | 
| + if (!radiusX || !radiusY || startAngle == endAngle) { | 
| + // The ellipse is empty but we still need to draw the connecting line to start point. | 
| + lineTo(x + radiusX * cosf(startAngle + rotation), y + radiusY * sinf(startAngle + rotation)); | 
| 
 
alph
2013/07/09 16:21:23
It still does not take into account axes rotation.
 
 | 
| + if ((radiusX || radiusY) && startAngle != endAngle) | 
| + degenerateEllipse(this, x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise); | 
| 
 
dshwang
2013/07/09 15:48:02
@alph yes, you are right. I understand what you sa
 
alph
2013/07/09 16:21:23
degenerateEllipse already looks scary to me despit
 
 | 
| return; | 
| } | 
| - m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise); | 
| + if (!isTransformInvertible()) | 
| + return; | 
| + | 
| + float adjustedEndAngle = adjustEndAngle(startAngle, endAngle, anticlockwise); | 
| + m_path.addEllipse(FloatPoint(x, y), radiusX, radiusY, rotation, startAngle, adjustedEndAngle, anticlockwise); | 
| } | 
| void CanvasPathMethods::rect(float x, float y, float width, float height) |