LibWeb: Resolve calc() values in CSS transform

There are two parts to this fix:

- First, StyleProperties::transformations() would previously omit calc()
  values entirely when returning the list of transformations. This was
  very confusing to StackingContext which then tried to index into the
  list based on faulty assumptions. Fix this by emitting calc values.

- Second, StackingContext::get_transformation_matrix() now always calls
  resolve() on length-percentages. This takes care of actually resolving
  calc() values. If no reference value for percentages is provided, we
  default to 0px.

This stops LibWeb from asserting on websites with calc() in transform
values, such as https://qt.io/ :^)
This commit is contained in:
Andreas Kling 2023-07-15 10:23:43 +02:00
parent 2a563b9de6
commit 3ec9fd0aae
Notes: sideshowbarker 2024-07-17 07:09:53 +09:00
4 changed files with 14 additions and 7 deletions

View file

@ -0,0 +1,3 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
BlockContainer <body> at (9,9) content-size 100x100 children: not-inline

View file

@ -0,0 +1,8 @@
<style>
body {
transform: translate3d(calc(50px), calc(100px), calc(0px));
border: 1px solid black;
width: 100px;
height: 100px;
}
</style>

View file

@ -442,7 +442,7 @@ Vector<CSS::Transformation> StyleProperties::transformations() const
if (transformation_value->is_calculated()) {
auto& calculated = transformation_value->as_calculated();
if (calculated.resolves_to_length()) {
dbgln("FIXME: Unable to resolve length with no layout node! {}", calculated.to_string());
values.append(CSS::LengthPercentage { calculated });
} else if (calculated.resolves_to_percentage()) {
values.append({ calculated.resolve_percentage().value() });
} else if (calculated.resolves_to_number()) {

View file

@ -238,14 +238,10 @@ void StackingContext::paint_internal(PaintContext& context) const
Gfx::FloatMatrix4x4 StackingContext::get_transformation_matrix(CSS::Transformation const& transformation) const
{
auto count = transformation.values.size();
auto value = [this, transformation](size_t index, Optional<CSS::Length const&> reference_length = {}) -> float {
auto value = [this, transformation](size_t index, CSS::Length const& reference_length = CSS::Length::make_px(0)) -> float {
return transformation.values[index].visit(
[this, reference_length](CSS::LengthPercentage const& value) -> double {
if (reference_length.has_value()) {
return value.resolved(m_box, reference_length.value()).to_px(m_box).to_float();
}
return value.length().to_px(m_box).to_float();
return value.resolved(m_box, reference_length).to_px(m_box).to_float();
},
[this](CSS::AngleOrCalculated const& value) {
return value.resolved(m_box).to_degrees() * M_DEG2RAD;