diff --git a/Tests/LibWeb/Ref/css-transform-box.html b/Tests/LibWeb/Ref/css-transform-box.html new file mode 100644 index 0000000000..9ca3dbcf38 --- /dev/null +++ b/Tests/LibWeb/Ref/css-transform-box.html @@ -0,0 +1,36 @@ + + + +
Hi
+
Hi
+ + + + + + + + + + + diff --git a/Tests/LibWeb/Ref/reference/css-transform-box-ref.html b/Tests/LibWeb/Ref/reference/css-transform-box-ref.html new file mode 100644 index 0000000000..57ae32963b --- /dev/null +++ b/Tests/LibWeb/Ref/reference/css-transform-box-ref.html @@ -0,0 +1,15 @@ + + + diff --git a/Tests/LibWeb/Ref/reference/images/css-transform-box-ref.png b/Tests/LibWeb/Ref/reference/images/css-transform-box-ref.png new file mode 100644 index 0000000000..58fe5260b5 Binary files /dev/null and b/Tests/LibWeb/Ref/reference/images/css-transform-box-ref.png differ diff --git a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp index c2b19b2c34..886524f794 100644 --- a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp +++ b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2022-2023, Andreas Kling + * Copyright (c) 2024, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -12,6 +13,7 @@ #include #include #include +#include #include namespace Web::Layout { @@ -369,8 +371,70 @@ void LayoutState::resolve_layout_dependent_properties() } auto const& transform_origin = paintable_box.computed_values().transform_origin(); - // FIXME: respect transform-box property - auto const& reference_box = paintable_box.absolute_border_box_rect(); + // https://www.w3.org/TR/css-transforms-1/#transform-box + auto transform_box = paintable_box.computed_values().transform_box(); + // For SVG elements without associated CSS layout box, the used value for content-box is fill-box and for + // border-box is stroke-box. + // FIXME: This currently detects any SVG element except the one. Is that correct? + // And is it correct to use `else` below? + if (is(paintable_box)) { + switch (transform_box) { + case CSS::TransformBox::ContentBox: + transform_box = CSS::TransformBox::FillBox; + break; + case CSS::TransformBox::BorderBox: + transform_box = CSS::TransformBox::StrokeBox; + break; + default: + break; + } + } + // For elements with associated CSS layout box, the used value for fill-box is content-box and for + // stroke-box and view-box is border-box. + else { + switch (transform_box) { + case CSS::TransformBox::FillBox: + transform_box = CSS::TransformBox::ContentBox; + break; + case CSS::TransformBox::StrokeBox: + case CSS::TransformBox::ViewBox: + transform_box = CSS::TransformBox::BorderBox; + break; + default: + break; + } + } + + CSSPixelRect reference_box = [&]() { + switch (transform_box) { + case CSS::TransformBox::ContentBox: + // Uses the content box as reference box. + // FIXME: The reference box of a table is the border box of its table wrapper box, not its table box. + return paintable_box.absolute_rect(); + case CSS::TransformBox::BorderBox: + // Uses the border box as reference box. + // FIXME: The reference box of a table is the border box of its table wrapper box, not its table box. + return paintable_box.absolute_border_box_rect(); + case CSS::TransformBox::FillBox: + // Uses the object bounding box as reference box. + // FIXME: For now we're using the content rect as an approximation. + return paintable_box.absolute_rect(); + case CSS::TransformBox::StrokeBox: + // Uses the stroke bounding box as reference box. + // FIXME: For now we're using the border rect as an approximation. + return paintable_box.absolute_border_box_rect(); + case CSS::TransformBox::ViewBox: + // Uses the nearest SVG viewport as reference box. + // FIXME: If a viewBox attribute is specified for the SVG viewport creating element: + // - The reference box is positioned at the origin of the coordinate system established by the viewBox attribute. + // - The dimension of the reference box is set to the width and height values of the viewBox attribute. + auto* svg_paintable = paintable_box.first_ancestor_of_type(); + if (!svg_paintable) + return paintable_box.absolute_border_box_rect(); + return svg_paintable->absolute_rect(); + } + VERIFY_NOT_REACHED(); + }(); auto x = reference_box.left() + transform_origin.x.to_px(node, reference_box.width()); auto y = reference_box.top() + transform_origin.y.to_px(node, reference_box.height()); paintable_box.set_transform_origin({ x, y });