LibWeb: Use transform-box for resolving percentage transform values
Some checks are pending
CI / Lagom (true, NO_FUZZ, ubuntu-22.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, FUZZ, ubuntu-22.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, macos-14, macOS, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-22.04, Linux, GNU) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-22.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run

Factor out computing the transform box rect into its own method. Then
use it when resolving the transformation matrix, to compute percentage
values.
This commit is contained in:
BenJilks 2024-09-05 15:15:17 +01:00 committed by Alexander Kalenik
parent a9d5a99568
commit 7e38e12bb0
Notes: github-actions[bot] 2024-09-05 23:35:41 +00:00
5 changed files with 92 additions and 65 deletions

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<style>
.a {
border: 20px solid crimson;
transform: translateY(0px);
}
.b {
border: 20px solid crimson;
transform: translateY(40px);
}
</style>
<div class="a"></div>
<div class="b"></div>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<link rel="match" href="reference/transform-box-ref.html" />
<style>
div {
border: 20px solid crimson;
transform: translateY(100%);
}
</style>
<div style="transform-box: fill-box"></div>
<div></div>

View file

@ -47,7 +47,7 @@ ErrorOr<Gfx::FloatMatrix4x4> Transformation::to_matrix(Optional<Painting::Painta
CSSPixels width = 1;
CSSPixels height = 1;
if (paintable_box.has_value()) {
auto reference_box = paintable_box->absolute_padding_box_rect();
auto reference_box = paintable_box->transform_box_rect();
width = reference_box.width();
height = reference_box.height();
}

View file

@ -969,6 +969,72 @@ Optional<CSSPixelRect> PaintableBox::get_masking_area() const
return absolute_border_box_rect();
}
// https://www.w3.org/TR/css-transforms-1/#transform-box
CSSPixelRect PaintableBox::transform_box_rect() const
{
auto transform_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 <svg> one. Is that correct?
// And is it correct to use `else` below?
if (is<Painting::SVGPaintable>(*this)) {
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;
}
}
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 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 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 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 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 = first_ancestor_of_type<Painting::SVGSVGPaintable>();
if (!svg_paintable)
return absolute_border_box_rect();
return svg_paintable->absolute_rect();
}
VERIFY_NOT_REACHED();
}
void PaintableBox::resolve_paint_properties()
{
auto const& computed_values = this->computed_values();
@ -1011,70 +1077,7 @@ void PaintableBox::resolve_paint_properties()
}
auto const& transform_origin = computed_values.transform_origin();
// https://www.w3.org/TR/css-transforms-1/#transform-box
auto transform_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 <svg> one. Is that correct?
// And is it correct to use `else` below?
if (is<Painting::SVGPaintable>(*this)) {
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 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 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 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 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 = first_ancestor_of_type<Painting::SVGSVGPaintable>();
if (!svg_paintable)
return absolute_border_box_rect();
return svg_paintable->absolute_rect();
}
VERIFY_NOT_REACHED();
}();
auto reference_box = transform_box_rect();
auto x = reference_box.left() + transform_origin.x.to_px(layout_node, reference_box.width());
auto y = reference_box.top() + transform_origin.y.to_px(layout_node, reference_box.height());
set_transform_origin({ x, y });

View file

@ -208,6 +208,7 @@ public:
virtual bool wants_mouse_events() const override;
CSSPixelRect transform_box_rect() const;
virtual void resolve_paint_properties() override;
RefPtr<ScrollFrame const> nearest_scroll_frame() const;