SVGFormattingContext.cpp 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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. #include <AK/Format.h>
  9. #include <LibWeb/Layout/SVGFormattingContext.h>
  10. #include <LibWeb/Layout/SVGGeometryBox.h>
  11. #include <LibWeb/SVG/SVGSVGElement.h>
  12. namespace Web::Layout {
  13. SVGFormattingContext::SVGFormattingContext(FormattingState& state, Box const& box, FormattingContext* parent)
  14. : FormattingContext(Type::SVG, state, box, parent)
  15. {
  16. }
  17. SVGFormattingContext::~SVGFormattingContext() = default;
  18. void SVGFormattingContext::run(Box const& box, LayoutMode)
  19. {
  20. box.for_each_in_subtree_of_type<SVGBox>([&](SVGBox const& descendant) {
  21. if (is<SVGGeometryBox>(descendant)) {
  22. auto const& geometry_box = static_cast<SVGGeometryBox const&>(descendant);
  23. auto& geometry_box_state = m_state.get_mutable(geometry_box);
  24. auto& dom_node = const_cast<SVGGeometryBox&>(geometry_box).dom_node();
  25. SVG::SVGSVGElement* svg_element = dom_node.first_ancestor_of_type<SVG::SVGSVGElement>();
  26. if (svg_element->has_attribute(HTML::AttributeNames::width) && svg_element->has_attribute(HTML::AttributeNames::height)) {
  27. geometry_box_state.offset = { 0, 0 };
  28. auto& layout_node = static_cast<Layout::Node&>(*(svg_element->layout_node()));
  29. // FIXME: Allow for relative lengths here
  30. geometry_box_state.content_width = layout_node.computed_values().width().value().resolved(layout_node, { 0, CSS::Length::Type::Px }).to_px(layout_node);
  31. geometry_box_state.content_height = layout_node.computed_values().height().value().resolved(layout_node, { 0, CSS::Length::Type::Px }).to_px(layout_node);
  32. return IterationDecision::Continue;
  33. }
  34. // FIXME: Allow for one of {width, height} to not be specified}
  35. if (svg_element->has_attribute(HTML::AttributeNames::width)) {
  36. }
  37. if (svg_element->has_attribute(HTML::AttributeNames::height)) {
  38. }
  39. auto& path = dom_node.get_path();
  40. auto path_bounding_box = path.bounding_box();
  41. // Stroke increases the path's size by stroke_width/2 per side.
  42. auto stroke_width = geometry_box.dom_node().stroke_width().value_or(0);
  43. path_bounding_box.inflate(stroke_width, stroke_width);
  44. auto& maybe_view_box = svg_element->view_box();
  45. if (maybe_view_box.has_value()) {
  46. auto view_box = maybe_view_box.value();
  47. Gfx::FloatPoint viewbox_offset = { view_box.min_x, view_box.min_y };
  48. geometry_box_state.offset = path_bounding_box.top_left() + viewbox_offset;
  49. geometry_box_state.content_width = view_box.width;
  50. geometry_box_state.content_height = view_box.height;
  51. return IterationDecision::Continue;
  52. }
  53. geometry_box_state.offset = path_bounding_box.top_left();
  54. geometry_box_state.content_width = path_bounding_box.width();
  55. geometry_box_state.content_height = path_bounding_box.height();
  56. }
  57. return IterationDecision::Continue;
  58. });
  59. }
  60. }