diff options
Diffstat (limited to 'Source/WebCore/page/FocusController.cpp')
| -rw-r--r-- | Source/WebCore/page/FocusController.cpp | 374 |
1 files changed, 182 insertions, 192 deletions
diff --git a/Source/WebCore/page/FocusController.cpp b/Source/WebCore/page/FocusController.cpp index bc20169c9..bc83e7f8c 100644 --- a/Source/WebCore/page/FocusController.cpp +++ b/Source/WebCore/page/FocusController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2013 Apple Inc. All rights reserved. * Copyright (C) 2008 Nuanti Ltd. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,6 @@ #include "AXObjectCache.h" #include "Chrome.h" -#include "ComposedShadowTreeWalker.h" #include "Document.h" #include "Editor.h" #include "EditorClient.h" @@ -45,9 +44,13 @@ #include "FrameView.h" #include "HTMLAreaElement.h" #include "HTMLImageElement.h" +#include "HTMLInputElement.h" #include "HTMLNames.h" +#include "HTMLTextAreaElement.h" #include "HitTestResult.h" #include "KeyboardEvent.h" +#include "NodeRenderingTraversal.h" +#include "NodeTraversal.h" #include "Page.h" #include "Range.h" #include "RenderObject.h" @@ -65,50 +68,20 @@ namespace WebCore { using namespace HTMLNames; using namespace std; -static inline ComposedShadowTreeWalker walkerFrom(const Node* node) -{ - return ComposedShadowTreeWalker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); -} - -static inline ComposedShadowTreeWalker walkerFromNext(const Node* node) -{ - ComposedShadowTreeWalker walker = ComposedShadowTreeWalker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); - walker.next(); - return walker; -} - -static inline ComposedShadowTreeWalker walkerFromPrevious(const Node* node) -{ - ComposedShadowTreeWalker walker = ComposedShadowTreeWalker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); - walker.previous(); - return walker; -} - -static inline Node* nextNode(const Node* node) -{ - return walkerFromNext(node).get(); -} - -static inline Node* previousNode(const Node* node) -{ - return walkerFromPrevious(node).get(); -} - FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope) : m_rootTreeScope(treeScope) { ASSERT(treeScope); - ASSERT(!treeScope->rootNode()->isShadowRoot() || toShadowRoot(treeScope->rootNode())->isYoungest()); } -Node* FocusNavigationScope::rootNode() const +ContainerNode* FocusNavigationScope::rootNode() const { return m_rootTreeScope->rootNode(); } Element* FocusNavigationScope::owner() const { - Node* root = rootNode(); + ContainerNode* root = rootNode(); if (root->isShadowRoot()) return toShadowRoot(root)->host(); if (Frame* frame = root->document()->frame()) @@ -119,12 +92,9 @@ Element* FocusNavigationScope::owner() const FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(Node* node) { ASSERT(node); - ComposedShadowTreeWalker walker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary); Node* root = node; - while (walker.get()) { - root = walker.get(); - walker.parent(); - } + for (Node* n = node; n; n = NodeRenderingTraversal::parentInScope(n)) + root = n; // The result is not always a ShadowRoot nor a DocumentNode since // a starting node is in an orphaned tree in composed shadow tree. return FocusNavigationScope(root->treeScope()); @@ -133,7 +103,7 @@ FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(Node* node) FocusNavigationScope FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(Node* node) { ASSERT(isShadowHost(node)); - return FocusNavigationScope(toElement(node)->shadow()->youngestShadowRoot()); + return FocusNavigationScope(toElement(node)->shadow()->shadowRoot()); } FocusNavigationScope FocusNavigationScope::focusNavigationScopeOwnedByIFrame(HTMLFrameOwnerElement* frame) @@ -142,7 +112,7 @@ FocusNavigationScope FocusNavigationScope::focusNavigationScopeOwnedByIFrame(HTM return FocusNavigationScope(frame->contentFrame()->document()); } -static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused) +static inline void dispatchEventsOnWindowAndFocusedElement(Document* document, bool focused) { // If we have a focused node we should dispatch blur on it before we blur the window. // If we have a focused node we should dispatch focus on it after we focus the window. @@ -154,11 +124,11 @@ static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool return; } - if (!focused && document->focusedNode()) - document->focusedNode()->dispatchBlurEvent(0); + if (!focused && document->focusedElement()) + document->focusedElement()->dispatchBlurEvent(0); document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false)); - if (focused && document->focusedNode()) - document->focusedNode()->dispatchFocusEvent(0); + if (focused && document->focusedElement()) + document->focusedElement()->dispatchFocusEvent(0, FocusDirectionNone); } static inline bool hasCustomFocusLogic(Node* node) @@ -166,28 +136,30 @@ static inline bool hasCustomFocusLogic(Node* node) return node->isHTMLElement() && toHTMLElement(node)->hasCustomFocusLogic(); } -static inline bool isNonFocusableShadowHost(Node* node, KeyboardEvent* event) +static inline bool isNonFocusableShadowHost(Element* element, KeyboardEvent* event) { - ASSERT(node); - return !node->isKeyboardFocusable(event) && isShadowHost(node) && !hasCustomFocusLogic(node); + ASSERT(element); + return !element->isKeyboardFocusable(event) && isShadowHost(element) && !hasCustomFocusLogic(element); } static inline bool isFocusableShadowHost(Node* node, KeyboardEvent* event) { ASSERT(node); - return node->isKeyboardFocusable(event) && isShadowHost(node) && !hasCustomFocusLogic(node); + return node->isElementNode() && toElement(node)->isKeyboardFocusable(event) && isShadowHost(node) && !hasCustomFocusLogic(node); } static inline int adjustedTabIndex(Node* node, KeyboardEvent* event) { ASSERT(node); - return isNonFocusableShadowHost(node, event) ? 0 : node->tabIndex(); + if (!node->isElementNode()) + return 0; + return isNonFocusableShadowHost(toElement(node), event) ? 0 : toElement(node)->tabIndex(); } -static inline bool shouldVisit(Node* node, KeyboardEvent* event) +static inline bool shouldVisit(Element* element, KeyboardEvent* event) { - ASSERT(node); - return node->isKeyboardFocusable(event) || isNonFocusableShadowHost(node, event); + ASSERT(element); + return element->isKeyboardFocusable(event) || isNonFocusableShadowHost(element, event); } FocusController::FocusController(Page* page) @@ -228,7 +200,7 @@ void FocusController::setFocusedFrame(PassRefPtr<Frame> frame) newFrame->document()->dispatchWindowEvent(Event::create(eventNames().focusEvent, false, false)); } - m_page->chrome()->focusedFrameChanged(newFrame.get()); + m_page->chrome().focusedFrameChanged(newFrame.get()); m_isChangingFocusedFrame = false; } @@ -255,26 +227,26 @@ void FocusController::setFocused(bool focused) if (m_focusedFrame->view()) { m_focusedFrame->selection()->setFocused(focused); - dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), focused); + dispatchEventsOnWindowAndFocusedElement(m_focusedFrame->document(), focused); } } -Node* FocusController::findFocusableNodeDecendingDownIntoFrameDocument(FocusDirection direction, Node* node, KeyboardEvent* event) +Element* FocusController::findFocusableElementDescendingDownIntoFrameDocument(FocusDirection direction, Element* element, KeyboardEvent* event) { // The node we found might be a HTMLFrameOwnerElement, so descend down the tree until we find either: // 1) a focusable node, or // 2) the deepest-nested HTMLFrameOwnerElement. - while (node && node->isFrameOwnerElement()) { - HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); + while (element && element->isFrameOwnerElement()) { + HTMLFrameOwnerElement* owner = toFrameOwnerElement(element); if (!owner->contentFrame()) break; - Node* foundNode = findFocusableNode(direction, FocusNavigationScope::focusNavigationScopeOwnedByIFrame(owner), 0, event); - if (!foundNode) + Element* foundElement = findFocusableElement(direction, FocusNavigationScope::focusNavigationScopeOwnedByIFrame(owner), 0, event); + if (!foundElement) break; - ASSERT(node != foundNode); - node = foundNode; + ASSERT(element != foundElement); + element = foundElement; } - return node; + return element; } bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* event) @@ -284,8 +256,8 @@ bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* e // If focus is being set initially, accessibility needs to be informed that system focus has moved // into the web area again, even if focus did not change within WebCore. PostNotification is called instead // of handleFocusedUIElementChanged, because this will send the notification even if the element is the same. - if (AXObjectCache::accessibilityEnabled()) - focusedOrMainFrame()->document()->axObjectCache()->postNotification(focusedOrMainFrame()->document(), AXObjectCache::AXFocusedUIElementChanged, true); + if (AXObjectCache* cache = focusedOrMainFrame()->document()->existingAXObjectCache()) + cache->postNotification(focusedOrMainFrame()->document(), AXObjectCache::AXFocusedUIElementChanged, true); return didAdvanceFocus; } @@ -314,7 +286,7 @@ bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, Keyb ASSERT(frame); Document* document = frame->document(); - Node* currentNode = document->focusedNode(); + Node* currentNode = document->focusedElement(); // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEnabled(); @@ -323,84 +295,82 @@ bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, Keyb document->updateLayoutIgnorePendingStylesheets(); - RefPtr<Node> node = findFocusableNodeAcrossFocusScope(direction, FocusNavigationScope::focusNavigationScopeOf(currentNode ? currentNode : document), currentNode, event); + RefPtr<Element> element = findFocusableElementAcrossFocusScope(direction, FocusNavigationScope::focusNavigationScopeOf(currentNode ? currentNode : document), currentNode, event); - if (!node) { + if (!element) { // We didn't find a node to focus, so we should try to pass focus to Chrome. - if (!initialFocus && m_page->chrome()->canTakeFocus(direction)) { - document->setFocusedNode(0); + if (!initialFocus && m_page->chrome().canTakeFocus(direction)) { + document->setFocusedElement(0); setFocusedFrame(0); - m_page->chrome()->takeFocus(direction); + m_page->chrome().takeFocus(direction); return true; } // Chrome doesn't want focus, so we should wrap focus. - node = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOf(m_page->mainFrame()->document()), 0, event); - node = findFocusableNodeDecendingDownIntoFrameDocument(direction, node.get(), event); + element = findFocusableElementRecursively(direction, FocusNavigationScope::focusNavigationScopeOf(m_page->mainFrame()->document()), 0, event); + element = findFocusableElementDescendingDownIntoFrameDocument(direction, element.get(), event); - if (!node) + if (!element) return false; } - ASSERT(node); + ASSERT(element); - if (node == document->focusedNode()) - // Focus wrapped around to the same node. + if (element == document->focusedElement()) { + // Focus wrapped around to the same Element. return true; + } - if (!node->isElementNode()) - // FIXME: May need a way to focus a document here. - return false; - - if (node->isFrameOwnerElement() && (!node->isPluginElement() || !node->isKeyboardFocusable(event))) { + if (element->isFrameOwnerElement() && (!element->isPluginElement() || !element->isKeyboardFocusable(event))) { // We focus frames rather than frame owners. // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user. - HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node.get()); + HTMLFrameOwnerElement* owner = toFrameOwnerElement(element.get()); if (!owner->contentFrame()) return false; - document->setFocusedNode(0); + document->setFocusedElement(0); setFocusedFrame(owner->contentFrame()); return true; } - // FIXME: It would be nice to just be able to call setFocusedNode(node) here, but we can't do + // FIXME: It would be nice to just be able to call setFocusedElement(node) here, but we can't do // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in // their focus() methods. - Document* newDocument = node->document(); + Document* newDocument = element->document(); - if (newDocument != document) + if (newDocument != document) { // Focus is going away from this document, so clear the focused node. - document->setFocusedNode(0); + document->setFocusedElement(0); + } if (newDocument) setFocusedFrame(newDocument->frame()); if (caretBrowsing) { - Position position = firstPositionInOrBeforeNode(node.get()); + Position position = firstPositionInOrBeforeNode(element.get()); VisibleSelection newSelection(position, position, DOWNSTREAM); if (frame->selection()->shouldChangeSelection(newSelection)) frame->selection()->setSelection(newSelection); } - static_cast<Element*>(node.get())->focus(false); + element->focus(false, direction); return true; } -Node* FocusController::findFocusableNodeAcrossFocusScope(FocusDirection direction, FocusNavigationScope scope, Node* currentNode, KeyboardEvent* event) +Element* FocusController::findFocusableElementAcrossFocusScope(FocusDirection direction, FocusNavigationScope scope, Node* currentNode, KeyboardEvent* event) { - ASSERT(!currentNode || !isNonFocusableShadowHost(currentNode, event)); - Node* found; + ASSERT(!currentNode || !currentNode->isElementNode() || !isNonFocusableShadowHost(toElement(currentNode), event)); + Element* found; if (currentNode && direction == FocusDirectionForward && isFocusableShadowHost(currentNode, event)) { - Node* foundInInnerFocusScope = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(currentNode), 0, event); - found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableNodeRecursively(direction, scope, currentNode, event); + Element* foundInInnerFocusScope = findFocusableElementRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(currentNode), 0, event); + found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableElementRecursively(direction, scope, currentNode, event); } else - found = findFocusableNodeRecursively(direction, scope, currentNode, event); + found = findFocusableElementRecursively(direction, scope, currentNode, event); // If there's no focusable node to advance to, move up the focus scopes until we find one. while (!found) { - Node* owner = scope.owner(); + Element* owner = scope.owner(); if (!owner) break; scope = FocusNavigationScope::focusNavigationScopeOf(owner); @@ -408,99 +378,112 @@ Node* FocusController::findFocusableNodeAcrossFocusScope(FocusDirection directio found = owner; break; } - found = findFocusableNodeRecursively(direction, scope, owner, event); + found = findFocusableElementRecursively(direction, scope, owner, event); } - found = findFocusableNodeDecendingDownIntoFrameDocument(direction, found, event); + found = findFocusableElementDescendingDownIntoFrameDocument(direction, found, event); return found; } -Node* FocusController::findFocusableNodeRecursively(FocusDirection direction, FocusNavigationScope scope, Node* start, KeyboardEvent* event) +Element* FocusController::findFocusableElementRecursively(FocusDirection direction, FocusNavigationScope scope, Node* start, KeyboardEvent* event) { // Starting node is exclusive. - Node* found = findFocusableNode(direction, scope, start, event); + Element* found = findFocusableElement(direction, scope, start, event); if (!found) return 0; if (direction == FocusDirectionForward) { if (!isNonFocusableShadowHost(found, event)) return found; - Node* foundInInnerFocusScope = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); - return foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableNodeRecursively(direction, scope, found, event); + Element* foundInInnerFocusScope = findFocusableElementRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); + return foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableElementRecursively(direction, scope, found, event); } ASSERT(direction == FocusDirectionBackward); if (isFocusableShadowHost(found, event)) { - Node* foundInInnerFocusScope = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); + Element* foundInInnerFocusScope = findFocusableElementRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); return foundInInnerFocusScope ? foundInInnerFocusScope : found; } if (isNonFocusableShadowHost(found, event)) { - Node* foundInInnerFocusScope = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); - return foundInInnerFocusScope ? foundInInnerFocusScope :findFocusableNodeRecursively(direction, scope, found, event); + Element* foundInInnerFocusScope = findFocusableElementRecursively(direction, FocusNavigationScope::focusNavigationScopeOwnedByShadowHost(found), 0, event); + return foundInInnerFocusScope ? foundInInnerFocusScope :findFocusableElementRecursively(direction, scope, found, event); } return found; } -Node* FocusController::findFocusableNode(FocusDirection direction, FocusNavigationScope scope, Node* node, KeyboardEvent* event) +Element* FocusController::findFocusableElement(FocusDirection direction, FocusNavigationScope scope, Node* node, KeyboardEvent* event) { return (direction == FocusDirectionForward) - ? nextFocusableNode(scope, node, event) - : previousFocusableNode(scope, node, event); + ? nextFocusableElement(scope, node, event) + : previousFocusableElement(scope, node, event); } -Node* FocusController::findNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event, FocusDirection direction) +Element* FocusController::findElementWithExactTabIndex(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(); + using namespace NodeRenderingTraversal; + for (Node* node = start; node; node = direction == FocusDirectionForward ? nextInScope(node) : previousInScope(node)) { + if (!node->isElementNode()) + continue; + Element* element = toElement(node); + if (shouldVisit(element, event) && adjustedTabIndex(element, event) == tabIndex) + return element; } return 0; } -static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event) +static Element* nextElementWithGreaterTabIndex(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(); + Element* winner = 0; + for (Node* node = start; node; node = NodeRenderingTraversal::nextInScope(node)) { + if (!node->isElementNode()) + continue; + Element* element = toElement(node); + if (shouldVisit(element, event) && element->tabIndex() > tabIndex && element->tabIndex() < winningTabIndex) { + winner = element; + winningTabIndex = element->tabIndex(); } } return winner; } -static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event) +static Element* previousElementWithLowerTabIndex(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; + Element* winner = 0; + for (Node* node = start; node; node = NodeRenderingTraversal::previousInScope(node)) { + if (!node->isElementNode()) + continue; + Element* element = toElement(node); + int currentTabIndex = adjustedTabIndex(element, event); + if ((shouldVisit(element, event) || isNonFocusableShadowHost(element, event)) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) { + winner = element; winningTabIndex = currentTabIndex; } } return winner; } -Node* FocusController::nextFocusableNode(FocusNavigationScope scope, Node* start, KeyboardEvent* event) +Element* FocusController::nextFocusableElement(FocusNavigationScope scope, Node* start, KeyboardEvent* event) { + using namespace NodeRenderingTraversal; + 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(); + for (Node* node = nextInScope(start); node; node = nextInScope(node)) { + if (!node->isElementNode()) + continue; + Element* element = toElement(node); + if (shouldVisit(element, event) && adjustedTabIndex(element, event) >= 0) + return element; } } // 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)) + if (Element* winner = findElementWithExactTabIndex(nextInScope(start), tabIndex, event, FocusDirectionForward)) return winner; if (!tabIndex) @@ -508,22 +491,24 @@ Node* FocusController::nextFocusableNode(FocusNavigationScope scope, Node* start return 0; } - // Look for the first node in the scope that: + // Look for the first Element 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)) + if (Element* winner = nextElementWithGreaterTabIndex(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); + return findElementWithExactTabIndex(scope.rootNode(), 0, event, FocusDirectionForward); } -Node* FocusController::previousFocusableNode(FocusNavigationScope scope, Node* start, KeyboardEvent* event) +Element* FocusController::previousFocusableElement(FocusNavigationScope scope, Node* start, KeyboardEvent* event) { + using namespace NodeRenderingTraversal; + Node* last = 0; - for (ComposedShadowTreeWalker walker = walkerFrom(scope.rootNode()); walker.get(); walker.lastChild()) - last = walker.get(); + for (Node* node = scope.rootNode(); node; node = lastChildInScope(node)) + last = node; ASSERT(last); // First try to find the last node in the scope that comes before start and has the same tabindex as start. @@ -531,7 +516,7 @@ Node* FocusController::previousFocusableNode(FocusNavigationScope scope, Node* s Node* startingNode; int startingTabIndex; if (start) { - startingNode = previousNode(start); + startingNode = previousInScope(start); startingTabIndex = adjustedTabIndex(start, event); } else { startingNode = last; @@ -540,20 +525,23 @@ Node* FocusController::previousFocusableNode(FocusNavigationScope scope, Node* s // 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(); + for (Node* node = startingNode; node; node = previousInScope(node)) { + if (!node->isElementNode()) + continue; + Element* element = toElement(node); + if (shouldVisit(element, event) && adjustedTabIndex(element, event) >= 0) + return element; } } - if (Node* winner = findNodeWithExactTabIndex(startingNode, startingTabIndex, event, FocusDirectionBackward)) + if (Element* winner = findElementWithExactTabIndex(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); + return previousElementWithLowerTabIndex(last, startingTabIndex, event); } static bool relinquishesEditingFocus(Node *node) @@ -566,7 +554,7 @@ static bool relinquishesEditingFocus(Node *node) if (!frame || !root) return false; - return frame->editor()->shouldEndEditing(rangeOfContents(root).get()); + return frame->editor().shouldEndEditing(rangeOfContents(root).get()); } static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode) @@ -586,7 +574,7 @@ static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFram return; Node* selectionStartNode = s->selection().start().deprecatedNode(); - if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode) + if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->deprecatedShadowAncestorNode() == newFocusedNode) return; if (Node* mousePressNode = newFocusedFrame->eventHandler()->mousePressNode()) { @@ -596,8 +584,8 @@ static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFram if (!root) return; - if (Node* shadowAncestorNode = root->shadowAncestorNode()) { - if (!shadowAncestorNode->hasTagName(inputTag) && !shadowAncestorNode->hasTagName(textareaTag)) + if (Node* shadowAncestorNode = root->deprecatedShadowAncestorNode()) { + if (!isHTMLInputElement(shadowAncestorNode) && !isHTMLTextAreaElement(shadowAncestorNode)) return; } } @@ -606,52 +594,55 @@ static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFram s->clear(); } -bool FocusController::setFocusedNode(Node* node, PassRefPtr<Frame> newFocusedFrame) +bool FocusController::setFocusedElement(Element* element, PassRefPtr<Frame> newFocusedFrame, FocusDirection direction) { RefPtr<Frame> oldFocusedFrame = focusedFrame(); RefPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0; - Node* oldFocusedNode = oldDocument ? oldDocument->focusedNode() : 0; - if (oldFocusedNode == node) + Element* oldFocusedElement = oldDocument ? oldDocument->focusedElement() : 0; + if (oldFocusedElement == element) return true; // FIXME: Might want to disable this check for caretBrowsing - if (oldFocusedNode && oldFocusedNode->isRootEditableElement() && !relinquishesEditingFocus(oldFocusedNode)) + if (oldFocusedElement && oldFocusedElement->isRootEditableElement() && !relinquishesEditingFocus(oldFocusedElement)) return false; m_page->editorClient()->willSetInputMethodState(); - clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), node); + clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), element); - if (!node) { + if (!element) { if (oldDocument) - oldDocument->setFocusedNode(0); + oldDocument->setFocusedElement(0); m_page->editorClient()->setInputMethodState(false); return true; } - RefPtr<Document> newDocument = node->document(); + RefPtr<Document> newDocument = element->document(); - if (newDocument && newDocument->focusedNode() == node) { - m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod()); + if (newDocument && newDocument->focusedElement() == element) { + m_page->editorClient()->setInputMethodState(element->shouldUseInputMethod()); return true; } if (oldDocument && oldDocument != newDocument) - oldDocument->setFocusedNode(0); - + oldDocument->setFocusedElement(0); + + if (newFocusedFrame && !newFocusedFrame->page()) { + setFocusedFrame(0); + return false; + } setFocusedFrame(newFocusedFrame); - // Setting the focused node can result in losing our last reft to node when JS event handlers fire. - RefPtr<Node> protect = node; + RefPtr<Element> protect(element); if (newDocument) { - bool successfullyFocused = newDocument->setFocusedNode(node); + bool successfullyFocused = newDocument->setFocusedElement(element, direction); if (!successfullyFocused) return false; } - if (newDocument->focusedNode() == node) - m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod()); + if (newDocument->focusedElement() == element) + m_page->editorClient()->setInputMethodState(element->shouldUseInputMethod()); return true; } @@ -673,7 +664,7 @@ void FocusController::setActive(bool active) focusedOrMainFrame()->selection()->pageActivationChanged(); if (m_focusedFrame && isFocused()) - dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), active); + dispatchEventsOnWindowAndFocusedElement(m_focusedFrame->document(), active); } static void contentAreaDidShowOrHide(ScrollableArea* scrollableArea, bool didShow) @@ -745,7 +736,7 @@ static void updateFocusCandidateIfNeeded(FocusDirection direction, const FocusCa // If 2 nodes are intersecting, do hit test to find which node in on top. LayoutUnit x = intersectionRect.x() + intersectionRect.width() / 2; LayoutUnit y = intersectionRect.y() + intersectionRect.height() / 2; - HitTestResult result = candidate.visibleNode->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, true); + HitTestResult result = candidate.visibleNode->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent); if (candidate.visibleNode->contains(result.innerNode())) { closest = candidate; return; @@ -767,25 +758,24 @@ static void updateFocusCandidateIfNeeded(FocusDirection direction, const FocusCa void FocusController::findFocusCandidateInContainer(Node* container, const LayoutRect& startingRect, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closest) { ASSERT(container); - Node* focusedNode = (focusedFrame() && focusedFrame()->document()) ? focusedFrame()->document()->focusedNode() : 0; + Node* focusedNode = (focusedFrame() && focusedFrame()->document()) ? focusedFrame()->document()->focusedElement() : 0; - Node* node = container->firstChild(); + Element* element = ElementTraversal::firstWithin(container); FocusCandidate current; current.rect = startingRect; current.focusableNode = focusedNode; current.visibleNode = focusedNode; - for (; node; node = (node->isFrameOwnerElement() || canScrollInDirection(node, direction)) ? node->traverseNextSibling(container) : node->traverseNextNode(container)) { - if (node == focusedNode) - continue; - - if (!node->isElementNode()) + for (; element; element = (element->isFrameOwnerElement() || canScrollInDirection(element, direction)) + ? ElementTraversal::nextSkippingChildren(element, container) + : ElementTraversal::next(element, container)) { + if (element == focusedNode) continue; - if (!node->isKeyboardFocusable(event) && !node->isFrameOwnerElement() && !canScrollInDirection(node, direction)) + if (!element->isKeyboardFocusable(event) && !element->isFrameOwnerElement() && !canScrollInDirection(element, direction)) continue; - FocusCandidate candidate = FocusCandidate(node, direction); + FocusCandidate candidate = FocusCandidate(element, direction); if (candidate.isNull()) continue; @@ -827,9 +817,9 @@ bool FocusController::advanceFocusDirectionallyInContainer(Node* container, cons } // Navigate into a new frame. LayoutRect rect; - Node* focusedNode = focusedOrMainFrame()->document()->focusedNode(); - if (focusedNode && !hasOffscreenRect(focusedNode)) - rect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */); + Element* focusedElement = focusedOrMainFrame()->document()->focusedElement(); + if (focusedElement && !hasOffscreenRect(focusedElement)) + rect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */); frameElement->contentFrame()->document()->updateLayoutIgnorePendingStylesheets(); if (!advanceFocusDirectionallyInContainer(frameElement->contentFrame()->document(), rect, direction, event)) { // The new frame had nothing interesting, need to find another candidate. @@ -845,9 +835,9 @@ bool FocusController::advanceFocusDirectionallyInContainer(Node* container, cons } // Navigate into a new scrollable container. LayoutRect startingRect; - Node* focusedNode = focusedOrMainFrame()->document()->focusedNode(); - if (focusedNode && !hasOffscreenRect(focusedNode)) - startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true); + Element* focusedElement = focusedOrMainFrame()->document()->focusedElement(); + if (focusedElement && !hasOffscreenRect(focusedElement)) + startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true); return advanceFocusDirectionallyInContainer(focusCandidate.visibleNode, startingRect, direction, event); } if (focusCandidate.isOffscreenAfterScrolling) { @@ -860,7 +850,7 @@ bool FocusController::advanceFocusDirectionallyInContainer(Node* container, cons Element* element = toElement(focusCandidate.focusableNode); ASSERT(element); - element->focus(false); + element->focus(false, direction); return true; } @@ -873,20 +863,20 @@ bool FocusController::advanceFocusDirectionally(FocusDirection direction, Keyboa if (!focusedDocument) return false; - Node* focusedNode = focusedDocument->focusedNode(); + Element* focusedElement = focusedDocument->focusedElement(); Node* container = focusedDocument; if (container->isDocumentNode()) - static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets(); + toDocument(container)->updateLayoutIgnorePendingStylesheets(); // Figure out the starting rect. LayoutRect startingRect; - if (focusedNode) { - if (!hasOffscreenRect(focusedNode)) { - container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedNode); - startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */); - } else if (focusedNode->hasTagName(areaTag)) { - HTMLAreaElement* area = static_cast<HTMLAreaElement*>(focusedNode); + if (focusedElement) { + if (!hasOffscreenRect(focusedElement)) { + container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedElement); + startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */); + } else if (isHTMLAreaElement(focusedElement)) { + HTMLAreaElement* area = toHTMLAreaElement(focusedElement); container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, area->imageElement()); startingRect = virtualRectForAreaElementAndDirection(area, direction); } @@ -898,7 +888,7 @@ bool FocusController::advanceFocusDirectionally(FocusDirection direction, Keyboa startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */); container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, container); if (container && container->isDocumentNode()) - static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets(); + toDocument(container)->updateLayoutIgnorePendingStylesheets(); } while (!consumed && container); return consumed; |
