| 
									
										
										
										
											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
 |