| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2008 Nuanti Ltd. | 3 * Copyright (C) 2008 Nuanti Ltd. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include "core/page/FocusController.h" | 27 #include "core/page/FocusController.h" |
| 28 | 28 |
| 29 #include "core/HTMLNames.h" | 29 #include "core/HTMLNames.h" |
| 30 #include "core/dom/AXObjectCache.h" | 30 #include "core/dom/AXObjectCache.h" |
| 31 #include "core/dom/AssignedNodeTraversal.h" |
| 32 #include "core/dom/CombinedNodeTraversal.h" |
| 33 #include "core/dom/ContainerNode.h" |
| 31 #include "core/dom/Document.h" | 34 #include "core/dom/Document.h" |
| 32 #include "core/dom/Element.h" | 35 #include "core/dom/Element.h" |
| 33 #include "core/dom/ElementTraversal.h" | 36 #include "core/dom/ElementTraversal.h" |
| 34 #include "core/dom/NodeTraversal.h" | |
| 35 #include "core/dom/Range.h" | 37 #include "core/dom/Range.h" |
| 36 #include "core/dom/shadow/ElementShadow.h" | 38 #include "core/dom/shadow/ElementShadow.h" |
| 37 #include "core/dom/shadow/ShadowRoot.h" | 39 #include "core/dom/shadow/ShadowRoot.h" |
| 38 #include "core/editing/EditingUtilities.h" // For firstPositionInOrBeforeNode | 40 #include "core/editing/EditingUtilities.h" // For firstPositionInOrBeforeNode |
| 39 #include "core/editing/Editor.h" | 41 #include "core/editing/Editor.h" |
| 40 #include "core/editing/FrameSelection.h" | 42 #include "core/editing/FrameSelection.h" |
| 41 #include "core/events/Event.h" | 43 #include "core/events/Event.h" |
| 42 #include "core/frame/FrameClient.h" | 44 #include "core/frame/FrameClient.h" |
| 43 #include "core/frame/FrameView.h" | 45 #include "core/frame/FrameView.h" |
| 44 #include "core/frame/LocalDOMWindow.h" | 46 #include "core/frame/LocalDOMWindow.h" |
| 45 #include "core/frame/LocalFrame.h" | 47 #include "core/frame/LocalFrame.h" |
| 46 #include "core/frame/RemoteFrame.h" | 48 #include "core/frame/RemoteFrame.h" |
| 47 #include "core/frame/Settings.h" | 49 #include "core/frame/Settings.h" |
| 48 #include "core/html/HTMLAreaElement.h" | 50 #include "core/html/HTMLAreaElement.h" |
| 49 #include "core/html/HTMLImageElement.h" | 51 #include "core/html/HTMLImageElement.h" |
| 50 #include "core/html/HTMLPlugInElement.h" | 52 #include "core/html/HTMLPlugInElement.h" |
| 51 #include "core/html/HTMLShadowElement.h" | 53 #include "core/html/HTMLShadowElement.h" |
| 54 #include "core/html/HTMLSlotElement.h" |
| 52 #include "core/html/HTMLTextFormControlElement.h" | 55 #include "core/html/HTMLTextFormControlElement.h" |
| 53 #include "core/input/EventHandler.h" | 56 #include "core/input/EventHandler.h" |
| 54 #include "core/page/ChromeClient.h" | 57 #include "core/page/ChromeClient.h" |
| 55 #include "core/page/FrameTree.h" | 58 #include "core/page/FrameTree.h" |
| 56 #include "core/page/Page.h" | 59 #include "core/page/Page.h" |
| 57 #include "core/layout/HitTestResult.h" | 60 #include "core/layout/HitTestResult.h" |
| 58 #include "core/page/SpatialNavigation.h" | 61 #include "core/page/SpatialNavigation.h" |
| 59 #include <limits> | 62 #include <limits> |
| 60 | 63 |
| 61 namespace blink { | 64 namespace blink { |
| 62 | 65 |
| 63 using namespace HTMLNames; | 66 using namespace HTMLNames; |
| 64 | 67 |
| 65 namespace { | 68 namespace { |
| 66 | 69 |
| 67 inline bool isShadowInsertionPointFocusScopeOwner(Element& element) | 70 inline bool isShadowInsertionPointFocusScopeOwner(Element& element) |
| 68 { | 71 { |
| 69 return isActiveShadowInsertionPoint(element) && toHTMLShadowElement(element)
.olderShadowRoot(); | 72 return isActiveShadowInsertionPoint(element) && toHTMLShadowElement(element)
.olderShadowRoot(); |
| 70 } | 73 } |
| 71 | 74 |
| 72 class FocusNavigationScope { | 75 class FocusNavigationScope { |
| 73 STACK_ALLOCATED(); | 76 STACK_ALLOCATED(); |
| 74 public: | 77 public: |
| 75 Node* rootNode() const; | 78 Node* rootNode() const; |
| 76 Element* owner() const; | 79 Element* owner() const; |
| 77 static FocusNavigationScope focusNavigationScopeOf(const Node&); | 80 static FocusNavigationScope focusNavigationScopeOf(const Node&); |
| 78 static FocusNavigationScope ownedByNonFocusableFocusScopeOwner(Element&); | 81 static FocusNavigationScope ownedByNonFocusableFocusScopeOwner(Element&); |
| 79 static FocusNavigationScope ownedByShadowHost(const Element&); | 82 static FocusNavigationScope ownedByShadowHost(const Element&); |
| 80 static FocusNavigationScope ownedByShadowInsertionPoint(HTMLShadowElement&); | 83 static FocusNavigationScope ownedByShadowInsertionPoint(HTMLShadowElement&); |
| 84 static FocusNavigationScope ownedByHTMLSlotElement(HTMLSlotElement&); |
| 81 static FocusNavigationScope ownedByIFrame(const HTMLFrameOwnerElement&); | 85 static FocusNavigationScope ownedByIFrame(const HTMLFrameOwnerElement&); |
| 82 | 86 |
| 83 private: | 87 private: |
| 84 explicit FocusNavigationScope(TreeScope*); | 88 explicit FocusNavigationScope(TreeScope*); |
| 89 explicit FocusNavigationScope(HTMLSlotElement*); |
| 85 RawPtrWillBeMember<TreeScope> m_rootTreeScope; | 90 RawPtrWillBeMember<TreeScope> m_rootTreeScope; |
| 91 RawPtrWillBeMember<HTMLSlotElement> m_rootSlot; |
| 86 }; | 92 }; |
| 87 | 93 |
| 88 FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope) | 94 FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope) |
| 89 : m_rootTreeScope(treeScope) | 95 : m_rootTreeScope(treeScope) |
| 90 { | 96 { |
| 91 ASSERT(treeScope); | 97 ASSERT(treeScope); |
| 92 } | 98 } |
| 93 | 99 |
| 100 FocusNavigationScope::FocusNavigationScope(HTMLSlotElement* slot) |
| 101 : m_rootSlot(slot) |
| 102 { |
| 103 ASSERT(slot); |
| 104 } |
| 105 |
| 94 Node* FocusNavigationScope::rootNode() const | 106 Node* FocusNavigationScope::rootNode() const |
| 95 { | 107 { |
| 108 if (m_rootSlot) |
| 109 return m_rootSlot; |
| 96 return &m_rootTreeScope->rootNode(); | 110 return &m_rootTreeScope->rootNode(); |
| 97 } | 111 } |
| 98 | 112 |
| 99 Element* FocusNavigationScope::owner() const | 113 Element* FocusNavigationScope::owner() const |
| 100 { | 114 { |
| 115 if (m_rootSlot) |
| 116 return m_rootSlot; |
| 101 Node* root = rootNode(); | 117 Node* root = rootNode(); |
| 102 if (root->isShadowRoot()) { | 118 if (root->isShadowRoot()) { |
| 103 ShadowRoot* shadowRoot = toShadowRoot(root); | 119 ShadowRoot* shadowRoot = toShadowRoot(root); |
| 104 return shadowRoot->isYoungest() ? shadowRoot->host() : shadowRoot->shado
wInsertionPointOfYoungerShadowRoot(); | 120 return shadowRoot->isYoungest() ? shadowRoot->host() : shadowRoot->shado
wInsertionPointOfYoungerShadowRoot(); |
| 105 } | 121 } |
| 106 // FIXME: Figure out the right thing for OOPI here. | 122 // FIXME: Figure out the right thing for OOPI here. |
| 107 if (Frame* frame = root->document().frame()) | 123 if (Frame* frame = root->document().frame()) |
| 108 return frame->deprecatedLocalOwner(); | 124 return frame->deprecatedLocalOwner(); |
| 109 return nullptr; | 125 return nullptr; |
| 110 } | 126 } |
| 111 | 127 |
| 112 FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(const Node& no
de) | 128 FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(const Node& no
de) |
| 113 { | 129 { |
| 130 if (AssignedNodeTraversal::isInAssignedScope(node)) |
| 131 return FocusNavigationScope(AssignedNodeTraversal::slot(node)); |
| 114 return FocusNavigationScope(&node.treeScope()); | 132 return FocusNavigationScope(&node.treeScope()); |
| 115 } | 133 } |
| 116 | 134 |
| 117 FocusNavigationScope FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(El
ement& element) | 135 FocusNavigationScope FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(El
ement& element) |
| 118 { | 136 { |
| 119 if (isShadowHost(element)) | 137 if (isShadowHost(element)) |
| 120 return FocusNavigationScope::ownedByShadowHost(element); | 138 return FocusNavigationScope::ownedByShadowHost(element); |
| 121 ASSERT(isShadowInsertionPointFocusScopeOwner(element)); | 139 if (isShadowInsertionPointFocusScopeOwner(element)) |
| 122 return FocusNavigationScope::ownedByShadowInsertionPoint(toHTMLShadowElement
(element)); | 140 return FocusNavigationScope::ownedByShadowInsertionPoint(toHTMLShadowEle
ment(element)); |
| 141 ASSERT(isHTMLSlotElement(element)); |
| 142 return FocusNavigationScope::ownedByHTMLSlotElement(toHTMLSlotElement(el
ement)); |
| 123 } | 143 } |
| 124 | 144 |
| 125 FocusNavigationScope FocusNavigationScope::ownedByShadowHost(const Element& elem
ent) | 145 FocusNavigationScope FocusNavigationScope::ownedByShadowHost(const Element& elem
ent) |
| 126 { | 146 { |
| 127 ASSERT(isShadowHost(element)); | 147 ASSERT(isShadowHost(element)); |
| 128 return FocusNavigationScope(&element.shadow()->youngestShadowRoot()); | 148 return FocusNavigationScope(&element.shadow()->youngestShadowRoot()); |
| 129 } | 149 } |
| 130 | 150 |
| 131 FocusNavigationScope FocusNavigationScope::ownedByIFrame(const HTMLFrameOwnerEle
ment& frame) | 151 FocusNavigationScope FocusNavigationScope::ownedByIFrame(const HTMLFrameOwnerEle
ment& frame) |
| 132 { | 152 { |
| 133 ASSERT(frame.contentFrame()); | 153 ASSERT(frame.contentFrame()); |
| 134 ASSERT(frame.contentFrame()->isLocalFrame()); | 154 ASSERT(frame.contentFrame()->isLocalFrame()); |
| 135 return FocusNavigationScope(toLocalFrame(frame.contentFrame())->document()); | 155 return FocusNavigationScope(toLocalFrame(frame.contentFrame())->document()); |
| 136 } | 156 } |
| 137 | 157 |
| 138 FocusNavigationScope FocusNavigationScope::ownedByShadowInsertionPoint(HTMLShado
wElement& shadowInsertionPoint) | 158 FocusNavigationScope FocusNavigationScope::ownedByShadowInsertionPoint(HTMLShado
wElement& shadowInsertionPoint) |
| 139 { | 159 { |
| 140 ASSERT(isShadowInsertionPointFocusScopeOwner(shadowInsertionPoint)); | 160 ASSERT(isShadowInsertionPointFocusScopeOwner(shadowInsertionPoint)); |
| 141 return FocusNavigationScope(shadowInsertionPoint.olderShadowRoot()); | 161 return FocusNavigationScope(shadowInsertionPoint.olderShadowRoot()); |
| 142 } | 162 } |
| 143 | 163 |
| 164 FocusNavigationScope FocusNavigationScope::ownedByHTMLSlotElement(HTMLSlotElemen
t& element) |
| 165 { |
| 166 return FocusNavigationScope(&element); |
| 167 } |
| 168 |
| 144 inline void dispatchBlurEvent(const Document& document, Element& focusedElement) | 169 inline void dispatchBlurEvent(const Document& document, Element& focusedElement) |
| 145 { | 170 { |
| 146 focusedElement.dispatchBlurEvent(nullptr, WebFocusTypePage); | 171 focusedElement.dispatchBlurEvent(nullptr, WebFocusTypePage); |
| 147 if (focusedElement == document.focusedElement()) { | 172 if (focusedElement == document.focusedElement()) { |
| 148 focusedElement.dispatchFocusOutEvent(EventTypeNames::focusout, nullptr); | 173 focusedElement.dispatchFocusOutEvent(EventTypeNames::focusout, nullptr); |
| 149 if (focusedElement == document.focusedElement()) | 174 if (focusedElement == document.focusedElement()) |
| 150 focusedElement.dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, nu
llptr); | 175 focusedElement.dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, nu
llptr); |
| 151 } | 176 } |
| 152 } | 177 } |
| 153 | 178 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 return isShadowHostWithoutCustomFocusLogic(element) && !element.isKeyboardFo
cusable(); | 242 return isShadowHostWithoutCustomFocusLogic(element) && !element.isKeyboardFo
cusable(); |
| 218 } | 243 } |
| 219 | 244 |
| 220 inline bool isKeyboardFocusableShadowHost(const Element& element) | 245 inline bool isKeyboardFocusableShadowHost(const Element& element) |
| 221 { | 246 { |
| 222 return isShadowHostWithoutCustomFocusLogic(element) && element.isKeyboardFoc
usable(); | 247 return isShadowHostWithoutCustomFocusLogic(element) && element.isKeyboardFoc
usable(); |
| 223 } | 248 } |
| 224 | 249 |
| 225 inline bool isNonFocusableFocusScopeOwner(Element& element) | 250 inline bool isNonFocusableFocusScopeOwner(Element& element) |
| 226 { | 251 { |
| 227 return isNonKeyboardFocusableShadowHost(element) || isShadowInsertionPointFo
cusScopeOwner(element); | 252 return isNonKeyboardFocusableShadowHost(element) || isShadowInsertionPointFo
cusScopeOwner(element) || isHTMLSlotElement(element); |
| 228 } | 253 } |
| 229 | 254 |
| 230 inline bool isShadowHostDelegatesFocus(const Element& element) | 255 inline bool isShadowHostDelegatesFocus(const Element& element) |
| 231 { | 256 { |
| 232 return element.authorShadowRoot() && element.authorShadowRoot()->delegatesFo
cus(); | 257 return element.authorShadowRoot() && element.authorShadowRoot()->delegatesFo
cus(); |
| 233 } | 258 } |
| 234 | 259 |
| 235 inline int adjustedTabIndex(Node& node) | 260 inline int adjustedTabIndex(Node& node) |
| 236 { | 261 { |
| 237 return node.isElementNode() && isNonFocusableFocusScopeOwner(toElement(node)
) ? 0 : node.tabIndex(); | 262 return node.isElementNode() && isNonFocusableFocusScopeOwner(toElement(node)
) ? 0 : node.tabIndex(); |
| 238 } | 263 } |
| 239 | 264 |
| 240 inline bool shouldVisit(Node& node) | 265 inline bool shouldVisit(Node& node) |
| 241 { | 266 { |
| 242 if (!node.isElementNode()) | 267 if (!node.isElementNode()) |
| 243 return false; | 268 return false; |
| 244 Element& element = toElement(node); | 269 Element& element = toElement(node); |
| 245 return element.isKeyboardFocusable() || isNonFocusableFocusScopeOwner(elemen
t); | 270 return element.isKeyboardFocusable() || isNonFocusableFocusScopeOwner(elemen
t); |
| 246 } | 271 } |
| 247 | 272 |
| 248 Element* findElementWithExactTabIndex(Node* start, int tabIndex, WebFocusType ty
pe) | 273 Element* findElementWithExactTabIndex(Node* start, int tabIndex, WebFocusType ty
pe) |
| 249 { | 274 { |
| 250 // Search is inclusive of start | 275 // Search is inclusive of start |
| 251 for (Node* node = start; node; node = type == WebFocusTypeForward ? ElementT
raversal::next(*node) : ElementTraversal::previous(*node)) { | 276 if (!start) |
| 277 return nullptr; |
| 278 CombinedNodeTraversal* traversal = new CombinedNodeTraversal(*start); |
| 279 for (Node* node = start; node; node = type == WebFocusTypeForward ? traversa
l->next() : traversal->previous()) { |
| 252 if (shouldVisit(*node) && adjustedTabIndex(*node) == tabIndex) | 280 if (shouldVisit(*node) && adjustedTabIndex(*node) == tabIndex) |
| 253 return toElement(node); | 281 return toElement(node); |
| 254 } | 282 } |
| 255 return nullptr; | 283 return nullptr; |
| 256 } | 284 } |
| 257 | 285 |
| 258 Element* nextElementWithGreaterTabIndex(Node* start, int tabIndex) | 286 Element* nextElementWithGreaterTabIndex(Node* start, int tabIndex) |
| 259 { | 287 { |
| 260 // Search is inclusive of start | 288 // Search is inclusive of start |
| 261 int winningTabIndex = std::numeric_limits<short>::max() + 1; | 289 int winningTabIndex = std::numeric_limits<short>::max() + 1; |
| 262 Node* winner = nullptr; | 290 Node* winner = nullptr; |
| 263 for (Node& node : NodeTraversal::startsAt(start)) { | 291 if (!start) |
| 264 int currentTabIndex = adjustedTabIndex(node); | 292 return nullptr; |
| 265 if (shouldVisit(node) && currentTabIndex > tabIndex && currentTabIndex <
winningTabIndex) { | 293 |
| 266 winner = &node; | 294 CombinedNodeTraversal* traversal = new CombinedNodeTraversal(*start); |
| 295 for (Node* node = start; node; node = traversal->next()) { |
| 296 int currentTabIndex = adjustedTabIndex(*node); |
| 297 if (shouldVisit(*node) && currentTabIndex > tabIndex && currentTabIndex
< winningTabIndex) { |
| 298 winner = node; |
| 267 winningTabIndex = currentTabIndex; | 299 winningTabIndex = currentTabIndex; |
| 268 } | 300 } |
| 269 } | 301 } |
| 270 ASSERT(!winner || winner->isElementNode()); | 302 ASSERT(!winner || winner->isElementNode()); |
| 271 return toElement(winner); | 303 return toElement(winner); |
| 272 } | 304 } |
| 273 | 305 |
| 274 Element* previousElementWithLowerTabIndex(Node* start, int tabIndex) | 306 Element* previousElementWithLowerTabIndex(Node* start, int tabIndex) |
| 275 { | 307 { |
| 276 // Search is inclusive of start | 308 // Search is inclusive of start |
| 277 int winningTabIndex = 0; | 309 int winningTabIndex = 0; |
| 278 Node* winner = nullptr; | 310 Node* winner = nullptr; |
| 279 for (Node* node = start; node; node = ElementTraversal::previous(*node)) { | 311 CombinedNodeTraversal* traversal = new CombinedNodeTraversal(*start); |
| 312 for (Node* node = start; node; node = traversal->previous()) { |
| 280 int currentTabIndex = adjustedTabIndex(*node); | 313 int currentTabIndex = adjustedTabIndex(*node); |
| 281 if (shouldVisit(*node) && currentTabIndex < tabIndex && currentTabIndex
> winningTabIndex) { | 314 if (shouldVisit(*node) && currentTabIndex < tabIndex && currentTabIndex
> winningTabIndex) { |
| 282 winner = node; | 315 winner = node; |
| 283 winningTabIndex = currentTabIndex; | 316 winningTabIndex = currentTabIndex; |
| 284 } | 317 } |
| 285 } | 318 } |
| 286 ASSERT(!winner || winner->isElementNode()); | 319 ASSERT(!winner || winner->isElementNode()); |
| 287 return toElement(winner); | 320 return toElement(winner); |
| 288 } | 321 } |
| 289 | 322 |
| 290 Element* nextFocusableElement(const FocusNavigationScope& scope, Node* start) | 323 Element* nextFocusableElement(const FocusNavigationScope& scope, Node* start) |
| 291 { | 324 { |
| 292 if (start) { | 325 if (start) { |
| 293 int tabIndex = adjustedTabIndex(*start); | 326 int tabIndex = adjustedTabIndex(*start); |
| 294 // If a node is excluded from the normal tabbing cycle, the next focusab
le node is determined by tree order | 327 // If a node is excluded from the normal tabbing cycle, the next focusab
le node is determined by tree order |
| 295 if (tabIndex < 0) { | 328 if (tabIndex < 0) { |
| 296 for (Node& node : NodeTraversal::startsAfter(*start)) { | 329 CombinedNodeTraversal* traversal = new CombinedNodeTraversal(*start)
; |
| 297 if (shouldVisit(node) && adjustedTabIndex(node) >= 0) | 330 for (Node* node = traversal->next(); node; node = traversal->next())
{ |
| 298 return &toElement(node); | 331 if (shouldVisit(*node) && adjustedTabIndex(*node) >= 0) |
| 332 return &toElement(*node); |
| 299 } | 333 } |
| 300 } else { | 334 } else { |
| 301 // First try to find a node with the same tabindex as start that com
es after start in the scope. | 335 // First try to find a node with the same tabindex as start that com
es after start in the scope. |
| 302 if (Element* winner = findElementWithExactTabIndex(ElementTraversal:
:next(*start), tabIndex, WebFocusTypeForward)) | 336 CombinedNodeTraversal* traversal = new CombinedNodeTraversal(*start)
; |
| 337 if (Element* winner = findElementWithExactTabIndex(traversal->next()
, tabIndex, WebFocusTypeForward)) |
| 303 return winner; | 338 return winner; |
| 304 } | 339 } |
| 305 if (!tabIndex) { | 340 if (!tabIndex) { |
| 306 // We've reached the last node in the document with a tabindex of 0.
This is the end of the tabbing order. | 341 // We've reached the last node in the document with a tabindex of 0.
This is the end of the tabbing order. |
| 307 return nullptr; | 342 return nullptr; |
| 308 } | 343 } |
| 309 } | 344 } |
| 310 | 345 |
| 311 // Look for the first node in the scope that: | 346 // Look for the first node in the scope that: |
| 312 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if
start is null), and | 347 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if
start is null), and |
| 313 // 2) comes first in the scope, if there's a tie. | 348 // 2) comes first in the scope, if there's a tie. |
| 314 if (Element* winner = nextElementWithGreaterTabIndex(scope.rootNode(), start
? adjustedTabIndex(*start) : 0)) | 349 if (isHTMLSlotElement(scope.rootNode())) { |
| 350 if (Element* winner = nextElementWithGreaterTabIndex(toHTMLSlotElement(s
cope.rootNode())->getAssignedNodes()[0].get(), start ? adjustedTabIndex(*start)
: 0)) |
| 351 return winner; |
| 352 return findElementWithExactTabIndex(toHTMLSlotElement(scope.rootNode())-
>getAssignedNodes()[0].get(), 0, WebFocusTypeForward); |
| 353 } |
| 354 |
| 355 if (Element* winner = nextElementWithGreaterTabIndex(scope.rootNode(), start
? adjustedTabIndex(*start) : 0)) { |
| 315 return winner; | 356 return winner; |
| 316 | 357 } |
| 317 // There are no nodes with a tabindex greater than start's tabindex, | 358 // There are no nodes with a tabindex greater than start's tabindex, |
| 318 // so find the first node with a tabindex of 0. | 359 // so find the first node with a tabindex of 0. |
| 319 return findElementWithExactTabIndex(scope.rootNode(), 0, WebFocusTypeForward
); | 360 return findElementWithExactTabIndex(scope.rootNode(), 0, WebFocusTypeForward
); |
| 320 } | 361 } |
| 321 | 362 |
| 322 Element* previousFocusableElement(const FocusNavigationScope& scope, Node* start
) | 363 Element* previousFocusableElement(const FocusNavigationScope& scope, Node* start
) |
| 323 { | 364 { |
| 324 Node* last = nullptr; | 365 Node* last = nullptr; |
| 325 for (Node* node = scope.rootNode(); node; node = node->lastChild()) | 366 if (isHTMLSlotElement(scope.rootNode()) && !toHTMLSlotElement(scope.rootNode
())->getAssignedNodes().isEmpty()) { |
| 326 last = node; | 367 last = toHTMLSlotElement(scope.rootNode())->getAssignedNodes().last().ge
t(); |
| 368 } else { |
| 369 for (Node* node = scope.rootNode(); node; node = node->lastChild()) |
| 370 last = node; |
| 371 } |
| 327 ASSERT(last); | 372 ASSERT(last); |
| 328 | 373 |
| 329 // First try to find the last node in the scope that comes before start and
has the same tabindex as start. | 374 // First try to find the last node in the scope that comes before start and
has the same tabindex as start. |
| 330 // If start is null, find the last node in the scope with a tabindex of 0. | 375 // If start is null, find the last node in the scope with a tabindex of 0. |
| 331 Node* startingNode; | 376 Node* startingNode; |
| 332 int startingTabIndex; | 377 int startingTabIndex; |
| 333 if (start) { | 378 if (start) { |
| 334 startingNode = ElementTraversal::previous(*start); | 379 CombinedNodeTraversal* traversal = new CombinedNodeTraversal(*start); |
| 380 startingNode = traversal->previous(); |
| 335 startingTabIndex = adjustedTabIndex(*start); | 381 startingTabIndex = adjustedTabIndex(*start); |
| 336 } else { | 382 } else { |
| 337 startingNode = last; | 383 startingNode = last; |
| 338 startingTabIndex = 0; | 384 startingTabIndex = 0; |
| 339 } | 385 } |
| 340 | 386 |
| 341 // However, if a node is excluded from the normal tabbing cycle, the previou
s focusable node is determined by tree order | 387 // However, if a node is excluded from the normal tabbing cycle, the previou
s focusable node is determined by tree order |
| 342 if (startingTabIndex < 0) { | 388 if (startingTabIndex < 0) { |
| 343 for (Node* node = startingNode; node; node = ElementTraversal::previous(
*node)) { | 389 CombinedNodeTraversal* traversal = new CombinedNodeTraversal(*startingNo
de); |
| 390 for (Node* node = startingNode; node; node = traversal->previous()) { |
| 344 if (shouldVisit(*node) && adjustedTabIndex(*node) >= 0) | 391 if (shouldVisit(*node) && adjustedTabIndex(*node) >= 0) |
| 345 return toElement(node); | 392 return toElement(node); |
| 346 } | 393 } |
| 347 } else { | 394 } else { |
| 348 if (Element* winner = findElementWithExactTabIndex(startingNode, startin
gTabIndex, WebFocusTypeBackward)) | 395 if (Element* winner = findElementWithExactTabIndex(startingNode, startin
gTabIndex, WebFocusTypeBackward)) |
| 349 return winner; | 396 return winner; |
| 350 } | 397 } |
| 351 | 398 |
| 352 // There are no nodes before start with the same tabindex as start, so look
for a node that: | 399 // There are no nodes before start with the same tabindex as start, so look
for a node that: |
| 353 // 1) has the highest non-zero tabindex (that is less than start's tabindex)
, and | 400 // 1) has the highest non-zero tabindex (that is less than start's tabindex)
, and |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 if (Element* foundInInnerFocusScope = findFocusableElementRecurs
ivelyForward(innerScope, nullptr)) | 434 if (Element* foundInInnerFocusScope = findFocusableElementRecurs
ivelyForward(innerScope, nullptr)) |
| 388 return foundInInnerFocusScope; | 435 return foundInInnerFocusScope; |
| 389 } | 436 } |
| 390 // Skip to the next node in the same scope. | 437 // Skip to the next node in the same scope. |
| 391 found = findFocusableElementInternal(WebFocusTypeForward, scope, fou
nd); | 438 found = findFocusableElementInternal(WebFocusTypeForward, scope, fou
nd); |
| 392 continue; | 439 continue; |
| 393 } | 440 } |
| 394 if (!isNonFocusableFocusScopeOwner(*found)) | 441 if (!isNonFocusableFocusScopeOwner(*found)) |
| 395 return found; | 442 return found; |
| 396 | 443 |
| 397 // Now |found| is on a non focusable scope owner (either shadow host or
<shadow>) | 444 // Now |found| is on a non focusable scope owner (either shadow host or
<shadow> or slot) |
| 398 // Find inside the inward scope and return it if found. Otherwise contin
ue searching in the same | 445 // Find inside the inward scope and return it if found. Otherwise contin
ue searching in the same |
| 399 // scope. | 446 // scope. |
| 400 FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFocusa
bleFocusScopeOwner(*found); | 447 FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFocusa
bleFocusScopeOwner(*found); |
| 401 if (Element* foundInInnerFocusScope = findFocusableElementRecursivelyFor
ward(innerScope, nullptr)) | 448 if (Element* foundInInnerFocusScope = findFocusableElementRecursivelyFor
ward(innerScope, nullptr)) |
| 402 return foundInInnerFocusScope; | 449 return foundInInnerFocusScope; |
| 403 | 450 |
| 404 found = findFocusableElementInternal(WebFocusTypeForward, scope, found); | 451 found = findFocusableElementInternal(WebFocusTypeForward, scope, found); |
| 405 } | 452 } |
| 406 return nullptr; | 453 return nullptr; |
| 407 } | 454 } |
| 408 | 455 |
| 409 Element* findFocusableElementRecursivelyBackward(const FocusNavigationScope& sco
pe, Node* start) | 456 Element* findFocusableElementRecursivelyBackward(const FocusNavigationScope& sco
pe, Node* start) |
| 410 { | 457 { |
| 411 // Starting node is exclusive. | 458 // Starting node is exclusive. |
| 412 Element* found = findFocusableElementInternal(WebFocusTypeBackward, scope, s
tart); | 459 Element* found = findFocusableElementInternal(WebFocusTypeBackward, scope, s
tart); |
| 460 |
| 413 while (found) { | 461 while (found) { |
| 414 // Now |found| is on a focusable shadow host. | 462 // Now |found| is on a focusable shadow host. |
| 415 // Find inside shadow backwards. If any focusable element is found, retu
rn it, otherwise return | 463 // Find inside shadow backwards. If any focusable element is found, retu
rn it, otherwise return |
| 416 // the host itself. | 464 // the host itself. |
| 417 if (isKeyboardFocusableShadowHost(*found)) { | 465 if (isKeyboardFocusableShadowHost(*found)) { |
| 418 FocusNavigationScope innerScope = FocusNavigationScope::ownedByShado
wHost(*found); | 466 FocusNavigationScope innerScope = FocusNavigationScope::ownedByShado
wHost(*found); |
| 419 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac
kward(innerScope, nullptr); | 467 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac
kward(innerScope, nullptr); |
| 420 if (foundInInnerFocusScope) | 468 if (foundInInnerFocusScope) |
| 421 return foundInInnerFocusScope; | 469 return foundInInnerFocusScope; |
| 422 if (isShadowHostDelegatesFocus(*found)) { | 470 if (isShadowHostDelegatesFocus(*found)) { |
| 423 found = findFocusableElementInternal(WebFocusTypeBackward, scope
, found); | 471 found = findFocusableElementInternal(WebFocusTypeBackward, scope
, found); |
| 424 continue; | 472 continue; |
| 425 } | 473 } |
| 426 return found; | 474 return found; |
| 427 } | 475 } |
| 428 | 476 |
| 429 // If delegatesFocus is true and tabindex is negative, skip the whole sh
adow tree under the | 477 // If delegatesFocus is true and tabindex is negative, skip the whole sh
adow tree under the |
| 430 // shadow host. | 478 // shadow host. |
| 431 if (isShadowHostDelegatesFocus(*found) && found->tabIndex() < 0) { | 479 if (isShadowHostDelegatesFocus(*found) && found->tabIndex() < 0) { |
| 432 found = findFocusableElementInternal(WebFocusTypeBackward, scope, fo
und); | 480 found = findFocusableElementInternal(WebFocusTypeBackward, scope, fo
und); |
| 433 continue; | 481 continue; |
| 434 } | 482 } |
| 435 | 483 |
| 436 // Now |found| is on a non focusable scope owner (either shadow host or
<shadow>). | 484 // Now |found| is on a non focusable scope owner (either shadow host or
<shadow> or slot). |
| 437 // Find focusable node in descendant scope. If not found, find next focu
sable node within the | 485 // Find focusable node in descendant scope. If not found, find next focu
sable node within the |
| 438 // current scope. | 486 // current scope. |
| 439 if (isNonFocusableFocusScopeOwner(*found)) { | 487 if (isNonFocusableFocusScopeOwner(*found)) { |
| 440 FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFo
cusableFocusScopeOwner(*found); | 488 FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFo
cusableFocusScopeOwner(*found); |
| 441 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac
kward(innerScope, nullptr); | 489 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac
kward(innerScope, nullptr); |
| 442 if (foundInInnerFocusScope) | 490 if (foundInInnerFocusScope) |
| 443 return foundInInnerFocusScope; | 491 return foundInInnerFocusScope; |
| 444 found = findFocusableElementInternal(WebFocusTypeBackward, scope, fo
und); | 492 found = findFocusableElementInternal(WebFocusTypeBackward, scope, fo
und); |
| 445 continue; | 493 continue; |
| 446 } | 494 } |
| (...skipping 670 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1117 return consumed; | 1165 return consumed; |
| 1118 } | 1166 } |
| 1119 | 1167 |
| 1120 DEFINE_TRACE(FocusController) | 1168 DEFINE_TRACE(FocusController) |
| 1121 { | 1169 { |
| 1122 visitor->trace(m_page); | 1170 visitor->trace(m_page); |
| 1123 visitor->trace(m_focusedFrame); | 1171 visitor->trace(m_focusedFrame); |
| 1124 } | 1172 } |
| 1125 | 1173 |
| 1126 } // namespace blink | 1174 } // namespace blink |
| OLD | NEW |