From f0fb84dfcb1ba2707766e6d82f24ac6e1c9acd2f Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 27 Jan 2022 14:51:51 +0000 Subject: [PATCH] LibWeb: Refactor calc() resolution logic using CalculationResult The previous static functions are now methods of their respective CalcFoo structs, but the logic has not changed, only that they work with CalculationResults instead of converting everything to floats. --- Userland/Libraries/LibWeb/CSS/StyleValue.cpp | 252 +++++++++++-------- Userland/Libraries/LibWeb/CSS/StyleValue.h | 11 + 2 files changed, 161 insertions(+), 102 deletions(-) diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp index 3c17869a30..c067a015ad 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -249,7 +249,6 @@ String BackgroundStyleValue::to_string() const return builder.to_string(); } -<<<<<<< HEAD String BackgroundRepeatStyleValue::to_string() const { return String::formatted("{} {}", CSS::to_string(m_repeat_x), CSS::to_string(m_repeat_y)); @@ -273,7 +272,8 @@ String BorderRadiusStyleValue::to_string() const String BoxShadowStyleValue::to_string() const { return String::formatted("{} {} {} {}", m_offset_x.to_string(), m_offset_y.to_string(), m_blur_radius.to_string(), m_color.to_string()); -======= +} + void CalculatedStyleValue::CalculationResult::add(CalculationResult const& other, Layout::Node const* layout_node, Length const& percentage_basis) { add_or_subtract_internal(SumOperation::Add, other, layout_node, percentage_basis); @@ -354,6 +354,7 @@ void CalculatedStyleValue::CalculationResult::multiply_by(CalculationResult cons } }, [&](Length const& length) { + VERIFY(layout_node); m_value = Length::make_px(length.to_px(*layout_node) * other.m_value.get()); }, [&](Percentage const& percentage) { @@ -374,126 +375,47 @@ void CalculatedStyleValue::CalculationResult::divide_by(CalculationResult const& m_value = f / denominator; }, [&](Length const& length) { + VERIFY(layout_node); m_value = Length::make_px(length.to_px(*layout_node) / denominator); }, [&](Percentage const& percentage) { m_value = Percentage { percentage.value() / denominator }; }); ->>>>>>> d91d120251 (LibWeb: Implement CalculationResult type for calc() results) } -static float resolve_calc_value(CalculatedStyleValue::CalcValue const& calc_value, Layout::Node const& layout_node); -static float resolve_calc_number_value(CalculatedStyleValue::CalcNumberValue const&); -static float resolve_calc_product(NonnullOwnPtr const& calc_product, Layout::Node const& layout_node); -static float resolve_calc_sum(NonnullOwnPtr const& calc_sum, Layout::Node const& layout_node); -static float resolve_calc_number_sum(NonnullOwnPtr const&); -static float resolve_calc_number_product(NonnullOwnPtr const&); - Optional CalculatedStyleValue::resolve_length(Layout::Node const& layout_node) const { - auto length = resolve_calc_sum(m_expression, layout_node); - return Length::make_px(length); -} + auto result = m_expression->resolve(&layout_node, {}); -static float resolve_calc_value(CalculatedStyleValue::CalcValue const& calc_value, Layout::Node const& layout_node) -{ - return calc_value.value.visit( - [](float value) { return value; }, - [&](Length const& length) { - return length.resolved_or_zero(layout_node).to_px(layout_node); + return result.value().visit( + [&](float) -> Optional { + return {}; }, - [&](NonnullOwnPtr const& calc_sum) { - return resolve_calc_sum(calc_sum, layout_node); + [&](Length const& length) -> Optional { + return length; }, - [](auto&) { - VERIFY_NOT_REACHED(); - return 0.0f; + [&](Percentage const&) -> Optional { + return {}; }); } -static float resolve_calc_number_product(NonnullOwnPtr const& calc_number_product) +Optional CalculatedStyleValue::resolve_length_percentage(Layout::Node const& layout_node, Length const& percentage_basis) const { - auto value = resolve_calc_number_value(calc_number_product->first_calc_number_value); + VERIFY(!percentage_basis.is_undefined()); + auto result = m_expression->resolve(&layout_node, percentage_basis); - for (auto& additional_number_value : calc_number_product->zero_or_more_additional_calc_number_values) { - auto additional_value = resolve_calc_number_value(additional_number_value.value); - if (additional_number_value.op == CalculatedStyleValue::ProductOperation::Multiply) - value *= additional_value; - else if (additional_number_value.op == CalculatedStyleValue::ProductOperation::Divide) - value /= additional_value; - else - VERIFY_NOT_REACHED(); - } - - return value; -} - -static float resolve_calc_number_sum(NonnullOwnPtr const& calc_number_sum) -{ - auto value = resolve_calc_number_product(calc_number_sum->first_calc_number_product); - - for (auto& additional_product : calc_number_sum->zero_or_more_additional_calc_number_products) { - auto additional_value = resolve_calc_number_product(additional_product.value); - if (additional_product.op == CSS::CalculatedStyleValue::SumOperation::Add) - value += additional_value; - else if (additional_product.op == CSS::CalculatedStyleValue::SumOperation::Subtract) - value -= additional_value; - else - VERIFY_NOT_REACHED(); - } - - return value; -} - -static float resolve_calc_number_value(CalculatedStyleValue::CalcNumberValue const& number_value) -{ - return number_value.value.visit( - [](float number) { return number; }, - [](NonnullOwnPtr const& calc_number_sum) { - return resolve_calc_number_sum(calc_number_sum); + return result.value().visit( + [&](float) -> Optional { + return {}; + }, + [&](Length const& length) -> Optional { + return length; + }, + [&](Percentage const& percentage) -> Optional { + return percentage; }); } -static float resolve_calc_product(NonnullOwnPtr const& calc_product, Layout::Node const& layout_node) -{ - auto value = resolve_calc_value(calc_product->first_calc_value, layout_node); - - for (auto& additional_value : calc_product->zero_or_more_additional_calc_values) { - additional_value.value.visit( - [&](CalculatedStyleValue::CalcValue const& calc_value) { - if (additional_value.op != CalculatedStyleValue::ProductOperation::Multiply) - VERIFY_NOT_REACHED(); - auto resolved_value = resolve_calc_value(calc_value, layout_node); - value *= resolved_value; - }, - [&](CalculatedStyleValue::CalcNumberValue const& calc_number_value) { - if (additional_value.op != CalculatedStyleValue::ProductOperation::Divide) - VERIFY_NOT_REACHED(); - auto resolved_calc_number_value = resolve_calc_number_value(calc_number_value); - value /= resolved_calc_number_value; - }); - } - - return value; -} - -static float resolve_calc_sum(NonnullOwnPtr const& calc_sum, Layout::Node const& layout_node) -{ - auto value = resolve_calc_product(calc_sum->first_calc_product, layout_node); - - for (auto& additional_product : calc_sum->zero_or_more_additional_calc_products) { - auto additional_value = resolve_calc_product(additional_product.value, layout_node); - if (additional_product.op == CalculatedStyleValue::SumOperation::Add) - value += additional_value; - else if (additional_product.op == CalculatedStyleValue::SumOperation::Subtract) - value -= additional_value; - else - VERIFY_NOT_REACHED(); - } - - return value; -} - static bool is_number(CalculatedStyleValue::ResolvedType type) { return type == CalculatedStyleValue::ResolvedType::Number || type == CalculatedStyleValue::ResolvedType::Integer; @@ -662,6 +584,132 @@ Optional CalculatedStyleValue::CalcNumberVal [](NonnullOwnPtr const& sum) { return sum->resolved_type(); }); } +CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberValue::resolve(Layout::Node const* layout_node, Length const& percentage_basis) const +{ + return value.visit( + [&](float f) -> CalculatedStyleValue::CalculationResult { + return CalculatedStyleValue::CalculationResult { f }; + }, + [&](NonnullOwnPtr const& sum) -> CalculatedStyleValue::CalculationResult { + return sum->resolve(layout_node, percentage_basis); + }); +} + +CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcValue::resolve(Layout::Node const* layout_node, Length const& percentage_basis) const +{ + return value.visit( + [&](float f) -> CalculatedStyleValue::CalculationResult { + return CalculatedStyleValue::CalculationResult { f }; + }, + [&](Length const& length) -> CalculatedStyleValue::CalculationResult { + return CalculatedStyleValue::CalculationResult { length }; + }, + [&](NonnullOwnPtr const& sum) -> CalculatedStyleValue::CalculationResult { + return sum->resolve(layout_node, percentage_basis); + }); +} + +CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcSum::resolve(Layout::Node const* layout_node, Length const& percentage_basis) const +{ + auto value = first_calc_product->resolve(layout_node, percentage_basis); + + for (auto& additional_product : zero_or_more_additional_calc_products) { + auto additional_value = additional_product.resolve(layout_node, percentage_basis); + + if (additional_product.op == CalculatedStyleValue::SumOperation::Add) + value.add(additional_value, layout_node, percentage_basis); + else if (additional_product.op == CalculatedStyleValue::SumOperation::Subtract) + value.subtract(additional_value, layout_node, percentage_basis); + else + VERIFY_NOT_REACHED(); + } + + return value; +} + +CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberSum::resolve(Layout::Node const* layout_node, Length const& percentage_basis) const +{ + auto value = first_calc_number_product->resolve(layout_node, percentage_basis); + + for (auto& additional_product : zero_or_more_additional_calc_number_products) { + auto additional_value = additional_product.resolve(layout_node, percentage_basis); + + if (additional_product.op == CSS::CalculatedStyleValue::SumOperation::Add) + value.add(additional_value, layout_node, percentage_basis); + else if (additional_product.op == CalculatedStyleValue::SumOperation::Subtract) + value.subtract(additional_value, layout_node, percentage_basis); + else + VERIFY_NOT_REACHED(); + } + + return value; +} + +CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcProduct::resolve(Layout::Node const* layout_node, Length const& percentage_basis) const +{ + auto value = first_calc_value.resolve(layout_node, percentage_basis); + + for (auto& additional_value : zero_or_more_additional_calc_values) { + additional_value.value.visit( + [&](CalculatedStyleValue::CalcValue const& calc_value) { + VERIFY(additional_value.op == CalculatedStyleValue::ProductOperation::Multiply); + auto resolved_value = calc_value.resolve(layout_node, percentage_basis); + value.multiply_by(resolved_value, layout_node); + }, + [&](CalculatedStyleValue::CalcNumberValue const& calc_number_value) { + VERIFY(additional_value.op == CalculatedStyleValue::ProductOperation::Divide); + auto resolved_calc_number_value = calc_number_value.resolve(layout_node, percentage_basis); + value.divide_by(resolved_calc_number_value, layout_node); + }); + } + + return value; +} + +CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberProduct::resolve(Layout::Node const* layout_node, Length const& percentage_basis) const +{ + auto value = first_calc_number_value.resolve(layout_node, percentage_basis); + + for (auto& additional_number_value : zero_or_more_additional_calc_number_values) { + auto additional_value = additional_number_value.resolve(layout_node, percentage_basis); + + if (additional_number_value.op == CalculatedStyleValue::ProductOperation::Multiply) + value.multiply_by(additional_value, layout_node); + else if (additional_number_value.op == CalculatedStyleValue::ProductOperation::Divide) + value.divide_by(additional_value, layout_node); + else + VERIFY_NOT_REACHED(); + } + + return value; +} + +CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcProductPartWithOperator::resolve(Layout::Node const* layout_node, Length const& percentage_basis) const +{ + return value.visit( + [&](CalcValue const& calc_value) { + return calc_value.resolve(layout_node, percentage_basis); + }, + [&](CalcNumberValue const& calc_number_value) { + return calc_number_value.resolve(layout_node, percentage_basis); + }); +} + +CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcSumPartWithOperator::resolve(Layout::Node const* layout_node, Length const& percentage_basis) const +{ + return value->resolve(layout_node, percentage_basis); +} + +CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberProductPartWithOperator::resolve(Layout::Node const* layout_node, Length const& percentage_basis) const +{ + return value.resolve(layout_node, percentage_basis); +} + +CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberSumPartWithOperator::resolve(Layout::Node const* layout_node, Length const& percentage_basis) const +{ + return value->resolve(layout_node, percentage_basis); +} + // https://www.w3.org/TR/css-color-4/#serializing-sRGB-values String ColorStyleValue::to_string() const { diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index 3bfd434bf9..5c753ac4f2 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -703,11 +703,13 @@ public: struct CalcNumberValue { Variant> value; Optional resolved_type() const; + CalculationResult resolve(Layout::Node const*, Length const& percentage_basis) const; }; struct CalcValue { Variant> value; Optional resolved_type() const; + CalculationResult resolve(Layout::Node const*, Length const& percentage_basis) const; }; // This represents that: https://www.w3.org/TR/css-values-3/#calc-syntax @@ -720,6 +722,7 @@ public: NonnullOwnPtrVector zero_or_more_additional_calc_products; Optional resolved_type() const; + CalculationResult resolve(Layout::Node const*, Length const& percentage_basis) const; }; struct CalcNumberSum { @@ -731,6 +734,7 @@ public: NonnullOwnPtrVector zero_or_more_additional_calc_number_products; Optional resolved_type() const; + CalculationResult resolve(Layout::Node const*, Length const& percentage_basis) const; }; struct CalcProduct { @@ -738,6 +742,7 @@ public: NonnullOwnPtrVector zero_or_more_additional_calc_values; Optional resolved_type() const; + CalculationResult resolve(Layout::Node const*, Length const& percentage_basis) const; }; struct CalcSumPartWithOperator { @@ -749,6 +754,7 @@ public: NonnullOwnPtr value; Optional resolved_type() const; + CalculationResult resolve(Layout::Node const*, Length const& percentage_basis) const; }; struct CalcProductPartWithOperator { @@ -756,6 +762,7 @@ public: Variant value; Optional resolved_type() const; + CalculationResult resolve(Layout::Node const*, Length const& percentage_basis) const; }; struct CalcNumberProduct { @@ -763,6 +770,7 @@ public: NonnullOwnPtrVector zero_or_more_additional_calc_number_values; Optional resolved_type() const; + CalculationResult resolve(Layout::Node const*, Length const& percentage_basis) const; }; struct CalcNumberProductPartWithOperator { @@ -770,6 +778,7 @@ public: CalcNumberValue value; Optional resolved_type() const; + CalculationResult resolve(Layout::Node const*, Length const& percentage_basis) const; }; struct CalcNumberSumPartWithOperator { @@ -781,6 +790,7 @@ public: NonnullOwnPtr value; Optional resolved_type() const; + CalculationResult resolve(Layout::Node const*, Length const& percentage_basis) const; }; static NonnullRefPtr create(String const& expression_string, NonnullOwnPtr calc_sum, ResolvedType resolved_type) @@ -792,6 +802,7 @@ public: ResolvedType resolved_type() const { return m_resolved_type; } NonnullOwnPtr const& expression() const { return m_expression; } Optional resolve_length(Layout::Node const& layout_node) const; + Optional resolve_length_percentage(Layout::Node const&, Length const& percentage_basis) const; private: explicit CalculatedStyleValue(String const& expression_string, NonnullOwnPtr calc_sum, ResolvedType resolved_type)