/* * Copyright (c) 2022-2023, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include namespace Web::CSS { template class PercentageOr { public: PercentageOr(T t) : m_value(move(t)) { } PercentageOr(Percentage percentage) : m_value(move(percentage)) { } PercentageOr(NonnullRefPtr calculated) : m_value(move(calculated)) { } ~PercentageOr() = default; PercentageOr& operator=(T t) { m_value = move(t); return *this; } PercentageOr& operator=(Percentage percentage) { m_value = move(percentage); return *this; } bool is_percentage() const { return m_value.template has(); } bool is_calculated() const { return m_value.template has>(); } bool contains_percentage() const { return m_value.visit( [&](T const&) { return false; }, [&](Percentage const&) { return true; }, [&](NonnullRefPtr const& calculated) { return calculated->contains_percentage(); }); } Percentage const& percentage() const { VERIFY(is_percentage()); return m_value.template get(); } NonnullRefPtr const& calculated() const { VERIFY(is_calculated()); return m_value.template get>(); } CSSPixels to_px(Layout::Node const& layout_node, CSSPixels reference_value) const { if constexpr (IsSame) { if (auto const* length = m_value.template get_pointer()) { if (length->is_absolute()) return length->absolute_length_to_px(); } } return resolved(layout_node, reference_value).to_px(layout_node); } T resolved(Layout::Node const& layout_node, T reference_value) const requires(!IsSame) { return m_value.visit( [&](T const& t) { return t; }, [&](Percentage const& percentage) { return reference_value.percentage_of(percentage); }, [&](NonnullRefPtr const& calculated) { return T::resolve_calculated(calculated, layout_node, reference_value); }); } T resolved(Layout::Node const& layout_node, CSSPixels reference_value) const { return m_value.visit( [&](T const& t) { return t; }, [&](Percentage const& percentage) { return Length::make_px(CSSPixels(percentage.value() * reference_value) / 100); }, [&](NonnullRefPtr const& calculated) { return T::resolve_calculated(calculated, layout_node, reference_value); }); } String to_string() const { if (is_calculated()) return m_value.template get>()->to_string(); if (is_percentage()) return m_value.template get().to_string(); return m_value.template get().to_string(); } bool operator==(PercentageOr const& other) const { if (is_calculated() != other.is_calculated()) return false; if (is_percentage() != other.is_percentage()) return false; if (is_calculated()) return (*m_value.template get>() == *other.m_value.template get>()); if (is_percentage()) return (m_value.template get() == other.m_value.template get()); return (m_value.template get() == other.m_value.template get()); } protected: bool is_t() const { return m_value.template has(); } T const& get_t() const { return m_value.template get(); } private: Variant> m_value; }; template bool operator==(PercentageOr const& percentage_or, T const& t) { return percentage_or == PercentageOr { t }; } template bool operator==(T const& t, PercentageOr const& percentage_or) { return t == percentage_or; } template bool operator==(PercentageOr const& percentage_or, Percentage const& percentage) { return percentage_or == PercentageOr { percentage }; } template bool operator==(Percentage const& percentage, PercentageOr const& percentage_or) { return percentage == percentage_or; } class AnglePercentage : public PercentageOr { public: using PercentageOr::PercentageOr; bool is_angle() const { return is_t(); } Angle const& angle() const { return get_t(); } }; class FrequencyPercentage : public PercentageOr { public: using PercentageOr::PercentageOr; bool is_frequency() const { return is_t(); } Frequency const& frequency() const { return get_t(); } }; class LengthPercentage : public PercentageOr { public: using PercentageOr::PercentageOr; bool is_auto() const { return is_length() && length().is_auto(); } bool is_length() const { return is_t(); } Length const& length() const { return get_t(); } }; class TimePercentage : public PercentageOr