forked from sammycage/lunasvg
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuseelement.cpp
127 lines (109 loc) · 3.42 KB
/
useelement.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "useelement.h"
#include "parser.h"
#include "layoutcontext.h"
#include "gelement.h"
#include "svgelement.h"
namespace lunasvg {
UseElement::UseElement()
: GraphicsElement(ElementID::Use)
{
}
Length UseElement::x() const
{
auto& value = get(PropertyID::X);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length UseElement::y() const
{
auto& value = get(PropertyID::Y);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length UseElement::width() const
{
auto& value = get(PropertyID::Width);
return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent);
}
Length UseElement::height() const
{
auto& value = get(PropertyID::Height);
return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent);
}
std::string UseElement::href() const
{
auto& value = get(PropertyID::Href);
return Parser::parseHref(value);
}
void UseElement::layout(LayoutContext* context, LayoutContainer* current)
{
if(isDisplayNone())
return;
LengthContext lengthContext(this);
auto _x = lengthContext.valueForLength(x(), LengthMode::Width);
auto _y = lengthContext.valueForLength(y(), LengthMode::Height);
auto group = makeUnique<LayoutGroup>(this);
group->transform = Transform::translated(_x, _y) * transform();
group->opacity = opacity();
group->masker = context->getMasker(mask());
group->clipper = context->getClipper(clip_path());
layoutChildren(context, group.get());
current->addChildIfNotEmpty(std::move(group));
}
std::unique_ptr<Element> UseElement::cloneTargetElement(const Element* targetElement) const
{
if(targetElement == this)
return nullptr;
switch(targetElement->id()) {
case ElementID::Circle:
case ElementID::Ellipse:
case ElementID::G:
case ElementID::Image:
case ElementID::Line:
case ElementID::Path:
case ElementID::Polygon:
case ElementID::Polyline:
case ElementID::Rect:
case ElementID::Svg:
case ElementID::Symbol:
case ElementID::Text:
case ElementID::TSpan:
case ElementID::Use:
break;
default:
return nullptr;
}
const auto& idAttr = targetElement->get(PropertyID::Id);
for(const auto* element = parent(); element; element = element->parent()) {
if(!idAttr.empty() && idAttr == element->get(PropertyID::Id)) {
return nullptr;
}
}
auto tagId = targetElement->id();
if(tagId == ElementID::Symbol) {
tagId = ElementID::Svg;
}
auto newElement = Element::create(tagId);
newElement->setPropertyList(targetElement->properties());
if(newElement->id() == ElementID::Svg) {
for(const auto& property : properties()) {
if(property.id == PropertyID::Width || property.id == PropertyID::Height) {
newElement->set(property.id, property.value, 0x0);
}
}
}
if(newElement->id() == ElementID::Use)
return newElement;
for(auto& child : targetElement->children())
newElement->addChild(child->clone());
return newElement;
}
void UseElement::build(const Document* document)
{
auto targetElement = document->getElementById(href());
if(!targetElement.isNull()) {
if(auto newElement = cloneTargetElement(targetElement.get())) {
addChild(std::move(newElement));
}
}
Element::build(document);
}
} // namespace lunasvg