diff --git a/Libraries/LibWeb/CSS/ComputedProperties.cpp b/Libraries/LibWeb/CSS/ComputedProperties.cpp index 1cdec337bbf..811c71a4c6c 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.cpp +++ b/Libraries/LibWeb/CSS/ComputedProperties.cpp @@ -1911,4 +1911,46 @@ ScrollbarWidth ComputedProperties::scrollbar_width() const return keyword_to_scrollbar_width(value.to_keyword()).release_value(); } +WillChange ComputedProperties::will_change() const +{ + auto const& value = property(PropertyID::WillChange); + if (value.to_keyword() == Keyword::Auto) + return WillChange::make_auto(); + + auto to_will_change_entry = [](StyleValue const& value) -> Optional { + if (value.is_keyword()) { + switch (value.as_keyword().keyword()) { + case Keyword::Contents: + return WillChange::Type::Contents; + case Keyword::ScrollPosition: + return WillChange::Type::ScrollPosition; + default: + VERIFY_NOT_REACHED(); + } + } + VERIFY(value.is_custom_ident()); + auto custom_ident = value.as_custom_ident().custom_ident(); + auto property_id = property_id_from_string(custom_ident); + if (!property_id.has_value()) + return {}; + + return property_id.release_value(); + }; + + if (value.is_value_list()) { + auto const& value_list = value.as_value_list(); + Vector will_change_entries; + for (auto const& style_value : value_list.values()) { + if (auto entry = to_will_change_entry(*style_value); entry.has_value()) + will_change_entries.append(*entry); + } + return WillChange(move(will_change_entries)); + } + + auto will_change_entry = to_will_change_entry(value); + if (will_change_entry.has_value()) + return WillChange({ *will_change_entry }); + return WillChange::make_auto(); +} + } diff --git a/Libraries/LibWeb/CSS/ComputedProperties.h b/Libraries/LibWeb/CSS/ComputedProperties.h index 18ac7eae49a..11fc8b57a3f 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.h +++ b/Libraries/LibWeb/CSS/ComputedProperties.h @@ -196,6 +196,8 @@ public: ClipRule clip_rule() const; float flood_opacity() const; + WillChange will_change() const; + Gfx::FontCascadeList const& computed_font_list() const { VERIFY(m_font_list); diff --git a/Libraries/LibWeb/CSS/ComputedValues.h b/Libraries/LibWeb/CSS/ComputedValues.h index 5dff89bd4e6..c5be01a87f4 100644 --- a/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Libraries/LibWeb/CSS/ComputedValues.h @@ -87,6 +87,33 @@ struct ScrollbarColorData { Color track_color { Color::Transparent }; }; +struct WillChange { + enum class Type : u8 { + Contents, + ScrollPosition, + }; + using WillChangeEntry = Variant; + + WillChange(Vector values) + : m_value(move(values)) + { + } + + static WillChange make_auto() { return WillChange(); } + + bool is_auto() const { return m_value.is_empty(); } + bool has_contents() const { return m_value.contains_slow(Type::Contents); } + bool has_scroll_position() const { return m_value.contains_slow(Type::ScrollPosition); } + bool has_property(PropertyID property_id) const { return m_value.contains_slow(property_id); } + +private: + WillChange() + { + } + + Vector m_value; +}; + using CursorData = Variant, CursorPredefined>; using ListStyleType = Variant; @@ -231,6 +258,7 @@ public: }; } static CSS::ScrollbarWidth scrollbar_width() { return CSS::ScrollbarWidth::Auto; } + static WillChange will_change() { return WillChange::make_auto(); } }; enum class BackgroundSize { @@ -609,6 +637,8 @@ public: ScrollbarColorData scrollbar_color() const { return m_inherited.scrollbar_color; } CSS::ScrollbarWidth scrollbar_width() const { return m_noninherited.scrollbar_width; } + WillChange will_change() const { return m_noninherited.will_change; } + NonnullOwnPtr clone_inherited_values() const { auto clone = make(); @@ -804,6 +834,8 @@ protected: Vector counter_reset; Vector counter_set; + WillChange will_change { InitialValues::will_change() }; + Color flood_color { InitialValues::flood_color() }; float flood_opacity { InitialValues::flood_opacity() }; } m_noninherited; @@ -1014,6 +1046,8 @@ public: void set_counter_increment(Vector value) { m_noninherited.counter_increment = move(value); } void set_counter_reset(Vector value) { m_noninherited.counter_reset = move(value); } void set_counter_set(Vector value) { m_noninherited.counter_set = move(value); } + + void set_will_change(WillChange value) { m_noninherited.will_change = move(value); } }; } diff --git a/Libraries/LibWeb/CSS/Keywords.json b/Libraries/LibWeb/CSS/Keywords.json index 25a2cdb5f79..43ec9afe3b9 100644 --- a/Libraries/LibWeb/CSS/Keywords.json +++ b/Libraries/LibWeb/CSS/Keywords.json @@ -449,6 +449,7 @@ "scale-down", "screen", "scroll", + "scroll-position", "scrollbar", "se-resize", "searchfield", diff --git a/Libraries/LibWeb/CSS/Parser/Parser.h b/Libraries/LibWeb/CSS/Parser/Parser.h index ae2a2019b42..ec8bb1cfbc6 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Libraries/LibWeb/CSS/Parser/Parser.h @@ -490,6 +490,7 @@ private: RefPtr parse_touch_action_value(TokenStream&); RefPtr parse_white_space_shorthand(TokenStream&); RefPtr parse_white_space_trim_value(TokenStream&); + RefPtr parse_will_change_value(TokenStream&); RefPtr parse_list_of_time_values(PropertyID, TokenStream&); diff --git a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp index df77b40e2e0..cd13ddfc706 100644 --- a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp @@ -797,6 +797,11 @@ Parser::ParseErrorOr> Parser::parse_css_value(Pr if (auto parsed_value = parse_white_space_trim_value(tokens); parsed_value && !tokens.has_next_token()) return parsed_value.release_nonnull(); return ParseError::SyntaxError; + case PropertyID::WillChange: + if (auto parsed_value = parse_will_change_value(tokens); parsed_value && !tokens.has_next_token()) + return parsed_value.release_nonnull(); + return ParseError::SyntaxError; + default: break; } @@ -5692,4 +5697,28 @@ RefPtr Parser::parse_white_space_shorthand(TokenStream Parser::parse_will_change_value(TokenStream& tokens) +{ + // auto | # + // = scroll-position | contents | + if (parse_all_as_single_keyword_value(tokens, Keyword::Auto)) + return KeywordStyleValue::create(Keyword::Auto); + + auto parse_animateable_feature = [this](TokenStream& tokens) -> RefPtr { + auto style_value = parse_css_value_for_property(PropertyID::WillChange, tokens); + if (!style_value) + return nullptr; + + if (style_value->to_keyword() == Keyword::Auto) + return nullptr; + + return style_value; + }; + + return parse_comma_separated_value_list(tokens, [&parse_animateable_feature](auto& tokens) { + return parse_animateable_feature(tokens); + }); +} + } diff --git a/Libraries/LibWeb/CSS/Properties.json b/Libraries/LibWeb/CSS/Properties.json index 32e55844fd0..b1a61dad32e 100644 --- a/Libraries/LibWeb/CSS/Properties.json +++ b/Libraries/LibWeb/CSS/Properties.json @@ -3565,6 +3565,21 @@ "unitless-length" ] }, + "will-change": { + "affects-layout": false, + "affects-stacking-context": true, + "animation-type": "none", + "inherited": false, + "initial": "auto", + "valid-types": [ + "custom-ident ![all,auto,contents,none,scroll-position,will-change]" + ], + "valid-identifiers": [ + "auto", + "scroll-position", + "contents" + ] + }, "word-break": { "animation-type": "discrete", "initial": "normal", diff --git a/Libraries/LibWeb/Layout/Node.cpp b/Libraries/LibWeb/Layout/Node.cpp index 8b1b804999b..1c545f65afc 100644 --- a/Libraries/LibWeb/Layout/Node.cpp +++ b/Libraries/LibWeb/Layout/Node.cpp @@ -1015,6 +1015,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style) computed_values.set_mix_blend_mode(computed_style.mix_blend_mode()); computed_values.set_view_transition_name(computed_style.view_transition_name()); computed_values.set_contain(computed_style.contain()); + computed_values.set_will_change(computed_style.will_change()); computed_values.set_caret_color(computed_style.caret_color(*this)); computed_values.set_color_interpolation(computed_style.color_interpolation()); 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 e5758f60978..485084195b1 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 @@ -258,6 +258,7 @@ All properties associated with getComputedStyle(document.body): "view-transition-name", "white-space-trim", "width", + "will-change", "x", "y", "z-index" diff --git a/Tests/LibWeb/Text/expected/css/CSSStyleProperties-all-supported-properties-and-default-values.txt b/Tests/LibWeb/Text/expected/css/CSSStyleProperties-all-supported-properties-and-default-values.txt index b31f0fad875..a08c9cfcec9 100644 --- a/Tests/LibWeb/Text/expected/css/CSSStyleProperties-all-supported-properties-and-default-values.txt +++ b/Tests/LibWeb/Text/expected/css/CSSStyleProperties-all-supported-properties-and-default-values.txt @@ -725,6 +725,8 @@ All supported properties and their default values exposed from CSSStylePropertie 'whiteSpaceTrim': 'none' 'white-space-trim': 'none' 'width': '284px' +'willChange': 'auto' +'will-change': 'auto' 'wordBreak': 'normal' 'word-break': 'normal' 'wordSpacing': 'normal' diff --git a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt index a599e7f9e7a..aedba5a6cbc 100644 --- a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt +++ b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt @@ -256,6 +256,7 @@ vertical-align: baseline view-transition-name: none white-space-trim: none width: 784px +will-change: auto x: 0px y: 0px z-index: auto diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt index d8c9d530982..13536380301 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt @@ -1,8 +1,8 @@ Harness status: OK -Found 255 tests +Found 256 tests -248 Pass +249 Pass 7 Fail Pass accent-color Pass border-collapse @@ -256,6 +256,7 @@ Pass vertical-align Pass view-transition-name Pass white-space-trim Fail width +Pass will-change Pass x Pass y Pass z-index \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-will-change/parsing/will-change-invalid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-will-change/parsing/will-change-invalid.txt new file mode 100644 index 00000000000..b8f4f6e50e0 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-will-change/parsing/will-change-invalid.txt @@ -0,0 +1,111 @@ +Harness status: OK + +Found 106 tests + +106 Pass +Pass e.style['will-change'] = "auto transform" should not set the property value +Pass e.style['will-change'] = "auto, transform" should not set the property value +Pass e.style['will-change'] = "contents auto" should not set the property value +Pass e.style['will-change'] = "contents, auto" should not set the property value +Pass e.style['will-change'] = "transform, initial" should not set the property value +Pass e.style['will-change'] = "initial, transform" should not set the property value +Pass e.style['will-change'] = "initial, initial" should not set the property value +Pass e.style['will-change'] = "initial, inherit" should not set the property value +Pass e.style['will-change'] = "initial, unset" should not set the property value +Pass e.style['will-change'] = "initial, revert" should not set the property value +Pass e.style['will-change'] = "initial, revert-layer" should not set the property value +Pass e.style['will-change'] = "initial, default" should not set the property value +Pass e.style['will-change'] = "initial, will-change" should not set the property value +Pass e.style['will-change'] = "initial, none" should not set the property value +Pass e.style['will-change'] = "initial, all" should not set the property value +Pass e.style['will-change'] = "transform, inherit" should not set the property value +Pass e.style['will-change'] = "inherit, transform" should not set the property value +Pass e.style['will-change'] = "inherit, initial" should not set the property value +Pass e.style['will-change'] = "inherit, inherit" should not set the property value +Pass e.style['will-change'] = "inherit, unset" should not set the property value +Pass e.style['will-change'] = "inherit, revert" should not set the property value +Pass e.style['will-change'] = "inherit, revert-layer" should not set the property value +Pass e.style['will-change'] = "inherit, default" should not set the property value +Pass e.style['will-change'] = "inherit, will-change" should not set the property value +Pass e.style['will-change'] = "inherit, none" should not set the property value +Pass e.style['will-change'] = "inherit, all" should not set the property value +Pass e.style['will-change'] = "transform, unset" should not set the property value +Pass e.style['will-change'] = "unset, transform" should not set the property value +Pass e.style['will-change'] = "unset, initial" should not set the property value +Pass e.style['will-change'] = "unset, inherit" should not set the property value +Pass e.style['will-change'] = "unset, unset" should not set the property value +Pass e.style['will-change'] = "unset, revert" should not set the property value +Pass e.style['will-change'] = "unset, revert-layer" should not set the property value +Pass e.style['will-change'] = "unset, default" should not set the property value +Pass e.style['will-change'] = "unset, will-change" should not set the property value +Pass e.style['will-change'] = "unset, none" should not set the property value +Pass e.style['will-change'] = "unset, all" should not set the property value +Pass e.style['will-change'] = "transform, revert" should not set the property value +Pass e.style['will-change'] = "revert, transform" should not set the property value +Pass e.style['will-change'] = "revert, initial" should not set the property value +Pass e.style['will-change'] = "revert, inherit" should not set the property value +Pass e.style['will-change'] = "revert, unset" should not set the property value +Pass e.style['will-change'] = "revert, revert" should not set the property value +Pass e.style['will-change'] = "revert, revert-layer" should not set the property value +Pass e.style['will-change'] = "revert, default" should not set the property value +Pass e.style['will-change'] = "revert, will-change" should not set the property value +Pass e.style['will-change'] = "revert, none" should not set the property value +Pass e.style['will-change'] = "revert, all" should not set the property value +Pass e.style['will-change'] = "transform, revert-layer" should not set the property value +Pass e.style['will-change'] = "revert-layer, transform" should not set the property value +Pass e.style['will-change'] = "revert-layer, initial" should not set the property value +Pass e.style['will-change'] = "revert-layer, inherit" should not set the property value +Pass e.style['will-change'] = "revert-layer, unset" should not set the property value +Pass e.style['will-change'] = "revert-layer, revert" should not set the property value +Pass e.style['will-change'] = "revert-layer, revert-layer" should not set the property value +Pass e.style['will-change'] = "revert-layer, default" should not set the property value +Pass e.style['will-change'] = "revert-layer, will-change" should not set the property value +Pass e.style['will-change'] = "revert-layer, none" should not set the property value +Pass e.style['will-change'] = "revert-layer, all" should not set the property value +Pass e.style['will-change'] = "transform, default" should not set the property value +Pass e.style['will-change'] = "default, transform" should not set the property value +Pass e.style['will-change'] = "default, initial" should not set the property value +Pass e.style['will-change'] = "default, inherit" should not set the property value +Pass e.style['will-change'] = "default, unset" should not set the property value +Pass e.style['will-change'] = "default, revert" should not set the property value +Pass e.style['will-change'] = "default, revert-layer" should not set the property value +Pass e.style['will-change'] = "default, default" should not set the property value +Pass e.style['will-change'] = "default, will-change" should not set the property value +Pass e.style['will-change'] = "default, none" should not set the property value +Pass e.style['will-change'] = "default, all" should not set the property value +Pass e.style['will-change'] = "transform, will-change" should not set the property value +Pass e.style['will-change'] = "will-change, transform" should not set the property value +Pass e.style['will-change'] = "will-change, initial" should not set the property value +Pass e.style['will-change'] = "will-change, inherit" should not set the property value +Pass e.style['will-change'] = "will-change, unset" should not set the property value +Pass e.style['will-change'] = "will-change, revert" should not set the property value +Pass e.style['will-change'] = "will-change, revert-layer" should not set the property value +Pass e.style['will-change'] = "will-change, default" should not set the property value +Pass e.style['will-change'] = "will-change, will-change" should not set the property value +Pass e.style['will-change'] = "will-change, none" should not set the property value +Pass e.style['will-change'] = "will-change, all" should not set the property value +Pass e.style['will-change'] = "transform, none" should not set the property value +Pass e.style['will-change'] = "none, transform" should not set the property value +Pass e.style['will-change'] = "none, initial" should not set the property value +Pass e.style['will-change'] = "none, inherit" should not set the property value +Pass e.style['will-change'] = "none, unset" should not set the property value +Pass e.style['will-change'] = "none, revert" should not set the property value +Pass e.style['will-change'] = "none, revert-layer" should not set the property value +Pass e.style['will-change'] = "none, default" should not set the property value +Pass e.style['will-change'] = "none, will-change" should not set the property value +Pass e.style['will-change'] = "none, none" should not set the property value +Pass e.style['will-change'] = "none, all" should not set the property value +Pass e.style['will-change'] = "transform, all" should not set the property value +Pass e.style['will-change'] = "all, transform" should not set the property value +Pass e.style['will-change'] = "all, initial" should not set the property value +Pass e.style['will-change'] = "all, inherit" should not set the property value +Pass e.style['will-change'] = "all, unset" should not set the property value +Pass e.style['will-change'] = "all, revert" should not set the property value +Pass e.style['will-change'] = "all, revert-layer" should not set the property value +Pass e.style['will-change'] = "all, default" should not set the property value +Pass e.style['will-change'] = "all, will-change" should not set the property value +Pass e.style['will-change'] = "all, none" should not set the property value +Pass e.style['will-change'] = "all, all" should not set the property value +Pass e.style['will-change'] = "will-change" should not set the property value +Pass e.style['will-change'] = "none" should not set the property value +Pass e.style['will-change'] = "all" should not set the property value \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-will-change/parsing/will-change-valid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-will-change/parsing/will-change-valid.txt new file mode 100644 index 00000000000..0382003c62a --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-will-change/parsing/will-change-valid.txt @@ -0,0 +1,14 @@ +Harness status: OK + +Found 9 tests + +9 Pass +Pass e.style['will-change'] = "auto" should set the property value +Pass e.style['will-change'] = "scroll-position" should set the property value +Pass e.style['will-change'] = "contents" should set the property value +Pass e.style['will-change'] = "transform" should set the property value +Pass e.style['will-change'] = "background-color" should set the property value +Pass e.style['will-change'] = "scroll-position, contents" should set the property value +Pass e.style['will-change'] = "scroll-position, transform" should set the property value +Pass e.style['will-change'] = "contents, transform" should set the property value +Pass e.style['will-change'] = "transform, background-color" should set the property value \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/css/css-will-change/parsing/will-change-invalid.html b/Tests/LibWeb/Text/input/wpt-import/css/css-will-change/parsing/will-change-invalid.html new file mode 100644 index 00000000000..d0d3dd81ee9 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/css/css-will-change/parsing/will-change-invalid.html @@ -0,0 +1,49 @@ + + + + +CSS Will Change Test: parsing will-change with invalid values + + + + + + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/css/css-will-change/parsing/will-change-valid.html b/Tests/LibWeb/Text/input/wpt-import/css/css-will-change/parsing/will-change-valid.html new file mode 100644 index 00000000000..d2b2c1a6a68 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/css/css-will-change/parsing/will-change-valid.html @@ -0,0 +1,29 @@ + + + + +CSS Will Change Test: parsing will-change with valid values + + + + + + + + + + +