From 01b57fa8b7275cba91e476ea6ba3f079514c4ac7 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 14 Jan 2022 12:23:54 +0000 Subject: LibWeb: Add CSS::Percentage, PercentageOr and LengthPercentage types Length and Percentage are different types, and sometimes only one or the other is allowed in a given CSS property. This is a first step towards separating them. --- .../LibWeb/Generate_CSS_PropertyID_cpp.cpp | 3 +- Userland/Libraries/LibWeb/CSS/Length.cpp | 12 ++ Userland/Libraries/LibWeb/CSS/Length.h | 1 + Userland/Libraries/LibWeb/CSS/Percentage.h | 141 +++++++++++++++++++++ Userland/Libraries/LibWeb/Forward.h | 3 +- 5 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 Userland/Libraries/LibWeb/CSS/Percentage.h diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/Generate_CSS_PropertyID_cpp.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/Generate_CSS_PropertyID_cpp.cpp index 12b0a84e38..e1ac87163f 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/Generate_CSS_PropertyID_cpp.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/Generate_CSS_PropertyID_cpp.cpp @@ -311,8 +311,9 @@ bool property_accepts_value(PropertyID property_id, StyleValue& style_value) return true; )~~~"); } else if (type_name == "percentage") { + // FIXME: Detecting lengths here is temporary until Length/Percentage are fully separated. property_generator.append(R"~~~( - if ((style_value.has_length() && style_value.to_length().is_percentage()) || style_value.is_calculated()) + if (style_value.is_percentage() || style_value.is_calculated() || (style_value.has_length() && !style_value.to_length().is_percentage())) return true; )~~~"); } else if (type_name == "number" || type_name == "integer") { diff --git a/Userland/Libraries/LibWeb/CSS/Length.cpp b/Userland/Libraries/LibWeb/CSS/Length.cpp index 9f51e56fc7..3cdd0117b6 100644 --- a/Userland/Libraries/LibWeb/CSS/Length.cpp +++ b/Userland/Libraries/LibWeb/CSS/Length.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -32,11 +33,22 @@ Length Length::make_auto() { return Length(0, Type::Auto); } + Length Length::make_px(float value) { return Length(value, Type::Px); } +Length Length::percentage_of(Percentage const& percentage) const +{ + if (is_undefined_or_auto()) { + dbgln("Attempting to get percentage of an undefined or auto length, this seems wrong? But for now we just return the original length."); + return *this; + } + + return Length { percentage.as_fraction() * raw_value(), m_type }; +} + Length Length::resolved(const Length& fallback_for_undefined, const Layout::Node& layout_node, float reference_for_percent) const { if (is_undefined()) diff --git a/Userland/Libraries/LibWeb/CSS/Length.h b/Userland/Libraries/LibWeb/CSS/Length.h index 349a1a7ad3..ddf620bced 100644 --- a/Userland/Libraries/LibWeb/CSS/Length.h +++ b/Userland/Libraries/LibWeb/CSS/Length.h @@ -44,6 +44,7 @@ public: static Length make_auto(); static Length make_px(float value); + Length percentage_of(Percentage const&) const; Length resolved(const Length& fallback_for_undefined, const Layout::Node& layout_node, float reference_for_percent) const; Length resolved_or_auto(const Layout::Node& layout_node, float reference_for_percent) const; diff --git a/Userland/Libraries/LibWeb/CSS/Percentage.h b/Userland/Libraries/LibWeb/CSS/Percentage.h new file mode 100644 index 0000000000..86dce08e6d --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/Percentage.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2022, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Web::CSS { + +class Percentage { +public: + explicit Percentage(int value) + : m_value(value) + { + } + + explicit Percentage(float value) + : m_value(value) + { + } + + float value() const { return m_value; } + float as_fraction() const { return m_value * 0.01f; } + + String to_string() const + { + return String::formatted("{}%", m_value); + } + + bool operator==(Percentage const& other) const { return m_value == other.m_value; } + bool operator!=(Percentage const& other) const { return !(*this == other); } + +private: + float m_value; +}; + +template +class PercentageOr { +public: + PercentageOr(T t) + : m_value(move(t)) + { + } + + PercentageOr(Percentage percentage) + : m_value(move(percentage)) + { + } + + 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(); } + + Percentage const& percentage() const + { + VERIFY(is_percentage()); + return m_value.template get(); + } + + T resolved(T const& reference_value) const + { + if (is_percentage()) + return reference_value.percentage_of(m_value.template get()); + + return m_value.template get(); + } + + String to_string() const + { + 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_percentage() != other.is_percentage()) + return false; + if (is_percentage()) + return (m_value.template get() == other.m_value.template get()); + return (m_value.template get() == other.m_value.template get()); + } + bool operator!=(PercentageOr const& other) const { return !(*this == other); } + +protected: + bool is_non_percentage_value() const { return m_value.template has(); } + T const& non_percentage_value() 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 LengthPercentage : public PercentageOr { +public: + using PercentageOr::PercentageOr; + + bool is_length() const { return is_non_percentage_value(); } + Length const& length() const { return non_percentage_value(); } +}; + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index ee116ffa0a..0454931ec4 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -26,7 +26,6 @@ class BorderRadiusStyleValue; class BorderStyleValue; class BoxShadowStyleValue; class CalculatedStyleValue; -class CalculatedStyleValue; class ColorStyleValue; class CSSImportRule; class CSSMediaRule; @@ -46,6 +45,7 @@ class ImageStyleValue; class InheritStyleValue; class InitialStyleValue; class Length; +class LengthPercentage; class LengthStyleValue; class ListStyleStyleValue; class MediaList; @@ -54,6 +54,7 @@ class MediaQueryList; class MediaQueryListEvent; class NumericStyleValue; class OverflowStyleValue; +class Percentage; class PositionStyleValue; class PropertyOwningCSSStyleDeclaration; class Screen; -- cgit v1.2.3