Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(141)

Side by Side Diff: third_party/WebKit/Source/core/page/FocusController.cpp

Issue 1707443003: Consider slots as a focus scope (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Refactoring related to OILPAN Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698