diff --git a/Libraries/LibWeb/CSS/ComputedProperties.cpp b/Libraries/LibWeb/CSS/ComputedProperties.cpp index 1642c3a1a2e..cc8b2bf7af6 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.cpp +++ b/Libraries/LibWeb/CSS/ComputedProperties.cpp @@ -836,6 +836,38 @@ WhiteSpaceCollapse ComputedProperties::white_space_collapse() const return keyword_to_white_space_collapse(value.to_keyword()).release_value(); } +WhiteSpaceTrimData ComputedProperties::white_space_trim() const +{ + auto const& value = property(PropertyID::WhiteSpaceTrim); + + if (value.is_keyword() && value.to_keyword() == Keyword::None) + return WhiteSpaceTrimData {}; + + if (value.is_value_list()) { + auto white_space_trim_data = WhiteSpaceTrimData {}; + + for (auto const& value : value.as_value_list().values()) { + switch (value->as_keyword().keyword()) { + case Keyword::DiscardBefore: + white_space_trim_data.discard_before = true; + break; + case Keyword::DiscardAfter: + white_space_trim_data.discard_after = true; + break; + case Keyword::DiscardInner: + white_space_trim_data.discard_inner = true; + break; + default: + VERIFY_NOT_REACHED(); + } + } + + return white_space_trim_data; + } + + VERIFY_NOT_REACHED(); +} + Optional ComputedProperties::letter_spacing() const { auto const& value = property(PropertyID::LetterSpacing); diff --git a/Libraries/LibWeb/CSS/ComputedProperties.h b/Libraries/LibWeb/CSS/ComputedProperties.h index 8213b0475a7..fb31ed867d8 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.h +++ b/Libraries/LibWeb/CSS/ComputedProperties.h @@ -102,6 +102,7 @@ public: Variant tab_size() const; WhiteSpace white_space() const; WhiteSpaceCollapse white_space_collapse() const; + WhiteSpaceTrimData white_space_trim() const; WordBreak word_break() const; Optional word_spacing() const; Optional letter_spacing() const; diff --git a/Libraries/LibWeb/CSS/ComputedValues.h b/Libraries/LibWeb/CSS/ComputedValues.h index 4d3518b807f..ec146adf401 100644 --- a/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Libraries/LibWeb/CSS/ComputedValues.h @@ -334,6 +334,12 @@ struct TouchActionData { } }; +struct WhiteSpaceTrimData { + bool discard_before : 1 { false }; + bool discard_after : 1 { false }; + bool discard_inner : 1 { false }; +}; + struct TransformOrigin { CSS::LengthPercentage x { Percentage(50) }; CSS::LengthPercentage y { Percentage(50) }; @@ -427,6 +433,7 @@ public: CSS::Positioning position() const { return m_noninherited.position; } CSS::WhiteSpace white_space() const { return m_inherited.white_space; } CSS::WhiteSpaceCollapse white_space_collapse() const { return m_inherited.white_space_collapse; } + WhiteSpaceTrimData white_space_trim() const { return m_noninherited.white_space_trim; } CSS::LengthOrCalculated word_spacing() const { return m_inherited.word_spacing; } LengthOrCalculated letter_spacing() const { return m_inherited.letter_spacing; } CSS::FlexDirection flex_direction() const { return m_noninherited.flex_direction; } @@ -742,6 +749,7 @@ protected: CSS::Isolation isolation { InitialValues::isolation() }; CSS::Containment contain { InitialValues::contain() }; CSS::MixBlendMode mix_blend_mode { InitialValues::mix_blend_mode() }; + WhiteSpaceTrimData white_space_trim; Optional view_transition_name; TouchActionData touch_action; @@ -827,6 +835,7 @@ public: void set_position(CSS::Positioning position) { m_noninherited.position = position; } void set_white_space(CSS::WhiteSpace value) { m_inherited.white_space = value; } void set_white_space_collapse(CSS::WhiteSpaceCollapse value) { m_inherited.white_space_collapse = value; } + void set_white_space_trim(WhiteSpaceTrimData value) { m_noninherited.white_space_trim = value; } void set_word_spacing(CSS::LengthOrCalculated value) { m_inherited.word_spacing = move(value); } void set_word_break(CSS::WordBreak value) { m_inherited.word_break = value; } void set_letter_spacing(CSS::LengthOrCalculated value) { m_inherited.letter_spacing = value; } diff --git a/Libraries/LibWeb/CSS/Keywords.json b/Libraries/LibWeb/CSS/Keywords.json index 5a27fd2a7a5..2e3173b1780 100644 --- a/Libraries/LibWeb/CSS/Keywords.json +++ b/Libraries/LibWeb/CSS/Keywords.json @@ -159,6 +159,9 @@ "difference", "disc", "discard", + "discard-before", + "discard-after", + "discard-inner", "disclosure-closed", "disclosure-open", "discretionary-ligatures", diff --git a/Libraries/LibWeb/CSS/Parser/Parser.h b/Libraries/LibWeb/CSS/Parser/Parser.h index bf378191146..08ccbf26804 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Libraries/LibWeb/CSS/Parser/Parser.h @@ -445,6 +445,7 @@ private: RefPtr parse_grid_area_shorthand_value(TokenStream&); RefPtr parse_grid_shorthand_value(TokenStream&); RefPtr parse_touch_action_value(TokenStream&); + RefPtr parse_white_space_trim_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 0b797a613f5..ba2097ba406 100644 --- a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp @@ -708,6 +708,10 @@ Parser::ParseErrorOr> Parser::parse_css_value if (auto parsed_value = parse_contain_value(tokens); parsed_value && !tokens.has_next_token()) return parsed_value.release_nonnull(); return ParseError::SyntaxError; + case PropertyID::WhiteSpaceTrim: + if (auto parsed_value = parse_white_space_trim_value(tokens); parsed_value && !tokens.has_next_token()) + return parsed_value.release_nonnull(); + return ParseError::SyntaxError; default: break; } @@ -4761,4 +4765,58 @@ RefPtr Parser::parse_contain_value(TokenStream Parser::parse_white_space_trim_value(TokenStream& tokens) +{ + // none | discard-before || discard-after || discard-inner + + if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None)) + return none; + + auto transaction = tokens.begin_transaction(); + + RefPtr discard_before; + RefPtr discard_after; + RefPtr discard_inner; + + while (auto parsed_value = parse_css_value_for_property(PropertyID::WhiteSpaceTrim, tokens)) { + switch (parsed_value->as_keyword().keyword()) { + case Keyword::DiscardBefore: + if (discard_before) + return {}; + discard_before = parsed_value; + break; + case Keyword::DiscardAfter: + if (discard_after) + return {}; + discard_after = parsed_value; + break; + case Keyword::DiscardInner: + if (discard_inner) + return {}; + discard_inner = parsed_value; + break; + default: + return {}; + } + + if (!tokens.has_next_token()) + break; + } + + StyleValueVector parsed_values; + + // NOTE: The values are appended here rather than in the loop above to canonicalize their order. + if (discard_before) + parsed_values.append(discard_before.release_nonnull()); + if (discard_after) + parsed_values.append(discard_after.release_nonnull()); + if (discard_inner) + parsed_values.append(discard_inner.release_nonnull()); + + transaction.commit(); + + return StyleValueList::create(move(parsed_values), StyleValueList::Separator::Space); +} + } diff --git a/Libraries/LibWeb/CSS/Properties.json b/Libraries/LibWeb/CSS/Properties.json index 3035c443c4e..3f151d3a8bc 100644 --- a/Libraries/LibWeb/CSS/Properties.json +++ b/Libraries/LibWeb/CSS/Properties.json @@ -3142,6 +3142,17 @@ "white-space-collapse" ] }, + "white-space-trim": { + "animation-type": "discrete", + "inherited": false, + "initial": "none", + "valid-identifiers": [ + "none", + "discard-before", + "discard-after", + "discard-inner" + ] + }, "width": { "animation-type": "by-computed-value", "inherited": false, diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp index cd1531e73d6..4b9fe02a181 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp @@ -437,7 +437,7 @@ bool pseudo_element_supports_property(PseudoElement pseudo_element, PropertyID p // FIXME: text-wrap-style append_property("white-space"sv); append_property("white-space-collapse"sv); - // FIXME: white-space-trim + append_property("white-space-trim"sv); append_property("word-break"sv); // FIXME: word-space-transform append_property("word-spacing"sv); 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 266eec03be5..00a52882ba8 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 @@ -233,10 +233,11 @@ All properties associated with getComputedStyle(document.body): "230": "user-select", "231": "vertical-align", "232": "view-transition-name", - "233": "width", - "234": "x", - "235": "y", - "236": "z-index" + "233": "white-space-trim", + "234": "width", + "235": "x", + "236": "y", + "237": "z-index" } All properties associated with document.body.style by default: {} 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 366cc987c07..0ef0a0cdcd7 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 @@ -650,6 +650,8 @@ All supported properties and their default values exposed from CSSStylePropertie 'white-space': 'normal' 'whiteSpaceCollapse': 'collapse' 'white-space-collapse': 'collapse' +'whiteSpaceTrim': 'none' +'white-space-trim': 'none' 'width': '284px' 'wordBreak': 'normal' 'word-break': 'normal' diff --git a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt index 257eb397ac2..ed893c1de07 100644 --- a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt +++ b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt @@ -231,6 +231,7 @@ unicode-bidi: normal user-select: auto vertical-align: baseline view-transition-name: none +white-space-trim: none width: 784px x: 0px y: 0px diff --git a/Tests/LibWeb/Text/expected/css/white-space-trim.txt b/Tests/LibWeb/Text/expected/css/white-space-trim.txt new file mode 100644 index 00000000000..33b171c40c0 --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/white-space-trim.txt @@ -0,0 +1,3 @@ +none +discard-inner +discard-after discard-inner 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 27f5d7dfea7..7420828baa8 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 199 tests +Found 200 tests -189 Pass +190 Pass 10 Fail Pass accent-color Pass border-collapse @@ -199,6 +199,7 @@ Pass unicode-bidi Pass user-select Pass vertical-align Pass view-transition-name +Pass white-space-trim Fail width Pass x Pass y diff --git a/Tests/LibWeb/Text/input/css/white-space-trim.html b/Tests/LibWeb/Text/input/css/white-space-trim.html new file mode 100644 index 00000000000..dac78082620 --- /dev/null +++ b/Tests/LibWeb/Text/input/css/white-space-trim.html @@ -0,0 +1,21 @@ + + +
+
+
+ + \ No newline at end of file