#include "config.h"
#include "SVGPathData.h"
#include "Path.h"
#include "RenderElement.h"
#include "RenderStyle.h"
#include "SVGCircleElement.h"
#include "SVGEllipseElement.h"
#include "SVGLengthContext.h"
#include "SVGLineElement.h"
#include "SVGNames.h"
#include "SVGPathElement.h"
#include "SVGPathUtilities.h"
#include "SVGPoint.h"
#include "SVGPointList.h"
#include "SVGPolygonElement.h"
#include "SVGPolylineElement.h"
#include "SVGRectElement.h"
#include <wtf/HashMap.h>
namespace WebCore {
static Path pathFromCircleElement(SVGElement& element)
{
ASSERT(is<SVGCircleElement>(element));
RenderElement* renderer = element.renderer();
if (!renderer)
return { };
Path path;
auto& style = renderer->style();
SVGLengthContext lengthContext(&element);
float r = lengthContext.valueForLength(style.svgStyle().r());
if (r > 0) {
float cx = lengthContext.valueForLength(style.svgStyle().cx(), LengthModeWidth);
float cy = lengthContext.valueForLength(style.svgStyle().cy(), LengthModeHeight);
path.addEllipse(FloatRect(cx - r, cy - r, r * 2, r * 2));
}
return path;
}
static Path pathFromEllipseElement(SVGElement& element)
{
RenderElement* renderer = element.renderer();
if (!renderer)
return { };
auto& style = renderer->style();
SVGLengthContext lengthContext(&element);
float rx = lengthContext.valueForLength(style.svgStyle().rx(), LengthModeWidth);
if (rx <= 0)
return { };
float ry = lengthContext.valueForLength(style.svgStyle().ry(), LengthModeHeight);
if (ry <= 0)
return { };
Path path;
float cx = lengthContext.valueForLength(style.svgStyle().cx(), LengthModeWidth);
float cy = lengthContext.valueForLength(style.svgStyle().cy(), LengthModeHeight);
path.addEllipse(FloatRect(cx - rx, cy - ry, rx * 2, ry * 2));
return path;
}
static Path pathFromLineElement(SVGElement& element)
{
Path path;
const auto& line = downcast<SVGLineElement>(element);
SVGLengthContext lengthContext(&element);
path.moveTo(FloatPoint(line.x1().value(lengthContext), line.y1().value(lengthContext)));
path.addLineTo(FloatPoint(line.x2().value(lengthContext), line.y2().value(lengthContext)));
return path;
}
static Path pathFromPathElement(SVGElement& element)
{
return downcast<SVGPathElement>(element).pathForByteStream();
}
static Path pathFromPolygonElement(SVGElement& element)
{
auto& points = downcast<SVGPolygonElement>(element).animatedPoints()->values();
if (points.isEmpty())
return { };
Path path;
path.moveTo(points.first());
unsigned size = points.size();
for (unsigned i = 1; i < size; ++i)
path.addLineTo(points.at(i));
path.closeSubpath();
return path;
}
static Path pathFromPolylineElement(SVGElement& element)
{
auto& points = downcast<SVGPolylineElement>(element).animatedPoints()->values();
if (points.isEmpty())
return { };
Path path;
path.moveTo(points.first());
unsigned size = points.size();
for (unsigned i = 1; i < size; ++i)
path.addLineTo(points.at(i));
return path;
}
static Path pathFromRectElement(SVGElement& element)
{
RenderElement* renderer = element.renderer();
if (!renderer)
return { };
auto& style = renderer->style();
SVGLengthContext lengthContext(&element);
float width = lengthContext.valueForLength(style.width(), LengthModeWidth);
if (width <= 0)
return { };
float height = lengthContext.valueForLength(style.height(), LengthModeHeight);
if (height <= 0)
return { };
Path path;
float x = lengthContext.valueForLength(style.svgStyle().x(), LengthModeWidth);
float y = lengthContext.valueForLength(style.svgStyle().y(), LengthModeHeight);
float rx = lengthContext.valueForLength(style.svgStyle().rx(), LengthModeWidth);
float ry = lengthContext.valueForLength(style.svgStyle().ry(), LengthModeHeight);
bool hasRx = rx > 0;
bool hasRy = ry > 0;
if (hasRx || hasRy) {
if (!hasRx)
rx = ry;
else if (!hasRy)
ry = rx;
path.addRoundedRect(FloatRect(x, y, width, height), FloatSize(rx, ry), Path::PreferBezierRoundedRect);
return path;
}
path.addRect(FloatRect(x, y, width, height));
return path;
}
Path pathFromGraphicsElement(SVGElement* element)
{
ASSERT(element);
typedef Path (*PathFromFunction)(SVGElement&);
static HashMap<AtomicStringImpl*, PathFromFunction>* map = 0;
if (!map) {
map = new HashMap<AtomicStringImpl*, PathFromFunction>;
map->set(SVGNames::circleTag->localName().impl(), pathFromCircleElement);
map->set(SVGNames::ellipseTag->localName().impl(), pathFromEllipseElement);
map->set(SVGNames::lineTag->localName().impl(), pathFromLineElement);
map->set(SVGNames::pathTag->localName().impl(), pathFromPathElement);
map->set(SVGNames::polygonTag->localName().impl(), pathFromPolygonElement);
map->set(SVGNames::polylineTag->localName().impl(), pathFromPolylineElement);
map->set(SVGNames::rectTag->localName().impl(), pathFromRectElement);
}
if (PathFromFunction pathFromFunction = map->get(element->localName().impl()))
return (*pathFromFunction)(*element);
return { };
}
}