diff options
author | Tobias Christiansen <tobi@tobyase.de> | 2021-06-12 00:50:16 +0200 |
---|---|---|
committer | Ali Mohammad Pur <Ali.mpfard@gmail.com> | 2021-07-24 03:02:07 +0430 |
commit | 9c65c102452adddfa1bf1d2f8c79ed760eb1c647 (patch) | |
tree | 019970f40fecee3b7ce9c605767d7f8d39e923f3 /Userland/Libraries/LibWeb | |
parent | 20667dfff561700df69c6a6b5ff78c00d652f200 (diff) | |
download | serenity-9c65c102452adddfa1bf1d2f8c79ed760eb1c647.zip |
LibWeb: Add calc() resolution to CSS::Length
This patch finally adds the actual calculation that goes into calc()
expressions. When the resolution of a Length that is a calculated value
the parsed CalculatedStyleValue gets traversed and appropriate values
get calculated.
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Length.cpp | 121 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Length.h | 5 |
2 files changed, 124 insertions, 2 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Length.cpp b/Userland/Libraries/LibWeb/CSS/Length.cpp index a8c73d134a..2b2c91d6d7 100644 --- a/Userland/Libraries/LibWeb/CSS/Length.cpp +++ b/Userland/Libraries/LibWeb/CSS/Length.cpp @@ -1,9 +1,13 @@ /* * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2021, Tobias Christiansen <tobi@tobyase.de> * * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/NonnullOwnPtr.h> +#include <AK/NonnullOwnPtrVector.h> +#include <AK/Variant.h> #include <LibWeb/CSS/Length.h> #include <LibWeb/DOM/Document.h> #include <LibWeb/HTML/HTMLHtmlElement.h> @@ -39,6 +43,123 @@ float Length::relative_length_to_px(const Layout::Node& layout_node) const } } +static float resolve_calc_value(CalculatedStyleValue::CalcValue const&, const Layout::Node& layout_node, float reference_for_percent); +static float resolve_calc_number_value(CalculatedStyleValue::CalcNumberValue const&); +static float resolve_calc_product(NonnullOwnPtr<CalculatedStyleValue::CalcProduct> const&, const Layout::Node& layout_node, float reference_for_percent); +static float resolve_calc_sum(NonnullOwnPtr<CalculatedStyleValue::CalcSum> const&, const Layout::Node& layout_node, float reference_for_percent); +static float resolve_calc_number_sum(NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum> const&); +static float resolve_calc_number_product(NonnullOwnPtr<CalculatedStyleValue::CalcNumberProduct> const&); + +float Length::resolve_calculated_value(const Layout::Node& layout_node, float reference_for_percent) const +{ + if (!m_calculated_style) + return 0.0f; + + auto& expression = m_calculated_style->expression(); + + auto length = resolve_calc_sum(expression, layout_node, reference_for_percent); + return length; +}; + +static float resolve_calc_value(CalculatedStyleValue::CalcValue const& calc_value, const Layout::Node& layout_node, float reference_for_percent) +{ + return calc_value.visit( + [](float value) { return value; }, + [&](Length length) { + return length.resolved_or_zero(layout_node, reference_for_percent).to_px(layout_node); + }, + [&](NonnullOwnPtr<CalculatedStyleValue::CalcSum>& calc_sum) { + return resolve_calc_sum(calc_sum, layout_node, reference_for_percent); + }, + [](auto&) { + VERIFY_NOT_REACHED(); + return 0.0f; + }); +} + +static float resolve_calc_number_product(NonnullOwnPtr<CalculatedStyleValue::CalcNumberProduct> const& calc_number_product) +{ + auto value = resolve_calc_number_value(calc_number_product->first_calc_number_value); + + 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::CalcNumberProductPartWithOperator::Multiply) + value *= additional_value; + else if (additional_number_value.op == CalculatedStyleValue::CalcNumberProductPartWithOperator::Divide) + value /= additional_value; + else + VERIFY_NOT_REACHED(); + } + + return value; +} + +static float resolve_calc_number_sum(NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum> 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.calc_number_product); + if (additional_product.op == CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Add) + value += additional_value; + else if (additional_product.op == CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Subtract) + value -= additional_value; + else + VERIFY_NOT_REACHED(); + } + + return value; +} + +static float resolve_calc_number_value(CalculatedStyleValue::CalcNumberValue const& number_value) +{ + return number_value.visit( + [](float number) { return number; }, + [](NonnullOwnPtr<CalculatedStyleValue::CalcNumberSum>& calc_number_sum) { + return resolve_calc_number_sum(calc_number_sum); + }); +} + +static float resolve_calc_product(NonnullOwnPtr<CalculatedStyleValue::CalcProduct> const& calc_product, const Layout::Node& layout_node, float reference_for_percent) +{ + auto value = resolve_calc_value(calc_product->first_calc_value, layout_node, reference_for_percent); + + 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::CalcProductPartWithOperator::Multiply) + VERIFY_NOT_REACHED(); + auto resolved_value = resolve_calc_value(calc_value, layout_node, reference_for_percent); + value *= resolved_value; + }, + [&](CalculatedStyleValue::CalcNumberValue const& calc_number_value) { + if (additional_value.op != CalculatedStyleValue::CalcProductPartWithOperator::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<CalculatedStyleValue::CalcSum> const& calc_sum, const Layout::Node& layout_node, float reference_for_percent) +{ + auto value = resolve_calc_product(calc_sum->first_calc_product, layout_node, reference_for_percent); + + for (auto& additional_product : calc_sum->zero_or_more_additional_calc_products) { + auto additional_value = resolve_calc_product(additional_product.calc_product, layout_node, reference_for_percent); + if (additional_product.op == CalculatedStyleValue::CalcSumPartWithOperator::Operation::Add) + value += additional_value; + else if (additional_product.op == CalculatedStyleValue::CalcSumPartWithOperator::Operation::Subtract) + value -= additional_value; + else + VERIFY_NOT_REACHED(); + } + + return value; +} + const char* Length::unit_name() const { switch (m_type) { diff --git a/Userland/Libraries/LibWeb/CSS/Length.h b/Userland/Libraries/LibWeb/CSS/Length.h index c9c8c465d1..5e14e11818 100644 --- a/Userland/Libraries/LibWeb/CSS/Length.h +++ b/Userland/Libraries/LibWeb/CSS/Length.h @@ -53,10 +53,10 @@ public: { if (is_undefined()) return fallback_for_undefined; + if (is_calculated()) + return Length(resolve_calculated_value(layout_node, reference_for_percent), Type::Px); if (is_percentage()) return make_px(raw_value() / 100.0f * reference_for_percent); - if (is_calculated()) - return {}; if (is_relative()) return make_px(to_px(layout_node)); return *this; @@ -153,6 +153,7 @@ public: private: float relative_length_to_px(const Layout::Node&) const; + float resolve_calculated_value(const Layout::Node& layout_node, float reference_for_percent) const; const char* unit_name() const; |