Explorar o código

LibWeb: Parse `aspect-ratio` property

Parse it, store the result in the ComputedValues, and also expose it to
ResolvedCSSStyleDeclaration.
Sam Atkins %!s(int64=2) %!d(string=hai) anos
pai
achega
6fd3b39bef

+ 10 - 0
Userland/Libraries/LibWeb/CSS/ComputedValues.h

@@ -15,6 +15,7 @@
 #include <LibWeb/CSS/GridTrackSize.h>
 #include <LibWeb/CSS/LengthBox.h>
 #include <LibWeb/CSS/PercentageOr.h>
+#include <LibWeb/CSS/Ratio.h>
 #include <LibWeb/CSS/Size.h>
 #include <LibWeb/CSS/StyleValues/AbstractImageStyleValue.h>
 #include <LibWeb/CSS/StyleValues/ShadowStyleValue.h>
@@ -22,8 +23,14 @@
 
 namespace Web::CSS {
 
+struct AspectRatio {
+    bool use_natural_aspect_ratio_if_available;
+    Optional<Ratio> preferred_ratio;
+};
+
 class InitialValues {
 public:
+    static AspectRatio aspect_ratio() { return AspectRatio { true, {} }; }
     static float font_size() { return 16; }
     static int font_weight() { return 400; }
     static CSS::FontVariant font_variant() { return CSS::FontVariant::Normal; }
@@ -211,6 +218,7 @@ inline Gfx::Painter::ScalingMode to_gfx_scaling_mode(CSS::ImageRendering css_val
 
 class ComputedValues {
 public:
+    AspectRatio aspect_ratio() const { return m_noninherited.aspect_ratio; }
     CSS::Float float_() const { return m_noninherited.float_; }
     CSS::Clear clear() const { return m_noninherited.clear; }
     CSS::Clip clip() const { return m_noninherited.clip; }
@@ -344,6 +352,7 @@ protected:
     } m_inherited;
 
     struct {
+        AspectRatio aspect_ratio { InitialValues::aspect_ratio() };
         CSS::Float float_ { InitialValues::float_() };
         CSS::Clear clear { InitialValues::clear() };
         CSS::Clip clip { InitialValues::clip() };
@@ -418,6 +427,7 @@ class ImmutableComputedValues final : public ComputedValues {
 
 class MutableComputedValues final : public ComputedValues {
 public:
+    void set_aspect_ratio(AspectRatio aspect_ratio) { m_noninherited.aspect_ratio = aspect_ratio; }
     void set_font_size(float font_size) { m_inherited.font_size = font_size; }
     void set_font_weight(int font_weight) { m_inherited.font_weight = font_weight; }
     void set_font_variant(CSS::FontVariant font_variant) { m_inherited.font_variant = font_variant; }

+ 49 - 0
Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -4457,6 +4457,51 @@ static void remove_property(Vector<PropertyID>& properties, PropertyID property_
     properties.remove_first_matching([&](auto it) { return it == property_to_remove; });
 }
 
+// https://www.w3.org/TR/css-sizing-4/#aspect-ratio
+ErrorOr<RefPtr<StyleValue>> Parser::parse_aspect_ratio_value(Vector<ComponentValue> const& component_values)
+{
+    // `auto || <ratio>`
+    RefPtr<StyleValue> auto_value;
+    RefPtr<StyleValue> ratio_value;
+
+    auto tokens = TokenStream { component_values };
+    while (tokens.has_next_token()) {
+        auto maybe_value = TRY(parse_css_value_for_property(PropertyID::AspectRatio, tokens));
+        if (!maybe_value)
+            return nullptr;
+
+        if (maybe_value->is_ratio()) {
+            if (ratio_value)
+                return nullptr;
+            ratio_value = maybe_value.release_nonnull();
+            continue;
+        }
+
+        if (maybe_value->is_identifier() && maybe_value->as_identifier().id() == ValueID::Auto) {
+            if (auto_value)
+                return nullptr;
+            auto_value = maybe_value.release_nonnull();
+            continue;
+        }
+
+        return nullptr;
+    }
+
+    if (auto_value && ratio_value) {
+        return TRY(StyleValueList::create(
+            StyleValueVector { auto_value.release_nonnull(), ratio_value.release_nonnull() },
+            StyleValueList::Separator::Space));
+    }
+
+    if (ratio_value)
+        return ratio_value.release_nonnull();
+
+    if (auto_value)
+        return auto_value.release_nonnull();
+
+    return nullptr;
+}
+
 ErrorOr<RefPtr<StyleValue>> Parser::parse_background_value(Vector<ComponentValue> const& component_values)
 {
     StyleValueVector background_images;
@@ -7307,6 +7352,10 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue>> Parser::parse_css_value(Property
 
     // Special-case property handling
     switch (property_id) {
+    case PropertyID::AspectRatio:
+        if (auto parsed_value = FIXME_TRY(parse_aspect_ratio_value(component_values)))
+            return parsed_value.release_nonnull();
+        return ParseError::SyntaxError;
     case PropertyID::BackdropFilter:
         if (auto parsed_value = FIXME_TRY(parse_filter_value_list_value(component_values)))
             return parsed_value.release_nonnull();

+ 1 - 0
Userland/Libraries/LibWeb/CSS/Parser/Parser.h

@@ -307,6 +307,7 @@ private:
     ErrorOr<RefPtr<StyleValue>> parse_simple_comma_separated_value_list(PropertyID, Vector<ComponentValue> const&);
 
     ErrorOr<RefPtr<StyleValue>> parse_filter_value_list_value(Vector<ComponentValue> const&);
+    ErrorOr<RefPtr<StyleValue>> parse_aspect_ratio_value(Vector<ComponentValue> const&);
     ErrorOr<RefPtr<StyleValue>> parse_background_value(Vector<ComponentValue> const&);
     ErrorOr<RefPtr<StyleValue>> parse_single_background_position_value(TokenStream<ComponentValue>&);
     ErrorOr<RefPtr<StyleValue>> parse_single_background_position_x_or_y_value(TokenStream<ComponentValue>&, PropertyID);

+ 11 - 0
Userland/Libraries/LibWeb/CSS/Properties.json

@@ -138,6 +138,17 @@
       "appearance"
     ]
   },
+  "aspect-ratio": {
+    "affects-layout": true,
+    "inherited": false,
+    "initial": "auto",
+    "valid-types": [
+      "ratio"
+    ],
+    "valid-identifiers":[
+      "auto"
+    ]
+  },
   "backdrop-filter": {
     "affects-layout": false,
     "affects-stacking-context": true,

+ 14 - 0
Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp

@@ -33,6 +33,7 @@
 #include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
 #include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
 #include <LibWeb/CSS/StyleValues/PositionStyleValue.h>
+#include <LibWeb/CSS/StyleValues/RatioStyleValue.h>
 #include <LibWeb/CSS/StyleValues/RectStyleValue.h>
 #include <LibWeb/CSS/StyleValues/ShadowStyleValue.h>
 #include <LibWeb/CSS/StyleValues/StyleValueList.h>
@@ -263,6 +264,19 @@ ErrorOr<RefPtr<StyleValue const>> ResolvedCSSStyleDeclaration::style_value_for_p
         return TRY(IdentifierStyleValue::create(to_value_id(layout_node.computed_values().align_self())));
     case PropertyID::Appearance:
         return TRY(IdentifierStyleValue::create(to_value_id(layout_node.computed_values().appearance())));
+    case PropertyID::AspectRatio: {
+        auto aspect_ratio = layout_node.computed_values().aspect_ratio();
+        if (aspect_ratio.use_natural_aspect_ratio_if_available && aspect_ratio.preferred_ratio.has_value()) {
+            return TRY(StyleValueList::create(
+                StyleValueVector {
+                    TRY(IdentifierStyleValue::create(ValueID::Auto)),
+                    TRY(RatioStyleValue::create(aspect_ratio.preferred_ratio.value())) },
+                StyleValueList::Separator::Space));
+        }
+        if (aspect_ratio.preferred_ratio.has_value())
+            return TRY(RatioStyleValue::create(aspect_ratio.preferred_ratio.value()));
+        return TRY(IdentifierStyleValue::create(ValueID::Auto));
+    }
     case PropertyID::Background: {
         auto maybe_background_color = property(PropertyID::BackgroundColor);
         auto maybe_background_image = property(PropertyID::BackgroundImage);

+ 17 - 0
Userland/Libraries/LibWeb/Layout/Node.cpp

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -10,9 +11,11 @@
 #include <LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h>
 #include <LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h>
 #include <LibWeb/CSS/StyleValues/EdgeStyleValue.h>
+#include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h>
 #include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
 #include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
 #include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
+#include <LibWeb/CSS/StyleValues/RatioStyleValue.h>
 #include <LibWeb/CSS/StyleValues/StyleValueList.h>
 #include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
 #include <LibWeb/CSS/StyleValues/URLStyleValue.h>
@@ -707,6 +710,20 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
 
     if (auto border_collapse = computed_style.border_collapse(); border_collapse.has_value())
         computed_values.set_border_collapse(border_collapse.value());
+
+    auto aspect_ratio = computed_style.property(CSS::PropertyID::AspectRatio);
+    if (aspect_ratio->is_value_list()) {
+        auto& values_list = aspect_ratio->as_value_list().values();
+        if (values_list.size() == 2
+            && values_list[0]->is_identifier() && values_list[0]->as_identifier().id() == CSS::ValueID::Auto
+            && values_list[1]->is_ratio()) {
+            computed_values.set_aspect_ratio({ true, values_list[1]->as_ratio().ratio() });
+        }
+    } else if (aspect_ratio->is_identifier() && aspect_ratio->as_identifier().id() == CSS::ValueID::Auto) {
+        computed_values.set_aspect_ratio({ true, {} });
+    } else if (aspect_ratio->is_ratio()) {
+        computed_values.set_aspect_ratio({ false, aspect_ratio->as_ratio().ratio() });
+    }
 }
 
 bool Node::is_root_element() const