1926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)/* 2926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. 3926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies) 4926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Copyright (C) 2007 Alp Toker <alp@atoker.com> 5926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Copyright (C) 2008 Eric Seidel <eric@webkit.org> 6926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Copyright (C) 2008 Dirk Schulze <krit@webkit.org> 7926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. 88abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) * Copyright (C) 2012, 2013 Intel Corporation. All rights reserved. 9926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved. 10926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * 11926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without 12926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * modification, are permitted provided that the following conditions 13926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * are met: 14926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * 15926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * 1. Redistributions of source code must retain the above copyright 16926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * notice, this list of conditions and the following disclaimer. 17926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright 18926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * notice, this list of conditions and the following disclaimer in the 19926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * documentation and/or other materials provided with the distribution. 20926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * 21926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY 22926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 25926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 26926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 30926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 31926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * SUCH DAMAGE. 33926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) */ 34926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 35926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include "config.h" 3653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/canvas/CanvasPathMethods.h" 37926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 38197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "bindings/core/v8/ExceptionState.h" 3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/ExceptionCode.h" 401e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/geometry/FloatRect.h" 411e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/transforms/AffineTransform.h" 42e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch#include "wtf/MathExtras.h" 43926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 44c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink { 45926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 46926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)void CanvasPathMethods::closePath() 47926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 48926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (m_path.isEmpty()) 49926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 50926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 5153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) FloatRect boundRect = m_path.boundingRect(); 52926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (boundRect.width() || boundRect.height()) 53926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.closeSubpath(); 54926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 55926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 56926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)void CanvasPathMethods::moveTo(float x, float y) 57926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 58926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!std::isfinite(x) || !std::isfinite(y)) 59926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 60926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!isTransformInvertible()) 61926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 62926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.moveTo(FloatPoint(x, y)); 63926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 64926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 65926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)void CanvasPathMethods::lineTo(float x, float y) 66926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 67926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!std::isfinite(x) || !std::isfinite(y)) 68926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 69926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!isTransformInvertible()) 70926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 71926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 72926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) FloatPoint p1 = FloatPoint(x, y); 73926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!m_path.hasCurrentPoint()) 74926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.moveTo(p1); 75926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) else if (p1 != m_path.currentPoint()) 76926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.addLineTo(p1); 77926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 78926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 79926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)void CanvasPathMethods::quadraticCurveTo(float cpx, float cpy, float x, float y) 80926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 81926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!std::isfinite(cpx) || !std::isfinite(cpy) || !std::isfinite(x) || !std::isfinite(y)) 82926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 83926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!isTransformInvertible()) 84926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 85926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!m_path.hasCurrentPoint()) 86926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.moveTo(FloatPoint(cpx, cpy)); 87926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 88926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) FloatPoint p1 = FloatPoint(x, y); 89926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) FloatPoint cp = FloatPoint(cpx, cpy); 90926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (p1 != m_path.currentPoint() || p1 != cp) 91926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.addQuadCurveTo(cp, p1); 92926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 93926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 94926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)void CanvasPathMethods::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y) 95926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 96926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!std::isfinite(cp1x) || !std::isfinite(cp1y) || !std::isfinite(cp2x) || !std::isfinite(cp2y) || !std::isfinite(x) || !std::isfinite(y)) 97926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 98926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!isTransformInvertible()) 99926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 100926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!m_path.hasCurrentPoint()) 101926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.moveTo(FloatPoint(cp1x, cp1y)); 102926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 103926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) FloatPoint p1 = FloatPoint(x, y); 104926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) FloatPoint cp1 = FloatPoint(cp1x, cp1y); 105926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) FloatPoint cp2 = FloatPoint(cp2x, cp2y); 106926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (p1 != m_path.currentPoint() || p1 != cp1 || p1 != cp2) 107926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.addBezierCurveTo(cp1, cp2, p1); 108926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 109926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 11051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void CanvasPathMethods::arcTo(float x1, float y1, float x2, float y2, float r, ExceptionState& exceptionState) 111926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 112926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!std::isfinite(x1) || !std::isfinite(y1) || !std::isfinite(x2) || !std::isfinite(y2) || !std::isfinite(r)) 113926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 114926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 115926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (r < 0) { 11609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) exceptionState.throwDOMException(IndexSizeError, "The radius provided (" + String::number(r) + ") is negative."); 117926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 118926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) } 119926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 120926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!isTransformInvertible()) 121926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 122926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 123926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) FloatPoint p1 = FloatPoint(x1, y1); 124926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) FloatPoint p2 = FloatPoint(x2, y2); 125926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 126926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!m_path.hasCurrentPoint()) 127926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.moveTo(p1); 128926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) else if (p1 == m_path.currentPoint() || p1 == p2 || !r) 129926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) lineTo(x1, y1); 130926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) else 131926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.addArcTo(p1, p2, r); 132926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 133926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 1348abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)namespace { 1358abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) 1368abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)float adjustEndAngle(float startAngle, float endAngle, bool anticlockwise) 137926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 138c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) float newEndAngle = endAngle; 139c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) /* http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-arc 140c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2pi, or, 141c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * if the anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2pi, 14209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) * then the arc is the whole circumference of this ellipse, and the point at startAngle along this circle's circumference, 14309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) * measured in radians clockwise from the ellipse's semi-major axis, acts as both the start point and the end point. 144c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) */ 145d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) if (!anticlockwise && endAngle - startAngle >= twoPiFloat) 146d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) newEndAngle = startAngle + twoPiFloat; 147d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) else if (anticlockwise && startAngle - endAngle >= twoPiFloat) 148d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) newEndAngle = startAngle - twoPiFloat; 149c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 150c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) /* 151c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * Otherwise, the arc is the path along the circumference of this ellipse from the start point to the end point, 152c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * going anti-clockwise if the anticlockwise argument is true, and clockwise otherwise. 153c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * Since the points are on the ellipse, as opposed to being simply angles from zero, 154c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * the arc can never cover an angle greater than 2pi radians. 155c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) */ 156c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) /* NOTE: When startAngle = 0, endAngle = 2Pi and anticlockwise = true, the spec does not indicate clearly. 157c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * We draw the entire circle, because some web sites use arc(x, y, r, 0, 2*Math.PI, true) to draw circle. 158c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * We preserve backward-compatibility. 159c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) */ 160c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) else if (!anticlockwise && startAngle > endAngle) 161d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) newEndAngle = startAngle + (twoPiFloat - fmodf(startAngle - endAngle, twoPiFloat)); 162c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) else if (anticlockwise && startAngle < endAngle) 163d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) newEndAngle = startAngle - (twoPiFloat - fmodf(endAngle - startAngle, twoPiFloat)); 164c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 16509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) ASSERT(ellipseIsRenderable(startAngle, newEndAngle)); 166c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) return newEndAngle; 167c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)} 168c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 1698abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)inline void lineToFloatPoint(CanvasPathMethods* path, const FloatPoint& p) 170c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles){ 171c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) path->lineTo(p.x(), p.y()); 172c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)} 173c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 1748abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)inline FloatPoint getPointOnEllipse(float radiusX, float radiusY, float theta) 175c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles){ 176c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) return FloatPoint(radiusX * cosf(theta), radiusY * sinf(theta)); 177c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)} 178c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 1798abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)void canonicalizeAngle(float* startAngle, float* endAngle) 180c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles){ 181c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) // Make 0 <= startAngle < 2*PI 182c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) float newStartAngle = *startAngle; 183c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) if (newStartAngle < 0) 184d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) newStartAngle = twoPiFloat + fmodf(newStartAngle, -twoPiFloat); 185c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) else 186d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) newStartAngle = fmodf(newStartAngle, twoPiFloat); 187c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 188c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) float delta = newStartAngle - *startAngle; 189c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) *startAngle = newStartAngle; 190c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) *endAngle = *endAngle + delta; 191d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) ASSERT(newStartAngle >= 0 && newStartAngle < twoPiFloat); 192c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)} 193c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 194c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)/* 195c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * degenerateEllipse() handles a degenerated ellipse using several lines. 196c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * 197c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * Let's see a following example: line to ellipse to line. 198c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * _--^\ 199c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * ( ) 200c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * -----( ) 201c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * ) 202c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * /-------- 203c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * 204c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * If radiusX becomes zero, the ellipse of the example is degenerated. 205c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * _ 206c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * // P 207c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * // 208c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * -----// 209c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * / 210c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * /-------- 211c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * 212c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * To draw the above example, need to get P that is a local maximum point. 213c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * Angles for P are 0.5Pi and 1.5Pi in the ellipse coordinates. 214c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * 215c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * If radiusY becomes zero, the result is as follows. 216c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * -----__ 217c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * --_ 218c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * ---------- 219c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * ``P 220c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * Angles for P are 0 and Pi in the ellipse coordinates. 221c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * 222c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) * To handle both cases, degenerateEllipse() lines to start angle, local maximum points(every 0.5Pi), and end angle. 22309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) * NOTE: Before ellipse() calls this function, adjustEndAngle() is called, so endAngle - startAngle must be equal to or less than 2Pi. 224c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) */ 2258abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)void degenerateEllipse(CanvasPathMethods* path, float x, float y, float radiusX, float radiusY, float rotation, float startAngle, float endAngle, bool anticlockwise) 226c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles){ 22709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) ASSERT(ellipseIsRenderable(startAngle, endAngle)); 228d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) ASSERT(startAngle >= 0 && startAngle < twoPiFloat); 2298abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) ASSERT((anticlockwise && (startAngle - endAngle) >= 0) || (!anticlockwise && (endAngle - startAngle) >= 0)); 230c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 231c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) FloatPoint center(x, y); 232c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) AffineTransform rotationMatrix; 233d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) rotationMatrix.rotateRadians(rotation); 234c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) // First, if the object's path has any subpaths, then the method must add a straight line from the last point in the subpath to the start point of the arc. 235c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) lineToFloatPoint(path, center + rotationMatrix.mapPoint(getPointOnEllipse(radiusX, radiusY, startAngle))); 236c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) if ((!radiusX && !radiusY) || startAngle == endAngle) 237c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) return; 238c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 239c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) if (!anticlockwise) { 240d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) // startAngle - fmodf(startAngle, piOverTwoFloat) + piOverTwoFloat is the one of (0, 0.5Pi, Pi, 1.5Pi, 2Pi) 241c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) // that is the closest to startAngle on the clockwise direction. 242d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) for (float angle = startAngle - fmodf(startAngle, piOverTwoFloat) + piOverTwoFloat; angle < endAngle; angle += piOverTwoFloat) 243c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) lineToFloatPoint(path, center + rotationMatrix.mapPoint(getPointOnEllipse(radiusX, radiusY, angle))); 244c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) } else { 245d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) for (float angle = startAngle - fmodf(startAngle, piOverTwoFloat); angle > endAngle; angle -= piOverTwoFloat) 246c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) lineToFloatPoint(path, center + rotationMatrix.mapPoint(getPointOnEllipse(radiusX, radiusY, angle))); 247c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) } 248c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 249c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) lineToFloatPoint(path, center + rotationMatrix.mapPoint(getPointOnEllipse(radiusX, radiusY, endAngle))); 250c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)} 251c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 2528abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)} // namespace 2538abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) 25451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void CanvasPathMethods::arc(float x, float y, float radius, float startAngle, float endAngle, bool anticlockwise, ExceptionState& exceptionState) 2558abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles){ 2568abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(radius) || !std::isfinite(startAngle) || !std::isfinite(endAngle)) 2578abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) return; 2588abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) 2598abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) if (radius < 0) { 26009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) exceptionState.throwDOMException(IndexSizeError, "The radius provided (" + String::number(radius) + ") is negative."); 2618abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) return; 2628abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) } 2638abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) 2648abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) if (!isTransformInvertible()) 2658abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) return; 2668abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) 2678abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) if (!radius || startAngle == endAngle) { 2688abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) // The arc is empty but we still need to draw the connecting line. 2698abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) lineTo(x + radius * cosf(startAngle), y + radius * sinf(startAngle)); 2708abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) return; 2718abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) } 2728abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) 2738abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) canonicalizeAngle(&startAngle, &endAngle); 2748abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) float adjustedEndAngle = adjustEndAngle(startAngle, endAngle, anticlockwise); 2758abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) m_path.addArc(FloatPoint(x, y), radius, startAngle, adjustedEndAngle, anticlockwise); 2768abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)} 2778abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) 27851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void CanvasPathMethods::ellipse(float x, float y, float radiusX, float radiusY, float rotation, float startAngle, float endAngle, bool anticlockwise, ExceptionState& exceptionState) 279c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles){ 280c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(radiusX) || !std::isfinite(radiusY) || !std::isfinite(rotation) || !std::isfinite(startAngle) || !std::isfinite(endAngle)) 281926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 282926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 28309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) if (radiusX < 0) { 28409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) exceptionState.throwDOMException(IndexSizeError, "The major-axis radius provided (" + String::number(radiusX) + ") is negative."); 28509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) return; 28609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) } 28709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) if (radiusY < 0) { 28809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) exceptionState.throwDOMException(IndexSizeError, "The minor-axis radius provided (" + String::number(radiusY) + ") is negative."); 289926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 290926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) } 291c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 292c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) if (!isTransformInvertible()) 293c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) return; 294c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 2958abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) canonicalizeAngle(&startAngle, &endAngle); 296c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) float adjustedEndAngle = adjustEndAngle(startAngle, endAngle, anticlockwise); 297c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) if (!radiusX || !radiusY || startAngle == adjustedEndAngle) { 298c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) // The ellipse is empty but we still need to draw the connecting line to start point. 299c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) degenerateEllipse(this, x, y, radiusX, radiusY, rotation, startAngle, adjustedEndAngle, anticlockwise); 300926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 301926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) } 302926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 303c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) m_path.addEllipse(FloatPoint(x, y), radiusX, radiusY, rotation, startAngle, adjustedEndAngle, anticlockwise); 304926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 305926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 306926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)void CanvasPathMethods::rect(float x, float y, float width, float height) 307926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 308926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!isTransformInvertible()) 309926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 310926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 311926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(width) || !std::isfinite(height)) 312926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 313926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 314926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!width && !height) { 315926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.moveTo(FloatPoint(x, y)); 316926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return; 317926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) } 318926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 319926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_path.addRect(FloatRect(x, y, width, height)); 320926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 321926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 322