Optimize the code to check if an element delegates focus to its shadow root or not master
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Feb 2021 06:50:56 +0000 (06:50 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Feb 2021 06:50:56 +0000 (06:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=222404

Reviewed by Simon Fraser.

Add a fast path for checking whether a given element is a shadow host with a shadow root
with delegatesFocus set to true in with a new node flag: DelegatesFocusToShadowRoot.

The flag is set in Element::attachShadow and never cleared as delegatesFocus can never be unset.

No new tests since there should be no observable behavioral differences.

* dom/Element.cpp:
(WebCore::Element::isKeyboardFocusable const): Optimized this code using the new flag.
(WebCore::shadowRootWithDelegatesFocus): Set the flag.
(WebCore::isProgramaticallyFocusable): Optimized this code using the new flag.
(WebCore::Element::focus): Ditto.
* dom/Node.h:
(WebCore::Node::delegatesFocusToShadowRoot const): Added.
(WebCore::Node::NodeFlag): Added NodeFlag::DelegatesFocusToShadowRoot.
(WebCore::Node::setDelegatesFocusToShadowRoot): Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@273474 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Node.h

index 3c77311..35bfcf9 100644 (file)
@@ -1,3 +1,27 @@
+2021-02-24  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Optimize the code to check if an element delegates focus to its shadow root or not
+        https://bugs.webkit.org/show_bug.cgi?id=222404
+
+        Reviewed by Simon Fraser.
+
+        Add a fast path for checking whether a given element is a shadow host with a shadow root
+        with delegatesFocus set to true in with a new node flag: DelegatesFocusToShadowRoot.
+
+        The flag is set in Element::attachShadow and never cleared as delegatesFocus can never be unset.
+
+        No new tests since there should be no observable behavioral differences.
+
+        * dom/Element.cpp:
+        (WebCore::Element::isKeyboardFocusable const): Optimized this code using the new flag.
+        (WebCore::shadowRootWithDelegatesFocus): Set the flag.
+        (WebCore::isProgramaticallyFocusable): Optimized this code using the new flag.
+        (WebCore::Element::focus): Ditto.
+        * dom/Node.h:
+        (WebCore::Node::delegatesFocusToShadowRoot const): Added.
+        (WebCore::Node::NodeFlag): Added NodeFlag::DelegatesFocusToShadowRoot.
+        (WebCore::Node::setDelegatesFocusToShadowRoot): Added.
+
 2021-02-24  Rob Buis  <rbuis@igalia.com>
 
         [css-grid] Do not allow negative heights
index 1fc4265..26e3b82 100644 (file)
@@ -315,11 +315,8 @@ bool Element::isKeyboardFocusable(KeyboardEvent*) const
 {
     if (!(isFocusable() && !shouldBeIgnoredInSequentialFocusNavigation() && tabIndexSetExplicitly().valueOr(0) >= 0))
         return false;
-    if (auto* root = shadowRoot()) {
-        if (root->delegatesFocus())
-            return false;
-    }
-    return true;
+    ASSERT(delegatesFocusToShadowRoot() == (shadowRoot() && shadowRoot()->delegatesFocus()));
+    return !delegatesFocusToShadowRoot();
 }
 
 bool Element::isMouseFocusable() const
@@ -2393,6 +2390,8 @@ ExceptionOr<ShadowRoot&> Element::attachShadow(const ShadowRootInit& init)
     if (init.mode == ShadowRootMode::UserAgent)
         return Exception { TypeError };
     auto shadow = ShadowRoot::create(document(), init.mode, init.delegatesFocus ? ShadowRoot::DelegatesFocus::Yes : ShadowRoot::DelegatesFocus::No);
+    if (init.delegatesFocus)
+        setDelegatesFocusToShadowRoot();
     auto& result = shadow.get();
     addShadowRoot(WTFMove(shadow));
     return result;
@@ -2976,7 +2975,8 @@ static bool isProgramaticallyFocusable(Element& element)
 {
     ScriptDisallowedScope::InMainThread scriptDisallowedScope;
 
-    if (shadowRootWithDelegatesFocus(element))
+    ASSERT(element.delegatesFocusToShadowRoot() == !!shadowRootWithDelegatesFocus(element));
+    if (element.delegatesFocusToShadowRoot())
         return false;
 
     // If the stylesheets have already been loaded we can reliably check isFocusable.
@@ -3023,7 +3023,9 @@ void Element::focus(SelectionRestorationMode restorationMode, FocusDirection dir
     if (&newTarget->document() != document.ptr())
         return;
 
-    if (auto root = shadowRootWithDelegatesFocus(*this)) {
+    ASSERT(delegatesFocusToShadowRoot() == !!shadowRootWithDelegatesFocus(*this));
+    if (delegatesFocusToShadowRoot()) {
+        auto root = shadowRootWithDelegatesFocus(*this);
         auto currentlyFocusedElement = makeRefPtr(document->focusedElement());
         if (root->containsIncludingShadowDOM(currentlyFocusedElement.get())) {
             if (document->page())
index 2ecd15d..715e3d3 100644 (file)
@@ -222,6 +222,7 @@ public:
     ShadowRoot* containingShadowRoot() const;
     ShadowRoot* shadowRoot() const;
     bool isClosedShadowHidden(const Node&) const;
+    bool delegatesFocusToShadowRoot() const { return hasNodeFlag(NodeFlag::DelegatesFocusToShadowRoot); }
 
     HTMLSlotElement* assignedSlot() const;
     HTMLSlotElement* assignedSlotForBindings() const;
@@ -550,8 +551,9 @@ protected:
         ContainsFullScreenElement = 1 << 25,
 #endif
         IsComputedStyleInvalidFlag = 1 << 26,
+        DelegatesFocusToShadowRoot = 1 << 27,
 
-        // Bits 27-31 are free.
+        // Bits 28-31 are free.
     };
 
     enum class TabIndexState : uint8_t {
@@ -591,6 +593,8 @@ protected:
     void setIsParsingChildrenFinished() { setNodeFlag(NodeFlag::IsParsingChildrenFinished); }
     void clearIsParsingChildrenFinished() { clearNodeFlag(NodeFlag::IsParsingChildrenFinished); }
 
+    void setDelegatesFocusToShadowRoot() { setNodeFlag(NodeFlag::DelegatesFocusToShadowRoot); }
+
     constexpr static auto DefaultNodeFlags = OptionSet<NodeFlag>(NodeFlag::IsParsingChildrenFinished);
     constexpr static auto CreateOther = DefaultNodeFlags;
     constexpr static auto CreateCharacterData = DefaultNodeFlags | NodeFlag::IsCharacterData;