Commit a9c8f08e authored by Kent Tamura's avatar Kent Tamura Committed by Commit Bot

delegatesFocus: Share code in Element::focus() and...

delegatesFocus: Share code in Element::focus() and MouseEventManager::SlideFocusOnShadowHostIfNecessary()

This CL has no behavior changes.

Bug: 1014094
Change-Id: I88dc1ca15210ff96c698f32416c3d284859ad583
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1880899Reviewed-by: default avatarRakina Zata Amni <rakina@chromium.org>
Commit-Queue: Kent Tamura <tkent@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709784}
parent b4234609
......@@ -3977,6 +3977,32 @@ bool Element::hasAttributeNS(const AtomicString& namespace_uri,
return GetElementData()->Attributes().Find(q_name);
}
// Step 1 of https://html.spec.whatwg.org/C/#focusing-steps in a case
// where |new focus target| is an element.
Element* Element::FindActualFocusTarget() const {
// TODO(crbug.com/1018619): Support AREA -> IMG delegation.
if (!AuthorShadowRoot() || !AuthorShadowRoot()->delegatesFocus())
return nullptr;
Document& doc = GetDocument();
UseCounter::Count(doc, WebFeature::kDelegateFocus);
// TODO(https://github.com/w3c/webcomponents/issues/840): We'd like to
// standardize this behavior.
Element* focused_element = doc.FocusedElement();
if (focused_element && IsShadowIncludingInclusiveAncestorOf(*focused_element))
return focused_element;
// Slide the focus to its inner node.
// TODO(crbug.com/1014094): We should pick the first focusable element in
// the flat tree.
Element* found =
doc.GetPage()->GetFocusController().FindFocusableElementInShadowHost(
*this);
if (found && IsShadowIncludingInclusiveAncestorOf(*found))
return found;
return nullptr;
}
void Element::focus(const FocusOptions* options) {
focus(FocusParams(SelectionBehaviorOnFocus::kRestore, kWebFocusTypeNone,
nullptr, options));
......@@ -4002,25 +4028,20 @@ void Element::focus(const FocusParams& params) {
DisplayLockUtilities::ScopedChainForcedUpdate scoped_update_forced(this);
GetDocument().UpdateStyleAndLayoutTree();
if (!IsFocusable()) {
if (AuthorShadowRoot() && AuthorShadowRoot()->delegatesFocus()) {
UseCounter::Count(GetDocument(), WebFeature::kDelegateFocus);
Element* focused_element = GetDocument().FocusedElement();
if (focused_element &&
IsShadowIncludingInclusiveAncestorOf(*focused_element))
return;
// Slide the focus to its inner node.
Element* found = GetDocument()
.GetPage()
->GetFocusController()
.FindFocusableElementInShadowHost(*this);
if (found && IsShadowIncludingInclusiveAncestorOf(*found)) {
found->focus(FocusParams(SelectionBehaviorOnFocus::kReset,
kWebFocusTypeForward, nullptr,
params.options));
}
// https://html.spec.whatwg.org/C/#focusing-steps
//
// 1. If new focus target is not a focusable area, ...
if (!IsFocusable()) {
if (Element* new_focus_target = FindActualFocusTarget()) {
// Unlike the specification, we re-run focus() for new_focus_target
// because we can't change |this| in a member function.
new_focus_target->focus(FocusParams(SelectionBehaviorOnFocus::kReset,
kWebFocusTypeForward, nullptr,
params.options));
}
// 2. If new focus target is null, then:
// 2.1. If no fallback target was specified, then return.
return;
}
// If script called focus(), then the type would be none. This means we are
......
......@@ -645,6 +645,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
virtual const AtomicString ImageSourceURL() const;
virtual Image* ImageContents() { return nullptr; }
Element* FindActualFocusTarget() const;
virtual void focus(const FocusParams& = FocusParams());
void focus(const FocusOptions*);
......
......@@ -649,30 +649,12 @@ WebInputEventResult MouseEventManager::HandleMouseFocus(
bool MouseEventManager::SlideFocusOnShadowHostIfNecessary(
const Element& element) {
if (element.AuthorShadowRoot() &&
element.AuthorShadowRoot()->delegatesFocus()) {
Document* doc = frame_->GetDocument();
UseCounter::Count(doc, WebFeature::kDelegateFocus);
Element* focused_element = doc->FocusedElement();
if (focused_element &&
element.IsShadowIncludingInclusiveAncestorOf(*focused_element)) {
// If the inner element is already focused, do nothing.
return true;
}
// If the host has a focusable inner element, focus it. Otherwise, the host
// takes focus.
Page* page = frame_->GetPage();
DCHECK(page);
Element* found =
page->GetFocusController().FindFocusableElementInShadowHost(element);
if (found && element.IsShadowIncludingInclusiveAncestorOf(*found)) {
// Use WebFocusTypeForward instead of WebFocusTypeMouse here to mean the
// focus has slided.
found->focus(FocusParams(SelectionBehaviorOnFocus::kReset,
kWebFocusTypeForward, nullptr));
return true;
}
if (Element* delegated_target = element.FindActualFocusTarget()) {
// Use WebFocusTypeForward instead of WebFocusTypeMouse here to mean the
// focus has slided.
delegated_target->focus(FocusParams(SelectionBehaviorOnFocus::kReset,
kWebFocusTypeForward, nullptr));
return true;
}
return false;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment