2022-10-03 16:25:42 +00:00
|
|
|
#include "geometryelement.h"
|
|
|
|
#include "parser.h"
|
|
|
|
#include "layoutcontext.h"
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
namespace lunasvg {
|
|
|
|
|
2022-10-03 21:55:09 +00:00
|
|
|
GeometryElement::GeometryElement(ElementId id)
|
2022-10-03 16:25:42 +00:00
|
|
|
: GraphicsElement(id)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void GeometryElement::layout(LayoutContext* context, LayoutContainer* current) const
|
|
|
|
{
|
|
|
|
if(isDisplayNone())
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto path = this->path();
|
|
|
|
if(path.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto shape = std::make_unique<LayoutShape>();
|
|
|
|
shape->path = std::move(path);
|
|
|
|
shape->transform = transform();
|
|
|
|
shape->fillData = context->fillData(this);
|
|
|
|
shape->strokeData = context->strokeData(this);
|
|
|
|
shape->markerData = context->markerData(this, shape->path);
|
|
|
|
shape->visibility = visibility();
|
|
|
|
shape->clipRule = clip_rule();
|
|
|
|
shape->opacity = opacity();
|
|
|
|
shape->masker = context->getMasker(mask());
|
|
|
|
shape->clipper = context->getClipper(clip_path());
|
|
|
|
current->addChild(std::move(shape));
|
|
|
|
}
|
|
|
|
|
|
|
|
PathElement::PathElement()
|
2022-10-03 21:55:09 +00:00
|
|
|
: GeometryElement(ElementId::Path)
|
2022-10-03 16:25:42 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Path PathElement::d() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::D);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parsePath(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
Path PathElement::path() const
|
|
|
|
{
|
|
|
|
return d();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<Node> PathElement::clone() const
|
|
|
|
{
|
|
|
|
return cloneElement<PathElement>();
|
|
|
|
}
|
|
|
|
|
2022-10-03 21:55:09 +00:00
|
|
|
PolyElement::PolyElement(ElementId id)
|
2022-10-03 16:25:42 +00:00
|
|
|
: GeometryElement(id)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
PointList PolyElement::points() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Points);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parsePointList(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
PolygonElement::PolygonElement()
|
2022-10-03 21:55:09 +00:00
|
|
|
: PolyElement(ElementId::Polygon)
|
2022-10-03 16:25:42 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Path PolygonElement::path() const
|
|
|
|
{
|
|
|
|
auto points = this->points();
|
|
|
|
if(points.empty())
|
|
|
|
return Path{};
|
|
|
|
|
|
|
|
Path path;
|
|
|
|
path.moveTo(points[0].x, points[0].y);
|
|
|
|
for(std::size_t i = 1;i < points.size();i++)
|
|
|
|
path.lineTo(points[i].x, points[i].y);
|
|
|
|
|
|
|
|
path.close();
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<Node> PolygonElement::clone() const
|
|
|
|
{
|
|
|
|
return cloneElement<PolygonElement>();
|
|
|
|
}
|
|
|
|
|
|
|
|
PolylineElement::PolylineElement()
|
2022-10-03 21:55:09 +00:00
|
|
|
: PolyElement(ElementId::Polyline)
|
2022-10-03 16:25:42 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Path PolylineElement::path() const
|
|
|
|
{
|
|
|
|
auto points = this->points();
|
|
|
|
if(points.empty())
|
|
|
|
return Path{};
|
|
|
|
|
|
|
|
Path path;
|
|
|
|
path.moveTo(points[0].x, points[0].y);
|
|
|
|
for(std::size_t i = 1;i < points.size();i++)
|
|
|
|
path.lineTo(points[i].x, points[i].y);
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<Node> PolylineElement::clone() const
|
|
|
|
{
|
|
|
|
return cloneElement<PolylineElement>();
|
|
|
|
}
|
|
|
|
|
|
|
|
CircleElement::CircleElement()
|
2022-10-03 21:55:09 +00:00
|
|
|
: GeometryElement(ElementId::Circle)
|
2022-10-03 16:25:42 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Length CircleElement::cx() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Cx);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length CircleElement::cy() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Cy);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length CircleElement::r() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::R);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Path CircleElement::path() const
|
|
|
|
{
|
|
|
|
auto r = this->r();
|
|
|
|
if(r.isZero())
|
|
|
|
return Path{};
|
|
|
|
|
|
|
|
LengthContext lengthContext(this);
|
|
|
|
auto _cx = lengthContext.valueForLength(cx(), LengthMode::Width);
|
|
|
|
auto _cy = lengthContext.valueForLength(cy(), LengthMode::Height);
|
|
|
|
auto _r = lengthContext.valueForLength(r, LengthMode::Both);
|
|
|
|
|
|
|
|
Path path;
|
|
|
|
path.ellipse(_cx, _cy, _r, _r);
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<Node> CircleElement::clone() const
|
|
|
|
{
|
|
|
|
return cloneElement<CircleElement>();
|
|
|
|
}
|
|
|
|
|
|
|
|
EllipseElement::EllipseElement()
|
2022-10-03 21:55:09 +00:00
|
|
|
: GeometryElement(ElementId::Ellipse)
|
2022-10-03 16:25:42 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Length EllipseElement::cx() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Cx);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length EllipseElement::cy() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Cy);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length EllipseElement::rx() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Rx);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length EllipseElement::ry() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Ry);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Path EllipseElement::path() const
|
|
|
|
{
|
|
|
|
auto rx = this->rx();
|
|
|
|
auto ry = this->ry();
|
|
|
|
if(rx.isZero() || ry.isZero())
|
|
|
|
return Path{};
|
|
|
|
|
|
|
|
LengthContext lengthContext(this);
|
|
|
|
auto _cx = lengthContext.valueForLength(cx(), LengthMode::Width);
|
|
|
|
auto _cy = lengthContext.valueForLength(cy(), LengthMode::Height);
|
|
|
|
auto _rx = lengthContext.valueForLength(rx, LengthMode::Width);
|
|
|
|
auto _ry = lengthContext.valueForLength(ry, LengthMode::Height);
|
|
|
|
|
|
|
|
Path path;
|
|
|
|
path.ellipse(_cx, _cy, _rx, _ry);
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<Node> EllipseElement::clone() const
|
|
|
|
{
|
|
|
|
return cloneElement<EllipseElement>();
|
|
|
|
}
|
|
|
|
|
|
|
|
LineElement::LineElement()
|
2022-10-03 21:55:09 +00:00
|
|
|
: GeometryElement(ElementId::Line)
|
2022-10-03 16:25:42 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Length LineElement::x1() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::X1);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length LineElement::y1() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Y1);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length LineElement::x2() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::X2);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length LineElement::y2() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Y2);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Path LineElement::path() const
|
|
|
|
{
|
|
|
|
LengthContext lengthContext(this);
|
|
|
|
auto _x1 = lengthContext.valueForLength(x1(), LengthMode::Width);
|
|
|
|
auto _y1 = lengthContext.valueForLength(y1(), LengthMode::Height);
|
|
|
|
auto _x2 = lengthContext.valueForLength(x2(), LengthMode::Width);
|
|
|
|
auto _y2 = lengthContext.valueForLength(y2(), LengthMode::Height);
|
|
|
|
|
|
|
|
Path path;
|
|
|
|
path.moveTo(_x1, _y1);
|
|
|
|
path.lineTo(_x2, _y2);
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<Node> LineElement::clone() const
|
|
|
|
{
|
|
|
|
return cloneElement<LineElement>();
|
|
|
|
}
|
|
|
|
|
|
|
|
RectElement::RectElement()
|
2022-10-03 21:55:09 +00:00
|
|
|
: GeometryElement(ElementId::Rect)
|
2022-10-03 16:25:42 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Length RectElement::x() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::X);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length RectElement::y() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Y);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length RectElement::rx() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Rx);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, ForbidNegativeLengths, Length::Unknown);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length RectElement::ry() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Ry);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, ForbidNegativeLengths, Length::Unknown);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length RectElement::width() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Width);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length RectElement::height() const
|
|
|
|
{
|
2022-10-03 21:55:09 +00:00
|
|
|
auto& value = get(PropertyId::Height);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Path RectElement::path() const
|
|
|
|
{
|
|
|
|
auto w = this->width();
|
|
|
|
auto h = this->height();
|
|
|
|
if(w.isZero() || h.isZero())
|
|
|
|
return Path{};
|
|
|
|
|
|
|
|
LengthContext lengthContext(this);
|
|
|
|
auto _x = lengthContext.valueForLength(x(), LengthMode::Width);
|
|
|
|
auto _y = lengthContext.valueForLength(y(), LengthMode::Height);
|
|
|
|
auto _w = lengthContext.valueForLength(w, LengthMode::Width);
|
|
|
|
auto _h = lengthContext.valueForLength(h, LengthMode::Height);
|
|
|
|
|
|
|
|
auto rx = this->rx();
|
|
|
|
auto ry = this->ry();
|
|
|
|
|
|
|
|
auto _rx = lengthContext.valueForLength(rx, LengthMode::Width);
|
|
|
|
auto _ry = lengthContext.valueForLength(ry, LengthMode::Height);
|
|
|
|
|
|
|
|
if(!rx.isValid()) _rx = _ry;
|
|
|
|
if(!ry.isValid()) _ry = _rx;
|
|
|
|
|
|
|
|
Path path;
|
|
|
|
path.rect(_x, _y, _w, _h, _rx, _ry);
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<Node> RectElement::clone() const
|
|
|
|
{
|
|
|
|
return cloneElement<RectElement>();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace lunasvg
|