From c0eb072645580af5248643e5d6882b12cbc78a42 Mon Sep 17 00:00:00 2001 From: Psychpsyo Date: Fri, 21 Feb 2025 17:56:24 +0100 Subject: [PATCH] LibWeb: Add CSS view-transition-name --- Libraries/LibWeb/CSS/ComputedProperties.cpp | 13 ++++++++ Libraries/LibWeb/CSS/ComputedProperties.h | 1 + Libraries/LibWeb/CSS/ComputedValues.h | 3 ++ Libraries/LibWeb/CSS/Parser/Parser.h | 1 + .../LibWeb/CSS/Parser/PropertyParsing.cpp | 30 +++++++++++++++++++ Libraries/LibWeb/CSS/Properties.json | 13 ++++++++ Libraries/LibWeb/Layout/Node.cpp | 8 +++++ ...upported-properties-and-default-values.txt | 4 ++- ...eclaration-has-indexed-property-getter.txt | 9 +++--- .../css/getComputedStyle-print-all.txt | 1 + 10 files changed, 78 insertions(+), 5 deletions(-) diff --git a/Libraries/LibWeb/CSS/ComputedProperties.cpp b/Libraries/LibWeb/CSS/ComputedProperties.cpp index 3d449625fb2..61887f283a8 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.cpp +++ b/Libraries/LibWeb/CSS/ComputedProperties.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1598,6 +1599,18 @@ MixBlendMode ComputedProperties::mix_blend_mode() const return keyword_to_mix_blend_mode(value.to_keyword()).release_value(); } +Optional ComputedProperties::view_transition_name() const +{ + auto const& value = property(PropertyID::ViewTransitionName); + if (value.is_custom_ident()) { + auto ident = value.as_custom_ident().custom_ident(); + if (ident == "none"_fly_string) + return {}; + return ident; + } + return {}; +} + MaskType ComputedProperties::mask_type() const { auto const& value = property(PropertyID::MaskType); diff --git a/Libraries/LibWeb/CSS/ComputedProperties.h b/Libraries/LibWeb/CSS/ComputedProperties.h index 220976d43de..dab52629d44 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.h +++ b/Libraries/LibWeb/CSS/ComputedProperties.h @@ -164,6 +164,7 @@ public: Isolation isolation() const; Containment contain() const; MixBlendMode mix_blend_mode() const; + Optional view_transition_name() const; static Vector transformations_for_style_value(CSSStyleValue const& value); Vector transformations() const; diff --git a/Libraries/LibWeb/CSS/ComputedValues.h b/Libraries/LibWeb/CSS/ComputedValues.h index ed65144655e..d9672913517 100644 --- a/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Libraries/LibWeb/CSS/ComputedValues.h @@ -447,6 +447,7 @@ public: CSS::Isolation isolation() const { return m_noninherited.isolation; } CSS::Containment const& contain() const { return m_noninherited.contain; } CSS::MixBlendMode mix_blend_mode() const { return m_noninherited.mix_blend_mode; } + Optional view_transition_name() const { return m_noninherited.view_transition_name; } CSS::LengthBox const& inset() const { return m_noninherited.inset; } const CSS::LengthBox& margin() const { return m_noninherited.margin; } @@ -702,6 +703,7 @@ protected: CSS::Isolation isolation { InitialValues::isolation() }; CSS::Containment contain { InitialValues::contain() }; CSS::MixBlendMode mix_blend_mode { InitialValues::mix_blend_mode() }; + Optional view_transition_name; Optional rotate; Optional translate; @@ -878,6 +880,7 @@ public: void set_isolation(CSS::Isolation value) { m_noninherited.isolation = value; } void set_contain(CSS::Containment value) { m_noninherited.contain = move(value); } void set_mix_blend_mode(CSS::MixBlendMode value) { m_noninherited.mix_blend_mode = value; } + void set_view_transition_name(Optional value) { m_noninherited.view_transition_name = value; } void set_fill(SVGPaint value) { m_inherited.fill = move(value); } void set_stroke(SVGPaint value) { m_inherited.stroke = move(value); } diff --git a/Libraries/LibWeb/CSS/Parser/Parser.h b/Libraries/LibWeb/CSS/Parser/Parser.h index b06e67fc7e7..9d62892bbcd 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Libraries/LibWeb/CSS/Parser/Parser.h @@ -404,6 +404,7 @@ private: RefPtr parse_transition_value(TokenStream&); RefPtr parse_translate_value(TokenStream&); RefPtr parse_scale_value(TokenStream&); + RefPtr parse_view_transition_name_value(TokenStream&); RefPtr parse_grid_track_size_list(TokenStream&, bool allow_separate_line_name_blocks = false); RefPtr parse_grid_auto_track_sizes(TokenStream&); RefPtr parse_grid_auto_flow_value(TokenStream&); diff --git a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp index d263a4e4f90..529cb453cb3 100644 --- a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp @@ -55,6 +55,7 @@ #include #include #include +#include namespace Web::CSS::Parser { @@ -713,6 +714,10 @@ Parser::ParseErrorOr> Parser::parse_css_value(Prope if (auto parsed_value = parse_scale_value(tokens); parsed_value && !tokens.has_next_token()) return parsed_value.release_nonnull(); return ParseError::SyntaxError; + case PropertyID::ViewTransitionName: + if (auto parsed_value = parse_view_transition_name_value(tokens); parsed_value && !tokens.has_next_token()) + return parsed_value.release_nonnull(); + return ParseError::SyntaxError; default: break; } @@ -4438,4 +4443,29 @@ RefPtr Parser::parse_filter_value_list_value(TokenStream Parser::parse_view_transition_name_value(TokenStream& tokens) +{ + // none | + tokens.discard_whitespace(); + { + auto transaction = tokens.begin_transaction(); + + // The values 'none' and 'auto' are excluded from here. + // Note: Only auto is excluded here since none isn't parsed differently. + auto ident = parse_custom_ident_value(tokens, { "auto"sv }); + if (!ident) + return {}; + + tokens.discard_whitespace(); + transaction.commit(); + + if (Infra::is_ascii_case_insensitive_match(ident->custom_ident().to_string(), "none"sv)) { + return CustomIdentStyleValue::create("none"_fly_string); + } else { + return ident; + } + } + return {}; +} + } diff --git a/Libraries/LibWeb/CSS/Properties.json b/Libraries/LibWeb/CSS/Properties.json index 030cadf185f..dc723eea839 100644 --- a/Libraries/LibWeb/CSS/Properties.json +++ b/Libraries/LibWeb/CSS/Properties.json @@ -2895,6 +2895,19 @@ "unitless-length" ] }, + "view-transition-name": { + "affects-layout": false, + "affects-stacking-context": true, + "animation-type": "discrete", + "inherited": false, + "initial": "none", + "valid-types": [ + "custom-ident" + ], + "valid-identifiers": [ + "none" + ] + }, "visibility": { "animation-type": "custom", "inherited": true, diff --git a/Libraries/LibWeb/Layout/Node.cpp b/Libraries/LibWeb/Layout/Node.cpp index 8c8770da8a1..27a5abfdb78 100644 --- a/Libraries/LibWeb/Layout/Node.cpp +++ b/Libraries/LibWeb/Layout/Node.cpp @@ -246,6 +246,13 @@ bool Node::establishes_stacking_context() const if (computed_values().mix_blend_mode() != CSS::MixBlendMode::Normal) return true; + // https://drafts.csswg.org/css-view-transitions-1/#named-and-transitioning + // Elements captured in a view transition during a view transition or whose view-transition-name computed value is + // not 'none' (at any time): + // - Form a stacking context. + if (computed_values().view_transition_name().has_value()) + return true; + return computed_values().opacity() < 1.0f; } @@ -932,6 +939,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style) computed_values.set_user_select(computed_style.user_select()); computed_values.set_isolation(computed_style.isolation()); computed_values.set_mix_blend_mode(computed_style.mix_blend_mode()); + computed_values.set_view_transition_name(computed_style.view_transition_name()); propagate_style_to_anonymous_wrappers(); diff --git a/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-all-supported-properties-and-default-values.txt b/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-all-supported-properties-and-default-values.txt index 38eaa889eaf..b3eaf490912 100644 --- a/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-all-supported-properties-and-default-values.txt +++ b/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-all-supported-properties-and-default-values.txt @@ -1,6 +1,6 @@ All supported properties and their default values exposed from CSSStyleDeclaration from getComputedStyle: 'cssText': '' -'length': '219' +'length': '220' 'parentRule': 'null' 'cssFloat': 'none' 'WebkitAlignContent': 'normal' @@ -589,6 +589,8 @@ All supported properties and their default values exposed from CSSStyleDeclarati 'user-select': 'auto' 'verticalAlign': 'baseline' 'vertical-align': 'baseline' +'viewTransitionName': 'none' +'view-transition-name': 'none' 'visibility': 'visible' 'whiteSpace': 'normal' 'white-space': 'normal' diff --git a/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt b/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt index 49fb6106a9e..15df8d37e4e 100644 --- a/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt +++ b/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt @@ -215,10 +215,11 @@ All properties associated with getComputedStyle(document.body): "212": "unicode-bidi", "213": "user-select", "214": "vertical-align", - "215": "width", - "216": "x", - "217": "y", - "218": "z-index" + "215": "view-transition-name", + "216": "width", + "217": "x", + "218": "y", + "219": "z-index" } All properties associated with document.body.style by default: {} diff --git a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt index d5b2bfe1471..e63b0a92240 100644 --- a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt +++ b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt @@ -213,6 +213,7 @@ translate: none unicode-bidi: normal user-select: auto vertical-align: baseline +view-transition-name: none width: 784px x: 0px y: 0px