mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00:00
LibWeb/CSS: Parse the container-type property
This applies size, inline-size, and style containment in some cases. There are other WPT tests for that, but we seem to not implement enough of containment for this to have an effect so I've not imported those. Gets us 35 WPT subtests.
This commit is contained in:
parent
b0bb775c05
commit
3916e33276
Notes:
github-actions[bot]
2025-09-30 21:07:12 +00:00
Author: https://github.com/AtkinsSJ
Commit: 3916e33276
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6350
Reviewed-by: https://github.com/tcl3 ✅
17 changed files with 355 additions and 7 deletions
|
|
@ -1887,6 +1887,38 @@ Containment ComputedProperties::contain() const
|
|||
return containment;
|
||||
}
|
||||
|
||||
ContainerType ComputedProperties::container_type() const
|
||||
{
|
||||
ContainerType container_type {};
|
||||
|
||||
auto const& value = property(PropertyID::Contain);
|
||||
|
||||
if (value.to_keyword() == Keyword::Normal)
|
||||
return container_type;
|
||||
|
||||
if (value.is_value_list()) {
|
||||
auto& values = value.as_value_list().values();
|
||||
for (auto const& item : values) {
|
||||
switch (item->to_keyword()) {
|
||||
case Keyword::Size:
|
||||
container_type.is_size_container = true;
|
||||
break;
|
||||
case Keyword::InlineSize:
|
||||
container_type.is_inline_size_container = true;
|
||||
break;
|
||||
case Keyword::ScrollState:
|
||||
container_type.is_scroll_state_container = true;
|
||||
break;
|
||||
default:
|
||||
dbgln("`{}` is not supported in `container-type` (yet?)", item->to_string(SerializationMode::Normal));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return container_type;
|
||||
}
|
||||
|
||||
MixBlendMode ComputedProperties::mix_blend_mode() const
|
||||
{
|
||||
auto const& value = property(PropertyID::MixBlendMode);
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ public:
|
|||
Isolation isolation() const;
|
||||
TouchActionData touch_action() const;
|
||||
Containment contain() const;
|
||||
ContainerType container_type() const;
|
||||
MixBlendMode mix_blend_mode() const;
|
||||
Optional<FlyString> view_transition_name() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,14 @@ struct Containment {
|
|||
bool is_empty() const { return !(size_containment || inline_size_containment || layout_containment || style_containment || paint_containment); }
|
||||
};
|
||||
|
||||
struct ContainerType {
|
||||
bool is_size_container : 1 { false };
|
||||
bool is_inline_size_container : 1 { false };
|
||||
bool is_scroll_state_container : 1 { false };
|
||||
|
||||
bool is_empty() const { return !(is_size_container || is_inline_size_container || is_scroll_state_container); }
|
||||
};
|
||||
|
||||
struct ScrollbarColorData {
|
||||
Color thumb_color { Color::Transparent };
|
||||
Color track_color { Color::Transparent };
|
||||
|
|
@ -242,6 +250,7 @@ public:
|
|||
static UserSelect user_select() { return UserSelect::Auto; }
|
||||
static Isolation isolation() { return Isolation::Auto; }
|
||||
static Containment contain() { return {}; }
|
||||
static ContainerType container_type() { return {}; }
|
||||
static MixBlendMode mix_blend_mode() { return MixBlendMode::Normal; }
|
||||
static Optional<int> z_index() { return OptionalNone(); }
|
||||
|
||||
|
|
@ -563,6 +572,7 @@ public:
|
|||
UserSelect user_select() const { return m_noninherited.user_select; }
|
||||
Isolation isolation() const { return m_noninherited.isolation; }
|
||||
Containment const& contain() const { return m_noninherited.contain; }
|
||||
ContainerType const& container_type() const { return m_noninherited.container_type; }
|
||||
MixBlendMode mix_blend_mode() const { return m_noninherited.mix_blend_mode; }
|
||||
Optional<FlyString> view_transition_name() const { return m_noninherited.view_transition_name; }
|
||||
TouchActionData touch_action() const { return m_noninherited.touch_action; }
|
||||
|
|
@ -841,6 +851,7 @@ protected:
|
|||
UserSelect user_select { InitialValues::user_select() };
|
||||
Isolation isolation { InitialValues::isolation() };
|
||||
Containment contain { InitialValues::contain() };
|
||||
ContainerType container_type { InitialValues::container_type() };
|
||||
MixBlendMode mix_blend_mode { InitialValues::mix_blend_mode() };
|
||||
WhiteSpaceTrimData white_space_trim;
|
||||
Optional<FlyString> view_transition_name;
|
||||
|
|
@ -1046,6 +1057,7 @@ public:
|
|||
void set_user_select(UserSelect value) { m_noninherited.user_select = value; }
|
||||
void set_isolation(Isolation value) { m_noninherited.isolation = value; }
|
||||
void set_contain(Containment value) { m_noninherited.contain = move(value); }
|
||||
void set_container_type(ContainerType value) { m_noninherited.container_type = move(value); }
|
||||
void set_mix_blend_mode(MixBlendMode value) { m_noninherited.mix_blend_mode = value; }
|
||||
void set_view_transition_name(Optional<FlyString> value) { m_noninherited.view_transition_name = move(value); }
|
||||
void set_touch_action(TouchActionData value) { m_noninherited.touch_action = value; }
|
||||
|
|
|
|||
|
|
@ -456,6 +456,7 @@
|
|||
"screen",
|
||||
"scroll",
|
||||
"scroll-position",
|
||||
"scroll-state",
|
||||
"scrollbar",
|
||||
"se-resize",
|
||||
"searchfield",
|
||||
|
|
|
|||
|
|
@ -395,6 +395,7 @@ private:
|
|||
RefPtr<PositionStyleValue const> parse_position_value(TokenStream<ComponentValue>&, PositionParsingMode = PositionParsingMode::Normal);
|
||||
RefPtr<StyleValue const> parse_filter_value_list_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_contain_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_container_type_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StringStyleValue const> parse_opentype_tag_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<FontSourceStyleValue const> parse_font_source_value(TokenStream<ComponentValue>&);
|
||||
|
||||
|
|
|
|||
|
|
@ -537,6 +537,14 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_css_value(Pr
|
|||
if (auto parsed_value = parse_columns_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::Contain:
|
||||
if (auto parsed_value = parse_contain_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::ContainerType:
|
||||
if (auto parsed_value = parse_container_type_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::Content:
|
||||
if (auto parsed_value = parse_content_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
|
|
@ -815,10 +823,6 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_css_value(Pr
|
|||
if (auto parsed_value = parse_scale_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::Contain:
|
||||
if (auto parsed_value = parse_contain_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::WhiteSpace:
|
||||
if (auto parsed_value = parse_white_space_shorthand(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
|
|
@ -6073,6 +6077,59 @@ RefPtr<StyleValue const> Parser::parse_contain_value(TokenStream<ComponentValue>
|
|||
return StyleValueList::create(move(containment_values), StyleValueList::Separator::Space);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-conditional-5/#propdef-container-type
|
||||
RefPtr<StyleValue const> Parser::parse_container_type_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// normal | [ [ size | inline-size ] || scroll-state ]
|
||||
auto transaction = tokens.begin_transaction();
|
||||
tokens.discard_whitespace();
|
||||
|
||||
// normal
|
||||
if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::Normal)) {
|
||||
transaction.commit();
|
||||
return none;
|
||||
}
|
||||
|
||||
// [ [ size | inline-size ] || scroll-state ]
|
||||
if (!tokens.has_next_token())
|
||||
return {};
|
||||
|
||||
RefPtr<StyleValue const> size_value;
|
||||
RefPtr<StyleValue const> scroll_state_value;
|
||||
|
||||
while (tokens.has_next_token()) {
|
||||
auto keyword_value = parse_keyword_value(tokens);
|
||||
if (!keyword_value)
|
||||
return {};
|
||||
switch (keyword_value->to_keyword()) {
|
||||
case Keyword::Size:
|
||||
case Keyword::InlineSize:
|
||||
if (size_value)
|
||||
return {};
|
||||
size_value = move(keyword_value);
|
||||
break;
|
||||
case Keyword::ScrollState:
|
||||
if (scroll_state_value)
|
||||
return {};
|
||||
scroll_state_value = move(keyword_value);
|
||||
break;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
tokens.discard_whitespace();
|
||||
}
|
||||
|
||||
StyleValueVector containment_values;
|
||||
if (size_value)
|
||||
containment_values.append(size_value.release_nonnull());
|
||||
if (scroll_state_value)
|
||||
containment_values.append(scroll_state_value.release_nonnull());
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return StyleValueList::create(move(containment_values), StyleValueList::Separator::Space);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-text-4/#white-space-trim
|
||||
RefPtr<StyleValue const> Parser::parse_white_space_trim_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1343,6 +1343,18 @@
|
|||
"contain"
|
||||
]
|
||||
},
|
||||
"container-type": {
|
||||
"affects-stacking-context": true,
|
||||
"animation-type": "none",
|
||||
"inherited": false,
|
||||
"initial": "normal",
|
||||
"valid-identifiers": [
|
||||
"normal",
|
||||
"size",
|
||||
"inline-size",
|
||||
"scroll-state"
|
||||
]
|
||||
},
|
||||
"content": {
|
||||
"animation-type": "discrete",
|
||||
"inherited": false,
|
||||
|
|
|
|||
|
|
@ -898,6 +898,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_container_type(computed_style.container_type());
|
||||
computed_values.set_shape_rendering(computed_values.shape_rendering());
|
||||
computed_values.set_will_change(computed_style.will_change());
|
||||
|
||||
|
|
@ -1226,6 +1227,9 @@ bool Node::has_size_containment() const
|
|||
if (computed_values().contain().size_containment)
|
||||
return true;
|
||||
|
||||
if (computed_values().container_type().is_size_container)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-inline-size
|
||||
|
|
@ -1250,6 +1254,9 @@ bool Node::has_inline_size_containment() const
|
|||
if (computed_values().contain().inline_size_containment)
|
||||
return true;
|
||||
|
||||
if (computed_values().container_type().is_inline_size_container)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
// https://drafts.csswg.org/css-contain-2/#containment-layout
|
||||
|
|
@ -1289,6 +1296,9 @@ bool Node::has_style_containment() const
|
|||
if (computed_values().contain().style_containment)
|
||||
return true;
|
||||
|
||||
if (computed_values().container_type().is_size_container || computed_values().container_type().is_inline_size_container)
|
||||
return true;
|
||||
|
||||
// https://drafts.csswg.org/css-contain-2/#valdef-content-visibility-auto
|
||||
// Changes the used value of the 'contain' property so as to turn on layout containment, style containment, and
|
||||
// paint containment for the element.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue