Serenity Operating System
at master 93 lines 3.5 kB view raw
1/* 2 * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org> 3 * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <LibWeb/HTML/Parser/HTMLParser.h> 9#include <LibWeb/Layout/ReplacedBox.h> 10#include <LibWeb/Layout/SVGGeometryBox.h> 11#include <LibWeb/Painting/SVGSVGPaintable.h> 12 13namespace Web::Layout { 14 15SVGSVGBox::SVGSVGBox(DOM::Document& document, SVG::SVGSVGElement& element, NonnullRefPtr<CSS::StyleProperties> properties) 16 : ReplacedBox(document, element, move(properties)) 17{ 18} 19 20JS::GCPtr<Painting::Paintable> SVGSVGBox::create_paintable() const 21{ 22 return Painting::SVGSVGPaintable::create(*this); 23} 24 25void SVGSVGBox::prepare_for_replaced_layout() 26{ 27 if (dom_node().has_attribute(HTML::AttributeNames::width) && dom_node().has_attribute(HTML::AttributeNames::height)) { 28 Optional<CSSPixels> w; 29 Optional<CSSPixels> h; 30 if (auto width = HTML::parse_dimension_value(dom_node().attribute(HTML::AttributeNames::width))) { 31 if (width->has_length()) 32 w = width->to_length().to_px(*this); 33 } 34 if (auto height = HTML::parse_dimension_value(dom_node().attribute(HTML::AttributeNames::height))) { 35 if (height->has_length()) 36 h = height->to_length().to_px(*this); 37 } 38 if (w.has_value() && h.has_value()) { 39 set_intrinsic_width(*w); 40 set_intrinsic_height(*h); 41 set_intrinsic_aspect_ratio(w->value() / h->value()); 42 return; 43 } 44 } 45 46 Optional<CSSPixelRect> united_rect; 47 48 auto add_to_united_rect = [&](CSSPixelRect const& rect) { 49 if (united_rect.has_value()) 50 united_rect = united_rect->united(rect); 51 else 52 united_rect = rect; 53 }; 54 55 for_each_in_subtree_of_type<SVGGeometryBox>([&](SVGGeometryBox const& geometry_box) { 56 auto& dom_node = const_cast<SVG::SVGGeometryElement&>(geometry_box.dom_node()); 57 if (dom_node.has_attribute(HTML::AttributeNames::width) && dom_node.has_attribute(HTML::AttributeNames::height)) { 58 CSSPixelRect rect; 59 // FIXME: Allow for relative lengths here 60 rect.set_width(computed_values().width().resolved(*this, CSS::Length::make_px(0)).to_px(*this)); 61 rect.set_height(computed_values().height().resolved(*this, CSS::Length::make_px(0)).to_px(*this)); 62 add_to_united_rect(rect); 63 return IterationDecision::Continue; 64 } 65 66 auto& path = dom_node.get_path(); 67 auto path_bounding_box = path.bounding_box().to_type<CSSPixels>(); 68 69 // Stroke increases the path's size by stroke_width/2 per side. 70 auto stroke_width = geometry_box.dom_node().stroke_width().value_or(0); 71 path_bounding_box.inflate(stroke_width, stroke_width); 72 73 auto& maybe_view_box = this->dom_node().view_box(); 74 75 if (maybe_view_box.has_value()) { 76 auto view_box = maybe_view_box.value(); 77 CSSPixelRect rect(view_box.min_x, view_box.min_y, view_box.width, view_box.height); 78 add_to_united_rect(rect); 79 return IterationDecision::Continue; 80 } 81 82 add_to_united_rect(path_bounding_box); 83 return IterationDecision::Continue; 84 }); 85 86 if (united_rect.has_value()) { 87 set_intrinsic_width(united_rect->width()); 88 set_intrinsic_height(united_rect->height()); 89 set_intrinsic_aspect_ratio(united_rect->width().value() / united_rect->height().value()); 90 } 91} 92 93}