Serenity Operating System
at master 101 lines 4.0 kB view raw
1/* 2 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org> 4 * Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org> 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#include <LibWeb/Layout/BlockFormattingContext.h> 10#include <LibWeb/Layout/SVGFormattingContext.h> 11#include <LibWeb/Layout/SVGGeometryBox.h> 12#include <LibWeb/SVG/SVGForeignObjectElement.h> 13#include <LibWeb/SVG/SVGSVGElement.h> 14 15namespace Web::Layout { 16 17SVGFormattingContext::SVGFormattingContext(LayoutState& state, Box const& box, FormattingContext* parent) 18 : FormattingContext(Type::SVG, state, box, parent) 19{ 20} 21 22SVGFormattingContext::~SVGFormattingContext() = default; 23 24CSSPixels SVGFormattingContext::automatic_content_height() const 25{ 26 return 0; 27} 28 29void SVGFormattingContext::run(Box const& box, LayoutMode, [[maybe_unused]] AvailableSpace const& available_space) 30{ 31 // FIXME: This entire thing is an ad-hoc hack. 32 33 auto& svg_svg_element = verify_cast<SVG::SVGSVGElement>(*box.dom_node()); 34 35 auto root_offset = m_state.get(box).offset; 36 37 box.for_each_child_of_type<BlockContainer>([&](BlockContainer const& child_box) { 38 if (is<SVG::SVGForeignObjectElement>(child_box.dom_node())) { 39 Layout::BlockFormattingContext bfc(m_state, child_box, this); 40 bfc.run(child_box, LayoutMode::Normal, available_space); 41 42 auto& child_state = m_state.get_mutable(child_box); 43 child_state.set_content_offset(child_state.offset.translated(root_offset)); 44 } 45 return IterationDecision::Continue; 46 }); 47 48 box.for_each_in_subtree_of_type<SVGBox>([&](SVGBox const& descendant) { 49 if (is<SVGGeometryBox>(descendant)) { 50 auto const& geometry_box = static_cast<SVGGeometryBox const&>(descendant); 51 52 auto& geometry_box_state = m_state.get_mutable(geometry_box); 53 54 auto& dom_node = const_cast<SVGGeometryBox&>(geometry_box).dom_node(); 55 56 auto& svg_svg_state = m_state.get(static_cast<Box const&>(*svg_svg_element.layout_node())); 57 58 if (svg_svg_state.has_definite_width() && svg_svg_state.has_definite_height()) { 59 geometry_box_state.set_content_offset({ 0, 0 }); 60 geometry_box_state.set_content_width(svg_svg_state.content_width()); 61 geometry_box_state.set_content_height(svg_svg_state.content_height()); 62 return IterationDecision::Continue; 63 } 64 65 // FIXME: Allow for one of {width, height} to not be specified} 66 if (svg_svg_element.has_attribute(HTML::AttributeNames::width)) { 67 } 68 69 if (svg_svg_element.has_attribute(HTML::AttributeNames::height)) { 70 } 71 72 auto& path = dom_node.get_path(); 73 auto path_bounding_box = path.bounding_box().to_type<CSSPixels>(); 74 75 // Stroke increases the path's size by stroke_width/2 per side. 76 CSSPixels stroke_width = geometry_box.dom_node().stroke_width().value_or(0); 77 path_bounding_box.inflate(stroke_width, stroke_width); 78 79 auto& maybe_view_box = svg_svg_element.view_box(); 80 81 if (maybe_view_box.has_value()) { 82 auto view_box = maybe_view_box.value(); 83 CSSPixelPoint viewbox_offset = { view_box.min_x, view_box.min_y }; 84 geometry_box_state.set_content_offset(path_bounding_box.top_left() + viewbox_offset); 85 86 geometry_box_state.set_content_width(view_box.width); 87 geometry_box_state.set_content_height(view_box.height); 88 89 return IterationDecision::Continue; 90 } 91 92 geometry_box_state.set_content_offset(path_bounding_box.top_left()); 93 geometry_box_state.set_content_width(path_bounding_box.width()); 94 geometry_box_state.set_content_height(path_bounding_box.height()); 95 } 96 97 return IterationDecision::Continue; 98 }); 99} 100 101}