Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[CSS Container Queries] Update query grammar to the spec
https://bugs.webkit.org/show_bug.cgi?id=243449
<rdar://97967682>

Reviewed by Tim Nguyen.

The spec was changed to allow logical operators on top level without parenthesis making

@container not (foo)

legal.

https://drafts.csswg.org/css-contain-3/#container-rule

* LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/at-container-parsing-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/at-container-parsing.html:
* LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/crashtests/chrome-bug-1346969-crash.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/crashtests/chrome-remove-insert-evaluator-crash.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/crashtests/w3c-import.log:
* Source/WebCore/css/CSSContainerRule.cpp:
(WebCore::CSSContainerRule::cssText const):

Factor query serialization to a function in CQ namespace.

(WebCore::CSSContainerRule::conditionText const):
(WebCore::CSSContainerRule::nameText const):
(WebCore::CSSContainerRule::nameFilterText const): Deleted.
* Source/WebCore/css/CSSContainerRule.h:
* Source/WebCore/css/ContainerQuery.cpp:
(WebCore::CQ::serialize):
(WebCore::serialize): Deleted.
* Source/WebCore/css/ContainerQuery.h:

Update to the spec grammar and terminology.
ContainerQuery now includes the name part and replaces FilteredContainerQuery.
QueryInParens replaces ContainerQuery.
Also move ContainerQuery to CQ namespace.

* Source/WebCore/css/ContainerQueryParser.cpp:
(WebCore::ContainerQueryParser::consumeContainerQuery):
(WebCore::ContainerQueryParser::consumeQueryInParens):
(WebCore::ContainerQueryParser::consumeCondition):
(WebCore::ContainerQueryParser::consumeFilteredContainerQuery): Deleted.
* Source/WebCore/css/ContainerQueryParser.h:
* Source/WebCore/css/StyleRule.cpp:
(WebCore::StyleRuleContainer::StyleRuleContainer):
(WebCore::StyleRuleContainer::create):
* Source/WebCore/css/StyleRule.h:
* Source/WebCore/css/parser/CSSParserImpl.cpp:
(WebCore::CSSParserImpl::consumeContainerRule):
* Source/WebCore/inspector/InspectorStyleSheet.cpp:
(WebCore::buildArrayForGroupings):
* Source/WebCore/style/ContainerQueryEvaluator.cpp:
(WebCore::Style::ContainerQueryEvaluator::evaluate const):
(WebCore::Style::ContainerQueryEvaluator::selectContainer const):
(WebCore::Style::ContainerQueryEvaluator::evaluateQueryInParens const):
(WebCore::Style::ContainerQueryEvaluator::evaluateCondition const):
(WebCore::Style::ContainerQueryEvaluator::evaluateQuery const): Deleted.
* Source/WebCore/style/ContainerQueryEvaluator.h:
* Source/WebCore/style/RuleSet.h:
(WebCore::Style:: const):

Canonical link: https://commits.webkit.org/253035@main
  • Loading branch information
anttijk committed Aug 2, 2022
1 parent 2b0c968 commit 2956c93
Show file tree
Hide file tree
Showing 18 changed files with 274 additions and 227 deletions.
Expand Up @@ -21,7 +21,7 @@ PASS (not (width: 100px))
PASS ((width: 100px) and (height: 100px))
PASS (((width: 40px) or (width: 50px)) and (height: 100px))
PASS ((width: 100px) and ((height: 40px) or (height: 50px)))
PASS (((width: 40x) and (height: 50px)) or (height: 100px))
PASS (((width: 40px) and (height: 50px)) or (height: 100px))
PASS ((width: 50px) or ((width: 40px) and (height: 50px)))
PASS ((width: 100px) and (not (height: 100px)))
PASS (width < 100px)
Expand All @@ -47,6 +47,9 @@ PASS (width < calc(10px + 10em))
PASS (width < max(10px, 10em))
PASS (calc(10px + 10em) < width)
PASS (calc(10px + 10em) < width < max(30px, 30em))
PASS (width: 100px) and (height: 100px)
PASS (width: 100px) or (height: 100px)
PASS not (width: 100px)
PASS foo(width)
PASS size(width)
PASS (asdf)
Expand Down Expand Up @@ -74,32 +77,31 @@ PASS screen or (width: 100px)
PASS not screen and (width: 100px)
PASS not screen or (width: 100px)
PASS (width: 100px), (height: 100px)
PASS (width: 100px) and (height: 100px)
PASS (width: 100px) or (height: 100px)
PASS not (width: 100px)
PASS foo (width: 100px)
PASS Container selector: foo
PASS Container selector: foo
PASS Container selector: foo
PASS Container selector: foo foo
PASS Container selector: 1px
PASS Container selector: 50gil
PASS Container selector: name(foo)
PASS Container selector: type(inline-size)
PASS Container selector: "foo"
PASS Container selector: "inherit"
PASS Container selector: none
PASS Container selector: None
PASS Container selector: normal
PASS Container selector: Normal
PASS Container selector: auto
PASS Container selector: Auto
PASS Container selector: and
PASS Container selector: or
PASS Container selector: not
PASS Container selector: And
PASS Container selector: oR
PASS Container selector: nOt
PASS name not (width <= 500px)
PASS not (width <= 500px)
PASS Container name: foo
PASS Container name: foo
PASS Container name: foo
PASS Container name: foo foo
PASS Container name: 1px
PASS Container name: 50gil
PASS Container name: name(foo)
PASS Container name: type(inline-size)
PASS Container name: "foo"
PASS Container name: "inherit"
PASS Container name: none
PASS Container name: None
PASS Container name: normal
PASS Container name: Normal
PASS Container name: auto
PASS Container name: Auto
PASS Container name: and
PASS Container name: or
PASS Container name: not
PASS Container name: And
PASS Container name: oR
PASS Container name: nOt
FAIL style(--my-prop: foo) assert_equals: expected "true" but got ""
FAIL style(--my-prop: foo - bar ()) assert_equals: expected "true" but got ""
FAIL style(not ((--foo: calc(10px + 2em)) and ((--foo: url(x))))) assert_equals: expected "true" but got ""
Expand Down
Expand Up @@ -22,170 +22,181 @@
return style;
}

function test_query_invalid(query) {
function test_rule_valid(query) {
test(t => {
t.add_cleanup(cleanup_main);
let style = set_style(`@container name ${query} {}`);
assert_equals(style.sheet.rules.length, 0);
let style = set_style(`@container ${query} {}`);
assert_equals(style.sheet.rules.length, 1);
}, query);
}

// Tests that 1) the query parses, and 2) is either "unknown" or not, as
function test_condition_invalid(condition) {
test(t => {
t.add_cleanup(cleanup_main);
let style = set_style(`@container name ${condition} {}`);
assert_equals(style.sheet.rules.length, 0);
}, condition);
}

// Tests that 1) the condition parses, and 2) is either "unknown" or not, as
// specified.
function test_query_valid(query, unknown) {
function test_condition_valid(condition, unknown) {
test(t => {
t.add_cleanup(cleanup_main);
let style = set_style(`
@container name ${query} {}
@container name (${query} or (not ${query})) { main { --match:true; } }
@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(main).getPropertyValue('--match'), expected);
}, query);
}, condition);
}

function test_query_known(query) {
test_query_valid(query, false /* unknown */);
function test_condition_known(condition) {
test_condition_valid(condition, false /* unknown */);
}

function test_query_unknown(query) {
test_query_valid(query, true /* unknown */);
function test_condition_unknown(condition) {
test_condition_valid(condition, true /* unknown */);
}

function test_container_selector_invalid(container_selector) {
function test_container_name_invalid(container_name) {
test(t => {
t.add_cleanup(cleanup_main);
let style = set_style(`@container ${container_selector} (width) {}`);
let style = set_style(`@container ${container_name} not (width) {}`);
assert_equals(style.sheet.rules.length, 0);
}, `Container selector: ${container_selector}`);
}, `Container name: ${container_name}`);
}

function test_container_selector_valid(container_selector) {
function test_container_name_valid(container_name) {
test(t => {
t.add_cleanup(cleanup_main);
let style = set_style(`@container ${container_selector} (width) {}`);
let style = set_style(`@container ${container_name} not (width) {}`);
assert_equals(style.sheet.rules.length, 1);
}, `Container selector: ${container_selector}`);
}, `Container name: ${container_name}`);
}

test_query_known('(width)');
test_query_known('(min-width: 0px)');
test_query_known('(max-width: 0px)');
test_query_known('(height)');
test_query_known('(min-height: 0px)');
test_query_known('(max-height: 0px)');
test_query_known('(aspect-ratio)');
test_query_known('(min-aspect-ratio: 1/2)');
test_query_known('(max-aspect-ratio: 1/2)');
test_query_known('(orientation: portrait)');
test_query_known('(inline-size)');
test_query_known('(min-inline-size: 0px)');
test_query_known('(max-inline-size: 0px)');
test_query_known('(block-size)');
test_query_known('(min-block-size: 0px)');
test_query_known('(max-block-size: 0px)');

test_query_known('(width: 100px)');
test_query_known('((width: 100px))');
test_query_known('(not (width: 100px))');
test_query_known('((width: 100px) and (height: 100px))');
test_query_known('(((width: 40px) or (width: 50px)) and (height: 100px))');
test_query_known('((width: 100px) and ((height: 40px) or (height: 50px)))');
test_query_known('(((width: 40x) and (height: 50px)) or (height: 100px))');
test_query_known('((width: 50px) or ((width: 40px) and (height: 50px)))');
test_query_known('((width: 100px) and (not (height: 100px)))');
test_query_known('(width < 100px)');
test_query_known('(width <= 100px)');
test_query_known('(width = 100px)');
test_query_known('(width > 100px)');
test_query_known('(width >= 100px)');
test_query_known('(100px < width)');
test_query_known('(100px <= width)');
test_query_known('(100px = width)');
test_query_known('(100px > width)');
test_query_known('(100px >= width)');
test_query_known('(100px < width < 200px)');
test_query_known('(100px < width <= 200px)');
test_query_known('(100px <= width < 200px)');
test_query_known('(100px > width > 200px)');
test_query_known('(100px > width >= 200px)');
test_query_known('(100px >= width > 200px)');

test_query_known('(width: calc(10px))');
test_query_known('(width: calc(10em))');
test_query_known('(width: calc(10px + 10em))');
test_query_known('(width < calc(10px + 10em))');
test_query_known('(width < max(10px, 10em))');
test_query_known('(calc(10px + 10em) < width)');
test_query_known('(calc(10px + 10em) < width < max(30px, 30em))');

test_query_unknown('foo(width)');
test_query_unknown('size(width)');
test_query_unknown('(asdf)');
test_query_unknown('(resolution > 100dpi)');
test_query_unknown('(resolution: 150dpi)');
test_query_unknown('(color)');
test_query_unknown('(min-color: 1)');
test_query_unknown('(color-index >= 1)');
test_query_unknown('size(grid)');
test_query_unknown('(grid)');
test_query_unknown('(width == 100px)');
test_query_unknown('(100px == width)');
test_query_unknown('(100px = width = 200px)');
test_query_unknown('(100px < width > 200px)');
test_query_unknown('(100px <= width >= 200px)');
test_query_unknown('(100px <= width > 200px)');
test_query_unknown('(100px < width >= 200px)');
test_query_unknown('(100px : width : 200px)');

test_query_invalid('screen');
test_query_invalid('print');
test_query_invalid('not print');
test_query_invalid('only print');
test_query_invalid('screen and (width: 100px)');
test_query_invalid('screen or (width: 100px)');
test_query_invalid('not screen and (width: 100px)');
test_query_invalid('not screen or (width: 100px)');
test_query_invalid('(width: 100px), (height: 100px)');
test_query_invalid('(width: 100px) and (height: 100px)');
test_query_invalid('(width: 100px) or (height: 100px)');
test_query_invalid('not (width: 100px)');
test_query_invalid('foo (width: 100px)');

test_container_selector_valid('foo');
test_container_selector_valid(' foo');
test_container_selector_valid(' foo ');

test_container_selector_invalid('foo foo');
test_container_selector_invalid('1px');
test_container_selector_invalid('50gil');
test_container_selector_invalid('name(foo)');
test_container_selector_invalid('type(inline-size)');
test_container_selector_invalid('"foo"');
test_container_selector_invalid('"inherit"');
test_container_selector_invalid('none');
test_container_selector_invalid('None');
test_container_selector_invalid('normal');
test_container_selector_invalid('Normal');
test_container_selector_invalid('auto');
test_container_selector_invalid('Auto');
test_container_selector_invalid('and');
test_container_selector_invalid('or');
test_container_selector_invalid('not');
test_container_selector_invalid('And');
test_container_selector_invalid('oR');
test_container_selector_invalid('nOt');

test_query_known('style(--my-prop: foo)');
test_query_known('style(--my-prop: foo - bar ())');
test_query_known('style(not ((--foo: calc(10px + 2em)) and ((--foo: url(x)))))');
test_query_known('style((--foo: bar) or (--bar: 10px))');
test_query_known('style(--foo: bar !important)');
test_query_known('style(--my-prop:)');
test_query_known('style(--my-prop: )');

test_query_unknown('style(--foo: bar;)');
test_query_unknown('style(--foo)');
test_query_unknown('style(style(--foo: bar))');
test_condition_known('(width)');
test_condition_known('(min-width: 0px)');
test_condition_known('(max-width: 0px)');
test_condition_known('(height)');
test_condition_known('(min-height: 0px)');
test_condition_known('(max-height: 0px)');
test_condition_known('(aspect-ratio)');
test_condition_known('(min-aspect-ratio: 1/2)');
test_condition_known('(max-aspect-ratio: 1/2)');
test_condition_known('(orientation: portrait)');
test_condition_known('(inline-size)');
test_condition_known('(min-inline-size: 0px)');
test_condition_known('(max-inline-size: 0px)');
test_condition_known('(block-size)');
test_condition_known('(min-block-size: 0px)');
test_condition_known('(max-block-size: 0px)');

test_condition_known('(width: 100px)');
test_condition_known('((width: 100px))');
test_condition_known('(not (width: 100px))');
test_condition_known('((width: 100px) and (height: 100px))');
test_condition_known('(((width: 40px) or (width: 50px)) and (height: 100px))');
test_condition_known('((width: 100px) and ((height: 40px) or (height: 50px)))');
test_condition_known('(((width: 40px) and (height: 50px)) or (height: 100px))');
test_condition_known('((width: 50px) or ((width: 40px) and (height: 50px)))');
test_condition_known('((width: 100px) and (not (height: 100px)))');
test_condition_known('(width < 100px)');
test_condition_known('(width <= 100px)');
test_condition_known('(width = 100px)');
test_condition_known('(width > 100px)');
test_condition_known('(width >= 100px)');
test_condition_known('(100px < width)');
test_condition_known('(100px <= width)');
test_condition_known('(100px = width)');
test_condition_known('(100px > width)');
test_condition_known('(100px >= width)');
test_condition_known('(100px < width < 200px)');
test_condition_known('(100px < width <= 200px)');
test_condition_known('(100px <= width < 200px)');
test_condition_known('(100px > width > 200px)');
test_condition_known('(100px > width >= 200px)');
test_condition_known('(100px >= width > 200px)');

test_condition_known('(width: calc(10px))');
test_condition_known('(width: calc(10em))');
test_condition_known('(width: calc(10px + 10em))');
test_condition_known('(width < calc(10px + 10em))');
test_condition_known('(width < max(10px, 10em))');
test_condition_known('(calc(10px + 10em) < width)');
test_condition_known('(calc(10px + 10em) < width < max(30px, 30em))');
test_condition_known('(width: 100px) and (height: 100px)');
test_condition_known('(width: 100px) or (height: 100px)');
test_condition_known('not (width: 100px)');

test_condition_unknown('foo(width)');
test_condition_unknown('size(width)');
test_condition_unknown('(asdf)');
test_condition_unknown('(resolution > 100dpi)');
test_condition_unknown('(resolution: 150dpi)');
test_condition_unknown('(color)');
test_condition_unknown('(min-color: 1)');
test_condition_unknown('(color-index >= 1)');
test_condition_unknown('size(grid)');
test_condition_unknown('(grid)');
test_condition_unknown('(width == 100px)');
test_condition_unknown('(100px == width)');
test_condition_unknown('(100px = width = 200px)');
test_condition_unknown('(100px < width > 200px)');
test_condition_unknown('(100px <= width >= 200px)');
test_condition_unknown('(100px <= width > 200px)');
test_condition_unknown('(100px < width >= 200px)');
test_condition_unknown('(100px : width : 200px)');

test_condition_invalid('screen');
test_condition_invalid('print');
test_condition_invalid('not print');
test_condition_invalid('only print');
test_condition_invalid('screen and (width: 100px)');
test_condition_invalid('screen or (width: 100px)');
test_condition_invalid('not screen and (width: 100px)');
test_condition_invalid('not screen or (width: 100px)');
test_condition_invalid('(width: 100px), (height: 100px)');
test_condition_invalid('foo (width: 100px)');

test_rule_valid('name not (width <= 500px)');
test_rule_valid('not (width <= 500px)');

test_container_name_valid('foo');
test_container_name_valid(' foo');
test_container_name_valid(' foo ');

test_container_name_invalid('foo foo');
test_container_name_invalid('1px');
test_container_name_invalid('50gil');
test_container_name_invalid('name(foo)');
test_container_name_invalid('type(inline-size)');
test_container_name_invalid('"foo"');
test_container_name_invalid('"inherit"');
test_container_name_invalid('none');
test_container_name_invalid('None');
test_container_name_invalid('normal');
test_container_name_invalid('Normal');
test_container_name_invalid('auto');
test_container_name_invalid('Auto');
test_container_name_invalid('and');
test_container_name_invalid('or');
test_container_name_invalid('not');
test_container_name_invalid('And');
test_container_name_invalid('oR');
test_container_name_invalid('nOt');

test_condition_known('style(--my-prop: foo)');
test_condition_known('style(--my-prop: foo - bar ())');
test_condition_known('style(not ((--foo: calc(10px + 2em)) and ((--foo: url(x)))))');
test_condition_known('style((--foo: bar) or (--bar: 10px))');
test_condition_known('style(--foo: bar !important)');
test_condition_known('style(--my-prop:)');
test_condition_known('style(--my-prop: )');

test_condition_unknown('style(--foo: bar;)');
test_condition_unknown('style(--foo)');
test_condition_unknown('style(style(--foo: bar))');
</script>

0 comments on commit 2956c93

Please sign in to comment.