15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2009 Antonio Gomes <tonikitoo@webkit.org>
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * All rights reserved.
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met:
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1. Redistributions of source code must retain the above copyright
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer.
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer in the
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    documentation and/or other materials provided with the distribution.
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
3053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/page/SpatialNavigation.h"
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
325d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "core/HTMLNames.h"
33d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "core/frame/FrameView.h"
34d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "core/frame/LocalFrame.h"
35d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "core/frame/Settings.h"
3653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLAreaElement.h"
3776c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)#include "core/html/HTMLFrameOwnerElement.h"
3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLImageElement.h"
3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/page/FrameTree.h"
4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/page/Page.h"
4153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderLayer.h"
421e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/geometry/IntRect.h"
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
44c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)using namespace HTMLNames;
4709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
4809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static RectsAlignment alignmentForRects(FocusType, const LayoutRect&, const LayoutRect&, const LayoutSize& viewSize);
4909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static bool areRectsFullyAligned(FocusType, const LayoutRect&, const LayoutRect&);
5009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static bool areRectsPartiallyAligned(FocusType, const LayoutRect&, const LayoutRect&);
5109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static bool areRectsMoreThanFullScreenApart(FocusType, const LayoutRect& curRect, const LayoutRect& targetRect, const LayoutSize& viewSize);
5209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static bool isRectInDirection(FocusType, const LayoutRect&, const LayoutRect&);
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void deflateIfOverlapped(LayoutRect&, LayoutRect&);
54d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)static LayoutRect rectToAbsoluteCoordinates(LocalFrame* initialFrame, const LayoutRect&);
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool isScrollableNode(const Node*);
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)FocusCandidate::FocusCandidate(Node* node, FocusType type)
58c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    : visibleNode(nullptr)
59c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    , focusableNode(nullptr)
60c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    , enclosingScrollableBox(nullptr)
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , distance(maxDistance())
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , alignment(None)
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , isOffscreen(true)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , isOffscreenAfterScrolling(true)
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(node);
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(node->isElementNode());
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
69d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (isHTMLAreaElement(*node)) {
70d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        HTMLAreaElement& area = toHTMLAreaElement(*node);
71d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        HTMLImageElement* image = area.imageElement();
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!image || !image->renderer())
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        visibleNode = image;
7609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        rect = virtualRectForAreaElementAndDirection(area, type);
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!node->renderer())
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        visibleNode = node;
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect = nodeRectInAbsoluteCoordinates(node, true /* ignore border */);
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    focusableNode = node;
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    isOffscreen = hasOffscreenRect(visibleNode);
8709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    isOffscreenAfterScrolling = hasOffscreenRect(visibleNode, type);
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
90d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)bool isSpatialNavigationEnabled(const LocalFrame* frame)
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
92926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return (frame && frame->settings() && frame->settings()->spatialNavigationEnabled());
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static RectsAlignment alignmentForRects(FocusType type, const LayoutRect& curRect, const LayoutRect& targetRect, const LayoutSize& viewSize)
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If we found a node in full alignment, but it is too far away, ignore it.
9809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (areRectsMoreThanFullScreenApart(type, curRect, targetRect, viewSize))
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return None;
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (areRectsFullyAligned(type, curRect, targetRect))
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return Full;
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (areRectsPartiallyAligned(type, curRect, targetRect))
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return Partial;
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return None;
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static inline bool isHorizontalMove(FocusType type)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
11209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return type == FocusTypeLeft || type == FocusTypeRight;
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static inline LayoutUnit start(FocusType type, const LayoutRect& rect)
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
11709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return isHorizontalMove(type) ? rect.y() : rect.x();
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static inline LayoutUnit middle(FocusType type, const LayoutRect& rect)
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutPoint center(rect.center());
12309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return isHorizontalMove(type) ? center.y(): center.x();
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static inline LayoutUnit end(FocusType type, const LayoutRect& rect)
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
12809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return isHorizontalMove(type) ? rect.maxY() : rect.maxX();
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// This method checks if rects |a| and |b| are fully aligned either vertically or
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// horizontally. In general, rects whose central point falls between the top or
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// bottom of each other are considered fully aligned.
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Rects that match this criteria are preferable target nodes in move focus changing
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// operations.
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// * a = Current focused node's rect.
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// * b = Focus candidate node's rect.
13809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static bool areRectsFullyAligned(FocusType type, const LayoutRect& a, const LayoutRect& b)
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit aStart, bStart, aEnd, bEnd;
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (type) {
14309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeLeft:
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        aStart = a.x();
145a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        bEnd = b.x();
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
14709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeRight:
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        aStart = b.x();
149a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        bEnd = a.x();
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
15109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeUp:
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        aStart = a.y();
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bEnd = b.y();
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
15509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeDown:
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        aStart = b.y();
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bEnd = a.y();
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (aStart < bEnd)
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    aStart = start(type, a);
16809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    bStart = start(type, b);
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
17009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    LayoutUnit aMiddle = middle(type, a);
17109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    LayoutUnit bMiddle = middle(type, b);
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
17309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    aEnd = end(type, a);
17409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    bEnd = end(type, b);
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Picture of the totally aligned logic:
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //     Horizontal    Vertical        Horizontal     Vertical
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //  ****************************  *****************************
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //  *  _          *   _ _ _ _  *  *         _   *      _ _    *
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //  * |_|     _   *  |_|_|_|_| *  *  _     |_|  *     |_|_|   *
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //  * |_|....|_|  *      .     *  * |_|....|_|  *       .     *
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //  * |_|    |_| (1)     .     *  * |_|    |_| (2)      .     *
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //  * |_|         *     _._    *  *        |_|  *    _ _._ _  *
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //  *             *    |_|_|   *  *             *   |_|_|_|_| *
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //  *             *            *  *             *             *
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //  ****************************  *****************************
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
189a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    return (bMiddle >= aStart && bMiddle <= aEnd) // (1)
190a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        || (aMiddle >= bStart && aMiddle <= bEnd); // (2)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
193a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// This method checks if rects |a| and |b| are partially aligned either vertically or
194a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// horizontally. In general, rects whose either of edges falls between the top or
195a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// bottom of each other are considered partially-aligned.
196a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// This is a separate set of conditions from "fully-aligned" and do not include cases
197a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// that satisfy the former.
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// * a = Current focused node's rect.
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// * b = Focus candidate node's rect.
20009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static bool areRectsPartiallyAligned(FocusType type, const LayoutRect& a, const LayoutRect& b)
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
20209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    LayoutUnit aStart  = start(type, a);
20309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    LayoutUnit bStart  = start(type, b);
20409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    LayoutUnit aEnd = end(type, a);
20509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    LayoutUnit bEnd = end(type, b);
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Picture of the partially aligned logic:
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //    Horizontal       Vertical
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // ********************************
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // *  _            *   _ _ _      *
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // * |_|           *  |_|_|_|     *
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // * |_|.... _     *      . .     *
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // * |_|    |_|    *      . .     *
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // * |_|....|_|    *      ._._ _  *
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // *        |_|    *      |_|_|_| *
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // *        |_|    *              *
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // *               *              *
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // ********************************
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    //
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // ... and variants of the above cases.
222a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    return (bStart >= aStart && bStart <= aEnd)
223a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        || (bEnd >= aStart && bEnd <= aEnd);
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
22609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static bool areRectsMoreThanFullScreenApart(FocusType type, const LayoutRect& curRect, const LayoutRect& targetRect, const LayoutSize& viewSize)
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
22809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ASSERT(isRectInDirection(type, curRect, targetRect));
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
23009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (type) {
23109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeLeft:
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return curRect.x() - targetRect.maxX() > viewSize.width();
23309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeRight:
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return targetRect.x() - curRect.maxX() > viewSize.width();
23509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeUp:
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return curRect.y() - targetRect.maxY() > viewSize.height();
23709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeDown:
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return targetRect.y() - curRect.maxY() > viewSize.height();
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Return true if rect |a| is below |b|. False otherwise.
246a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// For overlapping rects, |a| is considered to be below |b|
247a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// if both edges of |a| are below the respective ones of |b|
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline bool below(const LayoutRect& a, const LayoutRect& b)
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
250a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    return a.y() >= b.maxY()
251a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        || (a.y() >= b.y() && a.maxY() > b.maxY());
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Return true if rect |a| is on the right of |b|. False otherwise.
255a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// For overlapping rects, |a| is considered to be on the right of |b|
256a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// if both edges of |a| are on the right of the respective ones of |b|
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline bool rightOf(const LayoutRect& a, const LayoutRect& b)
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
259a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    return a.x() >= b.maxX()
260a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        || (a.x() >= b.x() && a.maxX() > b.maxX());
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
26309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static bool isRectInDirection(FocusType type, const LayoutRect& curRect, const LayoutRect& targetRect)
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
26509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (type) {
26609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeLeft:
267a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        return rightOf(curRect, targetRect);
26809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeRight:
269a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        return rightOf(targetRect, curRect);
27009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeUp:
271a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        return below(curRect, targetRect);
27209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeDown:
273a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        return below(targetRect, curRect);
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Checks if |node| is offscreen the visible area (viewport) of its container
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// document. In case it is, one can scroll in direction or take any different
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// desired action later on.
28309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)bool hasOffscreenRect(Node* node, FocusType type)
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Get the FrameView in which |node| is (which means the current viewport if |node|
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // is not in an inner document), so we can check if its content rect is visible
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // before we actually move the focus to it.
2888abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    FrameView* frameView = node->document().view();
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!frameView)
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(!frameView->needsLayout());
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect containerViewportRect = frameView->visibleContentRect();
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // We want to select a node if it is currently off screen, but will be
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // exposed after we scroll. Adjust the viewport to post-scrolling position.
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If the container has overflow:hidden, we cannot scroll, so we do not pass direction
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // and we do not adjust for scrolling.
29909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (type) {
30009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeLeft:
301f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)        containerViewportRect.setX(containerViewportRect.x() - ScrollableArea::pixelsPerLineStep());
302f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)        containerViewportRect.setWidth(containerViewportRect.width() + ScrollableArea::pixelsPerLineStep());
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
30409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeRight:
305f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)        containerViewportRect.setWidth(containerViewportRect.width() + ScrollableArea::pixelsPerLineStep());
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
30709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeUp:
308f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)        containerViewportRect.setY(containerViewportRect.y() - ScrollableArea::pixelsPerLineStep());
309f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)        containerViewportRect.setHeight(containerViewportRect.height() + ScrollableArea::pixelsPerLineStep());
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
31109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeDown:
312f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)        containerViewportRect.setHeight(containerViewportRect.height() + ScrollableArea::pixelsPerLineStep());
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderObject* render = node->renderer();
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!render)
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect rect(render->absoluteClippedOverflowRect());
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (rect.isEmpty())
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return !containerViewportRect.intersects(rect);
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
329d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)bool scrollInDirection(LocalFrame* frame, FocusType type)
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(frame);
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
33309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (frame && canScrollInDirection(frame->document(), type)) {
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LayoutUnit dx = 0;
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LayoutUnit dy = 0;
33609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        switch (type) {
33709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        case FocusTypeLeft:
338f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)            dx = - ScrollableArea::pixelsPerLineStep();
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
34009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        case FocusTypeRight:
341f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)            dx = ScrollableArea::pixelsPerLineStep();
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
34309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        case FocusTypeUp:
344f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)            dy = - ScrollableArea::pixelsPerLineStep();
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
34609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        case FocusTypeDown:
347f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)            dy = ScrollableArea::pixelsPerLineStep();
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        default:
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ASSERT_NOT_REACHED();
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        frame->view()->scrollBy(IntSize(dx, dy));
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return false;
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
36009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)bool scrollInDirection(Node* container, FocusType type)
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(container);
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (container->isDocumentNode())
36409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        return scrollInDirection(toDocument(container)->frame(), type);
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!container->renderBox())
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
36909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (canScrollInDirection(container, type)) {
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LayoutUnit dx = 0;
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LayoutUnit dy = 0;
37209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        switch (type) {
37309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        case FocusTypeLeft:
374e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            dx = - std::min<LayoutUnit>(ScrollableArea::pixelsPerLineStep(), container->renderBox()->scrollLeft());
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
37609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        case FocusTypeRight:
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ASSERT(container->renderBox()->scrollWidth() > (container->renderBox()->scrollLeft() + container->renderBox()->clientWidth()));
378e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            dx = std::min<LayoutUnit>(ScrollableArea::pixelsPerLineStep(), container->renderBox()->scrollWidth() - (container->renderBox()->scrollLeft() + container->renderBox()->clientWidth()));
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
38009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        case FocusTypeUp:
381e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            dy = - std::min<LayoutUnit>(ScrollableArea::pixelsPerLineStep(), container->renderBox()->scrollTop());
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
38309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        case FocusTypeDown:
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ASSERT(container->renderBox()->scrollHeight() - (container->renderBox()->scrollTop() + container->renderBox()->clientHeight()));
385e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            dy = std::min<LayoutUnit>(ScrollableArea::pixelsPerLineStep(), container->renderBox()->scrollHeight() - (container->renderBox()->scrollTop() + container->renderBox()->clientHeight()));
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        default:
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ASSERT_NOT_REACHED();
3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
392bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)        container->renderBox()->scrollByRecursively(IntSize(dx, dy));
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return false;
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void deflateIfOverlapped(LayoutRect& a, LayoutRect& b)
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!a.intersects(b) || a.contains(b) || b.contains(a))
4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit deflateFactor = -fudgeFactor();
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Avoid negative width or height values.
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if ((a.width() + 2 * deflateFactor > 0) && (a.height() + 2 * deflateFactor > 0))
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        a.inflate(deflateFactor);
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if ((b.width() + 2 * deflateFactor > 0) && (b.height() + 2 * deflateFactor > 0))
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        b.inflate(deflateFactor);
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool isScrollableNode(const Node* node)
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(!node->isDocumentNode());
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!node)
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (RenderObject* renderer = node->renderer())
422d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea() && node->hasChildren();
4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return false;
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
42709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)Node* scrollableEnclosingBoxOrParentFrameForNodeInDirection(FocusType type, Node* node)
4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(node);
4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Node* parent = node;
4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    do {
432f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        // FIXME: Spatial navigation is broken for OOPI.
4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (parent->isDocumentNode())
434f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            parent = toDocument(parent)->frame()->deprecatedLocalOwner();
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else
436c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)            parent = parent->parentOrShadowHostNode();
43709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    } while (parent && !canScrollInDirection(parent, type) && !parent->isDocumentNode());
4385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return parent;
4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
44209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)bool canScrollInDirection(const Node* container, FocusType type)
4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(container);
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (container->isDocumentNode())
44609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        return canScrollInDirection(toDocument(container)->frame(), type);
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!isScrollableNode(container))
4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
45109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (type) {
45209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeLeft:
4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return (container->renderer()->style()->overflowX() != OHIDDEN && container->renderBox()->scrollLeft() > 0);
45409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeUp:
4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return (container->renderer()->style()->overflowY() != OHIDDEN && container->renderBox()->scrollTop() > 0);
45609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeRight:
4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return (container->renderer()->style()->overflowX() != OHIDDEN && container->renderBox()->scrollLeft() + container->renderBox()->clientWidth() < container->renderBox()->scrollWidth());
45809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeDown:
4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return (container->renderer()->style()->overflowY() != OHIDDEN && container->renderBox()->scrollTop() + container->renderBox()->clientHeight() < container->renderBox()->scrollHeight());
4605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
4615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
466d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)bool canScrollInDirection(const LocalFrame* frame, FocusType type)
4675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!frame->view())
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ScrollbarMode verticalMode;
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ScrollbarMode horizontalMode;
47209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    frame->view()->calculateScrollbarModesForLayoutAndSetViewportRenderer(horizontalMode, verticalMode);
47309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if ((type == FocusTypeLeft || type == FocusTypeRight) && ScrollbarAlwaysOff == horizontalMode)
4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
47509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if ((type == FocusTypeUp || type == FocusTypeDown) &&  ScrollbarAlwaysOff == verticalMode)
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutSize size = frame->view()->contentsSize();
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutSize offset = frame->view()->scrollOffset();
479d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    LayoutRect rect = frame->view()->visibleContentRect(IncludeScrollbars);
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
48109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (type) {
48209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeLeft:
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return offset.width() > 0;
48409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeUp:
4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return offset.height() > 0;
48609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeRight:
4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return rect.width() + offset.width() < size.width();
48809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeDown:
4895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return rect.height() + offset.height() < size.height();
4905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
4915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
4925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
496d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)static LayoutRect rectToAbsoluteCoordinates(LocalFrame* initialFrame, const LayoutRect& initialRect)
4975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect rect = initialRect;
499f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    for (Frame* frame = initialFrame; frame; frame = frame->tree().parent()) {
500f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        if (!frame->isLocalFrame())
501f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            continue;
502f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        // FIXME: Spatial navigation is broken for OOPI.
503197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        Element* element = frame->deprecatedLocalOwner();
504197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        if (element) {
505197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            for (; element; element = element->offsetParent())
5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                rect.move(element->offsetLeft(), element->offsetTop());
507f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            rect.move((-toLocalFrame(frame)->view()->scrollOffset()));
5085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return rect;
5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutRect nodeRectInAbsoluteCoordinates(Node* node, bool ignoreBorder)
5145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5158abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    ASSERT(node && node->renderer() && !node->document().view()->needsLayout());
5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (node->isDocumentNode())
518926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return frameRectInAbsoluteCoordinates(toDocument(node)->frame());
5198abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    LayoutRect rect = rectToAbsoluteCoordinates(node->document().frame(), node->boundingBox());
5205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // For authors that use border instead of outline in their CSS, we compensate by ignoring the border when calculating
5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // the rect of the focused element.
5235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (ignoreBorder) {
5245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect.move(node->renderer()->style()->borderLeftWidth(), node->renderer()->style()->borderTopWidth());
5255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect.setWidth(rect.width() - node->renderer()->style()->borderLeftWidth() - node->renderer()->style()->borderRightWidth());
5265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect.setHeight(rect.height() - node->renderer()->style()->borderTopWidth() - node->renderer()->style()->borderBottomWidth());
5275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return rect;
5295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
531d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)LayoutRect frameRectInAbsoluteCoordinates(LocalFrame* frame)
5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return rectToAbsoluteCoordinates(frame, frame->view()->visibleContentRect());
5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// This method calculates the exitPoint from the startingRect and the entryPoint into the candidate rect.
5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// The line between those 2 points is the closest distance between the 2 rects.
538a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// Takes care of overlapping rects, defining points so that the distance between them
539a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch// is zero where necessary
54009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void entryAndExitPointsForDirection(FocusType type, const LayoutRect& startingRect, const LayoutRect& potentialRect, LayoutPoint& exitPoint, LayoutPoint& entryPoint)
5415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
54209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (type) {
54309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeLeft:
5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        exitPoint.setX(startingRect.x());
545a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        if (potentialRect.maxX() < startingRect.x())
546a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            entryPoint.setX(potentialRect.maxX());
547a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        else
548a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            entryPoint.setX(startingRect.x());
5495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
55009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeUp:
5515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        exitPoint.setY(startingRect.y());
552a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        if (potentialRect.maxY() < startingRect.y())
553a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            entryPoint.setY(potentialRect.maxY());
554a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        else
555a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            entryPoint.setY(startingRect.y());
5565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
55709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeRight:
5585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        exitPoint.setX(startingRect.maxX());
559a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        if (potentialRect.x() > startingRect.maxX())
560a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            entryPoint.setX(potentialRect.x());
561a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        else
562a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            entryPoint.setX(startingRect.maxX());
5635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
56409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeDown:
5655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        exitPoint.setY(startingRect.maxY());
566a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        if (potentialRect.y() > startingRect.maxY())
567a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            entryPoint.setY(potentialRect.y());
568a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        else
569a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            entryPoint.setY(startingRect.maxY());
5705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
5715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
5725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
57509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (type) {
57609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeLeft:
57709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeRight:
5785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (below(startingRect, potentialRect)) {
5795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            exitPoint.setY(startingRect.y());
580a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            if (potentialRect.maxY() < startingRect.y())
581a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch                entryPoint.setY(potentialRect.maxY());
582a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            else
583a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch                entryPoint.setY(startingRect.y());
5845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else if (below(potentialRect, startingRect)) {
5855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            exitPoint.setY(startingRect.maxY());
586a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            if (potentialRect.y() > startingRect.maxY())
587a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch                entryPoint.setY(potentialRect.y());
588a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            else
589a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch                entryPoint.setY(startingRect.maxY());
5905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else {
5915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            exitPoint.setY(max(startingRect.y(), potentialRect.y()));
5925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            entryPoint.setY(exitPoint.y());
5935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
59509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeUp:
59609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeDown:
5975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (rightOf(startingRect, potentialRect)) {
5985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            exitPoint.setX(startingRect.x());
599a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            if (potentialRect.maxX() < startingRect.x())
600a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch                entryPoint.setX(potentialRect.maxX());
601a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            else
602a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch                entryPoint.setX(startingRect.x());
6035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else if (rightOf(potentialRect, startingRect)) {
6045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            exitPoint.setX(startingRect.maxX());
605a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            if (potentialRect.x() > startingRect.maxX())
606a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch                entryPoint.setX(potentialRect.x());
607a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            else
608a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch                entryPoint.setX(startingRect.maxX());
6095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else {
6105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            exitPoint.setX(max(startingRect.x(), potentialRect.x()));
6115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            entryPoint.setX(exitPoint.x());
6125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
6145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
6155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
6165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool areElementsOnSameLine(const FocusCandidate& firstCandidate, const FocusCandidate& secondCandidate)
6205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
6215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (firstCandidate.isNull() || secondCandidate.isNull())
6225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
6235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!firstCandidate.visibleNode->renderer() || !secondCandidate.visibleNode->renderer())
6255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
6265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!firstCandidate.rect.intersects(secondCandidate.rect))
6285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
6295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
630d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (isHTMLAreaElement(*firstCandidate.focusableNode) || isHTMLAreaElement(*secondCandidate.focusableNode))
6315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
6325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!firstCandidate.visibleNode->renderer()->isRenderInline() || !secondCandidate.visibleNode->renderer()->isRenderInline())
6345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
6355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (firstCandidate.visibleNode->renderer()->containingBlock() != secondCandidate.visibleNode->renderer()->containingBlock())
6375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
6385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
6405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
64209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void distanceDataForNode(FocusType type, const FocusCandidate& current, FocusCandidate& candidate)
6435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
6445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (areElementsOnSameLine(current, candidate)) {
64509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if ((type == FocusTypeUp && current.rect.y() > candidate.rect.y()) || (type == FocusTypeDown && candidate.rect.y() > current.rect.y())) {
6465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            candidate.distance = 0;
6475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            candidate.alignment = Full;
6485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
6495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect nodeRect = candidate.rect;
6535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect currentRect = current.rect;
6545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    deflateIfOverlapped(currentRect, nodeRect);
6555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
65609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (!isRectInDirection(type, currentRect, nodeRect))
6575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
6585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutPoint exitPoint;
6605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutPoint entryPoint;
66109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    entryAndExitPointsForDirection(type, currentRect, nodeRect, exitPoint, entryPoint);
6625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
663a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    LayoutUnit xAxis = exitPoint.x() - entryPoint.x();
664a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    LayoutUnit yAxis = exitPoint.y() - entryPoint.y();
665a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch
666a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    LayoutUnit navigationAxisDistance;
667a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    LayoutUnit orthogonalAxisDistance;
668a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch
66909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (type) {
67009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeLeft:
67109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeRight:
672a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        navigationAxisDistance = xAxis.abs();
673a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        orthogonalAxisDistance = yAxis.abs();
6745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
675a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    case FocusTypeUp:
67609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeDown:
677a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        navigationAxisDistance = yAxis.abs();
678a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        orthogonalAxisDistance = xAxis.abs();
6795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
6805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
6815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
6825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
6835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
685a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    double euclidianDistancePow2 = (xAxis * xAxis + yAxis * yAxis).toDouble();
686a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    LayoutRect intersectionRect = intersection(currentRect, nodeRect);
687a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    double overlap = (intersectionRect.width() * intersectionRect.height()).toDouble();
6885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
689a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    // Distance calculation is based on http://www.w3.org/TR/WICD/#focus-handling
690a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    candidate.distance = sqrt(euclidianDistancePow2) + navigationAxisDistance+ orthogonalAxisDistance * 2 - sqrt(overlap);
6915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6925d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    LayoutSize viewSize = candidate.visibleNode->document().page()->deprecatedLocalMainFrame()->view()->visibleContentRect().size();
69309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    candidate.alignment = alignmentForRects(type, currentRect, nodeRect, viewSize);
6945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
6955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
69609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)bool canBeScrolledIntoView(FocusType type, const FocusCandidate& candidate)
6975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
6985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(candidate.visibleNode && candidate.isOffscreen);
6995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect candidateRect = candidate.rect;
7005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (Node* parentNode = candidate.visibleNode->parentNode(); parentNode; parentNode = parentNode->parentNode()) {
7015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        LayoutRect parentRect = nodeRectInAbsoluteCoordinates(parentNode);
7025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!candidateRect.intersects(parentRect)) {
70309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            if (((type == FocusTypeLeft || type == FocusTypeRight) && parentNode->renderer()->style()->overflowX() == OHIDDEN)
70409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                || ((type == FocusTypeUp || type == FocusTypeDown) && parentNode->renderer()->style()->overflowY() == OHIDDEN))
7055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return false;
7065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
7075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (parentNode == candidate.enclosingScrollableBox)
70809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return canScrollInDirection(parentNode, type);
7095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
7115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
7125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// The starting rect is the rect of the focused node, in document coordinates.
7145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Compose a virtual starting rect if there is no focused node or if it is off screen.
7155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// The virtual rect is the edge of the container or frame. We select which
7165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// edge depending on the direction of the navigation.
71709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)LayoutRect virtualRectForDirection(FocusType type, const LayoutRect& startingRect, LayoutUnit width)
7185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
7195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutRect virtualStartingRect = startingRect;
72009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (type) {
72109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeLeft:
7225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        virtualStartingRect.setX(virtualStartingRect.maxX() - width);
7235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        virtualStartingRect.setWidth(width);
7245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
72509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeUp:
7265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        virtualStartingRect.setY(virtualStartingRect.maxY() - width);
7275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        virtualStartingRect.setHeight(width);
7285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
72909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeRight:
7305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        virtualStartingRect.setWidth(width);
7315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
73209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    case FocusTypeDown:
7335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        virtualStartingRect.setHeight(width);
7345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
7355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
7365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
7375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return virtualStartingRect;
7405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
7415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
742d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)LayoutRect virtualRectForAreaElementAndDirection(HTMLAreaElement& area, FocusType type)
7435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
744d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    ASSERT(area.imageElement());
7455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Area elements tend to overlap more than other focusable elements. We flatten the rect of the area elements
7465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // to minimize the effect of overlapping areas.
747d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    LayoutRect rect = virtualRectForDirection(type, rectToAbsoluteCoordinates(area.document().frame(), area.computeRect(area.imageElement()->renderer())), 1);
7485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return rect;
7495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
7505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)HTMLFrameOwnerElement* frameOwnerElement(FocusCandidate& candidate)
7525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
753e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    return candidate.isFrameOwnerElement() ? toHTMLFrameOwnerElement(candidate.visibleNode) : 0;
7545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
7555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
756c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink
757