15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2012 Google, Inc. 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * All rights reserved. 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met: 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1. Redistributions of source code must retain the above copyright 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer. 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer in the 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * documentation and/or other materials provided with the distribution. 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/svg/RenderSVGEllipse.h" 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/svg/SVGCircleElement.h" 3253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/svg/SVGEllipseElement.h" 335d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "platform/graphics/GraphicsContext.h" 345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 35c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink { 365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 37591b958dee2cf159d33a0b931e6231072eaf38d5Ben MurdochRenderSVGEllipse::RenderSVGEllipse(SVGGraphicsElement* node) 385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : RenderSVGShape(node) 395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_usePathFallback(false) 405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)RenderSVGEllipse::~RenderSVGEllipse() 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderSVGEllipse::updateShapeFromElement() 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Before creating a new object we need to clear the cached bounding box 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // to avoid using garbage. 515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_fillBoundingBox = FloatRect(); 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_strokeBoundingBox = FloatRect(); 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_center = FloatPoint(); 545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_radii = FloatSize(); 557242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci m_usePathFallback = false; 565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) calculateRadiiAndCenter(); 585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch // Spec: "A negative value is an error. A value of zero disables rendering of the element." 60f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if (m_radii.width() < 0 || m_radii.height() < 0) 615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 63f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if (!m_radii.isEmpty()) { 64f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) // Fallback to RenderSVGShape if shape has a non-scaling stroke. 65f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if (hasNonScalingStroke()) { 66f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) RenderSVGShape::updateShapeFromElement(); 67f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) m_usePathFallback = true; 68f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) return; 69f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) } 70f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) } 71f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height()); 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_strokeBoundingBox = m_fillBoundingBox; 74197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if (style()->svgStyle().hasStroke()) 755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_strokeBoundingBox.inflate(strokeWidth() / 2); 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderSVGEllipse::calculateRadiiAndCenter() 795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 808abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) ASSERT(element()); 81d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) if (isSVGCircleElement(*element())) { 82d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) SVGCircleElement& circle = toSVGCircleElement(*element()); 835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 84d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) SVGLengthContext lengthContext(&circle); 85d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) float radius = circle.r()->currentValue()->value(lengthContext); 865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_radii = FloatSize(radius, radius); 87d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) m_center = FloatPoint(circle.cx()->currentValue()->value(lengthContext), circle.cy()->currentValue()->value(lengthContext)); 885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 91d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) SVGEllipseElement& ellipse = toSVGEllipseElement(*element()); 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 93d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) SVGLengthContext lengthContext(&ellipse); 94d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) m_radii = FloatSize(ellipse.rx()->currentValue()->value(lengthContext), ellipse.ry()->currentValue()->value(lengthContext)); 95d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) m_center = FloatPoint(ellipse.cx()->currentValue()->value(lengthContext), ellipse.cy()->currentValue()->value(lengthContext)); 965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderSVGEllipse::fillShape(GraphicsContext* context) const 995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_usePathFallback) { 1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RenderSVGShape::fillShape(context); 1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) context->fillEllipse(m_fillBoundingBox); 1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderSVGEllipse::strokeShape(GraphicsContext* context) const 1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 109197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if (!style()->svgStyle().hasVisibleStroke()) 1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_usePathFallback) { 1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RenderSVGShape::strokeShape(context); 1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) context->strokeEllipse(m_fillBoundingBox); 1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point) 1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // The optimized contains code below does not support non-smooth strokes so we need 1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cases. 1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_usePathFallback || !hasSmoothStroke()) { 1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!hasPath()) 1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RenderSVGShape::updateShapeFromElement(); 1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return RenderSVGShape::shapeDependentStrokeContains(point); 1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float halfStrokeWidth = strokeWidth() / 2; 1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y()); 1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // This works by checking if the point satisfies the ellipse equation, 1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // (x/rX)^2 + (y/rY)^2 <= 1, for the outer but not the inner stroke. 1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float xrXOuter = center.x() / (m_radii.width() + halfStrokeWidth); 1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float yrYOuter = center.y() / (m_radii.height() + halfStrokeWidth); 1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (xrXOuter * xrXOuter + yrYOuter * yrYOuter > 1.0) 1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float xrXInner = center.x() / (m_radii.width() - halfStrokeWidth); 1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float yrYInner = center.y() / (m_radii.height() - halfStrokeWidth); 1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return xrXInner * xrXInner + yrYInner * yrYInner >= 1.0; 1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool RenderSVGEllipse::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const 1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_usePathFallback) 1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return RenderSVGShape::shapeDependentFillContains(point, fillRule); 1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y()); 1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // This works by checking if the point satisfies the ellipse equation. 1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // (x/rX)^2 + (y/rY)^2 <= 1 1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float xrX = center.x() / m_radii.width(); 1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float yrY = center.y() / m_radii.height(); 1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return xrX * xrX + yrY * yrY <= 1.0; 1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 158