summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/FocusController.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page/FocusController.cpp')
-rw-r--r--Source/WebCore/page/FocusController.cpp374
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;