ladybird/Userland/Libraries/LibWeb/Layout/SVGSVGBox.cpp
Andreas Kling f0560fd087 LibWeb: Support <svg> elements with display: block
There are a couple of things that went into this:

- We now calculate the intrinsic width/height and aspect ratio of <svg>
  elements based on the spec algorithm instead of our previous ad-hoc
  guesswork solution.

- Replaced elements with automatic size and intrinsic aspect ratio but
  no intrinsic dimensions are now sized with the stretch-fit width
  formula.

- We take care to assign both used width and used height to <svg>
  elements before running their SVG formatting contexts. This ensures
  that the inside SVG content is laid out with knowledge of its
  viewport geometry.

- We avoid infinite recursion in tentative_height_for_replaced_element()
  by using the already-calculated used width instead of calling the
  function that calculates the used width (since that may call us right
  back again).
2023-05-20 08:49:42 +02:00

83 lines
3.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/Layout/ReplacedBox.h>
#include <LibWeb/Layout/SVGGeometryBox.h>
#include <LibWeb/Painting/SVGSVGPaintable.h>
namespace Web::Layout {
SVGSVGBox::SVGSVGBox(DOM::Document& document, SVG::SVGSVGElement& element, NonnullRefPtr<CSS::StyleProperties> properties)
: ReplacedBox(document, element, move(properties))
{
}
JS::GCPtr<Painting::Paintable> SVGSVGBox::create_paintable() const
{
return Painting::SVGSVGPaintable::create(*this);
}
void SVGSVGBox::prepare_for_replaced_layout()
{
// https://www.w3.org/TR/SVG2/coords.html#SizingSVGInCSS
// The intrinsic dimensions must also be determined from the width and height sizing properties.
// If either width or height are not specified, the used value is the initial value 'auto'.
// 'auto' and percentage lengths must not be used to determine an intrinsic width or intrinsic height.
auto const& computed_width = computed_values().width();
if (computed_width.is_length() && !computed_width.contains_percentage()) {
set_intrinsic_width(computed_width.to_px(*this, 0));
}
auto const& computed_height = computed_values().height();
if (computed_height.is_length() && !computed_height.contains_percentage()) {
set_intrinsic_height(computed_height.to_px(*this, 0));
}
set_intrinsic_aspect_ratio(calculate_intrinsic_aspect_ratio());
}
Optional<float> SVGSVGBox::calculate_intrinsic_aspect_ratio() const
{
// https://www.w3.org/TR/SVG2/coords.html#SizingSVGInCSS
// The intrinsic aspect ratio must be calculated using the following algorithm. If the algorithm returns null, then there is no intrinsic aspect ratio.
auto const& computed_width = computed_values().width();
auto const& computed_height = computed_values().height();
// 1. If the width and height sizing properties on the ‘svg’ element are both absolute values:
if (computed_width.is_length() && !computed_width.contains_percentage() && computed_height.is_length() && !computed_height.contains_percentage()) {
auto width = computed_width.to_px(*this, 0);
auto height = computed_height.to_px(*this, 0);
if (width != 0 && height != 0) {
// 1. return width / height
return width.value() / height.value();
}
return {};
}
// FIXME: 2. If an SVG View is active:
// FIXME: 1. let viewbox be the viewbox defined by the active SVG View
// FIXME: 2. return viewbox.width / viewbox.height
// 3. If the ‘viewBox’ on the ‘svg’ element is correctly specified:
if (dom_node().view_box().has_value()) {
// 1. let viewbox be the viewbox defined by the ‘viewBox’ attribute on the ‘svg’ element
auto const& viewbox = dom_node().view_box().value();
// 2. return viewbox.width / viewbox.height
return viewbox.width / viewbox.height;
}
// 4. return null
return {};
}
}