Skip to content

Commit

Permalink
[@container] Support state(stuck: ...) query parsing
Browse files Browse the repository at this point in the history
Support parsing and finding the correct container, but always evaluate
queries to false.

Also track style and evaluator dependency on stuck queries.

Bug: 1445189
Change-Id: I16058c03f9614c21bf7e256558ba5157edf52361
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4567850
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1151756}
  • Loading branch information
Rune Lillesveen authored and Chromium LUCI CQ committed Jun 1, 2023
1 parent b3c0ebc commit c925ceb
Show file tree
Hide file tree
Showing 19 changed files with 293 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ bool ContainerQueryEvaluator::EvalAndAdd(
const ContainerSelector& selector = query.Selector();
bool selects_size = selector.SelectsSizeContainers();
bool selects_style = selector.SelectsStyleContainers();
if (!selects_size && !selects_style) {
bool selects_sticky = selector.SelectsStickyContainers();
if (!selects_size && !selects_style && !selects_sticky) {
return false;
}

Expand All @@ -138,6 +139,9 @@ bool ContainerQueryEvaluator::EvalAndAdd(
if (selects_style) {
match_result.SetDependsOnStyleContainerQueries();
}
if (selects_sticky) {
match_result.SetDependsOnStickyContainerQueries();
}

Element* starting_element =
selects_size ? context.container : style_container_candidate;
Expand Down Expand Up @@ -235,6 +239,9 @@ bool ContainerQueryEvaluator::EvalAndAdd(const ContainerQuery& query,
if (!depends_on_style_) {
depends_on_style_ = query.Selector().SelectsStyleContainers();
}
if (!depends_on_sticky_) {
depends_on_sticky_ = query.Selector().SelectsStickyContainers();
}
unit_flags_ |= result.unit_flags;

return result.value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class CORE_EXPORT ContainerQueryEvaluator final
bool referenced_by_unit_ = false;
bool font_dirty_ = false;
bool depends_on_style_ = false;
bool depends_on_sticky_ = false;
};

} // namespace blink
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,49 @@ TEST_F(ContainerQueryEvaluatorTest, FindContainer) {
outer_size);
}

TEST_F(ContainerQueryEvaluatorTest, FindStickyContainer) {
SetBodyInnerHTML(R"HTML(
<div style="container-type: sticky size">
<div style="container-name:outer;container-type: sticky">
<div style="container-name:outer">
<div style="container-type: sticky">
<div>
<div></div>
</div>
</div>
</div>
</div>
</div>
)HTML");

UpdateAllLifecyclePhasesForTest();

Element* sticky_size = ParentNode::firstElementChild(*GetDocument().body());
Element* outer_sticky = ParentNode::firstElementChild(*sticky_size);
Element* outer = ParentNode::firstElementChild(*outer_sticky);
Element* inner_sticky = ParentNode::firstElementChild(*outer);
Element* inner = ParentNode::firstElementChild(*inner_sticky);

EXPECT_EQ(
ContainerQueryEvaluator::FindContainer(
inner,
ParseContainer("state(stuck: top) and style(--foo: bar)")->Selector(),
&GetDocument()),
inner_sticky);
EXPECT_EQ(ContainerQueryEvaluator::FindContainer(
inner,
ParseContainer("outer state(stuck: top) and style(--foo: bar)")
->Selector(),
&GetDocument()),
outer_sticky);
EXPECT_EQ(
ContainerQueryEvaluator::FindContainer(
inner,
ParseContainer("state(stuck: top) and (width > 0px)")->Selector(),
&GetDocument()),
sticky_size);
}

TEST_F(ContainerQueryEvaluatorTest, ScopedCaching) {
GetDocument()
.documentElement()
Expand Down
20 changes: 20 additions & 0 deletions third_party/blink/renderer/core/css/container_query_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,26 @@ TEST_F(ContainerQueryTest, ImplicitContainerSelector) {
orientation.Type(WritingMode::kVerticalRl));
}

TEST_F(ContainerQueryTest, StickyContainerSelector) {
ContainerSelector stuck_right = ContainerSelectorFrom("state(stuck: right)");
EXPECT_EQ(kContainerTypeSticky, stuck_right.Type(WritingMode::kHorizontalTb));

ContainerSelector stuck_and_style =
ContainerSelectorFrom("state(stuck: right) and style(--foo: bar)");
EXPECT_EQ(kContainerTypeSticky,
stuck_and_style.Type(WritingMode::kHorizontalTb));

ContainerSelector stuck_and_inline_size = ContainerSelectorFrom(
"state(stuck: inset-block-end) or (inline-size > 10px)");
EXPECT_EQ((kContainerTypeSticky | kContainerTypeInlineSize),
stuck_and_inline_size.Type(WritingMode::kHorizontalTb));

ContainerSelector stuck_and_block_size =
ContainerSelectorFrom("state(stuck: inset-block-end) and (height)");
EXPECT_EQ((kContainerTypeSticky | kContainerTypeBlockSize),
stuck_and_block_size.Type(WritingMode::kHorizontalTb));
}

TEST_F(ContainerQueryTest, RuleParsing) {
StyleRuleContainer* container = ParseAtContainer(R"CSS(
@container test_name (min-width: 100px) {
Expand Down
8 changes: 7 additions & 1 deletion third_party/blink/renderer/core/css/container_selector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@ ContainerSelector::ContainerSelector(AtomicString name,
if (feature_flags & MediaQueryExpNode::kFeatureStyle) {
has_style_query_ = true;
}
if (feature_flags & MediaQueryExpNode::kFeatureState) {
has_sticky_query_ = true;
}
}

unsigned ContainerSelector::GetHash() const {
unsigned hash = !name_.empty() ? WTF::GetHash(name_) : 0;
WTF::AddIntToHash(hash, physical_axes_.value());
WTF::AddIntToHash(hash, logical_axes_.value());
WTF::AddIntToHash(hash, has_style_query_);
WTF::AddIntToHash(hash, has_sticky_query_);
return hash;
}

Expand All @@ -51,7 +55,9 @@ unsigned ContainerSelector::Type(WritingMode writing_mode) const {
if ((axes & kLogicalAxisBlock).value()) {
type |= kContainerTypeBlockSize;
}

if (has_sticky_query_) {
type |= kContainerTypeSticky;
}
return type;
}

Expand Down
5 changes: 4 additions & 1 deletion third_party/blink/renderer/core/css/container_selector.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class CORE_EXPORT ContainerSelector {
bool operator==(const ContainerSelector& o) const {
return (name_ == o.name_) && (physical_axes_ == o.physical_axes_) &&
(logical_axes_ == o.logical_axes_) &&
(has_style_query_ == o.has_style_query_);
(has_style_query_ == o.has_style_query_) &&
(has_sticky_query_ == o.has_sticky_query_);
}
bool operator!=(const ContainerSelector& o) const { return !(*this == o); }

Expand All @@ -63,6 +64,7 @@ class CORE_EXPORT ContainerSelector {
}

bool SelectsStyleContainers() const { return has_style_query_; }
bool SelectsStickyContainers() const { return has_sticky_query_; }

PhysicalAxes GetPhysicalAxes() const { return physical_axes_; }
LogicalAxes GetLogicalAxes() const { return logical_axes_; }
Expand All @@ -72,6 +74,7 @@ class CORE_EXPORT ContainerSelector {
PhysicalAxes physical_axes_{kPhysicalAxisNone};
LogicalAxes logical_axes_{kLogicalAxisNone};
bool has_style_query_{false};
bool has_sticky_query_{false};
};

class ScopedContainerSelector
Expand Down
14 changes: 12 additions & 2 deletions third_party/blink/renderer/core/css/css_value_keywords.json5
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,7 @@
"-webkit-repeating-radial-gradient",
"-webkit-image-set",
"image-set",
"type",

// deprecated gradients
"from",
Expand Down Expand Up @@ -1475,8 +1476,17 @@
"inline-size",

// @container
"name",
"type",
// size
// style
"state",
// top
// left
// right
// bottom
"inset-block-start",
"inset-block-end",
"inset-inline-start",
"inset-inline-end",

// grid auto-repeat
"auto-fill",
Expand Down
5 changes: 5 additions & 0 deletions third_party/blink/renderer/core/css/element_rule_collector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -574,17 +574,22 @@ void ElementRuleCollector::CollectMatchingRulesForListInternal(
// changes may cause pseudo elements to start being generated.
bool selects_size = false;
bool selects_style = false;
bool selects_sticky = false;
for (const ContainerQuery* current = container_query; current;
current = current->Parent()) {
selects_size |= current->Selector().SelectsSizeContainers();
selects_style |= current->Selector().SelectsStyleContainers();
selects_sticky |= current->Selector().SelectsStickyContainers();
}
if (selects_size) {
result_.SetDependsOnSizeContainerQueries();
}
if (selects_style) {
result_.SetDependsOnStyleContainerQueries();
}
if (selects_sticky) {
result_.SetDependsOnStickyContainerQueries();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,6 @@
"device-posture",
"horizontal-viewport-segments",
"vertical-viewport-segments",
"stuck",
],
}
7 changes: 7 additions & 0 deletions third_party/blink/renderer/core/css/media_query_evaluator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1434,6 +1434,13 @@ static bool UpdateMediaFeatureEval(const MediaQueryExpValue& value,
}
}

static bool StuckMediaFeatureEval(const MediaQueryExpValue& value,
MediaQueryOperator op,
const MediaValues& media_values) {
// TODO(crbug.com/1445189): Implement matching.
return false;
}

static MediaQueryOperator ReverseOperator(MediaQueryOperator op) {
switch (op) {
case MediaQueryOperator::kNone:
Expand Down
22 changes: 22 additions & 0 deletions third_party/blink/renderer/core/css/media_query_exp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,25 @@ static inline bool FeatureWithValidIdent(const String& media_feature,
}
}

if (RuntimeEnabledFeatures::CSSStickyContainerQueriesEnabled()) {
if (media_feature == media_feature_names::kStuckMediaFeature) {
switch (ident) {
case CSSValueID::kNone:
case CSSValueID::kTop:
case CSSValueID::kLeft:
case CSSValueID::kBottom:
case CSSValueID::kRight:
case CSSValueID::kInsetBlockStart:
case CSSValueID::kInsetBlockEnd:
case CSSValueID::kInsetInlineStart:
case CSSValueID::kInsetInlineEnd:
return true;
default:
return false;
}
}
}

return false;
}

Expand Down Expand Up @@ -807,6 +826,9 @@ MediaQueryExpNode::FeatureFlags MediaQueryFunctionExpNode::CollectFeatureFlags()
if (name_ == AtomicString("style")) {
flags |= kFeatureStyle;
}
if (name_ == AtomicString("state")) {
flags |= kFeatureState;
}
return flags;
}

Expand Down
1 change: 1 addition & 0 deletions third_party/blink/renderer/core/css/media_query_exp.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ class CORE_EXPORT MediaQueryExpNode
kFeatureInlineSize = 1 << 4,
kFeatureBlockSize = 1 << 5,
kFeatureStyle = 1 << 6,
kFeatureState = 1 << 7,
};

using FeatureFlags = unsigned;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,21 @@ class StyleFeatureSet : public MediaQueryParser::FeatureSet {
bool SupportsRange() const override { return false; }
};

class StateFeatureSet : public MediaQueryParser::FeatureSet {
STACK_ALLOCATED();

public:
bool IsAllowed(const String& feature) const override {
return feature == media_feature_names::kStuckMediaFeature;
}
bool IsAllowedWithoutValue(const String& feature,
const ExecutionContext*) const override {
return true;
}
bool IsCaseSensitive(const String& feature) const override { return false; }
bool SupportsRange() const override { return false; }
};

} // namespace

ContainerQueryParser::ContainerQueryParser(const CSSParserContext& context)
Expand Down Expand Up @@ -174,6 +189,18 @@ const MediaQueryExpNode* ContainerQueryParser::ConsumeQueryInParens(
context_.Count(WebFeature::kCSSStyleContainerQuery);
return MediaQueryExpNode::Function(query, AtomicString("style"));
}
} else if (RuntimeEnabledFeatures::CSSStickyContainerQueriesEnabled() &&
range.Peek().GetType() == kFunctionToken &&
range.Peek().FunctionId() == CSSValueID::kState) {
// state(stuck: [top | left | right | bottom | inset-* ] )
CSSParserTokenRange block = range.ConsumeBlock();
block.ConsumeWhitespace();
range.ConsumeWhitespace();

if (const MediaQueryExpNode* query =
ConsumeFeatureQuery(block, offsets, StateFeatureSet())) {
return MediaQueryExpNode::Function(query, AtomicString("state"));
}
}
range = original_range;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class MediaQueryFeatureSet : public MediaQueryParser::FeatureSet {
feature == media_feature_names::kBlockSizeMediaFeature ||
feature == media_feature_names::kMinBlockSizeMediaFeature ||
feature == media_feature_names::kMaxBlockSizeMediaFeature ||
feature == media_feature_names::kStuckMediaFeature ||
CSSVariableParser::IsValidVariableName(feature)) {
return false;
}
Expand Down
7 changes: 7 additions & 0 deletions third_party/blink/renderer/core/css/resolver/match_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ class CORE_EXPORT MatchResult {
bool DependsOnStyleContainerQueries() const {
return depends_on_style_container_queries_;
}
void SetDependsOnStickyContainerQueries() {
depends_on_sticky_container_queries_ = true;
}
bool DependsOnStickyContainerQueries() const {
return depends_on_sticky_container_queries_;
}
void SetFirstLineDependsOnSizeContainerQueries() {
first_line_depends_on_size_container_queries_ = true;
}
Expand Down Expand Up @@ -255,6 +261,7 @@ class CORE_EXPORT MatchResult {
bool is_cacheable_{true};
bool depends_on_size_container_queries_{false};
bool depends_on_style_container_queries_{false};
bool depends_on_sticky_container_queries_{false};
bool first_line_depends_on_size_container_queries_{false};
bool depends_on_static_viewport_units_{false};
bool depends_on_dynamic_viewport_units_{false};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,9 @@ void StyleResolver::ApplyBaseStyleNoCache(
if (match_result.DependsOnStyleContainerQueries()) {
state.StyleBuilder().SetDependsOnStyleContainerQueries(true);
}
if (match_result.DependsOnStickyContainerQueries()) {
state.StyleBuilder().SetDependsOnStickyContainerQueries(true);
}
if (match_result.FirstLineDependsOnSizeContainerQueries()) {
state.StyleBuilder().SetFirstLineDependsOnSizeContainerQueries(true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,13 @@
field_group: "*",
default_value: "false",
},
{
name: "DependsOnStickyContainerQueries",
field_template: "primitive",
type_name: "bool",
field_group: "*",
default_value: "false",
},
{
// Set to true if this ComputedStyle is for an element whose ::first-line
// style depends on size container queries.
Expand Down

0 comments on commit c925ceb

Please sign in to comment.