Skip to content

Commit

Permalink
[anchor-position] Allow multiple anchor names on the same element
Browse files Browse the repository at this point in the history
This patch implements the recent CSSWG resolution to change
`anchor-name` property into a comma-separated list of names:

w3c/csswg-drafts#8837 (comment)

Fixed: 1475812
Change-Id: I5d8abb58fa8bfc9ee5dd72a833098ae8685496c1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4811709
Auto-Submit: Xiaocheng Hu <xiaochengh@chromium.org>
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1188229}
  • Loading branch information
xiaochengh authored and Chromium LUCI CQ committed Aug 25, 2023
1 parent 71df57b commit b7ed2af
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 16 deletions.
4 changes: 2 additions & 2 deletions third_party/blink/renderer/core/css/css_properties.json5
Original file line number Diff line number Diff line change
Expand Up @@ -1626,12 +1626,12 @@
name: "anchor-name",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal" ],
include_paths: ["third_party/blink/renderer/core/style/scoped_css_name.h"],
type_name: "ScopedCSSName",
type_name: "ScopedCSSNameList",
wrapper_pointer_name: "Member",
default_value: "nullptr",
field_group: "*",
field_template: "external",
converter: "ConvertNoneOrCustomIdent",
converter: "ConvertAnchorName",
keywords: ["none"],
typedom_types: ["Keyword"],
runtime_flag: "CSSAnchorPositioning",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ const CSSValue* AnchorDefault::CSSValueFromComputedStyleInternal(
return MakeGarbageCollected<CSSCustomIdentValue>(*style.AnchorDefault());
}

// anchor-name: none | <dashed-ident>#
const CSSValue* AnchorName::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
Expand All @@ -183,7 +184,8 @@ const CSSValue* AnchorName::ParseSingleValue(
css_parsing_utils::ConsumeIdent<CSSValueID::kNone>(range)) {
return value;
}
return css_parsing_utils::ConsumeDashedIdent(range, context);
return css_parsing_utils::ConsumeCommaSeparatedList(
css_parsing_utils::ConsumeDashedIdent, range, context);
}
const CSSValue* AnchorName::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
Expand All @@ -192,7 +194,12 @@ const CSSValue* AnchorName::CSSValueFromComputedStyleInternal(
if (!style.AnchorName()) {
return CSSIdentifierValue::Create(CSSValueID::kNone);
}
return MakeGarbageCollected<CSSCustomIdentValue>(*style.AnchorName());
CSSValueList* list = CSSValueList::CreateCommaSeparated();
for (const Member<const ScopedCSSName>& name :
style.AnchorName()->GetNames()) {
list->Append(*MakeGarbageCollected<CSSCustomIdentValue>(*name));
}
return list;
}

const CSSValue* AnimationComposition::ParseSingleValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,22 @@ ScopedCSSName* StyleBuilderConverter::ConvertAnchorDefault(
custom_ident.GetTreeScope());
}

ScopedCSSNameList* StyleBuilderConverter::ConvertAnchorName(
StyleResolverState& state,
const CSSValue& value) {
DCHECK(value.IsScopedValue());
if (const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
DCHECK_EQ(identifier_value->GetValueID(), CSSValueID::kNone);
return nullptr;
}
DCHECK(value.IsBaseValueList());
HeapVector<Member<const ScopedCSSName>> names;
for (const Member<const CSSValue>& item : To<CSSValueList>(value)) {
names.push_back(ConvertCustomIdent(state, *item));
}
return MakeGarbageCollected<ScopedCSSNameList>(std::move(names));
}

StyleInitialLetter StyleBuilderConverter::ConvertInitialLetter(
StyleResolverState&,
const CSSValue& value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ class StyleBuilderConverter {
const CSSValue&);
static ScopedCSSName* ConvertAnchorDefault(StyleResolverState&,
const CSSValue&);
static ScopedCSSNameList* ConvertAnchorName(StyleResolverState&,
const CSSValue&);
static StyleInitialLetter ConvertInitialLetter(StyleResolverState&,
const CSSValue&);
static StyleOffsetRotation ConvertOffsetRotate(StyleResolverState&,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3149,16 +3149,16 @@ TEST_F(StyleResolverTest, ScopedAnchorName) {

EXPECT_EQ(*MakeGarbageCollected<ScopedCSSName>(AtomicString("--outer"),
&GetDocument()),
*outer_anchor->ComputedStyleRef().AnchorName());
*outer_anchor->ComputedStyleRef().AnchorName()->GetNames()[0]);
EXPECT_EQ(
*MakeGarbageCollected<ScopedCSSName>(AtomicString("--host"), shadow),
*host->ComputedStyleRef().AnchorName());
*host->ComputedStyleRef().AnchorName()->GetNames()[0]);
EXPECT_EQ(*MakeGarbageCollected<ScopedCSSName>(AtomicString("--part"),
&GetDocument()),
*part->ComputedStyleRef().AnchorName());
*part->ComputedStyleRef().AnchorName()->GetNames()[0]);
EXPECT_EQ(
*MakeGarbageCollected<ScopedCSSName>(AtomicString("--inner"), shadow),
*inner_anchor->ComputedStyleRef().AnchorName());
*inner_anchor->ComputedStyleRef().AnchorName()->GetNames()[0]);
}

TEST_F(StyleResolverTest, ScopedAnchorDefault) {
Expand Down
11 changes: 7 additions & 4 deletions third_party/blink/renderer/core/layout/ng/ng_anchor_query_map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,13 @@ struct NGStitchedAnchorQueries {
NGStitchedAnchorQuery& query =
EnsureStitchedAnchorQuery(*containing_block);
if (fragment.Style().AnchorName()) {
query.AddAnchorReference(
fragment.Style().AnchorName(), *fragment.GetLayoutObject(),
{offset_from_fragmentainer, fragment.Size()}, fragmentainer,
NGStitchedAnchorQuery::Conflict::kOverwriteIfAfter);
for (const ScopedCSSName* name :
fragment.Style().AnchorName()->GetNames()) {
query.AddAnchorReference(
name, *fragment.GetLayoutObject(),
{offset_from_fragmentainer, fragment.Size()}, fragmentainer,
NGStitchedAnchorQuery::Conflict::kOverwriteIfAfter);
}
}
if (fragment.IsImplicitAnchor()) {
query.AddAnchorReference(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,9 @@ void NGFragmentBuilder::PropagateChildAnchors(
options = AnchorQuerySetOptions(
child, node_, IsBlockFragmentationContextRoot() || HasItems());
if (child.Style().AnchorName()) {
EnsureAnchorQuery().Set(child.Style().AnchorName(),
*child.GetLayoutObject(), rect, *options);
for (const ScopedCSSName* name : child.Style().AnchorName()->GetNames()) {
EnsureAnchorQuery().Set(name, *child.GetLayoutObject(), rect, *options);
}
}
if (child.IsImplicitAnchor()) {
EnsureAnchorQuery().Set(child.GetLayoutObject(), *child.GetLayoutObject(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#determining">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script src="support/test-common.js"></script>
<style>
.relpos {
position: relative;
}
.anchor1 {
anchor-name: --a1, --a2;
width: 30px;
height: 10px;
background: orange;
}
.target {
position: absolute;
height: 10px;
background: lime;
}
#target1 {
width: anchor-size(--a1 width);
}
#target2 {
width: anchor-size(--a2 width);
}
#target3 {
width: anchor-size(--a3 width, 11px);
}
</style>
<body onload="checkLayoutForAnchorPos('.target')">
<!--
First two targets should find the same anchor via different names.
Third target shouldn't find the anchor, as the name is invalid.
-->
<div class="relpos">
<div class="anchor1" style="width: 30px"></div>
<div class="target" id="target1" data-expected-width=30></div>
<div class="target" id="target2" data-expected-width=30></div>
<div class="target" id="target3" data-expected-width=11></div>
</div>
</body>
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@
</div>

<script>
// anchor-name: none | <dashed-ident>
// anchor-name: none | <dashed-ident>#
test_valid_value('anchor-name', 'none');
test_valid_value('anchor-name', '--foo');
test_valid_value('anchor-name', '--foo, --bar')
test_invalid_value('anchor-name', 'foo-bar');
test_invalid_value('anchor-name', '--foo --bar')
test_invalid_value('anchor-name', '--foo, --bar')
test_invalid_value('anchor-name', '100px');
test_invalid_value('anchor-name', '100%');

// Computed value: as specified
test_computed_value('anchor-name', 'none');
test_computed_value('anchor-name', '--foo');
test_computed_value('anchor-name', '--foo, --bar');

// Initial: none
// Inherited: no
Expand Down

0 comments on commit b7ed2af

Please sign in to comment.