| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  | #include "element.h"
 | 
					
						
							|  |  |  | #include "parser.h"
 | 
					
						
							|  |  |  | #include "svgelement.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace lunasvg { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  | void PropertyList::set(PropertyID id, const std::string& value, int specificity) | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     auto property = get(id); | 
					
						
							|  |  |  |     if(property == nullptr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Property property{id, value, specificity}; | 
					
						
							|  |  |  |         m_properties.push_back(std::move(property)); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if(property->specificity > specificity) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     property->specificity = specificity; | 
					
						
							|  |  |  |     property->value = value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  | Property* PropertyList::get(PropertyID id) const | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     auto data = m_properties.data(); | 
					
						
							|  |  |  |     auto end = data + m_properties.size(); | 
					
						
							|  |  |  |     while(data < end) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if(data->id == id) | 
					
						
							|  |  |  |             return const_cast<Property*>(data); | 
					
						
							|  |  |  |         ++data; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PropertyList::add(const Property& property) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     set(property.id, property.value, property.specificity); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PropertyList::add(const PropertyList& properties) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto it = properties.m_properties.begin(); | 
					
						
							|  |  |  |     auto end = properties.m_properties.end(); | 
					
						
							|  |  |  |     for(;it != end;++it) | 
					
						
							|  |  |  |         add(*it); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Node::layout(LayoutContext*, LayoutContainer*) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::unique_ptr<Node> TextNode::clone() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto node = std::make_unique<TextNode>(); | 
					
						
							|  |  |  |     node->text = text; | 
					
						
							|  |  |  |     return std::move(node); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  | Element::Element(ElementID id) | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  |     : id(id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  | void Element::set(PropertyID id, const std::string& value, int specificity) | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     properties.set(id, value, specificity); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const std::string EmptyString; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  | const std::string& Element::get(PropertyID id) const | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     auto property = properties.get(id); | 
					
						
							|  |  |  |     if(property == nullptr) | 
					
						
							|  |  |  |         return EmptyString; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return property->value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const std::string InheritString{"inherit"}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  | const std::string& Element::find(PropertyID id) const | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     auto element = this; | 
					
						
							|  |  |  |     do { | 
					
						
							|  |  |  |         auto& value = element->get(id); | 
					
						
							|  |  |  |         if(!value.empty() && value != InheritString) | 
					
						
							|  |  |  |             return value; | 
					
						
							|  |  |  |         element = element->parent; | 
					
						
							|  |  |  |     } while(element); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return EmptyString; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  | bool Element::has(PropertyID id) const | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     return properties.get(id); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  | Element* Element::previousElement() const | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     if(parent == nullptr) | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Element* element = nullptr; | 
					
						
							|  |  |  |     auto it = parent->children.begin(); | 
					
						
							|  |  |  |     auto end = parent->children.end(); | 
					
						
							|  |  |  |     for(;it != end;++it) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         auto node = it->get(); | 
					
						
							|  |  |  |         if(node->isText()) | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(node == this) | 
					
						
							|  |  |  |             return element; | 
					
						
							|  |  |  |         element = static_cast<Element*>(node); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  | Element* Element::nextElement() const | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     if(parent == nullptr) | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Element* element = nullptr; | 
					
						
							|  |  |  |     auto it = parent->children.rbegin(); | 
					
						
							|  |  |  |     auto end = parent->children.rend(); | 
					
						
							|  |  |  |     for(;it != end;++it) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         auto node = it->get(); | 
					
						
							|  |  |  |         if(node->isText()) | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(node == this) | 
					
						
							|  |  |  |             return element; | 
					
						
							|  |  |  |         element = static_cast<Element*>(node); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Node* Element::addChild(std::unique_ptr<Node> child) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     child->parent = this; | 
					
						
							|  |  |  |     children.push_back(std::move(child)); | 
					
						
							|  |  |  |     return &*children.back(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Element::layoutChildren(LayoutContext* context, LayoutContainer* current) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     for(auto& child : children) | 
					
						
							|  |  |  |         child->layout(context, current); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Rect Element::currentViewport() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if(parent == nullptr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         auto element = static_cast<const SVGElement*>(this); | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  |         if(element->has(PropertyID::ViewBox)) | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  |             return element->viewBox();  | 
					
						
							|  |  |  |         return Rect{0, 0, 300, 150}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  |     if(parent->id == ElementID::Svg) | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |         auto element = static_cast<SVGElement*>(parent); | 
					
						
							| 
									
										
										
										
											2022-10-16 10:31:43 +00:00
										 |  |  |         if(element->has(PropertyID::ViewBox)) | 
					
						
							| 
									
										
										
										
											2022-10-03 16:25:42 +00:00
										 |  |  |             return element->viewBox(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         LengthContext lengthContext(element); | 
					
						
							|  |  |  |         auto _x = lengthContext.valueForLength(element->x(), LengthMode::Width); | 
					
						
							|  |  |  |         auto _y = lengthContext.valueForLength(element->y(), LengthMode::Height); | 
					
						
							|  |  |  |         auto _w = lengthContext.valueForLength(element->width(), LengthMode::Width); | 
					
						
							|  |  |  |         auto _h = lengthContext.valueForLength(element->height(), LengthMode::Height); | 
					
						
							|  |  |  |         return Rect{_x, _y, _w, _h}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return parent->currentViewport(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace lunasvg
 |