1/*
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)
4 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
6 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
7 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
8 * Copyright (C) 2012 Intel Corporation. All rights reserved.
9 * Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1.  Redistributions of source code must retain the above copyright
16 *     notice, this list of conditions and the following disclaimer.
17 * 2.  Redistributions in binary form must reproduce the above copyright
18 *     notice, this list of conditions and the following disclaimer in the
19 *     documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
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
32 * SUCH DAMAGE.
33 */
34
35#include "config.h"
36#include "CanvasPathMethods.h"
37
38#include "ExceptionCode.h"
39#include "FloatRect.h"
40#include <wtf/MathExtras.h>
41
42namespace WebCore {
43
44void CanvasPathMethods::closePath()
45{
46    if (m_path.isEmpty())
47        return;
48
49    FloatRect boundRect = m_path.fastBoundingRect();
50    if (boundRect.width() || boundRect.height())
51        m_path.closeSubpath();
52}
53
54void CanvasPathMethods::moveTo(float x, float y)
55{
56    if (!std::isfinite(x) || !std::isfinite(y))
57        return;
58    if (!hasInvertibleTransform())
59        return;
60    m_path.moveTo(FloatPoint(x, y));
61}
62
63void CanvasPathMethods::lineTo(float x, float y)
64{
65    if (!std::isfinite(x) || !std::isfinite(y))
66        return;
67    if (!hasInvertibleTransform())
68        return;
69
70    FloatPoint p1 = FloatPoint(x, y);
71    if (!m_path.hasCurrentPoint())
72        m_path.moveTo(p1);
73    else if (p1 != m_path.currentPoint())
74        m_path.addLineTo(p1);
75}
76
77void CanvasPathMethods::quadraticCurveTo(float cpx, float cpy, float x, float y)
78{
79    if (!std::isfinite(cpx) || !std::isfinite(cpy) || !std::isfinite(x) || !std::isfinite(y))
80        return;
81    if (!hasInvertibleTransform())
82        return;
83    if (!m_path.hasCurrentPoint())
84        m_path.moveTo(FloatPoint(cpx, cpy));
85
86    FloatPoint p1 = FloatPoint(x, y);
87    FloatPoint cp = FloatPoint(cpx, cpy);
88    if (p1 != m_path.currentPoint() || p1 != cp)
89        m_path.addQuadCurveTo(cp, p1);
90}
91
92void CanvasPathMethods::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
93{
94    if (!std::isfinite(cp1x) || !std::isfinite(cp1y) || !std::isfinite(cp2x) || !std::isfinite(cp2y) || !std::isfinite(x) || !std::isfinite(y))
95        return;
96    if (!hasInvertibleTransform())
97        return;
98    if (!m_path.hasCurrentPoint())
99        m_path.moveTo(FloatPoint(cp1x, cp1y));
100
101    FloatPoint p1 = FloatPoint(x, y);
102    FloatPoint cp1 = FloatPoint(cp1x, cp1y);
103    FloatPoint cp2 = FloatPoint(cp2x, cp2y);
104    if (p1 != m_path.currentPoint() || p1 != cp1 ||  p1 != cp2)
105        m_path.addBezierCurveTo(cp1, cp2, p1);
106}
107
108void CanvasPathMethods::arcTo(float x1, float y1, float x2, float y2, float r, ExceptionCode& ec)
109{
110    ec = 0;
111    if (!std::isfinite(x1) || !std::isfinite(y1) || !std::isfinite(x2) || !std::isfinite(y2) || !std::isfinite(r))
112        return;
113
114    if (r < 0) {
115        ec = INDEX_SIZE_ERR;
116        return;
117    }
118
119    if (!hasInvertibleTransform())
120        return;
121
122    FloatPoint p1 = FloatPoint(x1, y1);
123    FloatPoint p2 = FloatPoint(x2, y2);
124
125    if (!m_path.hasCurrentPoint())
126        m_path.moveTo(p1);
127    else if (p1 == m_path.currentPoint() || p1 == p2 || !r)
128        lineTo(x1, y1);
129    else
130        m_path.addArcTo(p1, p2, r);
131}
132
133void CanvasPathMethods::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec)
134{
135    ec = 0;
136    if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(r) || !std::isfinite(sa) || !std::isfinite(ea))
137        return;
138
139    if (r < 0) {
140        ec = INDEX_SIZE_ERR;
141        return;
142    }
143
144    if (!r || sa == ea) {
145        // The arc is empty but we still need to draw the connecting line.
146        lineTo(x + r * cosf(sa), y + r * sinf(sa));
147        return;
148    }
149
150    if (!hasInvertibleTransform())
151        return;
152
153    // If 'sa' and 'ea' differ by more than 2Pi, just add a circle starting/ending at 'sa'.
154    if (anticlockwise && sa - ea >= 2 * piFloat) {
155        m_path.addArc(FloatPoint(x, y), r, sa, sa - 2 * piFloat, anticlockwise);
156        return;
157    }
158    if (!anticlockwise && ea - sa >= 2 * piFloat) {
159        m_path.addArc(FloatPoint(x, y), r, sa, sa + 2 * piFloat, anticlockwise);
160        return;
161    }
162
163    m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise);
164}
165
166void CanvasPathMethods::rect(float x, float y, float width, float height)
167{
168    if (!hasInvertibleTransform())
169        return;
170
171    if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(width) || !std::isfinite(height))
172        return;
173
174    if (!width && !height) {
175        m_path.moveTo(FloatPoint(x, y));
176        return;
177    }
178
179    m_path.addRect(FloatRect(x, y, width, height));
180}
181}
182