2022-10-03 16:25:42 +00:00
|
|
|
#include "svgelement.h"
|
|
|
|
#include "parser.h"
|
|
|
|
#include "layoutcontext.h"
|
|
|
|
|
|
|
|
namespace lunasvg {
|
|
|
|
|
|
|
|
SVGElement::SVGElement()
|
2022-10-16 10:31:43 +00:00
|
|
|
: GraphicsElement(ElementID::Svg)
|
2022-10-03 16:25:42 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Length SVGElement::x() const
|
|
|
|
{
|
2022-10-16 10:31:43 +00:00
|
|
|
auto& value = get(PropertyID::X);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length SVGElement::y() const
|
|
|
|
{
|
2022-10-16 10:31:43 +00:00
|
|
|
auto& value = get(PropertyID::Y);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length SVGElement::width() const
|
|
|
|
{
|
2022-10-16 10:31:43 +00:00
|
|
|
auto& value = get(PropertyID::Width);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent);
|
|
|
|
}
|
|
|
|
|
|
|
|
Length SVGElement::height() const
|
|
|
|
{
|
2022-10-16 10:31:43 +00:00
|
|
|
auto& value = get(PropertyID::Height);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent);
|
|
|
|
}
|
|
|
|
|
|
|
|
Rect SVGElement::viewBox() const
|
|
|
|
{
|
2022-10-16 10:31:43 +00:00
|
|
|
auto& value = get(PropertyID::ViewBox);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parseViewBox(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
PreserveAspectRatio SVGElement::preserveAspectRatio() const
|
|
|
|
{
|
2022-10-16 10:31:43 +00:00
|
|
|
auto& value = get(PropertyID::PreserveAspectRatio);
|
2022-10-03 16:25:42 +00:00
|
|
|
return Parser::parsePreserveAspectRatio(value);
|
|
|
|
}
|
|
|
|
|
2022-10-16 10:31:43 +00:00
|
|
|
std::unique_ptr<LayoutSymbol> SVGElement::build(const TreeBuilder* builder) const
|
2022-10-03 16:25:42 +00:00
|
|
|
{
|
|
|
|
if(isDisplayNone())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
auto w = this->width();
|
|
|
|
auto h = this->height();
|
|
|
|
if(w.isZero() || h.isZero())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
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 viewBox = this->viewBox();
|
|
|
|
auto preserveAspectRatio = this->preserveAspectRatio();
|
|
|
|
auto viewTranslation = Transform::translated(_x, _y);
|
|
|
|
auto viewTransform = preserveAspectRatio.getMatrix(_w, _h, viewBox);
|
|
|
|
|
|
|
|
auto root = std::make_unique<LayoutSymbol>();
|
|
|
|
root->width = _w;
|
|
|
|
root->height = _h;
|
|
|
|
root->transform = (viewTransform * viewTranslation) * transform();
|
|
|
|
root->clip = isOverflowHidden() ? preserveAspectRatio.getClip(_w, _h, viewBox) : Rect::Invalid;
|
|
|
|
root->opacity = opacity();
|
|
|
|
|
2022-10-16 10:31:43 +00:00
|
|
|
LayoutContext context(builder, root.get());
|
2022-10-03 16:25:42 +00:00
|
|
|
root->masker = context.getMasker(mask());
|
|
|
|
root->clipper = context.getClipper(clip_path());
|
|
|
|
layoutChildren(&context, root.get());
|
2022-11-05 12:56:31 +00:00
|
|
|
if((w.isRelative() || h.isRelative()) && !has(PropertyID::ViewBox)) {
|
|
|
|
auto box = root->map(root->strokeBoundingBox());
|
|
|
|
root->width = w.value(box.x + box.w);
|
|
|
|
root->height = h.value(box.y + box.h);
|
|
|
|
}
|
|
|
|
|
2022-10-03 16:25:42 +00:00
|
|
|
return root;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SVGElement::layout(LayoutContext* context, LayoutContainer* current) const
|
|
|
|
{
|
|
|
|
if(isDisplayNone())
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto w = this->width();
|
|
|
|
auto h = this->height();
|
|
|
|
if(w.isZero() || h.isZero())
|
|
|
|
return;
|
|
|
|
|
|
|
|
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 viewBox = this->viewBox();
|
|
|
|
auto preserveAspectRatio = this->preserveAspectRatio();
|
|
|
|
auto viewTranslation = Transform::translated(_x, _y);
|
|
|
|
auto viewTransform = preserveAspectRatio.getMatrix(_w, _h, viewBox);
|
|
|
|
|
|
|
|
auto symbol = std::make_unique<LayoutSymbol>();
|
|
|
|
symbol->width = _w;
|
|
|
|
symbol->height = _h;
|
|
|
|
symbol->transform = (viewTransform * viewTranslation) * transform();
|
|
|
|
symbol->clip = isOverflowHidden() ? preserveAspectRatio.getClip(_w, _h, viewBox) : Rect::Invalid;
|
|
|
|
symbol->opacity = opacity();
|
|
|
|
symbol->masker = context->getMasker(mask());
|
|
|
|
symbol->clipper = context->getClipper(clip_path());
|
|
|
|
layoutChildren(context, symbol.get());
|
|
|
|
current->addChildIfNotEmpty(std::move(symbol));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<Node> SVGElement::clone() const
|
|
|
|
{
|
|
|
|
return cloneElement<SVGElement>();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace lunasvg
|