mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +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();
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -159,6 +159,9 @@
|
|||
"difference",
|
||||
"disc",
|
||||
"discard",
|
||||
"discard-before",
|
||||
"discard-after",
|
||||
"discard-inner",
|
||||
"disclosure-closed",
|
||||
"disclosure-open",
|
||||
"discretionary-ligatures",
|
||||
|
|
|
@ -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>&);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
{}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
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
|
||||
|
||||
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
|
||||
|
|
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