mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-16 21:20:18 +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;
|
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
|
MixBlendMode ComputedProperties::mix_blend_mode() const
|
||||||
{
|
{
|
||||||
auto const& value = property(PropertyID::MixBlendMode);
|
auto const& value = property(PropertyID::MixBlendMode);
|
||||||
|
|
|
@ -183,6 +183,7 @@ public:
|
||||||
Isolation isolation() const;
|
Isolation isolation() const;
|
||||||
TouchActionData touch_action() const;
|
TouchActionData touch_action() const;
|
||||||
Containment contain() const;
|
Containment contain() const;
|
||||||
|
ContainerType container_type() const;
|
||||||
MixBlendMode mix_blend_mode() const;
|
MixBlendMode mix_blend_mode() const;
|
||||||
Optional<FlyString> view_transition_name() 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); }
|
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 {
|
struct ScrollbarColorData {
|
||||||
Color thumb_color { Color::Transparent };
|
Color thumb_color { Color::Transparent };
|
||||||
Color track_color { Color::Transparent };
|
Color track_color { Color::Transparent };
|
||||||
|
@ -242,6 +250,7 @@ public:
|
||||||
static UserSelect user_select() { return UserSelect::Auto; }
|
static UserSelect user_select() { return UserSelect::Auto; }
|
||||||
static Isolation isolation() { return Isolation::Auto; }
|
static Isolation isolation() { return Isolation::Auto; }
|
||||||
static Containment contain() { return {}; }
|
static Containment contain() { return {}; }
|
||||||
|
static ContainerType container_type() { return {}; }
|
||||||
static MixBlendMode mix_blend_mode() { return MixBlendMode::Normal; }
|
static MixBlendMode mix_blend_mode() { return MixBlendMode::Normal; }
|
||||||
static Optional<int> z_index() { return OptionalNone(); }
|
static Optional<int> z_index() { return OptionalNone(); }
|
||||||
|
|
||||||
|
@ -563,6 +572,7 @@ public:
|
||||||
UserSelect user_select() const { return m_noninherited.user_select; }
|
UserSelect user_select() const { return m_noninherited.user_select; }
|
||||||
Isolation isolation() const { return m_noninherited.isolation; }
|
Isolation isolation() const { return m_noninherited.isolation; }
|
||||||
Containment const& contain() const { return m_noninherited.contain; }
|
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; }
|
MixBlendMode mix_blend_mode() const { return m_noninherited.mix_blend_mode; }
|
||||||
Optional<FlyString> view_transition_name() const { return m_noninherited.view_transition_name; }
|
Optional<FlyString> view_transition_name() const { return m_noninherited.view_transition_name; }
|
||||||
TouchActionData touch_action() const { return m_noninherited.touch_action; }
|
TouchActionData touch_action() const { return m_noninherited.touch_action; }
|
||||||
|
@ -841,6 +851,7 @@ protected:
|
||||||
UserSelect user_select { InitialValues::user_select() };
|
UserSelect user_select { InitialValues::user_select() };
|
||||||
Isolation isolation { InitialValues::isolation() };
|
Isolation isolation { InitialValues::isolation() };
|
||||||
Containment contain { InitialValues::contain() };
|
Containment contain { InitialValues::contain() };
|
||||||
|
ContainerType container_type { InitialValues::container_type() };
|
||||||
MixBlendMode mix_blend_mode { InitialValues::mix_blend_mode() };
|
MixBlendMode mix_blend_mode { InitialValues::mix_blend_mode() };
|
||||||
WhiteSpaceTrimData white_space_trim;
|
WhiteSpaceTrimData white_space_trim;
|
||||||
Optional<FlyString> view_transition_name;
|
Optional<FlyString> view_transition_name;
|
||||||
|
@ -1046,6 +1057,7 @@ public:
|
||||||
void set_user_select(UserSelect value) { m_noninherited.user_select = value; }
|
void set_user_select(UserSelect value) { m_noninherited.user_select = value; }
|
||||||
void set_isolation(Isolation value) { m_noninherited.isolation = value; }
|
void set_isolation(Isolation value) { m_noninherited.isolation = value; }
|
||||||
void set_contain(Containment value) { m_noninherited.contain = move(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_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_view_transition_name(Optional<FlyString> value) { m_noninherited.view_transition_name = move(value); }
|
||||||
void set_touch_action(TouchActionData value) { m_noninherited.touch_action = value; }
|
void set_touch_action(TouchActionData value) { m_noninherited.touch_action = value; }
|
||||||
|
|
|
@ -456,6 +456,7 @@
|
||||||
"screen",
|
"screen",
|
||||||
"scroll",
|
"scroll",
|
||||||
"scroll-position",
|
"scroll-position",
|
||||||
|
"scroll-state",
|
||||||
"scrollbar",
|
"scrollbar",
|
||||||
"se-resize",
|
"se-resize",
|
||||||
"searchfield",
|
"searchfield",
|
||||||
|
|
|
@ -395,6 +395,7 @@ private:
|
||||||
RefPtr<PositionStyleValue const> parse_position_value(TokenStream<ComponentValue>&, PositionParsingMode = PositionParsingMode::Normal);
|
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_filter_value_list_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<StyleValue const> parse_contain_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<StringStyleValue const> parse_opentype_tag_value(TokenStream<ComponentValue>&);
|
||||||
RefPtr<FontSourceStyleValue const> parse_font_source_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())
|
if (auto parsed_value = parse_columns_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::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:
|
case PropertyID::Content:
|
||||||
if (auto parsed_value = parse_content_value(tokens); parsed_value && !tokens.has_next_token())
|
if (auto parsed_value = parse_content_value(tokens); parsed_value && !tokens.has_next_token())
|
||||||
return parsed_value.release_nonnull();
|
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())
|
if (auto parsed_value = parse_scale_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::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:
|
case PropertyID::WhiteSpace:
|
||||||
if (auto parsed_value = parse_white_space_shorthand(tokens); parsed_value && !tokens.has_next_token())
|
if (auto parsed_value = parse_white_space_shorthand(tokens); parsed_value && !tokens.has_next_token())
|
||||||
return parsed_value.release_nonnull();
|
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);
|
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
|
// https://www.w3.org/TR/css-text-4/#white-space-trim
|
||||||
RefPtr<StyleValue const> Parser::parse_white_space_trim_value(TokenStream<ComponentValue>& tokens)
|
RefPtr<StyleValue const> Parser::parse_white_space_trim_value(TokenStream<ComponentValue>& tokens)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1343,6 +1343,18 @@
|
||||||
"contain"
|
"contain"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"container-type": {
|
||||||
|
"affects-stacking-context": true,
|
||||||
|
"animation-type": "none",
|
||||||
|
"inherited": false,
|
||||||
|
"initial": "normal",
|
||||||
|
"valid-identifiers": [
|
||||||
|
"normal",
|
||||||
|
"size",
|
||||||
|
"inline-size",
|
||||||
|
"scroll-state"
|
||||||
|
]
|
||||||
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"animation-type": "discrete",
|
"animation-type": "discrete",
|
||||||
"inherited": false,
|
"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_mix_blend_mode(computed_style.mix_blend_mode());
|
||||||
computed_values.set_view_transition_name(computed_style.view_transition_name());
|
computed_values.set_view_transition_name(computed_style.view_transition_name());
|
||||||
computed_values.set_contain(computed_style.contain());
|
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_shape_rendering(computed_values.shape_rendering());
|
||||||
computed_values.set_will_change(computed_style.will_change());
|
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)
|
if (computed_values().contain().size_containment)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (computed_values().container_type().is_size_container)
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// https://drafts.csswg.org/css-contain-2/#containment-inline-size
|
// 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)
|
if (computed_values().contain().inline_size_containment)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (computed_values().container_type().is_inline_size_container)
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// https://drafts.csswg.org/css-contain-2/#containment-layout
|
// 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)
|
if (computed_values().contain().style_containment)
|
||||||
return true;
|
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
|
// 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
|
// Changes the used value of the 'contain' property so as to turn on layout containment, style containment, and
|
||||||
// paint containment for the element.
|
// paint containment for the element.
|
||||||
|
|
|
@ -149,6 +149,7 @@ All properties associated with getComputedStyle(document.body):
|
||||||
"column-span",
|
"column-span",
|
||||||
"column-width",
|
"column-width",
|
||||||
"contain",
|
"contain",
|
||||||
|
"container-type",
|
||||||
"content",
|
"content",
|
||||||
"content-visibility",
|
"content-visibility",
|
||||||
"counter-increment",
|
"counter-increment",
|
||||||
|
|
|
@ -358,6 +358,8 @@ All supported properties and their default values exposed from CSSStylePropertie
|
||||||
'column-width': 'auto'
|
'column-width': 'auto'
|
||||||
'columns': 'auto'
|
'columns': 'auto'
|
||||||
'contain': 'none'
|
'contain': 'none'
|
||||||
|
'containerType': 'normal'
|
||||||
|
'container-type': 'normal'
|
||||||
'content': 'normal'
|
'content': 'normal'
|
||||||
'contentVisibility': 'visible'
|
'contentVisibility': 'visible'
|
||||||
'content-visibility': 'visible'
|
'content-visibility': 'visible'
|
||||||
|
|
|
@ -147,6 +147,7 @@ column-height: auto
|
||||||
column-span: none
|
column-span: none
|
||||||
column-width: auto
|
column-width: auto
|
||||||
contain: none
|
contain: none
|
||||||
|
container-type: normal
|
||||||
content: normal
|
content: normal
|
||||||
content-visibility: visible
|
content-visibility: visible
|
||||||
counter-increment: none
|
counter-increment: none
|
||||||
|
@ -174,7 +175,7 @@ grid-row-start: auto
|
||||||
grid-template-areas: none
|
grid-template-areas: none
|
||||||
grid-template-columns: none
|
grid-template-columns: none
|
||||||
grid-template-rows: none
|
grid-template-rows: none
|
||||||
height: 2640px
|
height: 2655px
|
||||||
inline-size: 784px
|
inline-size: 784px
|
||||||
inset-block-end: auto
|
inset-block-end: auto
|
||||||
inset-block-start: auto
|
inset-block-start: auto
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
Harness status: OK
|
Harness status: OK
|
||||||
|
|
||||||
Found 265 tests
|
Found 266 tests
|
||||||
|
|
||||||
259 Pass
|
260 Pass
|
||||||
6 Fail
|
6 Fail
|
||||||
Pass accent-color
|
Pass accent-color
|
||||||
Pass border-collapse
|
Pass border-collapse
|
||||||
|
@ -147,6 +147,7 @@ Pass column-gap
|
||||||
Pass column-span
|
Pass column-span
|
||||||
Pass column-width
|
Pass column-width
|
||||||
Pass contain
|
Pass contain
|
||||||
|
Pass container-type
|
||||||
Pass content
|
Pass content
|
||||||
Pass content-visibility
|
Pass content-visibility
|
||||||
Pass counter-increment
|
Pass counter-increment
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 5 tests
|
||||||
|
|
||||||
|
5 Pass
|
||||||
|
Pass Property container-type value 'initial'
|
||||||
|
Pass Property container-type value 'unset'
|
||||||
|
Pass Property container-type value 'inline-size'
|
||||||
|
Pass Property container-type value 'size'
|
||||||
|
Pass Property container-type value 'normal'
|
|
@ -0,0 +1,35 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 30 tests
|
||||||
|
|
||||||
|
30 Pass
|
||||||
|
Pass e.style['container-type'] = "initial" should set the property value
|
||||||
|
Pass e.style['container-type'] = "inherit" should set the property value
|
||||||
|
Pass e.style['container-type'] = "unset" should set the property value
|
||||||
|
Pass e.style['container-type'] = "revert" should set the property value
|
||||||
|
Pass e.style['container-type'] = "normal" should set the property value
|
||||||
|
Pass e.style['container-type'] = "size" should set the property value
|
||||||
|
Pass e.style['container-type'] = "inline-size" should set the property value
|
||||||
|
Pass e.style['container-type'] = "none" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "auto" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "block-size" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "normal normal" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "normal inline-size" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "inline-size normal" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "inline-size inline-size" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "inline-size block-size" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "block-size inline-size" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "size inline-size" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "inline-size size" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "normal, normal" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "foo" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "\"foo\"" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "foo, bar" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "#fff" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "1px" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "default" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "size nonsense" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "style" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "inline-size style" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "style inline-size" should not set the property value
|
||||||
|
Pass e.style['container-type'] = "style size" should not set the property value
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Computed values of container-type</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#container-type">
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<script src="../../../css/support/computed-testcommon.js"></script>
|
||||||
|
<script src="support/cq-testcommon.js"></script>
|
||||||
|
<div id="target"></div>
|
||||||
|
<script>
|
||||||
|
setup(() => assert_implements_size_container_queries());
|
||||||
|
|
||||||
|
test_computed_value('container-type', 'initial', 'normal');
|
||||||
|
test_computed_value('container-type', 'unset', 'normal');
|
||||||
|
test_computed_value('container-type', 'inline-size');
|
||||||
|
test_computed_value('container-type', 'size');
|
||||||
|
test_computed_value('container-type', 'normal');
|
||||||
|
</script>
|
|
@ -0,0 +1,44 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Conditional Test: Parsing of container-type</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#container-type">
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<script src="../../../css/support/parsing-testcommon.js"></script>
|
||||||
|
<script src="support/cq-testcommon.js"></script>
|
||||||
|
<div id="target"></div>
|
||||||
|
<script>
|
||||||
|
setup(() => assert_implements_size_container_queries());
|
||||||
|
|
||||||
|
test_valid_value('container-type', 'initial');
|
||||||
|
test_valid_value('container-type', 'inherit');
|
||||||
|
test_valid_value('container-type', 'unset');
|
||||||
|
test_valid_value('container-type', 'revert');
|
||||||
|
test_valid_value('container-type', 'normal');
|
||||||
|
test_valid_value('container-type', 'size');
|
||||||
|
test_valid_value('container-type', 'inline-size');
|
||||||
|
|
||||||
|
test_invalid_value('container-type', 'none');
|
||||||
|
test_invalid_value('container-type', 'auto');
|
||||||
|
test_invalid_value('container-type', 'block-size');
|
||||||
|
test_invalid_value('container-type', 'normal normal');
|
||||||
|
test_invalid_value('container-type', 'normal inline-size');
|
||||||
|
test_invalid_value('container-type', 'inline-size normal');
|
||||||
|
test_invalid_value('container-type', 'inline-size inline-size');
|
||||||
|
test_invalid_value('container-type', 'inline-size block-size');
|
||||||
|
test_invalid_value('container-type', 'block-size inline-size');
|
||||||
|
test_invalid_value('container-type', 'size inline-size');
|
||||||
|
test_invalid_value('container-type', 'inline-size size');
|
||||||
|
test_invalid_value('container-type', 'normal, normal');
|
||||||
|
test_invalid_value('container-type', 'foo');
|
||||||
|
test_invalid_value('container-type', '"foo"');
|
||||||
|
test_invalid_value('container-type', 'foo, bar');
|
||||||
|
test_invalid_value('container-type', '#fff');
|
||||||
|
test_invalid_value('container-type', '1px');
|
||||||
|
test_invalid_value('container-type', 'default');
|
||||||
|
test_invalid_value('container-type', 'size nonsense');
|
||||||
|
test_invalid_value('container-type', 'style');
|
||||||
|
test_invalid_value('container-type', 'inline-size style', 'style inline-size');
|
||||||
|
test_invalid_value('container-type', 'style inline-size');
|
||||||
|
test_invalid_value('container-type', 'style size');
|
||||||
|
</script>
|
|
@ -0,0 +1,110 @@
|
||||||
|
function assert_implements_size_container_queries() {
|
||||||
|
assert_implements(CSS.supports("container-type:size"),
|
||||||
|
"Basic support for size container queries required");
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_implements_scroll_state_container_queries() {
|
||||||
|
assert_implements(CSS.supports("container-type:scroll-state"),
|
||||||
|
"Basic support for scroll-state container queries required");
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_implements_style_container_queries() {
|
||||||
|
// TODO: Replace with CSS.supports() when/if this can be expressed with at-rule().
|
||||||
|
const sheet = new CSSStyleSheet();
|
||||||
|
// No support means the style() function is <general-enclosed> which should
|
||||||
|
// affect serialization. Although serialization for <general-enclosed> is not
|
||||||
|
// specified[1], unknown function names are unlikely to be resolved to be
|
||||||
|
// serialized lower-case. Also, keeping the case is currently interoperable.
|
||||||
|
//
|
||||||
|
// [1] https://github.com/w3c/csswg-drafts/issues/7266
|
||||||
|
sheet.replaceSync('@container STYLE(--foo: bar){}');
|
||||||
|
assert_implements(sheet.cssRules[0].containerQuery === "style(--foo: bar)",
|
||||||
|
"Basic support for style container queries required");
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup_container_query_main() {
|
||||||
|
const main = document.querySelector("#cq-main");
|
||||||
|
while (main.firstChild)
|
||||||
|
main.firstChild.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_container_query_style(text) {
|
||||||
|
let style = document.createElement('style');
|
||||||
|
style.innerText = text;
|
||||||
|
document.querySelector("#cq-main").append(style);
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_cq_rule_invalid(query) {
|
||||||
|
const ruleText = `@container ${query} {}`;
|
||||||
|
test(t => {
|
||||||
|
t.add_cleanup(cleanup_container_query_main);
|
||||||
|
let style = set_container_query_style(ruleText);
|
||||||
|
assert_equals(style.sheet.rules.length, 0);
|
||||||
|
}, `@container rule should be invalid: ${ruleText} {}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_cq_rule_valid(query) {
|
||||||
|
const ruleText = `@container ${query} {}`;
|
||||||
|
test(t => {
|
||||||
|
t.add_cleanup(cleanup_container_query_main);
|
||||||
|
let style = set_container_query_style(`@container ${query} {}`);
|
||||||
|
assert_equals(style.sheet.rules.length, 1);
|
||||||
|
}, `@container rule should be valid: ${ruleText} {}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_cq_condition_invalid(condition) {
|
||||||
|
test(t => {
|
||||||
|
t.add_cleanup(cleanup_container_query_main);
|
||||||
|
let style = set_container_query_style(`@container name ${condition} {}`);
|
||||||
|
assert_equals(style.sheet.rules.length, 0);
|
||||||
|
}, `Query condition should be invalid: ${condition}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that 1) the condition parses, and 2) is either "unknown" or not, as
|
||||||
|
// specified.
|
||||||
|
function test_cq_condition_valid(condition, unknown) {
|
||||||
|
test(t => {
|
||||||
|
t.add_cleanup(cleanup_container_query_main);
|
||||||
|
let style = set_container_query_style(`
|
||||||
|
@container name ${condition} {}
|
||||||
|
@container name (${condition}) or (not (${condition})) { main { --match:true; } }
|
||||||
|
`);
|
||||||
|
assert_equals(style.sheet.rules.length, 2);
|
||||||
|
const expected = unknown ? '' : 'true';
|
||||||
|
assert_equals(getComputedStyle(document.querySelector("#cq-main")).getPropertyValue('--match'), expected);
|
||||||
|
}, `Query condition should be valid${unknown ? ' but unknown' : ''}: ${condition}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_cq_condition_known(condition) {
|
||||||
|
test_cq_condition_valid(condition, false /* unknown */);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_cq_condition_unknown(condition) {
|
||||||
|
test_cq_condition_valid(condition, true /* unknown */);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_container_name_invalid(container_name) {
|
||||||
|
test(t => {
|
||||||
|
t.add_cleanup(cleanup_container_query_main);
|
||||||
|
let style = set_container_query_style(`@container ${container_name} not (width) {}`);
|
||||||
|
assert_equals(style.sheet.rules.length, 0);
|
||||||
|
}, `Container name: ${container_name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_container_name_valid(container_name) {
|
||||||
|
test(t => {
|
||||||
|
t.add_cleanup(cleanup_container_query_main);
|
||||||
|
let style = set_container_query_style(`@container ${container_name} not (width) {}`);
|
||||||
|
assert_equals(style.sheet.rules.length, 1);
|
||||||
|
}, `Container name: ${container_name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_cq_condition_serialization(query, expected) {
|
||||||
|
test(t => {
|
||||||
|
t.add_cleanup(cleanup_container_query_main);
|
||||||
|
let style = set_container_query_style(`@container ${query} {}`);
|
||||||
|
assert_equals(style.sheet.rules.length, 1);
|
||||||
|
assert_equals(style.sheet.rules[0].conditionText, expected);
|
||||||
|
}, `@container conditionText serialization: ${query}`);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue