1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 18:57:35 +00:00

LibWeb: Add Length::resolved() overload for CSSPixels

Since we always pass the px value as an argument to resolved(), we can
pass it directly as CSSPixels instead of wrapping it in Length. This
approach allows us to avoid converting to a double, resulting in fewer
precision issues.
This commit is contained in:
Aliaksandr Kalenik 2023-08-29 18:57:09 +02:00 committed by Alexander Kalenik
parent 5eb0f65cc0
commit 0fb571c1c2
14 changed files with 154 additions and 75 deletions

View file

@ -23,6 +23,11 @@ Length LengthPercentage::resolve_calculated(NonnullRefPtr<CalculatedStyleValue>
return calculated->resolve_length_percentage(layout_node, reference_value).value();
}
Length LengthPercentage::resolve_calculated(NonnullRefPtr<CalculatedStyleValue> const& calculated, Layout::Node const& layout_node, CSSPixels reference_value) const
{
return calculated->resolve_length_percentage(layout_node, reference_value).value();
}
Time TimePercentage::resolve_calculated(NonnullRefPtr<CalculatedStyleValue> const& calculated, Layout::Node const&, Time const& reference_value) const
{
return calculated->resolve_time_percentage(reference_value).value();

View file

@ -83,8 +83,15 @@ public:
return m_value.template get<NonnullRefPtr<CalculatedStyleValue>>();
}
virtual T resolve_calculated(NonnullRefPtr<CalculatedStyleValue> const&, [[maybe_unused]] Layout::Node const&, [[maybe_unused]] T const& reference_value) const
virtual T resolve_calculated(NonnullRefPtr<CalculatedStyleValue> const&, Layout::Node const&, T const& reference_value) const
{
(void)reference_value;
VERIFY_NOT_REACHED();
}
virtual T resolve_calculated(NonnullRefPtr<CalculatedStyleValue> const&, Layout::Node const&, CSSPixels reference_value) const
{
(void)reference_value;
VERIFY_NOT_REACHED();
}
@ -112,6 +119,25 @@ public:
});
}
T resolved(Layout::Node const& layout_node, CSSPixels reference_value) const
{
return m_value.visit(
[&](T const& t) {
if constexpr (requires { t.is_calculated(); }) {
if (t.is_calculated())
return resolve_calculated(t.calculated_style_value(), layout_node, reference_value);
}
return t;
},
[&](Percentage const& percentage) {
return Length::make_px(CSSPixels(percentage.value() * reference_value) / 100);
},
[&](NonnullRefPtr<CalculatedStyleValue> const& calculated) {
return resolve_calculated(calculated, layout_node, reference_value);
});
}
String to_string() const
{
if (is_calculated())
@ -193,6 +219,7 @@ public:
bool is_length() const { return is_t(); }
Length const& length() const { return get_t(); }
virtual Length resolve_calculated(NonnullRefPtr<CalculatedStyleValue> const&, Layout::Node const&, Length const& reference_value) const override;
virtual Length resolve_calculated(NonnullRefPtr<CalculatedStyleValue> const&, Layout::Node const&, CSSPixels reference_value) const override;
};
class TimePercentage : public PercentageOr<Time> {

View file

@ -24,6 +24,11 @@ CSS::Length Size::resolved(Layout::Node const& node, Length const& reference_val
return m_length_percentage.resolved(node, reference_value);
}
CSS::Length Size::resolved(Layout::Node const& node, CSSPixels reference_value) const
{
return m_length_percentage.resolved(node, reference_value);
}
Size Size::make_auto()
{
return Size { Type::Auto, Length::make_auto() };

View file

@ -47,6 +47,7 @@ public:
// FIXME: This is a stopgap API that will go away once all layout code is aware of CSS::Size.
CSS::Length resolved(Layout::Node const&, Length const& reference_value) const;
CSS::Length resolved(Layout::Node const&, CSSPixels reference_value) const;
[[nodiscard]] CSSPixels to_px(Layout::Node const&, CSSPixels reference_value) const;

View file

@ -2338,6 +2338,22 @@ Optional<Length> CalculatedStyleValue::resolve_length_percentage(Layout::Node co
});
}
Optional<Length> CalculatedStyleValue::resolve_length_percentage(Layout::Node const& layout_node, CSSPixels percentage_basis) const
{
auto result = m_calculation->resolve(Length::ResolutionContext::for_layout_node(layout_node), Length::make_px(percentage_basis));
return result.value().visit(
[&](Length const& length) -> Optional<Length> {
return length;
},
[&](Percentage const& percentage) -> Optional<Length> {
return Length::make_px(CSSPixels(percentage.value() * percentage_basis) / 100);
},
[&](auto const&) -> Optional<Length> {
return {};
});
}
Optional<Percentage> CalculatedStyleValue::resolve_percentage() const
{
auto result = m_calculation->resolve({}, {});

View file

@ -89,6 +89,7 @@ public:
[[nodiscard]] Optional<Length> resolve_length(Length::ResolutionContext const&) const;
Optional<Length> resolve_length(Layout::Node const& layout_node) const;
Optional<Length> resolve_length_percentage(Layout::Node const&, Length const& percentage_basis) const;
Optional<Length> resolve_length_percentage(Layout::Node const&, CSSPixels percentage_basis) const;
bool resolves_to_percentage() const { return m_resolved_type.matches_percentage(); }
Optional<Percentage> resolve_percentage() const;

View file

@ -150,8 +150,8 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node,
return Gfx::FloatSize { radius.to_float(), radius.to_float() };
},
[&](EllipseSize const& ellipse_size) {
auto radius_a = ellipse_size.radius_a.resolved(node, CSS::Length::make_px(CSSPixels::nearest_value_for(size.width()))).to_px(node);
auto radius_b = ellipse_size.radius_b.resolved(node, CSS::Length::make_px(CSSPixels::nearest_value_for(size.height()))).to_px(node);
auto radius_a = ellipse_size.radius_a.resolved(node, CSSPixels::nearest_value_for(size.width())).to_px(node);
auto radius_b = ellipse_size.radius_b.resolved(node, CSSPixels::nearest_value_for(size.height())).to_px(node);
return Gfx::FloatSize { radius_a.to_float(), radius_b.to_float() };
});