LibWeb: Parse and propagate white-space-trim CSS property

This commit is contained in:
Callum Law 2025-05-18 02:21:42 +12:00 committed by Jelle Raaijmakers
commit 9480b1fc5c
Notes: github-actions[bot] 2025-05-29 10:06:01 +00:00
14 changed files with 151 additions and 7 deletions

View file

@ -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<LengthOrCalculated> ComputedProperties::letter_spacing() const
{
auto const& value = property(PropertyID::LetterSpacing);

View file

@ -102,6 +102,7 @@ public:
Variant<LengthOrCalculated, NumberOrCalculated> tab_size() const;
WhiteSpace white_space() const;
WhiteSpaceCollapse white_space_collapse() const;
WhiteSpaceTrimData white_space_trim() const;
WordBreak word_break() const;
Optional<LengthOrCalculated> word_spacing() const;
Optional<LengthOrCalculated> letter_spacing() const;

View file

@ -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<FlyString> 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; }

View file

@ -159,6 +159,9 @@
"difference",
"disc",
"discard",
"discard-before",
"discard-after",
"discard-inner",
"disclosure-closed",
"disclosure-open",
"discretionary-ligatures",

View file

@ -445,6 +445,7 @@ private:
RefPtr<CSSStyleValue const> parse_grid_area_shorthand_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue const> parse_grid_shorthand_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue const> parse_touch_action_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue const> parse_white_space_trim_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue const> parse_list_of_time_values(PropertyID, TokenStream<ComponentValue>&);

View file

@ -708,6 +708,10 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue const>> 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<CSSStyleValue const> Parser::parse_contain_value(TokenStream<ComponentVal
return StyleValueList::create(move(containments), StyleValueList::Separator::Space);
}
// https://www.w3.org/TR/css-text-4/#white-space-trim
RefPtr<CSSStyleValue const> Parser::parse_white_space_trim_value(TokenStream<ComponentValue>& 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<CSSStyleValue const> discard_before;
RefPtr<CSSStyleValue const> discard_after;
RefPtr<CSSStyleValue const> 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);
}
}

View file

@ -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,