1/* 2 * Copyright (C) Research In Motion Limited 2011. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20#include "config.h" 21#include "SVGPathData.h" 22 23#include "Path.h" 24#include "SVGCircleElement.h" 25#include "SVGEllipseElement.h" 26#include "SVGLineElement.h" 27#include "SVGNames.h" 28#include "SVGPathElement.h" 29#include "SVGPathUtilities.h" 30#include "SVGPolygonElement.h" 31#include "SVGPolylineElement.h" 32#include "SVGRectElement.h" 33#include <wtf/HashMap.h> 34 35namespace WebCore { 36 37static void updatePathFromCircleElement(SVGElement* element, Path& path) 38{ 39 ASSERT(isSVGCircleElement(element)); 40 SVGCircleElement* circle = toSVGCircleElement(element); 41 42 SVGLengthContext lengthContext(element); 43 float r = circle->r().value(lengthContext); 44 if (r > 0) 45 path.addEllipse(FloatRect(circle->cx().value(lengthContext) - r, circle->cy().value(lengthContext) - r, r * 2, r * 2)); 46} 47 48static void updatePathFromEllipseElement(SVGElement* element, Path& path) 49{ 50 SVGEllipseElement* ellipse = toSVGEllipseElement(element); 51 52 SVGLengthContext lengthContext(element); 53 float rx = ellipse->rx().value(lengthContext); 54 if (rx <= 0) 55 return; 56 float ry = ellipse->ry().value(lengthContext); 57 if (ry <= 0) 58 return; 59 path.addEllipse(FloatRect(ellipse->cx().value(lengthContext) - rx, ellipse->cy().value(lengthContext) - ry, rx * 2, ry * 2)); 60} 61 62static void updatePathFromLineElement(SVGElement* element, Path& path) 63{ 64 SVGLineElement* line = toSVGLineElement(element); 65 66 SVGLengthContext lengthContext(element); 67 path.moveTo(FloatPoint(line->x1().value(lengthContext), line->y1().value(lengthContext))); 68 path.addLineTo(FloatPoint(line->x2().value(lengthContext), line->y2().value(lengthContext))); 69} 70 71static void updatePathFromPathElement(SVGElement* element, Path& path) 72{ 73 buildPathFromByteStream(toSVGPathElement(element)->pathByteStream(), path); 74} 75 76static void updatePathFromPolygonElement(SVGElement* element, Path& path) 77{ 78 SVGPointList& points = toSVGPolygonElement(element)->animatedPoints()->values(); 79 if (points.isEmpty()) 80 return; 81 82 path.moveTo(points.first()); 83 84 unsigned size = points.size(); 85 for (unsigned i = 1; i < size; ++i) 86 path.addLineTo(points.at(i)); 87 88 path.closeSubpath(); 89} 90 91static void updatePathFromPolylineElement(SVGElement* element, Path& path) 92{ 93 SVGPointList& points = toSVGPolylineElement(element)->animatedPoints()->values(); 94 if (points.isEmpty()) 95 return; 96 97 path.moveTo(points.first()); 98 99 unsigned size = points.size(); 100 for (unsigned i = 1; i < size; ++i) 101 path.addLineTo(points.at(i)); 102} 103 104static void updatePathFromRectElement(SVGElement* element, Path& path) 105{ 106 SVGRectElement* rect = toSVGRectElement(element); 107 108 SVGLengthContext lengthContext(element); 109 float width = rect->width().value(lengthContext); 110 if (width <= 0) 111 return; 112 float height = rect->height().value(lengthContext); 113 if (height <= 0) 114 return; 115 float x = rect->x().value(lengthContext); 116 float y = rect->y().value(lengthContext); 117 float rx = rect->rx().value(lengthContext); 118 float ry = rect->ry().value(lengthContext); 119 bool hasRx = rx > 0; 120 bool hasRy = ry > 0; 121 if (hasRx || hasRy) { 122 if (!hasRx) 123 rx = ry; 124 else if (!hasRy) 125 ry = rx; 126 // FIXME: We currently enforce using beziers here, as at least on CoreGraphics/Lion, as 127 // the native method uses a different line dash origin, causing svg/custom/dashOrigin.svg to fail. 128 // See bug https://bugs.webkit.org/show_bug.cgi?id=79932 which tracks this issue. 129 path.addRoundedRect(FloatRect(x, y, width, height), FloatSize(rx, ry), Path::PreferBezierRoundedRect); 130 return; 131 } 132 133 path.addRect(FloatRect(x, y, width, height)); 134} 135 136void updatePathFromGraphicsElement(SVGElement* element, Path& path) 137{ 138 ASSERT(element); 139 ASSERT(path.isEmpty()); 140 141 typedef void (*PathUpdateFunction)(SVGElement*, Path&); 142 static HashMap<AtomicStringImpl*, PathUpdateFunction>* map = 0; 143 if (!map) { 144 map = new HashMap<AtomicStringImpl*, PathUpdateFunction>; 145 map->set(SVGNames::circleTag.localName().impl(), &updatePathFromCircleElement); 146 map->set(SVGNames::ellipseTag.localName().impl(), &updatePathFromEllipseElement); 147 map->set(SVGNames::lineTag.localName().impl(), &updatePathFromLineElement); 148 map->set(SVGNames::pathTag.localName().impl(), &updatePathFromPathElement); 149 map->set(SVGNames::polygonTag.localName().impl(), &updatePathFromPolygonElement); 150 map->set(SVGNames::polylineTag.localName().impl(), &updatePathFromPolylineElement); 151 map->set(SVGNames::rectTag.localName().impl(), &updatePathFromRectElement); 152 } 153 154 if (PathUpdateFunction pathUpdateFunction = map->get(element->localName().impl())) 155 (*pathUpdateFunction)(element, path); 156} 157 158} // namespace WebCore 159