Use ScopedCSSName for animation-name to fix cross-scope keyframes lookup [chromium/src : main]

0 views
Skip to first unread message

Robert Flack (Gerrit)

unread,
Mar 23, 2026, 11:04:40 AM (19 hours ago) Mar 23
to Hyowon Kim, AyeAye, Chromium LUCI CQ, Menard, Alexis, chromium...@chromium.org, Olga Gerchikov, blink-revie...@chromium.org, apavlo...@chromium.org, blink-revie...@chromium.org, blink-re...@chromium.org, blink-...@chromium.org, devtools-re...@chromium.org
Attention needed from Hyowon Kim

Robert Flack added 7 comments

File third_party/blink/renderer/core/animation/css/css_animation_data.cc
Line 61, Patchset 8 (Latest):bool CSSAnimationData::NamesMatch(const CSSAnimationData& other) const {
Robert Flack . unresolved

What's the difference between this method and the HeapVector::operator==? Why can we not use the == operator?

File third_party/blink/renderer/core/animation/css/css_animations.cc
Line 524, Patchset 8 (Latest): const TreeScope* name_tree_scope = nullptr) {
Robert Flack . unresolved

When do we not pass the tree scope for the name? Can we require that a value is passed here? It looks like all calls already pass a value.

File third_party/blink/renderer/core/css/properties/computed_style_utils.cc
Line 2917, Patchset 8 (Latest): AtomicString name = scoped_name ? scoped_name->GetName() : AtomicString();
Robert Flack . unresolved

In CalculateAnimationUpdate we expected CSSAnimationData::InitialName() for these cases, is there a difference between AtomicString() and AtomicString("")? Should we continue to have a single static method to serve as the unset string value?

File third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
Line 178, Patchset 8 (Latest): scoped_name ? scoped_name->GetName() : g_empty_atom;
Robert Flack . unresolved

Here you use g_empty_atom where in another function you use AtomicString, and where previously we used a static local AtomicString(""). What's the expected consistent name to use?

File third_party/blink/renderer/core/css/resolver/style_resolver.h
Line 182, Patchset 8 (Latest): const TreeScope* name_tree_scope = nullptr);
Robert Flack . unresolved

It looks like all call sites pass a name_tree_scope, don't have a default value to ensure that all future code passes a tree scope. Otherwise we could end up with inconsistent lookups.

File third_party/blink/renderer/core/css/resolver/style_resolver.cc
Line 2672, Patchset 8 (Latest): if (name_tree_scope) {
Robert Flack . unresolved

Is there any case where we do not pass in a name_tree_scope? What does this look like?

Line 2686, Patchset 8 (Latest): }
Robert Flack . unresolved

Rather than duplicating this code in the else block, move this resolvers.empty() check and code after the if block.

Open in Gerrit

Related details

Attention is currently required from:
  • Hyowon Kim
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ib638b000ea111109e63ec6ef1a4c6593100ebe6e
Gerrit-Change-Number: 7672918
Gerrit-PatchSet: 8
Gerrit-Owner: Hyowon Kim <hyo...@igalia.com>
Gerrit-Reviewer: Hyowon Kim <hyo...@igalia.com>
Gerrit-Reviewer: Robert Flack <fla...@chromium.org>
Gerrit-CC: Menard, Alexis <alexis...@intel.com>
Gerrit-CC: Olga Gerchikov <gerc...@microsoft.com>
Gerrit-Attention: Hyowon Kim <hyo...@igalia.com>
Gerrit-Comment-Date: Mon, 23 Mar 2026 15:04:34 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Hyowon Kim (Gerrit)

unread,
3:26 AM (2 hours ago) 3:26 AM
to Robert Flack, AyeAye, Chromium LUCI CQ, Menard, Alexis, chromium...@chromium.org, Olga Gerchikov, blink-revie...@chromium.org, apavlo...@chromium.org, blink-revie...@chromium.org, blink-re...@chromium.org, blink-...@chromium.org, devtools-re...@chromium.org
Attention needed from Robert Flack

Hyowon Kim added 7 comments

File third_party/blink/renderer/core/animation/css/css_animation_data.cc
Line 61, Patchset 8:bool CSSAnimationData::NamesMatch(const CSSAnimationData& other) const {
Robert Flack . unresolved

What's the difference between this method and the HeapVector::operator==? Why can we not use the == operator?

Hyowon Kim

`name_list_` is `HeapVector<Member<const ScopedCSSName>>`.

`HeapVector<Member<T>>::operator==` compares `Member` pointers, not the pointed-to values. Since two different `ScopedCSSName` objects can have the same name and tree scope, we need `base::ValuesEquivalent` to do value comparison.

This is the same pattern used by `ScopedCSSNameList::operator==`.
https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/style/scoped_css_name.h;l=72-77

File third_party/blink/renderer/core/animation/css/css_animations.cc
Line 524, Patchset 8: const TreeScope* name_tree_scope = nullptr) {
Robert Flack . unresolved

When do we not pass the tree scope for the name? Can we require that a value is passed here? It looks like all calls already pass a value.

Hyowon Kim

You're right. All callers already pass a value. I'll remove the default and make it a required parameter.

File third_party/blink/renderer/core/css/properties/computed_style_utils.cc
Line 2917, Patchset 8: AtomicString name = scoped_name ? scoped_name->GetName() : AtomicString();
Robert Flack . unresolved

In CalculateAnimationUpdate we expected CSSAnimationData::InitialName() for these cases, is there a difference between AtomicString() and AtomicString("")? Should we continue to have a single static method to serve as the unset string value?

Hyowon Kim

Good catch - added CSSAnimationData::InitialNameString() as a single static method for the unset name string, and updated this call site to use it.

File third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
Line 178, Patchset 8: scoped_name ? scoped_name->GetName() : g_empty_atom;
Robert Flack . unresolved

Here you use g_empty_atom where in another function you use AtomicString, and where previously we used a static local AtomicString(""). What's the expected consistent name to use?

Hyowon Kim

Right, same fix - replaced g_empty_atom with CSSAnimationData::InitialNameString() for consistency.

File third_party/blink/renderer/core/css/resolver/style_resolver.h
Line 182, Patchset 8: const TreeScope* name_tree_scope = nullptr);
Robert Flack . unresolved

It looks like all call sites pass a name_tree_scope, don't have a default value to ensure that all future code passes a tree scope. Otherwise we could end up with inconsistent lookups.

Hyowon Kim

`name_tree_scope` can be null in two cases:

1) test code in style_engine_test.cc calls `FindKeyframesRule` without it.
- [style_engine_test.cc;l=473](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/css/style_engine_test.cc;l=473)

2) `ScopedCSSName::GetTreeScope()` returns null for UA stylesheet names.
- [scoped_css_name.h;l=23-26](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/style/scoped_css_name.h;l=23-26)

I'll remove the default value and have these call sites pass nullptr explicitly.
File third_party/blink/renderer/core/css/resolver/style_resolver.cc
Line 2672, Patchset 8: if (name_tree_scope) {
Robert Flack . unresolved

Is there any case where we do not pass in a name_tree_scope? What does this look like?

Hyowon Kim

Please see my reply above.

Robert Flack . unresolved

Rather than duplicating this code in the else block, move this resolvers.empty() check and code after the if block.

Hyowon Kim
These two branches can't be merged because they work differently:
- `if (name_tree_scope)` branch:
- uses `ScopedResolverFor` only as a fallback — only when `name_tree_scope` has no resolver.
- `else` branch:
- always adds `ScopedResolverFor` in addition to hosted shadow tree resolvers.

If we move the `resolvers.empty()` check after the if/else block, the `else` branch would skip `ScopedResolverFor` when `CollectScopedResolversForHostedShadowTrees` already added resolvers.

Open in Gerrit

Related details

Attention is currently required from:
  • Robert Flack
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ib638b000ea111109e63ec6ef1a4c6593100ebe6e
Gerrit-Change-Number: 7672918
Gerrit-PatchSet: 9
Gerrit-Owner: Hyowon Kim <hyo...@igalia.com>
Gerrit-Reviewer: Hyowon Kim <hyo...@igalia.com>
Gerrit-Reviewer: Robert Flack <fla...@chromium.org>
Gerrit-CC: Menard, Alexis <alexis...@intel.com>
Gerrit-CC: Olga Gerchikov <gerc...@microsoft.com>
Gerrit-Attention: Robert Flack <fla...@chromium.org>
Gerrit-Comment-Date: Tue, 24 Mar 2026 07:26:11 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Robert Flack <fla...@chromium.org>
satisfied_requirement
unsatisfied_requirement
open
diffy
Reply all
Reply to author
Forward
0 new messages