
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).
83 lines
3.1 KiB
C++
83 lines
3.1 KiB
C++
/*
|
||
* 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 {};
|
||
}
|
||
|
||
}
|