Node* FocusController::nextFocusableNode(FocusNavigationScope scope, Node* start, KeyboardEvent* event) { if (start) { int tabIndex = adjustedTabIndex(start, event); // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order if (tabIndex < 0) { for (ComposedShadowTreeWalker walker = walkerFromNext(start); walker.get(); walker.next()) { if (shouldVisit(walker.get(), event) && adjustedTabIndex(walker.get(), event) >= 0) return walker.get(); } } // First try to find a node with the same tabindex as start that comes after start in the scope. if (Node* winner = findNodeWithExactTabIndex(nextNode(start), tabIndex, event, FocusDirectionForward)) return winner; if (!tabIndex) // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order. return 0; } // Look for the first node in the scope that: // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and // 2) comes first in the scope, if there's a tie. if (Node* winner = nextNodeWithGreaterTabIndex(scope.rootNode(), start ? adjustedTabIndex(start, event) : 0, event)) return winner; // There are no nodes with a tabindex greater than start's tabindex, // so find the first node with a tabindex of 0. return findNodeWithExactTabIndex(scope.rootNode(), 0, event, FocusDirectionForward); }
Node* nextInScope(const Node* node) { // FIXME: ComposedShadowTreeWalker shouldn't be used when !ENABLE(SHADOW_DOM) https://bugs.webkit.org/show_bug.cgi?id=103339 ComposedShadowTreeWalker walker = ComposedShadowTreeWalker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); walker.next(); return walker.get(); }
Node* FocusController::findNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event, FocusDirection direction) { // Search is inclusive of start for (ComposedShadowTreeWalker walker = walkerFrom(start); walker.get(); direction == FocusDirectionForward ? walker.next() : walker.previous()) { if (shouldVisit(walker.get(), event) && adjustedTabIndex(walker.get(), event) == tabIndex) return walker.get(); } return 0; }
static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event) { // Search is inclusive of start int winningTabIndex = 0; Node* winner = 0; for (ComposedShadowTreeWalker walker = walkerFrom(start); walker.get(); walker.previous()) { Node* node = walker.get(); int currentTabIndex = adjustedTabIndex(node, event); if ((shouldVisit(node, event) || isNonFocusableShadowHost(node, event)) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) { winner = node; winningTabIndex = currentTabIndex; } } return winner; }
static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event) { // Search is inclusive of start int winningTabIndex = std::numeric_limits<short>::max() + 1; Node* winner = 0; for (ComposedShadowTreeWalker walker = walkerFrom(start); walker.get(); walker.next()) { Node* node = walker.get(); if (shouldVisit(node, event) && node->tabIndex() > tabIndex && node->tabIndex() < winningTabIndex) { winner = node; winningTabIndex = node->tabIndex(); } } return winner; }
Node* FocusController::previousFocusableNode(FocusNavigationScope scope, Node* start, KeyboardEvent* event) { Node* last = 0; for (ComposedShadowTreeWalker walker = walkerFrom(scope.rootNode()); walker.get(); walker.lastChild()) last = walker.get(); ASSERT(last); // First try to find the last node in the scope that comes before start and has the same tabindex as start. // If start is null, find the last node in the scope with a tabindex of 0. Node* startingNode; int startingTabIndex; if (start) { startingNode = previousNode(start); startingTabIndex = adjustedTabIndex(start, event); } else { startingNode = last; startingTabIndex = 0; } // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order if (startingTabIndex < 0) { for (ComposedShadowTreeWalker walker = walkerFrom(startingNode); walker.get(); walker.previous()) { if (shouldVisit(walker.get(), event) && adjustedTabIndex(walker.get(), event) >= 0) return walker.get(); } } if (Node* winner = findNodeWithExactTabIndex(startingNode, startingTabIndex, event, FocusDirectionBackward)) return winner; // There are no nodes before start with the same tabindex as start, so look for a node that: // 1) has the highest non-zero tabindex (that is less than start's tabindex), and // 2) comes last in the scope, if there's a tie. startingTabIndex = (start && startingTabIndex) ? startingTabIndex : std::numeric_limits<short>::max(); return previousNodeWithLowerTabIndex(last, startingTabIndex, event); }
Node* nextInScope(const Node* node) { ComposedShadowTreeWalker walker = ComposedShadowTreeWalker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); walker.next(); return walker.get(); }
static inline ComposedShadowTreeWalker walkerFromPrevious(const Node* node) { ComposedShadowTreeWalker walker = ComposedShadowTreeWalker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); walker.previous(); return walker; }