summaryrefslogtreecommitdiffstats
path: root/WebCore/page/SpatialNavigation.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /WebCore/page/SpatialNavigation.cpp
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'WebCore/page/SpatialNavigation.cpp')
-rw-r--r--WebCore/page/SpatialNavigation.cpp711
1 files changed, 0 insertions, 711 deletions
diff --git a/WebCore/page/SpatialNavigation.cpp b/WebCore/page/SpatialNavigation.cpp
deleted file mode 100644
index 5cb3c95..0000000
--- a/WebCore/page/SpatialNavigation.cpp
+++ /dev/null
@@ -1,711 +0,0 @@
-/*
- * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
- * Copyright (C) 2009 Antonio Gomes <tonikitoo@webkit.org>
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SpatialNavigation.h"
-
-#include "Frame.h"
-#include "FrameTree.h"
-#include "FrameView.h"
-#include "HTMLAreaElement.h"
-#include "HTMLImageElement.h"
-#include "HTMLMapElement.h"
-#include "HTMLNames.h"
-#include "IntRect.h"
-#include "Node.h"
-#include "Page.h"
-#include "RenderLayer.h"
-#include "Settings.h"
-
-namespace WebCore {
-
-static RectsAlignment alignmentForRects(FocusDirection, const IntRect&, const IntRect&, const IntSize& viewSize);
-static bool areRectsFullyAligned(FocusDirection, const IntRect&, const IntRect&);
-static bool areRectsPartiallyAligned(FocusDirection, const IntRect&, const IntRect&);
-static bool areRectsMoreThanFullScreenApart(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect, const IntSize& viewSize);
-static bool isRectInDirection(FocusDirection, const IntRect&, const IntRect&);
-static void deflateIfOverlapped(IntRect&, IntRect&);
-static IntRect rectToAbsoluteCoordinates(Frame* initialFrame, const IntRect&);
-static void entryAndExitPointsForDirection(FocusDirection direction, const IntRect& startingRect, const IntRect& potentialRect, IntPoint& exitPoint, IntPoint& entryPoint);
-static bool isScrollableContainerNode(const Node*);
-
-FocusCandidate::FocusCandidate(Node* node, FocusDirection direction)
- : visibleNode(0)
- , focusableNode(0)
- , enclosingScrollableBox(0)
- , distance(maxDistance())
- , parentDistance(maxDistance())
- , alignment(None)
- , parentAlignment(None)
- , isOffscreen(true)
- , isOffscreenAfterScrolling(true)
-{
- ASSERT(node);
- if (node->hasTagName(HTMLNames::areaTag)) {
- HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
- HTMLImageElement* image = area->imageElement();
- if (!image || !image->renderer())
- return;
-
- visibleNode = image;
- rect = virtualRectForAreaElementAndDirection(direction, area);
- } else {
- if (!node->renderer())
- return;
-
- visibleNode = node;
- rect = nodeRectInAbsoluteCoordinates(node, true /* ignore border */);
- }
-
- focusableNode = node;
- isOffscreen = hasOffscreenRect(visibleNode);
- isOffscreenAfterScrolling = hasOffscreenRect(visibleNode, direction);
-}
-
-bool isSpatialNavigationEnabled(const Frame* frame)
-{
- return (frame && frame->settings() && frame->settings()->isSpatialNavigationEnabled());
-}
-
-static RectsAlignment alignmentForRects(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect, const IntSize& viewSize)
-{
- // If we found a node in full alignment, but it is too far away, ignore it.
- if (areRectsMoreThanFullScreenApart(direction, curRect, targetRect, viewSize))
- return None;
-
- if (areRectsFullyAligned(direction, curRect, targetRect))
- return Full;
-
- if (areRectsPartiallyAligned(direction, curRect, targetRect))
- return Partial;
-
- return None;
-}
-
-static inline bool isHorizontalMove(FocusDirection direction)
-{
- return direction == FocusDirectionLeft || direction == FocusDirectionRight;
-}
-
-static inline int start(FocusDirection direction, const IntRect& rect)
-{
- return isHorizontalMove(direction) ? rect.y() : rect.x();
-}
-
-static inline int middle(FocusDirection direction, const IntRect& rect)
-{
- IntPoint center(rect.center());
- return isHorizontalMove(direction) ? center.y(): center.x();
-}
-
-static inline int end(FocusDirection direction, const IntRect& rect)
-{
- return isHorizontalMove(direction) ? rect.bottom() : rect.right();
-}
-
-// This method checks if rects |a| and |b| are fully aligned either vertically or
-// horizontally. In general, rects whose central point falls between the top or
-// bottom of each other are considered fully aligned.
-// Rects that match this criteria are preferable target nodes in move focus changing
-// operations.
-// * a = Current focused node's rect.
-// * b = Focus candidate node's rect.
-static bool areRectsFullyAligned(FocusDirection direction, const IntRect& a, const IntRect& b)
-{
- int aStart, bStart, aEnd, bEnd;
-
- switch (direction) {
- case FocusDirectionLeft:
- aStart = a.x();
- bEnd = b.right();
- break;
- case FocusDirectionRight:
- aStart = b.x();
- bEnd = a.right();
- break;
- case FocusDirectionUp:
- aStart = a.y();
- bEnd = b.y();
- break;
- case FocusDirectionDown:
- aStart = b.y();
- bEnd = a.y();
- break;
- default:
- ASSERT_NOT_REACHED();
- return false;
- }
-
- if (aStart < bEnd)
- return false;
-
- aStart = start(direction, a);
- bStart = start(direction, b);
-
- int aMiddle = middle(direction, a);
- int bMiddle = middle(direction, b);
-
- aEnd = end(direction, a);
- bEnd = end(direction, b);
-
- // Picture of the totally aligned logic:
- //
- // Horizontal Vertical Horizontal Vertical
- // **************************** *****************************
- // * _ * _ _ _ _ * * _ * _ _ *
- // * |_| _ * |_|_|_|_| * * _ |_| * |_|_| *
- // * |_|....|_| * . * * |_|....|_| * . *
- // * |_| |_| (1) . * * |_| |_| (2) . *
- // * |_| * _._ * * |_| * _ _._ _ *
- // * * |_|_| * * * |_|_|_|_| *
- // * * * * * *
- // **************************** *****************************
-
- // Horizontal Vertical Horizontal Vertical
- // **************************** *****************************
- // * _......_ * _ _ _ _ * * _ * _ _ _ _ *
- // * |_| |_| * |_|_|_|_| * * |_| _ * |_|_|_|_| *
- // * |_| |_| * . * * |_| |_| * . *
- // * |_| (3) . * * |_|....|_| (4) . *
- // * * ._ _ * * * _ _. *
- // * * |_|_| * * * |_|_| *
- // * * * * * *
- // **************************** *****************************
-
- return ((bMiddle >= aStart && bMiddle <= aEnd) // (1)
- || (aMiddle >= bStart && aMiddle <= bEnd) // (2)
- || (bStart == aStart) // (3)
- || (bEnd == aEnd)); // (4)
-}
-
-// This method checks if |start| and |dest| have a partial intersection, either
-// horizontally or vertically.
-// * a = Current focused node's rect.
-// * b = Focus candidate node's rect.
-static bool areRectsPartiallyAligned(FocusDirection direction, const IntRect& a, const IntRect& b)
-{
- int aStart = start(direction, a);
- int bStart = start(direction, b);
- int bMiddle = middle(direction, b);
- int aEnd = end(direction, a);
- int bEnd = end(direction, b);
-
- // Picture of the partially aligned logic:
- //
- // Horizontal Vertical
- // ********************************
- // * _ * _ _ _ *
- // * |_| * |_|_|_| *
- // * |_|.... _ * . . *
- // * |_| |_| * . . *
- // * |_|....|_| * ._._ _ *
- // * |_| * |_|_|_| *
- // * |_| * *
- // * * *
- // ********************************
- //
- // ... and variants of the above cases.
- return ((bStart >= aStart && bStart <= aEnd)
- || (bStart >= aStart && bStart <= aEnd)
- || (bEnd >= aStart && bEnd <= aEnd)
- || (bMiddle >= aStart && bMiddle <= aEnd)
- || (bEnd >= aStart && bEnd <= aEnd));
-}
-
-static bool areRectsMoreThanFullScreenApart(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect, const IntSize& viewSize)
-{
- ASSERT(isRectInDirection(direction, curRect, targetRect));
-
- switch (direction) {
- case FocusDirectionLeft:
- return curRect.x() - targetRect.right() > viewSize.width();
- case FocusDirectionRight:
- return targetRect.x() - curRect.right() > viewSize.width();
- case FocusDirectionUp:
- return curRect.y() - targetRect.bottom() > viewSize.height();
- case FocusDirectionDown:
- return targetRect.y() - curRect.bottom() > viewSize.height();
- default:
- ASSERT_NOT_REACHED();
- return true;
- }
-}
-
-// Return true if rect |a| is below |b|. False otherwise.
-static inline bool below(const IntRect& a, const IntRect& b)
-{
- return a.y() > b.bottom();
-}
-
-// Return true if rect |a| is on the right of |b|. False otherwise.
-static inline bool rightOf(const IntRect& a, const IntRect& b)
-{
- return a.x() > b.right();
-}
-
-static bool isRectInDirection(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect)
-{
- switch (direction) {
- case FocusDirectionLeft:
- return targetRect.right() <= curRect.x();
- case FocusDirectionRight:
- return targetRect.x() >= curRect.right();
- case FocusDirectionUp:
- return targetRect.bottom() <= curRect.y();
- case FocusDirectionDown:
- return targetRect.y() >= curRect.bottom();
- default:
- ASSERT_NOT_REACHED();
- return false;
- }
-}
-
-// Checks if |node| is offscreen the visible area (viewport) of its container
-// document. In case it is, one can scroll in direction or take any different
-// desired action later on.
-bool hasOffscreenRect(Node* node, FocusDirection direction)
-{
- // Get the FrameView in which |node| is (which means the current viewport if |node|
- // is not in an inner document), so we can check if its content rect is visible
- // before we actually move the focus to it.
- FrameView* frameView = node->document()->view();
- if (!frameView)
- return true;
-
- IntRect containerViewportRect = frameView->visibleContentRect();
- // We want to select a node if it is currently off screen, but will be
- // exposed after we scroll. Adjust the viewport to post-scrolling position.
- // If the container has overflow:hidden, we cannot scroll, so we do not pass direction
- // and we do not adjust for scrolling.
- switch (direction) {
- case FocusDirectionLeft:
- containerViewportRect.setX(containerViewportRect.x() - Scrollbar::pixelsPerLineStep());
- containerViewportRect.setWidth(containerViewportRect.width() + Scrollbar::pixelsPerLineStep());
- break;
- case FocusDirectionRight:
- containerViewportRect.setWidth(containerViewportRect.width() + Scrollbar::pixelsPerLineStep());
- break;
- case FocusDirectionUp:
- containerViewportRect.setY(containerViewportRect.y() - Scrollbar::pixelsPerLineStep());
- containerViewportRect.setHeight(containerViewportRect.height() + Scrollbar::pixelsPerLineStep());
- break;
- case FocusDirectionDown:
- containerViewportRect.setHeight(containerViewportRect.height() + Scrollbar::pixelsPerLineStep());
- break;
- default:
- break;
- }
-
- RenderObject* render = node->renderer();
- if (!render)
- return true;
-
- IntRect rect(render->absoluteClippedOverflowRect());
- if (rect.isEmpty())
- return true;
-
- return !containerViewportRect.intersects(rect);
-}
-
-bool scrollInDirection(Frame* frame, FocusDirection direction)
-{
- ASSERT(frame);
-
- if (frame && canScrollInDirection(direction, frame->document())) {
- int dx = 0;
- int dy = 0;
- switch (direction) {
- case FocusDirectionLeft:
- dx = - Scrollbar::pixelsPerLineStep();
- break;
- case FocusDirectionRight:
- dx = Scrollbar::pixelsPerLineStep();
- break;
- case FocusDirectionUp:
- dy = - Scrollbar::pixelsPerLineStep();
- break;
- case FocusDirectionDown:
- dy = Scrollbar::pixelsPerLineStep();
- break;
- default:
- ASSERT_NOT_REACHED();
- return false;
- }
-
- frame->view()->scrollBy(IntSize(dx, dy));
- return true;
- }
- return false;
-}
-
-bool scrollInDirection(Node* container, FocusDirection direction)
-{
- ASSERT(container);
- if (container->isDocumentNode())
- return scrollInDirection(static_cast<Document*>(container)->frame(), direction);
-
- if (!container->renderBox())
- return false;
-
- if (canScrollInDirection(direction, container)) {
- int dx = 0;
- int dy = 0;
- switch (direction) {
- case FocusDirectionLeft:
- dx = - min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollLeft());
- break;
- case FocusDirectionRight:
- ASSERT(container->renderBox()->scrollWidth() > (container->renderBox()->scrollLeft() + container->renderBox()->clientWidth()));
- dx = min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollWidth() - (container->renderBox()->scrollLeft() + container->renderBox()->clientWidth()));
- break;
- case FocusDirectionUp:
- dy = - min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollTop());
- break;
- case FocusDirectionDown:
- ASSERT(container->renderBox()->scrollHeight() - (container->renderBox()->scrollTop() + container->renderBox()->clientHeight()));
- dy = min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollHeight() - (container->renderBox()->scrollTop() + container->renderBox()->clientHeight()));
- break;
- default:
- ASSERT_NOT_REACHED();
- return false;
- }
-
- container->renderBox()->enclosingLayer()->scrollByRecursively(dx, dy);
- return true;
- }
-
- return false;
-}
-
-static void deflateIfOverlapped(IntRect& a, IntRect& b)
-{
- if (!a.intersects(b) || a.contains(b) || b.contains(a))
- return;
-
- int deflateFactor = -fudgeFactor();
-
- // Avoid negative width or height values.
- if ((a.width() + 2 * deflateFactor > 0) && (a.height() + 2 * deflateFactor > 0))
- a.inflate(deflateFactor);
-
- if ((b.width() + 2 * deflateFactor > 0) && (b.height() + 2 * deflateFactor > 0))
- b.inflate(deflateFactor);
-}
-
-bool isScrollableContainerNode(const Node* node)
-{
- if (!node)
- return false;
-
- if (RenderObject* renderer = node->renderer()) {
- return (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()
- && node->hasChildNodes() && !node->isDocumentNode());
- }
-
- return false;
-}
-
-Node* scrollableEnclosingBoxOrParentFrameForNodeInDirection(FocusDirection direction, Node* node)
-{
- ASSERT(node);
- Node* parent = node;
- do {
- if (parent->isDocumentNode())
- parent = static_cast<Document*>(parent)->document()->frame()->ownerElement();
- else
- parent = parent->parentNode();
- } while (parent && !canScrollInDirection(direction, parent) && !parent->isDocumentNode());
-
- return parent;
-}
-
-bool canScrollInDirection(FocusDirection direction, const Node* container)
-{
- ASSERT(container);
- if (container->isDocumentNode())
- return canScrollInDirection(direction, static_cast<const Document*>(container)->frame());
-
- if (!isScrollableContainerNode(container))
- return false;
-
- switch (direction) {
- case FocusDirectionLeft:
- return (container->renderer()->style()->overflowX() != OHIDDEN && container->renderBox()->scrollLeft() > 0);
- case FocusDirectionUp:
- return (container->renderer()->style()->overflowY() != OHIDDEN && container->renderBox()->scrollTop() > 0);
- case FocusDirectionRight:
- return (container->renderer()->style()->overflowX() != OHIDDEN && container->renderBox()->scrollLeft() + container->renderBox()->clientWidth() < container->renderBox()->scrollWidth());
- case FocusDirectionDown:
- return (container->renderer()->style()->overflowY() != OHIDDEN && container->renderBox()->scrollTop() + container->renderBox()->clientHeight() < container->renderBox()->scrollHeight());
- default:
- ASSERT_NOT_REACHED();
- return false;
- }
-}
-
-bool canScrollInDirection(FocusDirection direction, const Frame* frame)
-{
- if (!frame->view())
- return false;
- ScrollbarMode verticalMode;
- ScrollbarMode horizontalMode;
- frame->view()->calculateScrollbarModesForLayout(horizontalMode, verticalMode);
- if ((direction == FocusDirectionLeft || direction == FocusDirectionRight) && ScrollbarAlwaysOff == horizontalMode)
- return false;
- if ((direction == FocusDirectionUp || direction == FocusDirectionDown) && ScrollbarAlwaysOff == verticalMode)
- return false;
- IntSize size = frame->view()->contentsSize();
- IntSize offset = frame->view()->scrollOffset();
- IntRect rect = frame->view()->visibleContentRect(true);
-
- switch (direction) {
- case FocusDirectionLeft:
- return offset.width() > 0;
- case FocusDirectionUp:
- return offset.height() > 0;
- case FocusDirectionRight:
- return rect.width() + offset.width() < size.width();
- case FocusDirectionDown:
- return rect.height() + offset.height() < size.height();
- default:
- ASSERT_NOT_REACHED();
- return false;
- }
-}
-
-static IntRect rectToAbsoluteCoordinates(Frame* initialFrame, const IntRect& initialRect)
-{
- IntRect rect = initialRect;
- for (Frame* frame = initialFrame; frame; frame = frame->tree()->parent()) {
- if (Element* element = static_cast<Element*>(frame->ownerElement())) {
- do {
- rect.move(element->offsetLeft(), element->offsetTop());
- } while ((element = element->offsetParent()));
- rect.move((-frame->view()->scrollOffset()));
- }
- }
- return rect;
-}
-
-IntRect nodeRectInAbsoluteCoordinates(Node* node, bool ignoreBorder)
-{
- ASSERT(node && node->renderer());
-
- if (node->isDocumentNode())
- return frameRectInAbsoluteCoordinates(static_cast<Document*>(node)->frame());
- IntRect rect = rectToAbsoluteCoordinates(node->document()->frame(), node->getRect());
-
- // For authors that use border instead of outline in their CSS, we compensate by ignoring the border when calculating
- // the rect of the focused element.
- if (ignoreBorder) {
- rect.move(node->renderer()->style()->borderLeftWidth(), node->renderer()->style()->borderTopWidth());
- rect.setWidth(rect.width() - node->renderer()->style()->borderLeftWidth() - node->renderer()->style()->borderRightWidth());
- rect.setHeight(rect.height() - node->renderer()->style()->borderTopWidth() - node->renderer()->style()->borderBottomWidth());
- }
- return rect;
-}
-
-IntRect frameRectInAbsoluteCoordinates(Frame* frame)
-{
- return rectToAbsoluteCoordinates(frame, frame->view()->visibleContentRect());
-}
-
-// This method calculates the exitPoint from the startingRect and the entryPoint into the candidate rect.
-// The line between those 2 points is the closest distance between the 2 rects.
-void entryAndExitPointsForDirection(FocusDirection direction, const IntRect& startingRect, const IntRect& potentialRect, IntPoint& exitPoint, IntPoint& entryPoint)
-{
- switch (direction) {
- case FocusDirectionLeft:
- exitPoint.setX(startingRect.x());
- entryPoint.setX(potentialRect.right());
- break;
- case FocusDirectionUp:
- exitPoint.setY(startingRect.y());
- entryPoint.setY(potentialRect.bottom());
- break;
- case FocusDirectionRight:
- exitPoint.setX(startingRect.right());
- entryPoint.setX(potentialRect.x());
- break;
- case FocusDirectionDown:
- exitPoint.setY(startingRect.bottom());
- entryPoint.setY(potentialRect.y());
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-
- switch (direction) {
- case FocusDirectionLeft:
- case FocusDirectionRight:
- if (below(startingRect, potentialRect)) {
- exitPoint.setY(startingRect.y());
- entryPoint.setY(potentialRect.bottom());
- } else if (below(potentialRect, startingRect)) {
- exitPoint.setY(startingRect.bottom());
- entryPoint.setY(potentialRect.y());
- } else {
- exitPoint.setY(max(startingRect.y(), potentialRect.y()));
- entryPoint.setY(exitPoint.y());
- }
- break;
- case FocusDirectionUp:
- case FocusDirectionDown:
- if (rightOf(startingRect, potentialRect)) {
- exitPoint.setX(startingRect.x());
- entryPoint.setX(potentialRect.right());
- } else if (rightOf(potentialRect, startingRect)) {
- exitPoint.setX(startingRect.right());
- entryPoint.setX(potentialRect.x());
- } else {
- exitPoint.setX(max(startingRect.x(), potentialRect.x()));
- entryPoint.setX(exitPoint.x());
- }
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void distanceDataForNode(FocusDirection direction, const FocusCandidate& current, FocusCandidate& candidate)
-{
- if (candidate.isNull())
- return;
- if (!candidate.visibleNode->renderer())
- return;
- IntRect nodeRect = candidate.rect;
- IntRect currentRect = current.rect;
- deflateIfOverlapped(currentRect, nodeRect);
-
- if (!isRectInDirection(direction, currentRect, nodeRect))
- return;
-
- IntPoint exitPoint;
- IntPoint entryPoint;
- int sameAxisDistance = 0;
- int otherAxisDistance = 0;
- entryAndExitPointsForDirection(direction, currentRect, nodeRect, exitPoint, entryPoint);
-
- switch (direction) {
- case FocusDirectionLeft:
- sameAxisDistance = exitPoint.x() - entryPoint.x();
- otherAxisDistance = abs(exitPoint.y() - entryPoint.y());
- break;
- case FocusDirectionUp:
- sameAxisDistance = exitPoint.y() - entryPoint.y();
- otherAxisDistance = abs(exitPoint.x() - entryPoint.x());
- break;
- case FocusDirectionRight:
- sameAxisDistance = entryPoint.x() - exitPoint.x();
- otherAxisDistance = abs(entryPoint.y() - exitPoint.y());
- break;
- case FocusDirectionDown:
- sameAxisDistance = entryPoint.y() - exitPoint.y();
- otherAxisDistance = abs(entryPoint.x() - exitPoint.x());
- break;
- default:
- ASSERT_NOT_REACHED();
- return;
- }
-
- int x = (entryPoint.x() - exitPoint.x()) * (entryPoint.x() - exitPoint.x());
- int y = (entryPoint.y() - exitPoint.y()) * (entryPoint.y() - exitPoint.y());
-
- float euclidianDistance = sqrt((x + y) * 1.0f);
-
- // Loosely based on http://www.w3.org/TR/WICD/#focus-handling
- // df = dotDist + dx + dy + 2 * (xdisplacement + ydisplacement) - sqrt(Overlap)
-
- float distance = euclidianDistance + sameAxisDistance + 2 * otherAxisDistance;
- candidate.distance = roundf(distance);
- IntSize viewSize = candidate.visibleNode->document()->page()->mainFrame()->view()->visibleContentRect().size();
- candidate.alignment = alignmentForRects(direction, currentRect, nodeRect, viewSize);
-}
-
-bool canBeScrolledIntoView(FocusDirection direction, const FocusCandidate& candidate)
-{
- ASSERT(candidate.visibleNode && candidate.isOffscreen);
- IntRect candidateRect = candidate.rect;
- for (Node* parentNode = candidate.visibleNode->parentNode(); parentNode; parentNode = parentNode->parentNode()) {
- IntRect parentRect = nodeRectInAbsoluteCoordinates(parentNode);
- if (!candidateRect.intersects(parentRect)) {
- if (((direction == FocusDirectionLeft || direction == FocusDirectionRight) && parentNode->renderer()->style()->overflowX() == OHIDDEN)
- || ((direction == FocusDirectionUp || direction == FocusDirectionDown) && parentNode->renderer()->style()->overflowY() == OHIDDEN))
- return false;
- }
- if (parentNode == candidate.enclosingScrollableBox)
- return canScrollInDirection(direction, parentNode);
- }
- return true;
-}
-
-// The starting rect is the rect of the focused node, in document coordinates.
-// Compose a virtual starting rect if there is no focused node or if it is off screen.
-// The virtual rect is the edge of the container or frame. We select which
-// edge depending on the direction of the navigation.
-IntRect virtualRectForDirection(FocusDirection direction, const IntRect& startingRect, int width)
-{
- IntRect virtualStartingRect = startingRect;
- switch (direction) {
- case FocusDirectionLeft:
- virtualStartingRect.setX(virtualStartingRect.right() - width);
- virtualStartingRect.setWidth(width);
- break;
- case FocusDirectionUp:
- virtualStartingRect.setY(virtualStartingRect.bottom() - width);
- virtualStartingRect.setHeight(width);
- break;
- case FocusDirectionRight:
- virtualStartingRect.setWidth(width);
- break;
- case FocusDirectionDown:
- virtualStartingRect.setHeight(width);
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-
- return virtualStartingRect;
-}
-
-IntRect virtualRectForAreaElementAndDirection(FocusDirection direction, HTMLAreaElement* area)
-{
- ASSERT(area);
- ASSERT(area->imageElement());
- // Area elements tend to overlap more than other focusable elements. We flatten the rect of the area elements
- // to minimize the effect of overlapping areas.
- IntRect rect = virtualRectForDirection(direction, rectToAbsoluteCoordinates(area->document()->frame(), area->getRect(area->imageElement()->renderer())), 1);
- return rect;
-}
-
-HTMLFrameOwnerElement* frameOwnerElement(FocusCandidate& candidate)
-{
- return candidate.isFrameOwnerElement() ? static_cast<HTMLFrameOwnerElement*>(candidate.visibleNode) : 0;
-};
-
-} // namespace WebCore