-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create helpers for easier iteration of elements in a CSS toggle(-grou…
…p) scope. This refactors existing code that iterates through the elements in the scope of a CSS toggle group into code that is usable for both toggle scopes and toggle group scopes. The iteration of toggle scopes (as opposed to toggle group scopes) is unused as of this commit, but it will be useful for implementing accessibility heuristics, which require a good bit of enumeration of the elements in a CSS toggle scope. Support for toggles is controlled by the CSSToggles flag (currently off) in RuntimeEnabledFeatures. Bug: 1250716 Change-Id: Id882631c769a72a9e7ad7c05ab47e8693e947c06 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4184799 Commit-Queue: David Baron <dbaron@chromium.org> Reviewed-by: Joey Arhar <jarhar@chromium.org> Cr-Commit-Position: refs/heads/main@{#1100597}
- Loading branch information
Showing
3 changed files
with
162 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
154 changes: 154 additions & 0 deletions
154
third_party/blink/renderer/core/dom/css_toggle_traversal.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_CSS_TOGGLE_TRAVERSAL_H_ | ||
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_CSS_TOGGLE_TRAVERSAL_H_ | ||
|
||
#include "third_party/abseil-cpp/absl/types/optional.h" | ||
#include "third_party/blink/renderer/core/dom/css_toggle.h" | ||
#include "third_party/blink/renderer/core/dom/css_toggle_map.h" | ||
#include "third_party/blink/renderer/core/dom/element.h" | ||
#include "third_party/blink/renderer/core/dom/element_traversal.h" | ||
#include "third_party/blink/renderer/core/dom/node_computed_style.h" | ||
#include "third_party/blink/renderer/core/style/computed_style.h" | ||
#include "third_party/blink/renderer/core/style/toggle_group.h" | ||
#include "third_party/blink/renderer/core/style/toggle_group_list.h" | ||
|
||
namespace blink { | ||
|
||
struct CSSToggleGroupScopeIteratorTraits { | ||
static absl::optional<ToggleScope> Lookup(Element* element, | ||
const AtomicString& name) { | ||
// TODO(dbaron): What if style is null? See | ||
// https://github.com/tabatkins/css-toggle/issues/24 . | ||
if (const ComputedStyle* style = element->GetComputedStyle()) { | ||
if (const ToggleGroupList* toggle_groups = style->ToggleGroup()) { | ||
for (const ToggleGroup& group : toggle_groups->Groups()) { | ||
// TODO(https://github.com/tabatkins/css-toggle/issues/25): | ||
// Consider multiple occurrences of the same name. | ||
if (group.Name() == name) { | ||
return group.Scope(); | ||
} | ||
} | ||
} | ||
} | ||
return absl::nullopt; | ||
} | ||
}; | ||
|
||
struct CSSToggleScopeIteratorTraits { | ||
static absl::optional<ToggleScope> Lookup(Element* element, | ||
const AtomicString& name) { | ||
if (CSSToggleMap* toggle_map = element->GetToggleMap()) { | ||
const auto& toggles = toggle_map->Toggles(); | ||
auto iter = toggles.find(name); | ||
if (iter != toggles.end()) { | ||
return iter->value->Scope(); | ||
} | ||
} | ||
return absl::nullopt; | ||
} | ||
}; | ||
|
||
// An iterator over the elements that are in the scope of a named toggle | ||
// or toggle group. (This excludes elements that are not in the scope | ||
// because they are in the scope of a closer toggle or toggle group with | ||
// the same name.) | ||
template <class IteratorTraits> | ||
class CSSTogglesScopeIteratorBase { | ||
STACK_ALLOCATED(); | ||
|
||
private: | ||
Element* current_; | ||
Element* stay_within_; | ||
AtomicString name_; | ||
|
||
public: | ||
CSSTogglesScopeIteratorBase(Element* current, | ||
Element* stay_within, | ||
const AtomicString& name) | ||
: current_(current), stay_within_(stay_within), name_(name) {} | ||
|
||
void operator++() { | ||
Element* e = ElementTraversal::Next(*current_, stay_within_); | ||
while (e) { | ||
// Skip descendants in a different group. | ||
absl::optional<ToggleScope> element_scope = | ||
IteratorTraits::Lookup(e, name_); | ||
if (!element_scope) { | ||
break; | ||
} | ||
switch (*element_scope) { | ||
case ToggleScope::kWide: | ||
if (e->parentElement()) { | ||
e = ElementTraversal::NextSkippingChildren(*e->parentElement(), | ||
stay_within_); | ||
} else { | ||
e = nullptr; | ||
} | ||
break; | ||
case ToggleScope::kNarrow: | ||
e = ElementTraversal::NextSkippingChildren(*e, stay_within_); | ||
break; | ||
} | ||
} | ||
current_ = e; | ||
} | ||
|
||
Element* operator*() const { return current_; } | ||
|
||
bool operator==(const CSSTogglesScopeIteratorBase& other) const { | ||
DCHECK(stay_within_ == other.stay_within_); | ||
DCHECK(name_ == other.name_); | ||
return current_ == other.current_; | ||
} | ||
|
||
bool operator!=(const CSSTogglesScopeIteratorBase& other) const { | ||
return !(*this == other); | ||
} | ||
}; | ||
|
||
// The elements that are in the scope of a named toggle or toggle group. | ||
// (This excludes elements that are not in the scope because they are in | ||
// the scope of a closer toggle or toggle group with the same name.) | ||
template <class IteratorTraits> | ||
class CSSTogglesScopeRangeBase { | ||
STACK_ALLOCATED(); | ||
|
||
private: | ||
Element* establishing_element_; | ||
Element* stay_within_; | ||
AtomicString name_; | ||
|
||
public: | ||
typedef CSSTogglesScopeIteratorBase<IteratorTraits> Iterator; | ||
|
||
CSSTogglesScopeRangeBase(Element* establishing_element, | ||
const AtomicString& name, | ||
ToggleScope scope) | ||
: establishing_element_(establishing_element), name_(name) { | ||
switch (scope) { | ||
case ToggleScope::kNarrow: | ||
stay_within_ = establishing_element; | ||
break; | ||
case ToggleScope::kWide: | ||
stay_within_ = establishing_element->parentElement(); | ||
break; | ||
} | ||
} | ||
|
||
Iterator begin() { | ||
return Iterator(establishing_element_, stay_within_, name_); | ||
} | ||
Iterator end() { return Iterator(nullptr, stay_within_, name_); } | ||
}; | ||
|
||
typedef CSSTogglesScopeRangeBase<CSSToggleGroupScopeIteratorTraits> | ||
CSSToggleGroupScopeRange; | ||
typedef CSSTogglesScopeRangeBase<CSSToggleScopeIteratorTraits> | ||
CSSToggleScopeRange; | ||
|
||
} // namespace blink | ||
|
||
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_CSS_TOGGLE_TRAVERSAL_H_ |