Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Update shadow DOM and dialog element focusing to latest spec
https://bugs.webkit.org/show_bug.cgi?id=233320
<rdar://85753180>

Reviewed by Ryosuke Niwa.

* LayoutTests/imported/w3c/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow-double-nested-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow-expected.txt:
* Source/WebCore/dom/Element.cpp:
(WebCore::autoFocusDelegate):
(WebCore::findFocusDelegateInternal):
(WebCore::Element::findFocusDelegate):
(WebCore::Element::focus):
(WebCore::focusDelegateFromShadowHost): Deleted.
* Source/WebCore/dom/Element.h:
* Source/WebCore/html/HTMLDialogElement.cpp:
(WebCore::HTMLDialogElement::runFocusingSteps):

Canonical link: https://commits.webkit.org/252959@main
  • Loading branch information
nt1m committed Jul 29, 2022
1 parent 1b9e51c commit 696e8c1
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 44 deletions.
@@ -1,4 +1,4 @@

FAIL show() assert_equals: document.activeElement expected Element node <div></div> but got Element node <button tabindex="-1">Focusable</button>
FAIL showModal() assert_equals: document.activeElement expected Element node <div></div> but got Element node <button tabindex="-1">Focusable</button>
PASS show()
PASS showModal()

Expand Up @@ -6,15 +6,12 @@ PASS show: No autofocus, no delegatesFocus, sibling before
PASS showModal: No autofocus, no delegatesFocus, sibling before
PASS show: No autofocus, no delegatesFocus, sibling after
PASS showModal: No autofocus, no delegatesFocus, sibling after
FAIL show: No autofocus, yes delegatesFocus, no siblings assert_equals: expected Element node <div></div> but got Element node <button tabindex="-1" id="focus-between-tests">Focus betw...
FAIL showModal: No autofocus, yes delegatesFocus, no siblings assert_equals: expected Element node <div></div> but got Element node <body>

<!--
We focus this one between each test, to en...
PASS show: No autofocus, yes delegatesFocus, no siblings
PASS showModal: No autofocus, yes delegatesFocus, no siblings
PASS show: No autofocus, yes delegatesFocus, sibling before
PASS showModal: No autofocus, yes delegatesFocus, sibling before
FAIL show: No autofocus, yes delegatesFocus, sibling after assert_equals: expected Element node <div></div> but got Element node <button tabindex="-1">Focusable</button>
FAIL showModal: No autofocus, yes delegatesFocus, sibling after assert_equals: expected Element node <div></div> but got Element node <button tabindex="-1">Focusable</button>
PASS show: No autofocus, yes delegatesFocus, sibling after
PASS showModal: No autofocus, yes delegatesFocus, sibling after
PASS show: Autofocus before, no delegatesFocus
PASS showModal: Autofocus before, no delegatesFocus
PASS show: Autofocus before, yes delegatesFocus
Expand All @@ -23,30 +20,24 @@ PASS show: Autofocus after, no delegatesFocus
PASS showModal: Autofocus after, no delegatesFocus
PASS show: Autofocus after, yes delegatesFocus
PASS showModal: Autofocus after, yes delegatesFocus
FAIL show: Autofocus on shadow host, yes delegatesFocus, no siblings assert_equals: expected Element node <div autofocus=""></div> but got Element node <button tabindex="-1" id="focus-between-tests">Focus betw...
FAIL showModal: Autofocus on shadow host, yes delegatesFocus, no siblings assert_equals: expected Element node <div autofocus=""></div> but got Element node <body>

<!--
We focus this one between each test, to en...
PASS show: Autofocus on shadow host, yes delegatesFocus, no siblings
PASS showModal: Autofocus on shadow host, yes delegatesFocus, no siblings
FAIL show: Autofocus on shadow host, yes delegatesFocus, sibling before assert_equals: expected Element node <div autofocus=""></div> but got Element node <button tabindex="-1">Focusable</button>
FAIL showModal: Autofocus on shadow host, yes delegatesFocus, sibling before assert_equals: expected Element node <div autofocus=""></div> but got Element node <button tabindex="-1">Focusable</button>
FAIL show: Autofocus on shadow host, yes delegatesFocus, sibling after assert_equals: expected Element node <div autofocus=""></div> but got Element node <button tabindex="-1">Focusable</button>
FAIL showModal: Autofocus on shadow host, yes delegatesFocus, sibling after assert_equals: expected Element node <div autofocus=""></div> but got Element node <button tabindex="-1">Focusable</button>
PASS show: Autofocus on shadow host, yes delegatesFocus, sibling after
PASS showModal: Autofocus on shadow host, yes delegatesFocus, sibling after
PASS show: Autofocus on shadow host, no delegatesFocus, no siblings
PASS showModal: Autofocus on shadow host, no delegatesFocus, no siblings
PASS show: Autofocus on shadow host, no delegatesFocus, sibling before
PASS showModal: Autofocus on shadow host, no delegatesFocus, sibling before
PASS show: Autofocus on shadow host, no delegatesFocus, sibling after
PASS showModal: Autofocus on shadow host, no delegatesFocus, sibling after
FAIL show: Autofocus inside shadow tree, yes delegatesFocus, no siblings assert_equals: expected Element node <div></div> but got Element node <button tabindex="-1" id="focus-between-tests">Focus betw...
FAIL showModal: Autofocus inside shadow tree, yes delegatesFocus, no siblings assert_equals: expected Element node <div></div> but got Element node <body>

<!--
We focus this one between each test, to en...
PASS show: Autofocus inside shadow tree, yes delegatesFocus, no siblings
PASS showModal: Autofocus inside shadow tree, yes delegatesFocus, no siblings
PASS show: Autofocus inside shadow tree, yes delegatesFocus, sibling before
PASS showModal: Autofocus inside shadow tree, yes delegatesFocus, sibling before
PASS show: Autofocus inside shadow tree, yes delegatesFocus, sibling after
PASS showModal: Autofocus inside shadow tree, yes delegatesFocus, sibling after
FAIL show: Autofocus inside shadow tree, yes delegatesFocus, sibling after assert_equals: expected Element node <button tabindex="-1" class="focus-me">Focusable</button> but got Element node <div></div>
FAIL showModal: Autofocus inside shadow tree, yes delegatesFocus, sibling after assert_equals: expected Element node <button tabindex="-1" class="focus-me">Focusable</button> but got Element node <div></div>
PASS show: Autofocus inside shadow tree, no delegatesFocus, no siblings
PASS showModal: Autofocus inside shadow tree, no delegatesFocus, no siblings
PASS show: Autofocus inside shadow tree, no delegatesFocus, sibling before
Expand Down
20 changes: 13 additions & 7 deletions Source/WebCore/dom/Element.cpp
Expand Up @@ -3206,7 +3206,7 @@ static bool isProgramaticallyFocusable(Element& element)
}

// https://html.spec.whatwg.org/multipage/interaction.html#autofocus-delegate
static RefPtr<Element> autoFocusDelegate(ShadowRoot& target)
static RefPtr<Element> autoFocusDelegate(ContainerNode& target)
{
for (auto& element : descendantsOfType<Element>(target)) {
if (!element.hasAttributeWithoutSynchronization(HTMLNames::autofocusAttr))
Expand All @@ -3222,21 +3222,27 @@ static RefPtr<Element> autoFocusDelegate(ShadowRoot& target)
}

// https://html.spec.whatwg.org/multipage/interaction.html#focus-delegate
static RefPtr<Element> focusDelegateFromShadowHost(ShadowRoot& target)
static RefPtr<Element> findFocusDelegateInternal(ContainerNode& target)
{
if (auto element = autoFocusDelegate(target))
return element;
for (auto& element : descendantsOfType<Element>(target)) {
for (auto& element : childrenOfType<Element>(target)) {
if (isProgramaticallyFocusable(element))
return &element;
if (auto root = shadowRootWithDelegatesFocus(element)) {
if (auto target = focusDelegateFromShadowHost(*root))
if (auto target = findFocusDelegateInternal(*root))
return target;
}
if (isProgramaticallyFocusable(element))
return &element;
}
return nullptr;
}

// https://html.spec.whatwg.org/multipage/interaction.html#focus-delegate
RefPtr<Element> Element::findFocusDelegate()
{
return findFocusDelegateInternal(*this);
}

void Element::focus(const FocusOptions& options)
{
if (!isConnected())
Expand Down Expand Up @@ -3267,7 +3273,7 @@ void Element::focus(const FocusOptions& options)
return;
}

newTarget = focusDelegateFromShadowHost(*root);
newTarget = findFocusDelegateInternal(*root);
if (!newTarget)
return;
} else if (!isProgramaticallyFocusable(*newTarget))
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/dom/Element.h
Expand Up @@ -437,6 +437,8 @@ class Element : public ContainerNode {
virtual const AtomString& imageSourceURL() const;
virtual AtomString target() const { return nullAtom(); }

RefPtr<Element> findFocusDelegate();

static AXTextStateChangeIntent defaultFocusTextStateChangeIntent() { return AXTextStateChangeIntent(AXTextStateChangeTypeSelectionMove, AXTextSelection { AXTextSelectionDirectionDiscontiguous, AXTextSelectionGranularityUnknown, true }); }
virtual void focus(const FocusOptions& = { });
virtual void focusForBindings(FocusOptions&&);
Expand Down
15 changes: 1 addition & 14 deletions Source/WebCore/html/HTMLDialogElement.cpp
Expand Up @@ -126,20 +126,7 @@ void HTMLDialogElement::queueCancelTask()
// https://html.spec.whatwg.org/multipage/interactive-elements.html#dialog-focusing-steps
void HTMLDialogElement::runFocusingSteps()
{
RefPtr<Element> control;
for (auto& element : descendantsOfType<Element>(*this)) {
if (!element.isFocusable())
continue;

if (element.hasAttribute(autofocusAttr)) {
control = &element;
break;
}

// FIXME: Potentially remove this and adjust related WPTs after https://github.com/whatwg/html/pull/4184.
if (!control)
control = &element;
}
RefPtr control = findFocusDelegate();

if (!control)
control = this;
Expand Down

0 comments on commit 696e8c1

Please sign in to comment.