summaryrefslogtreecommitdiffstats
path: root/WebCore/page/FocusController.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/page/FocusController.cpp')
-rw-r--r--WebCore/page/FocusController.cpp66
1 files changed, 36 insertions, 30 deletions
diff --git a/WebCore/page/FocusController.cpp b/WebCore/page/FocusController.cpp
index 5418c89..9ca18dd 100644
--- a/WebCore/page/FocusController.cpp
+++ b/WebCore/page/FocusController.cpp
@@ -40,9 +40,10 @@
#include "Frame.h"
#include "FrameTree.h"
#include "FrameView.h"
-#include "HitTestResult.h"
-#include "HTMLFrameOwnerElement.h"
+#include "HTMLAreaElement.h"
+#include "HTMLImageElement.h"
#include "HTMLNames.h"
+#include "HitTestResult.h"
#include "KeyboardEvent.h"
#include "Page.h"
#include "Range.h"
@@ -59,7 +60,6 @@ namespace WebCore {
using namespace HTMLNames;
using namespace std;
-static void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& startingRect, FocusCandidate& candidate, FocusCandidate& closest);
static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused)
{
// If we have a focused node we should dispatch blur on it before we blur the window.
@@ -130,6 +130,9 @@ void FocusController::setFocused(bool focused)
m_isFocused = focused;
+ if (!m_isFocused)
+ focusedOrMainFrame()->eventHandler()->stopAutoscrollTimer();
+
if (!m_focusedFrame)
setFocusedFrame(m_page->mainFrame());
@@ -412,13 +415,13 @@ void FocusController::setActive(bool active)
dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), active);
}
-void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& startingRect, FocusCandidate& candidate, FocusCandidate& closest)
+static void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& startingRect, FocusCandidate& candidate, FocusCandidate& closest)
{
- if (!candidate.node->isElementNode() || !candidate.node->renderer())
+ if (!candidate.visibleNode->isElementNode() || !candidate.visibleNode->renderer())
return;
// Ignore iframes that don't have a src attribute
- if (candidate.node->isFrameOwnerElement() && !static_cast<HTMLFrameOwnerElement*>(candidate.node)->contentFrame())
+ if (frameOwnerElement(candidate) && (!frameOwnerElement(candidate)->contentFrame() || candidate.rect.isEmpty()))
return;
// Ignore off screen child nodes of containers that do not scroll (overflow:hidden)
@@ -444,12 +447,12 @@ void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& start
// If 2 nodes are intersecting, do hit test to find which node in on top.
int x = intersectionRect.x() + intersectionRect.width() / 2;
int y = intersectionRect.y() + intersectionRect.height() / 2;
- HitTestResult result = candidate.node->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, true);
- if (candidate.node->contains(result.innerNode())) {
+ HitTestResult result = candidate.visibleNode->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, true);
+ if (candidate.visibleNode->contains(result.innerNode())) {
closest = candidate;
return;
}
- if (closest.node->contains(result.innerNode()))
+ if (closest.visibleNode->contains(result.innerNode()))
return;
}
@@ -473,13 +476,13 @@ void FocusController::findFocusCandidateInContainer(Node* container, const IntRe
if (node == focusedNode)
continue;
- if (!node->renderer())
+ if (!node->isKeyboardFocusable(event) && !node->isFrameOwnerElement() && !canScrollInDirection(direction, node))
continue;
- if (!node->isKeyboardFocusable(event) && !node->isFrameOwnerElement() && !canScrollInDirection(direction, node))
+ FocusCandidate candidate = FocusCandidate(node, direction);
+ if (candidate.isNull())
continue;
- FocusCandidate candidate(node, direction);
candidate.enclosingScrollableBox = container;
updateFocusCandidateIfNeeded(direction, startingRect, candidate, closest);
}
@@ -500,23 +503,20 @@ bool FocusController::advanceFocusDirectionallyInContainer(Node* container, cons
findFocusCandidateInContainer(container, newStartingRect, direction, event, focusCandidate);
if (focusCandidate.isNull()) {
- if (canScrollInDirection(direction, container)) {
- // Nothing to focus, scroll if possible.
- scrollInDirection(container, direction);
- return true;
- }
- // Return false will cause a re-try, skipping this container.
- return false;
+ // Nothing to focus, scroll if possible.
+ // NOTE: If no scrolling is performed (i.e. scrollInDirection returns false), the
+ // spatial navigation algorithm will skip this container.
+ return scrollInDirection(container, direction);
}
- if (focusCandidate.node->isFrameOwnerElement()) {
- HTMLFrameOwnerElement* frameElement = static_cast<HTMLFrameOwnerElement*>(focusCandidate.node);
+
+ if (HTMLFrameOwnerElement* frameElement = frameOwnerElement(focusCandidate)) {
// If we have an iframe without the src attribute, it will not have a contentFrame().
// We ASSERT here to make sure that
// updateFocusCandidateIfNeeded() will never consider such an iframe as a candidate.
ASSERT(frameElement->contentFrame());
if (focusCandidate.isOffscreenAfterScrolling) {
- scrollInDirection(focusCandidate.node->document(), direction);
+ scrollInDirection(focusCandidate.visibleNode->document(), direction);
return true;
}
// Navigate into a new frame.
@@ -527,13 +527,13 @@ bool FocusController::advanceFocusDirectionallyInContainer(Node* container, cons
frameElement->contentFrame()->document()->updateLayoutIgnorePendingStylesheets();
if (!advanceFocusDirectionallyInContainer(frameElement->contentFrame()->document(), rect, direction, event)) {
// The new frame had nothing interesting, need to find another candidate.
- return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.node, true), direction, event);
+ return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.visibleNode, true), direction, event);
}
return true;
}
- if (canScrollInDirection(direction, focusCandidate.node)) {
+ if (canScrollInDirection(direction, focusCandidate.visibleNode)) {
if (focusCandidate.isOffscreenAfterScrolling) {
- scrollInDirection(focusCandidate.node, direction);
+ scrollInDirection(focusCandidate.visibleNode, direction);
return true;
}
// Navigate into a new scrollable container.
@@ -541,7 +541,7 @@ bool FocusController::advanceFocusDirectionallyInContainer(Node* container, cons
Node* focusedNode = focusedOrMainFrame()->document()->focusedNode();
if (focusedNode && !hasOffscreenRect(focusedNode))
startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true);
- return advanceFocusDirectionallyInContainer(focusCandidate.node, startingRect, direction, event);
+ return advanceFocusDirectionallyInContainer(focusCandidate.visibleNode, startingRect, direction, event);
}
if (focusCandidate.isOffscreenAfterScrolling) {
Node* container = focusCandidate.enclosingScrollableBox;
@@ -550,7 +550,7 @@ bool FocusController::advanceFocusDirectionallyInContainer(Node* container, cons
}
// We found a new focus node, navigate to it.
- Element* element = toElement(focusCandidate.node);
+ Element* element = toElement(focusCandidate.focusableNode);
ASSERT(element);
element->focus(false);
@@ -571,9 +571,15 @@ bool FocusController::advanceFocusDirectionally(FocusDirection direction, Keyboa
// Figure out the starting rect.
IntRect startingRect;
- if (focusedNode && !hasOffscreenRect(focusedNode)) {
- container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedNode);
- startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */);
+ 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);
+ container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, area->imageElement());
+ startingRect = virtualRectForAreaElementAndDirection(direction, area);
+ }
}
bool consumed = false;