Skip to content

Commit

Permalink
[anchor-position] Implement the anchor specifier concept
Browse files Browse the repository at this point in the history
After adding `anchor-default` property, anchor references are now not
just a name, but a tri-state "anchor specifier", which can be [1]:
- `implicit`: the implicit anchor defined by other specs (eg popover)
- `default`: the default anchor defined by `anchor-default` property
- named: an explicit anchor name

This patch:
- Adds the AnchorSpecifierValue class to represent an anchor specifier,
  by converting the existing AnchorScrollValue class
- Uses AnchorSpecifierValue in `anchor-scroll` property and `anchor()`
  functions
- Changes clients of the above, namely, AnchorScrollData and
  NGAnchorEvaluatorImpl to handle anchor specifier properly

[1] https://drafts4.csswg.org/css-anchor-1/#target-anchor-element

Bug: 1412633
Change-Id: I0655d2ce4e8c918642f925df294fbdc11137fa7a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4228517
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1103476}
  • Loading branch information
xiaochengh authored and Chromium LUCI CQ committed Feb 9, 2023
1 parent 0e45aae commit 003ae32
Show file tree
Hide file tree
Showing 22 changed files with 314 additions and 185 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,44 @@

#include "third_party/blink/renderer/core/css/calculation_expression_anchor_query_node.h"
#include "base/memory/values_equivalent.h"
#include "third_party/blink/renderer/core/style/anchor_specifier_value.h"
#include "third_party/blink/renderer/platform/geometry/length_functions.h"

namespace blink {

// static
scoped_refptr<const CalculationExpressionAnchorQueryNode>
CalculationExpressionAnchorQueryNode::CreateAnchor(const ScopedCSSName* name,
AnchorValue side,
const Length& fallback) {
CalculationExpressionAnchorQueryNode::CreateAnchor(
const AnchorSpecifierValue& anchor_specifier,
AnchorValue side,
const Length& fallback) {
AnchorQueryValue value = {.anchor_side = side};
return base::MakeRefCounted<CalculationExpressionAnchorQueryNode>(
AnchorQueryType::kAnchor, name, value, /* percentage */ 0, fallback);
AnchorQueryType::kAnchor, anchor_specifier, value, /* percentage */ 0,
fallback);
}

// static
scoped_refptr<const CalculationExpressionAnchorQueryNode>
CalculationExpressionAnchorQueryNode::CreateAnchorPercentage(
const ScopedCSSName* name,
const AnchorSpecifierValue& anchor_specifier,
float percentage,
const Length& fallback) {
AnchorQueryValue value = {.anchor_side = AnchorValue::kPercentage};
return base::MakeRefCounted<CalculationExpressionAnchorQueryNode>(
AnchorQueryType::kAnchor, name, value, percentage, fallback);
AnchorQueryType::kAnchor, anchor_specifier, value, percentage, fallback);
}

// static
scoped_refptr<const CalculationExpressionAnchorQueryNode>
CalculationExpressionAnchorQueryNode::CreateAnchorSize(
const ScopedCSSName* name,
const AnchorSpecifierValue& anchor_specifier,
AnchorSizeValue size,
const Length& fallback) {
AnchorQueryValue value = {.anchor_size = size};
return base::MakeRefCounted<CalculationExpressionAnchorQueryNode>(
AnchorQueryType::kAnchorSize, name, value, /* percentage */ 0, fallback);
AnchorQueryType::kAnchorSize, anchor_specifier, value, /* percentage */ 0,
fallback);
}

bool CalculationExpressionAnchorQueryNode::operator==(
Expand All @@ -50,7 +54,8 @@ bool CalculationExpressionAnchorQueryNode::operator==(
if (type_ != other_anchor_query->type_) {
return false;
}
if (!base::ValuesEquivalent(anchor_name_, other_anchor_query->anchor_name_)) {
if (!base::ValuesEquivalent(anchor_specifier_,
other_anchor_query->anchor_specifier_)) {
return false;
}
if (type_ == AnchorQueryType::kAnchor) {
Expand All @@ -75,7 +80,8 @@ bool CalculationExpressionAnchorQueryNode::operator==(
scoped_refptr<const CalculationExpressionNode>
CalculationExpressionAnchorQueryNode::Zoom(double factor) const {
return base::MakeRefCounted<CalculationExpressionAnchorQueryNode>(
type_, anchor_name_, value_, side_percentage_, fallback_.Zoom(factor));
type_, *anchor_specifier_, value_, side_percentage_,
fallback_.Zoom(factor));
}

float CalculationExpressionAnchorQueryNode::Evaluate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,28 @@

namespace blink {

class AnchorSpecifierValue;

class CORE_EXPORT CalculationExpressionAnchorQueryNode final
: public CalculationExpressionNode {
public:
static scoped_refptr<const CalculationExpressionAnchorQueryNode> CreateAnchor(
const ScopedCSSName* name,
const AnchorSpecifierValue& anchor_specifier,
AnchorValue side,
const Length& fallback);
static scoped_refptr<const CalculationExpressionAnchorQueryNode>
CreateAnchorPercentage(const ScopedCSSName* name,
CreateAnchorPercentage(const AnchorSpecifierValue& anchor_specifier,
float percentage,
const Length& fallback);
static scoped_refptr<const CalculationExpressionAnchorQueryNode>
CreateAnchorSize(const ScopedCSSName* name,
CreateAnchorSize(const AnchorSpecifierValue& anchor_specifier,
AnchorSizeValue size,
const Length& fallback);

AnchorQueryType Type() const { return type_; }
const ScopedCSSName* AnchorName() const { return anchor_name_; }
const AnchorSpecifierValue& AnchorSpecifier() const {
return *anchor_specifier_;
}
AnchorValue AnchorSide() const {
DCHECK_EQ(type_, AnchorQueryType::kAnchor);
return value_.anchor_side;
Expand Down Expand Up @@ -67,13 +71,14 @@ class CORE_EXPORT CalculationExpressionAnchorQueryNode final
AnchorSizeValue anchor_size;
};

CalculationExpressionAnchorQueryNode(AnchorQueryType type,
const ScopedCSSName* anchor_name,
AnchorQueryValue value,
float side_percentage,
const Length& fallback)
CalculationExpressionAnchorQueryNode(
AnchorQueryType type,
const AnchorSpecifierValue& anchor_specifier,
AnchorQueryValue value,
float side_percentage,
const Length& fallback)
: type_(type),
anchor_name_(anchor_name),
anchor_specifier_(anchor_specifier),
value_(value),
side_percentage_(side_percentage),
fallback_(fallback) {
Expand All @@ -82,7 +87,7 @@ class CORE_EXPORT CalculationExpressionAnchorQueryNode final

private:
AnchorQueryType type_;
Persistent<const ScopedCSSName> anchor_name_;
Persistent<const AnchorSpecifierValue> anchor_specifier_;
AnchorQueryValue value_;
float side_percentage_ = 0; // For AnchorSideValue::kPercentage only
Length fallback_;
Expand Down
78 changes: 47 additions & 31 deletions third_party/blink/renderer/core/css/css_math_expression_node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1240,23 +1240,24 @@ bool CSSMathExpressionOperation::InvolvesPercentageComparisons() const {

CSSMathExpressionAnchorQuery::CSSMathExpressionAnchorQuery(
CSSAnchorQueryType type,
const CSSCustomIdentValue* anchor_name,
const CSSValue* anchor_specifier,
const CSSValue& value,
const CSSPrimitiveValue* fallback)
: CSSMathExpressionNode(kCalcPercentLength,
false /* has_comparisons */,
(anchor_name && !anchor_name->IsScopedValue()) ||
(fallback && !fallback->IsScopedValue())),
: CSSMathExpressionNode(
kCalcPercentLength,
false /* has_comparisons */,
(anchor_specifier && !anchor_specifier->IsScopedValue()) ||
(fallback && !fallback->IsScopedValue())),
type_(type),
anchor_name_(anchor_name),
anchor_specifier_(anchor_specifier),
value_(value),
fallback_(fallback) {}

String CSSMathExpressionAnchorQuery::CustomCSSText() const {
StringBuilder result;
result.Append(IsAnchor() ? "anchor(" : "anchor-size(");
if (anchor_name_) {
result.Append(anchor_name_->CustomCSSText());
if (anchor_specifier_) {
result.Append(anchor_specifier_->CssText());
result.Append(" ");
}
result.Append(value_->CssText());
Expand All @@ -1275,7 +1276,8 @@ bool CSSMathExpressionAnchorQuery::operator==(
return false;
}
return type_ == other_anchor->type_ &&
base::ValuesEquivalent(anchor_name_, other_anchor->anchor_name_) &&
base::ValuesEquivalent(anchor_specifier_,
other_anchor->anchor_specifier_) &&
base::ValuesEquivalent(value_, other_anchor->value_) &&
base::ValuesEquivalent(fallback_, other_anchor->fallback_);
}
Expand Down Expand Up @@ -1334,10 +1336,17 @@ scoped_refptr<const CalculationExpressionNode>
CSSMathExpressionAnchorQuery::ToCalculationExpression(
const CSSLengthResolver& length_resolver) const {
DCHECK(IsScopedValue());
ScopedCSSName* anchor_name =
anchor_name_ ? MakeGarbageCollected<ScopedCSSName>(
anchor_name_->Value(), anchor_name_->GetTreeScope())
: nullptr;
AnchorSpecifierValue* anchor_specifier = AnchorSpecifierValue::Default();
if (const auto* implicit =
DynamicTo<CSSIdentifierValue>(anchor_specifier_.Get())) {
DCHECK_EQ(implicit->GetValueID(), CSSValueID::kImplicit);
anchor_specifier = AnchorSpecifierValue::Implicit();
} else if (const auto* custom_ident =
DynamicTo<CSSCustomIdentValue>(anchor_specifier_.Get())) {
anchor_specifier = MakeGarbageCollected<AnchorSpecifierValue>(
*MakeGarbageCollected<ScopedCSSName>(custom_ident->Value(),
custom_ident->GetTreeScope()));
}
Length fallback = fallback_ ? fallback_->ConvertToLength(length_resolver)
: Length::Fixed(0);

Expand All @@ -1346,17 +1355,18 @@ CSSMathExpressionAnchorQuery::ToCalculationExpression(
DynamicTo<CSSPrimitiveValue>(*value_)) {
DCHECK(percentage->IsPercentage());
return CalculationExpressionAnchorQueryNode::CreateAnchorPercentage(
anchor_name, percentage->GetFloatValue(), fallback);
*anchor_specifier, percentage->GetFloatValue(), fallback);
}
const CSSIdentifierValue& side = To<CSSIdentifierValue>(*value_);
return CalculationExpressionAnchorQueryNode::CreateAnchor(
anchor_name, CSSValueIDToAnchorValueEnum(side.GetValueID()), fallback);
*anchor_specifier, CSSValueIDToAnchorValueEnum(side.GetValueID()),
fallback);
}

DCHECK_EQ(type_, CSSAnchorQueryType::kAnchorSize);
const CSSIdentifierValue& size = To<CSSIdentifierValue>(*value_);
return CalculationExpressionAnchorQueryNode::CreateAnchorSize(
anchor_name, CSSValueIDToAnchorSizeValueEnum(size.GetValueID()),
*anchor_specifier, CSSValueIDToAnchorSizeValueEnum(size.GetValueID()),
fallback);
}

Expand All @@ -1365,17 +1375,16 @@ CSSMathExpressionAnchorQuery::PopulateWithTreeScope(
const TreeScope* tree_scope) const {
return *MakeGarbageCollected<CSSMathExpressionAnchorQuery>(
type_,
anchor_name_ ? To<CSSCustomIdentValue>(
&anchor_name_->EnsureScopedValue(tree_scope))
: nullptr,
anchor_specifier_ ? &anchor_specifier_->EnsureScopedValue(tree_scope)
: nullptr,
*value_,
fallback_
? To<CSSPrimitiveValue>(&fallback_->EnsureScopedValue(tree_scope))
: nullptr);
}

void CSSMathExpressionAnchorQuery::Trace(Visitor* visitor) const {
visitor->Trace(anchor_name_);
visitor->Trace(anchor_specifier_);
visitor->Trace(value_);
visitor->Trace(fallback_);
CSSMathExpressionNode::Trace(visitor);
Expand Down Expand Up @@ -1436,9 +1445,13 @@ class CSSMathExpressionNodeParser {
return nullptr;
}

const CSSCustomIdentValue* anchor_name =
css_parsing_utils::ConsumeDashedIdent(tokens, context_);
// |anchor_name| may be omitted for the implicit anchor elements
// |anchor_specifier| may be omitted to represent the default anchor.
const CSSValue* anchor_specifier =
css_parsing_utils::ConsumeIdent<CSSValueID::kImplicit>(tokens);
if (!anchor_specifier) {
anchor_specifier =
css_parsing_utils::ConsumeDashedIdent(tokens, context_);
}

tokens.ConsumeWhitespace();
const CSSValue* value = nullptr;
Expand Down Expand Up @@ -1480,7 +1493,7 @@ class CSSMathExpressionNodeParser {
return nullptr;
}
return MakeGarbageCollected<CSSMathExpressionAnchorQuery>(
anchor_query_type, anchor_name, *value, fallback);
anchor_query_type, anchor_specifier, *value, fallback);
}

CSSMathExpressionNode* ParseMathFunction(CSSValueID function_id,
Expand Down Expand Up @@ -1867,17 +1880,20 @@ CSSMathExpressionNode* CSSMathExpressionNode::Create(
CSSAnchorQueryType type = anchor_query.Type() == AnchorQueryType::kAnchor
? CSSAnchorQueryType::kAnchor
: CSSAnchorQueryType::kAnchorSize;
const CSSCustomIdentValue* anchor_name = nullptr;
if (const ScopedCSSName* passed_name = anchor_query.AnchorName()) {
anchor_name = To<CSSCustomIdentValue>(
&MakeGarbageCollected<CSSCustomIdentValue>(passed_name->GetName())
->EnsureScopedValue(passed_name->GetTreeScope()));
const CSSValue* anchor_specifier = nullptr;
if (anchor_query.AnchorSpecifier().IsImplicit()) {
anchor_specifier = CSSIdentifierValue::Create(CSSValueID::kImplicit);
} else if (anchor_query.AnchorSpecifier().IsNamed()) {
const ScopedCSSName& name = anchor_query.AnchorSpecifier().GetName();
anchor_specifier = To<CSSCustomIdentValue>(
&MakeGarbageCollected<CSSCustomIdentValue>(name.GetName())
->EnsureScopedValue(name.GetTreeScope()));
}
CSSValue* value = AnchorQueryValueToCSSValue(anchor_query);
CSSPrimitiveValue* fallback = CSSPrimitiveValue::CreateFromLength(
anchor_query.GetFallback(), /* zoom */ 1);
return MakeGarbageCollected<CSSMathExpressionAnchorQuery>(type, anchor_name,
*value, fallback);
return MakeGarbageCollected<CSSMathExpressionAnchorQuery>(
type, anchor_specifier, *value, fallback);
}

DCHECK(node.IsOperation());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ namespace blink {
static const int kMaxExpressionDepth = 100;

class CalculationExpressionNode;
class CSSCustomIdentValue;
class CSSNumericLiteralValue;

// The order of this enum should not change since its elements are used as
Expand Down Expand Up @@ -337,7 +336,7 @@ class CORE_EXPORT CSSMathExpressionAnchorQuery final
: public CSSMathExpressionNode {
public:
CSSMathExpressionAnchorQuery(CSSAnchorQueryType type,
const CSSCustomIdentValue* anchor_name,
const CSSValue* anchor_specifier,
const CSSValue& value,
const CSSPrimitiveValue* fallback);

Expand Down Expand Up @@ -399,7 +398,7 @@ class CORE_EXPORT CSSMathExpressionAnchorQuery final

private:
CSSAnchorQueryType type_;
Member<const CSSCustomIdentValue> anchor_name_;
Member<const CSSValue> anchor_specifier_;
Member<const CSSValue> value_;
Member<const CSSPrimitiveValue> fallback_;
};
Expand Down
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,8 +1626,8 @@
{
name: "anchor-scroll",
property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal" ],
include_paths: ["third_party/blink/renderer/core/style/anchor_scroll_value.h"],
type_name: "AnchorScrollValue",
include_paths: ["third_party/blink/renderer/core/style/anchor_specifier_value.h"],
type_name: "AnchorSpecifierValue",
wrapper_pointer_name: "Persistent",
default_value: "nullptr",
field_group: "*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,9 @@ const CSSValue* AnchorScroll::ParseSingleValue(
CSSParserTokenRange& range,
const CSSParserContext& context,
const CSSParserLocalContext&) const {
if (CSSValue* value =
css_parsing_utils::ConsumeIdent<CSSValueID::kNone,
CSSValueID::kImplicit>(range)) {
if (CSSValue* value = css_parsing_utils::ConsumeIdent<
CSSValueID::kNone, CSSValueID::kDefault, CSSValueID::kImplicit>(
range)) {
return value;
}
return css_parsing_utils::ConsumeDashedIdent(range, context);
Expand All @@ -207,6 +207,9 @@ const CSSValue* AnchorScroll::CSSValueFromComputedStyleInternal(
if (!style.AnchorScroll()) {
return CSSIdentifierValue::Create(CSSValueID::kNone);
}
if (style.AnchorScroll()->IsDefault()) {
return CSSIdentifierValue::Create(CSSValueID::kDefault);
}
if (style.AnchorScroll()->IsImplicit()) {
return CSSIdentifierValue::Create(CSSValueID::kImplicit);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/style/anchor_scroll_value.h"
#include "third_party/blink/renderer/core/style/anchor_specifier_value.h"
#include "third_party/blink/renderer/core/style/reference_clip_path_operation.h"
#include "third_party/blink/renderer/core/style/scoped_css_name.h"
#include "third_party/blink/renderer/core/style/shape_clip_path_operation.h"
Expand Down Expand Up @@ -1691,23 +1691,25 @@ ScopedCSSName* StyleBuilderConverter::ConvertAnchorDefault(
custom_ident.GetTreeScope());
}

AnchorScrollValue* StyleBuilderConverter::ConvertAnchorScroll(
AnchorSpecifierValue* StyleBuilderConverter::ConvertAnchorScroll(
StyleResolverState& state,
const CSSValue& value) {
DCHECK(value.IsScopedValue());
if (const auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
switch (identifier_value->GetValueID()) {
case CSSValueID::kNone:
return nullptr;
case CSSValueID::kDefault:
return AnchorSpecifierValue::Default();
case CSSValueID::kImplicit:
return AnchorScrollValue::Implicit();
return AnchorSpecifierValue::Implicit();
default:
NOTREACHED();
return nullptr;
}
}
const CSSCustomIdentValue& custom_ident = To<CSSCustomIdentValue>(value);
return MakeGarbageCollected<AnchorScrollValue>(
return MakeGarbageCollected<AnchorSpecifierValue>(
*MakeGarbageCollected<ScopedCSSName>(custom_ident.Value(),
custom_ident.GetTreeScope()));
}
Expand Down

0 comments on commit 003ae32

Please sign in to comment.