mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-23 09:48:56 +00:00
LibWeb: Parse and propagate white-space-trim
CSS property
This commit is contained in:
parent
50bdd2cb85
commit
9480b1fc5c
Notes:
github-actions[bot]
2025-05-29 10:06:01 +00:00
Author: https://github.com/Calme1709
Commit: 9480b1fc5c
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4832
Reviewed-by: https://github.com/AtkinsSJ
Reviewed-by: https://github.com/gmta ✅
14 changed files with 151 additions and 7 deletions
|
@ -836,6 +836,38 @@ WhiteSpaceCollapse ComputedProperties::white_space_collapse() const
|
||||||
return keyword_to_white_space_collapse(value.to_keyword()).release_value();
|
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
|
Optional<LengthOrCalculated> ComputedProperties::letter_spacing() const
|
||||||
{
|
{
|
||||||
auto const& value = property(PropertyID::LetterSpacing);
|
auto const& value = property(PropertyID::LetterSpacing);
|
||||||
|
|
|
@ -102,6 +102,7 @@ public:
|
||||||
Variant<LengthOrCalculated, NumberOrCalculated> tab_size() const;
|
Variant<LengthOrCalculated, NumberOrCalculated> tab_size() const;
|
||||||
WhiteSpace white_space() const;
|
WhiteSpace white_space() const;
|
||||||
WhiteSpaceCollapse white_space_collapse() const;
|
WhiteSpaceCollapse white_space_collapse() const;
|
||||||
|
WhiteSpaceTrimData white_space_trim() const;
|
||||||
WordBreak word_break() const;
|
WordBreak word_break() const;
|
||||||
Optional<LengthOrCalculated> word_spacing() const;
|
Optional<LengthOrCalculated> word_spacing() const;
|
||||||
Optional<LengthOrCalculated> letter_spacing() const;
|
Optional<LengthOrCalculated> letter_spacing() const;
|
||||||
|
|
|
@ -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 {
|
struct TransformOrigin {
|
||||||
CSS::LengthPercentage x { Percentage(50) };
|
CSS::LengthPercentage x { Percentage(50) };
|
||||||
CSS::LengthPercentage y { Percentage(50) };
|
CSS::LengthPercentage y { Percentage(50) };
|
||||||
|
@ -427,6 +433,7 @@ public:
|
||||||
CSS::Positioning position() const { return m_noninherited.position; }
|
CSS::Positioning position() const { return m_noninherited.position; }
|
||||||
CSS::WhiteSpace white_space() const { return m_inherited.white_space; }
|
CSS::WhiteSpace white_space() const { return m_inherited.white_space; }
|
||||||
CSS::WhiteSpaceCollapse white_space_collapse() const { return m_inherited.white_space_collapse; }
|
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; }
|
CSS::LengthOrCalculated word_spacing() const { return m_inherited.word_spacing; }
|
||||||
LengthOrCalculated letter_spacing() const { return m_inherited.letter_spacing; }
|
LengthOrCalculated letter_spacing() const { return m_inherited.letter_spacing; }
|
||||||
CSS::FlexDirection flex_direction() const { return m_noninherited.flex_direction; }
|
CSS::FlexDirection flex_direction() const { return m_noninherited.flex_direction; }
|
||||||
|
@ -742,6 +749,7 @@ protected:
|
||||||
CSS::Isolation isolation { InitialValues::isolation() };
|
CSS::Isolation isolation { InitialValues::isolation() };
|
||||||
CSS::Containment contain { InitialValues::contain() };
|
CSS::Containment contain { InitialValues::contain() };
|
||||||
CSS::MixBlendMode mix_blend_mode { InitialValues::mix_blend_mode() };
|
CSS::MixBlendMode mix_blend_mode { InitialValues::mix_blend_mode() };
|
||||||
|
WhiteSpaceTrimData white_space_trim;
|
||||||
Optional<FlyString> view_transition_name;
|
Optional<FlyString> view_transition_name;
|
||||||
TouchActionData touch_action;
|
TouchActionData touch_action;
|
||||||
|
|
||||||
|
@ -827,6 +835,7 @@ public:
|
||||||
void set_position(CSS::Positioning position) { m_noninherited.position = position; }
|
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(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_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_spacing(CSS::LengthOrCalculated value) { m_inherited.word_spacing = move(value); }
|
||||||
void set_word_break(CSS::WordBreak value) { m_inherited.word_break = 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; }
|
void set_letter_spacing(CSS::LengthOrCalculated value) { m_inherited.letter_spacing = value; }
|
||||||
|
|
|
@ -159,6 +159,9 @@
|
||||||
"difference",
|
"difference",
|
||||||
"disc",
|
"disc",
|
||||||
"discard",
|
"discard",
|
||||||
|
"discard-before",
|
||||||
|
"discard-after",
|
||||||
|
"discard-inner",
|
||||||
"disclosure-closed",
|
"disclosure-closed",
|
||||||
"disclosure-open",
|
"disclosure-open",
|
||||||
"discretionary-ligatures",
|
"discretionary-ligatures",
|
||||||
|
|
|
@ -445,6 +445,7 @@ private:
|
||||||
RefPtr<CSSStyleValue const> parse_grid_area_shorthand_value(TokenStream<ComponentValue>&);
|
RefPtr<CSSStyleValue const> parse_grid_area_shorthand_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<CSSStyleValue const> parse_grid_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_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>&);
|
RefPtr<CSSStyleValue const> parse_list_of_time_values(PropertyID, TokenStream<ComponentValue>&);
|
||||||
|
|
||||||
|
|
|
@ -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())
|
if (auto parsed_value = parse_contain_value(tokens); parsed_value && !tokens.has_next_token())
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
return ParseError::SyntaxError;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4761,4 +4765,58 @@ RefPtr<CSSStyleValue const> Parser::parse_contain_value(TokenStream<ComponentVal
|
||||||
return StyleValueList::create(move(containments), StyleValueList::Separator::Space);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3142,6 +3142,17 @@
|
||||||
"white-space-collapse"
|
"white-space-collapse"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"white-space-trim": {
|
||||||
|
"animation-type": "discrete",
|
||||||
|
"inherited": false,
|
||||||
|
"initial": "none",
|
||||||
|
"valid-identifiers": [
|
||||||
|
"none",
|
||||||
|
"discard-before",
|
||||||
|
"discard-after",
|
||||||
|
"discard-inner"
|
||||||
|
]
|
||||||
|
},
|
||||||
"width": {
|
"width": {
|
||||||
"animation-type": "by-computed-value",
|
"animation-type": "by-computed-value",
|
||||||
"inherited": false,
|
"inherited": false,
|
||||||
|
|
|
@ -437,7 +437,7 @@ bool pseudo_element_supports_property(PseudoElement pseudo_element, PropertyID p
|
||||||
// FIXME: text-wrap-style
|
// FIXME: text-wrap-style
|
||||||
append_property("white-space"sv);
|
append_property("white-space"sv);
|
||||||
append_property("white-space-collapse"sv);
|
append_property("white-space-collapse"sv);
|
||||||
// FIXME: white-space-trim
|
append_property("white-space-trim"sv);
|
||||||
append_property("word-break"sv);
|
append_property("word-break"sv);
|
||||||
// FIXME: word-space-transform
|
// FIXME: word-space-transform
|
||||||
append_property("word-spacing"sv);
|
append_property("word-spacing"sv);
|
||||||
|
|
|
@ -233,10 +233,11 @@ All properties associated with getComputedStyle(document.body):
|
||||||
"230": "user-select",
|
"230": "user-select",
|
||||||
"231": "vertical-align",
|
"231": "vertical-align",
|
||||||
"232": "view-transition-name",
|
"232": "view-transition-name",
|
||||||
"233": "width",
|
"233": "white-space-trim",
|
||||||
"234": "x",
|
"234": "width",
|
||||||
"235": "y",
|
"235": "x",
|
||||||
"236": "z-index"
|
"236": "y",
|
||||||
|
"237": "z-index"
|
||||||
}
|
}
|
||||||
All properties associated with document.body.style by default:
|
All properties associated with document.body.style by default:
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -650,6 +650,8 @@ All supported properties and their default values exposed from CSSStylePropertie
|
||||||
'white-space': 'normal'
|
'white-space': 'normal'
|
||||||
'whiteSpaceCollapse': 'collapse'
|
'whiteSpaceCollapse': 'collapse'
|
||||||
'white-space-collapse': 'collapse'
|
'white-space-collapse': 'collapse'
|
||||||
|
'whiteSpaceTrim': 'none'
|
||||||
|
'white-space-trim': 'none'
|
||||||
'width': '284px'
|
'width': '284px'
|
||||||
'wordBreak': 'normal'
|
'wordBreak': 'normal'
|
||||||
'word-break': 'normal'
|
'word-break': 'normal'
|
||||||
|
|
|
@ -231,6 +231,7 @@ unicode-bidi: normal
|
||||||
user-select: auto
|
user-select: auto
|
||||||
vertical-align: baseline
|
vertical-align: baseline
|
||||||
view-transition-name: none
|
view-transition-name: none
|
||||||
|
white-space-trim: none
|
||||||
width: 784px
|
width: 784px
|
||||||
x: 0px
|
x: 0px
|
||||||
y: 0px
|
y: 0px
|
||||||
|
|
3
Tests/LibWeb/Text/expected/css/white-space-trim.txt
Normal file
3
Tests/LibWeb/Text/expected/css/white-space-trim.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
none
|
||||||
|
discard-inner
|
||||||
|
discard-after discard-inner
|
|
@ -1,8 +1,8 @@
|
||||||
Harness status: OK
|
Harness status: OK
|
||||||
|
|
||||||
Found 199 tests
|
Found 200 tests
|
||||||
|
|
||||||
189 Pass
|
190 Pass
|
||||||
10 Fail
|
10 Fail
|
||||||
Pass accent-color
|
Pass accent-color
|
||||||
Pass border-collapse
|
Pass border-collapse
|
||||||
|
@ -199,6 +199,7 @@ Pass unicode-bidi
|
||||||
Pass user-select
|
Pass user-select
|
||||||
Pass vertical-align
|
Pass vertical-align
|
||||||
Pass view-transition-name
|
Pass view-transition-name
|
||||||
|
Pass white-space-trim
|
||||||
Fail width
|
Fail width
|
||||||
Pass x
|
Pass x
|
||||||
Pass y
|
Pass y
|
||||||
|
|
21
Tests/LibWeb/Text/input/css/white-space-trim.html
Normal file
21
Tests/LibWeb/Text/input/css/white-space-trim.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
#single-value {
|
||||||
|
white-space-trim: discard-inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
#multiple-values {
|
||||||
|
white-space-trim: discard-inner discard-after;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="default"></div>
|
||||||
|
<div id="single-value"></div>
|
||||||
|
<div id="multiple-values"></div>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
println(getComputedStyle(document.getElementById("default")).whiteSpaceTrim);
|
||||||
|
println(getComputedStyle(document.getElementById("single-value")).whiteSpaceTrim);
|
||||||
|
println(getComputedStyle(document.getElementById("multiple-values")).whiteSpaceTrim);
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue