Home | History | Annotate | Download | only in page
      1 /*
      2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
      3  * Copyright (C) 2008 Nuanti Ltd.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "FocusController.h"
     29 
     30 #include "AXObjectCache.h"
     31 #include "Chrome.h"
     32 #include "Document.h"
     33 #include "Editor.h"
     34 #include "EditorClient.h"
     35 #include "Element.h"
     36 #include "Event.h"
     37 #include "EventHandler.h"
     38 #include "EventNames.h"
     39 #include "ExceptionCode.h"
     40 #include "Frame.h"
     41 #include "FrameTree.h"
     42 #include "FrameView.h"
     43 #include "HTMLAreaElement.h"
     44 #include "HTMLImageElement.h"
     45 #include "HTMLNames.h"
     46 #include "HitTestResult.h"
     47 #include "KeyboardEvent.h"
     48 #include "Page.h"
     49 #include "Range.h"
     50 #include "RenderLayer.h"
     51 #include "RenderObject.h"
     52 #include "RenderWidget.h"
     53 #include "ScrollAnimator.h"
     54 #include "SelectionController.h"
     55 #include "Settings.h"
     56 #include "SpatialNavigation.h"
     57 #include "Widget.h"
     58 #include "htmlediting.h" // For firstPositionInOrBeforeNode
     59 
     60 namespace WebCore {
     61 
     62 using namespace HTMLNames;
     63 using namespace std;
     64 
     65 static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused)
     66 {
     67     // If we have a focused node we should dispatch blur on it before we blur the window.
     68     // If we have a focused node we should dispatch focus on it after we focus the window.
     69     // https://bugs.webkit.org/show_bug.cgi?id=27105
     70 
     71     // Do not fire events while modal dialogs are up.  See https://bugs.webkit.org/show_bug.cgi?id=33962
     72     if (Page* page = document->page()) {
     73         if (page->defersLoading())
     74             return;
     75     }
     76 
     77     if (!focused && document->focusedNode())
     78         document->focusedNode()->dispatchBlurEvent();
     79     document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false));
     80     if (focused && document->focusedNode())
     81         document->focusedNode()->dispatchFocusEvent();
     82 }
     83 
     84 FocusController::FocusController(Page* page)
     85     : m_page(page)
     86     , m_isActive(false)
     87     , m_isFocused(false)
     88     , m_isChangingFocusedFrame(false)
     89 {
     90 }
     91 
     92 void FocusController::setFocusedFrame(PassRefPtr<Frame> frame)
     93 {
     94     ASSERT(!frame || frame->page() == m_page);
     95     if (m_focusedFrame == frame || m_isChangingFocusedFrame)
     96         return;
     97 
     98     m_isChangingFocusedFrame = true;
     99 
    100     RefPtr<Frame> oldFrame = m_focusedFrame;
    101     RefPtr<Frame> newFrame = frame;
    102 
    103     m_focusedFrame = newFrame;
    104 
    105     // Now that the frame is updated, fire events and update the selection focused states of both frames.
    106     if (oldFrame && oldFrame->view()) {
    107         oldFrame->selection()->setFocused(false);
    108         oldFrame->document()->dispatchWindowEvent(Event::create(eventNames().blurEvent, false, false));
    109     }
    110 
    111     if (newFrame && newFrame->view() && isFocused()) {
    112         newFrame->selection()->setFocused(true);
    113         newFrame->document()->dispatchWindowEvent(Event::create(eventNames().focusEvent, false, false));
    114     }
    115 
    116     m_page->chrome()->focusedFrameChanged(newFrame.get());
    117 
    118     m_isChangingFocusedFrame = false;
    119 }
    120 
    121 Frame* FocusController::focusedOrMainFrame() const
    122 {
    123     if (Frame* frame = focusedFrame())
    124         return frame;
    125     return m_page->mainFrame();
    126 }
    127 
    128 void FocusController::setFocused(bool focused)
    129 {
    130     if (isFocused() == focused)
    131         return;
    132 
    133     m_isFocused = focused;
    134 
    135     if (!m_isFocused)
    136         focusedOrMainFrame()->eventHandler()->stopAutoscrollTimer();
    137 
    138     if (!m_focusedFrame)
    139         setFocusedFrame(m_page->mainFrame());
    140 
    141     if (m_focusedFrame->view()) {
    142         m_focusedFrame->selection()->setFocused(focused);
    143         dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), focused);
    144     }
    145 }
    146 
    147 static Node* deepFocusableNode(FocusDirection direction, Node* node, KeyboardEvent* event)
    148 {
    149     // The node we found might be a HTMLFrameOwnerElement, so descend down the frame tree until we find either:
    150     // 1) a focusable node, or
    151     // 2) the deepest-nested HTMLFrameOwnerElement
    152     while (node && node->isFrameOwnerElement()) {
    153         HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node);
    154         if (!owner->contentFrame())
    155             break;
    156 
    157         Document* document = owner->contentFrame()->document();
    158 
    159         node = (direction == FocusDirectionForward)
    160             ? document->nextFocusableNode(0, event)
    161             : document->previousFocusableNode(0, event);
    162         if (!node) {
    163             node = owner;
    164             break;
    165         }
    166     }
    167 
    168     return node;
    169 }
    170 
    171 bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* event)
    172 {
    173     bool didAdvanceFocus = advanceFocus(direction, event, true);
    174 
    175     // If focus is being set initially, accessibility needs to be informed that system focus has moved
    176     // into the web area again, even if focus did not change within WebCore. PostNotification is called instead
    177     // of handleFocusedUIElementChanged, because this will send the notification even if the element is the same.
    178     if (AXObjectCache::accessibilityEnabled())
    179         focusedOrMainFrame()->document()->axObjectCache()->postNotification(focusedOrMainFrame()->document()->renderer(), AXObjectCache::AXFocusedUIElementChanged, true);
    180 
    181     return didAdvanceFocus;
    182 }
    183 
    184 bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* event, bool initialFocus)
    185 {
    186     switch (direction) {
    187     case FocusDirectionForward:
    188     case FocusDirectionBackward:
    189         return advanceFocusInDocumentOrder(direction, event, initialFocus);
    190     case FocusDirectionLeft:
    191     case FocusDirectionRight:
    192     case FocusDirectionUp:
    193     case FocusDirectionDown:
    194         return advanceFocusDirectionally(direction, event);
    195     default:
    196         ASSERT_NOT_REACHED();
    197     }
    198 
    199     return false;
    200 }
    201 
    202 bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, KeyboardEvent* event, bool initialFocus)
    203 {
    204     Frame* frame = focusedOrMainFrame();
    205     ASSERT(frame);
    206     Document* document = frame->document();
    207 
    208     Node* currentNode = document->focusedNode();
    209     // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself
    210     bool caretBrowsing = focusedOrMainFrame()->settings()->caretBrowsingEnabled();
    211 
    212     if (caretBrowsing && !currentNode)
    213         currentNode = frame->selection()->start().deprecatedNode();
    214 
    215     document->updateLayoutIgnorePendingStylesheets();
    216 
    217     Node* node = (direction == FocusDirectionForward)
    218         ? document->nextFocusableNode(currentNode, event)
    219         : document->previousFocusableNode(currentNode, event);
    220 
    221     // If there's no focusable node to advance to, move up the frame tree until we find one.
    222     while (!node && frame) {
    223         Frame* parentFrame = frame->tree()->parent();
    224         if (!parentFrame)
    225             break;
    226 
    227         Document* parentDocument = parentFrame->document();
    228 
    229         HTMLFrameOwnerElement* owner = frame->ownerElement();
    230         if (!owner)
    231             break;
    232 
    233         node = (direction == FocusDirectionForward)
    234             ? parentDocument->nextFocusableNode(owner, event)
    235             : parentDocument->previousFocusableNode(owner, event);
    236 
    237         frame = parentFrame;
    238     }
    239 
    240     node = deepFocusableNode(direction, node, event);
    241 
    242     if (!node) {
    243         // We didn't find a node to focus, so we should try to pass focus to Chrome.
    244         if (!initialFocus && m_page->chrome()->canTakeFocus(direction)) {
    245             document->setFocusedNode(0);
    246             setFocusedFrame(0);
    247             m_page->chrome()->takeFocus(direction);
    248             return true;
    249         }
    250 
    251         // Chrome doesn't want focus, so we should wrap focus.
    252         Document* d = m_page->mainFrame()->document();
    253         node = (direction == FocusDirectionForward)
    254             ? d->nextFocusableNode(0, event)
    255             : d->previousFocusableNode(0, event);
    256 
    257         node = deepFocusableNode(direction, node, event);
    258 
    259         if (!node)
    260             return false;
    261     }
    262 
    263     ASSERT(node);
    264 
    265     if (node == document->focusedNode())
    266         // Focus wrapped around to the same node.
    267         return true;
    268 
    269     if (!node->isElementNode())
    270         // FIXME: May need a way to focus a document here.
    271         return false;
    272 
    273     if (node->isFrameOwnerElement()) {
    274         // We focus frames rather than frame owners.
    275         // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user.
    276         HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node);
    277         if (!owner->contentFrame())
    278             return false;
    279 
    280         document->setFocusedNode(0);
    281         setFocusedFrame(owner->contentFrame());
    282         return true;
    283     }
    284 
    285     // FIXME: It would be nice to just be able to call setFocusedNode(node) here, but we can't do
    286     // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in
    287     // their focus() methods.
    288 
    289     Document* newDocument = node->document();
    290 
    291     if (newDocument != document)
    292         // Focus is going away from this document, so clear the focused node.
    293         document->setFocusedNode(0);
    294 
    295     if (newDocument)
    296         setFocusedFrame(newDocument->frame());
    297 
    298     if (caretBrowsing) {
    299         Position position = firstPositionInOrBeforeNode(node);
    300         VisibleSelection newSelection(position, position, DOWNSTREAM);
    301         if (frame->selection()->shouldChangeSelection(newSelection))
    302             frame->selection()->setSelection(newSelection);
    303     }
    304 
    305     static_cast<Element*>(node)->focus(false);
    306     return true;
    307 }
    308 
    309 static bool relinquishesEditingFocus(Node *node)
    310 {
    311     ASSERT(node);
    312     ASSERT(node->rendererIsEditable());
    313 
    314     Node* root = node->rootEditableElement();
    315     Frame* frame = node->document()->frame();
    316     if (!frame || !root)
    317         return false;
    318 
    319     return frame->editor()->shouldEndEditing(rangeOfContents(root).get());
    320 }
    321 
    322 static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode)
    323 {
    324     if (!oldFocusedFrame || !newFocusedFrame)
    325         return;
    326 
    327     if (oldFocusedFrame->document() != newFocusedFrame->document())
    328         return;
    329 
    330     SelectionController* s = oldFocusedFrame->selection();
    331     if (s->isNone())
    332         return;
    333 
    334     bool caretBrowsing = oldFocusedFrame->settings()->caretBrowsingEnabled();
    335     if (caretBrowsing)
    336         return;
    337 
    338     Node* selectionStartNode = s->selection().start().deprecatedNode();
    339     if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode)
    340         return;
    341 
    342     if (Node* mousePressNode = newFocusedFrame->eventHandler()->mousePressNode()) {
    343         if (mousePressNode->renderer() && !mousePressNode->canStartSelection()) {
    344             // Don't clear the selection for contentEditable elements, but do clear it for input and textarea. See bug 38696.
    345             Node * root = s->rootEditableElement();
    346             if (!root)
    347                 return;
    348 
    349             if (Node* shadowAncestorNode = root->shadowAncestorNode()) {
    350                 if (!shadowAncestorNode->hasTagName(inputTag) && !shadowAncestorNode->hasTagName(textareaTag))
    351                     return;
    352             }
    353         }
    354     }
    355 
    356     s->clear();
    357 }
    358 
    359 bool FocusController::setFocusedNode(Node* node, PassRefPtr<Frame> newFocusedFrame)
    360 {
    361     RefPtr<Frame> oldFocusedFrame = focusedFrame();
    362     RefPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0;
    363 
    364     Node* oldFocusedNode = oldDocument ? oldDocument->focusedNode() : 0;
    365     if (oldFocusedNode == node)
    366         return true;
    367 
    368     // FIXME: Might want to disable this check for caretBrowsing
    369     if (oldFocusedNode && oldFocusedNode->rootEditableElement() == oldFocusedNode && !relinquishesEditingFocus(oldFocusedNode))
    370         return false;
    371 
    372     m_page->editorClient()->willSetInputMethodState();
    373 
    374     clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), node);
    375 
    376     if (!node) {
    377         if (oldDocument)
    378             oldDocument->setFocusedNode(0);
    379         m_page->editorClient()->setInputMethodState(false);
    380         return true;
    381     }
    382 
    383     RefPtr<Document> newDocument = node->document();
    384 
    385     if (newDocument && newDocument->focusedNode() == node) {
    386         m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod());
    387         return true;
    388     }
    389 
    390     if (oldDocument && oldDocument != newDocument)
    391         oldDocument->setFocusedNode(0);
    392 
    393     setFocusedFrame(newFocusedFrame);
    394 
    395     // Setting the focused node can result in losing our last reft to node when JS event handlers fire.
    396     RefPtr<Node> protect = node;
    397     if (newDocument) {
    398         bool successfullyFocused = newDocument->setFocusedNode(node);
    399         if (!successfullyFocused)
    400             return false;
    401     }
    402 
    403     if (newDocument->focusedNode() == node)
    404         m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod());
    405 
    406     return true;
    407 }
    408 
    409 void FocusController::setActive(bool active)
    410 {
    411     if (m_isActive == active)
    412         return;
    413 
    414     m_isActive = active;
    415 
    416     if (FrameView* view = m_page->mainFrame()->view()) {
    417         if (!view->platformWidget()) {
    418             view->updateLayoutAndStyleIfNeededRecursive();
    419             view->updateControlTints();
    420         }
    421 
    422         if (const HashSet<ScrollableArea*>* scrollableAreas = m_page->scrollableAreaSet()) {
    423             HashSet<ScrollableArea*>::const_iterator end = scrollableAreas->end();
    424             for (HashSet<ScrollableArea*>::const_iterator it = scrollableAreas->begin(); it != end; ++it) {
    425                 if (!active)
    426                     (*it)->scrollAnimator()->contentAreaDidHide();
    427                 else
    428                     (*it)->scrollAnimator()->contentAreaDidShow();
    429             }
    430         }
    431     }
    432 
    433     focusedOrMainFrame()->selection()->pageActivationChanged();
    434 
    435     if (m_focusedFrame && isFocused())
    436         dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), active);
    437 }
    438 
    439 static void updateFocusCandidateIfNeeded(FocusDirection direction, const FocusCandidate& current, FocusCandidate& candidate, FocusCandidate& closest)
    440 {
    441     ASSERT(candidate.visibleNode->isElementNode());
    442     ASSERT(candidate.visibleNode->renderer());
    443 
    444     // Ignore iframes that don't have a src attribute
    445     if (frameOwnerElement(candidate) && (!frameOwnerElement(candidate)->contentFrame() || candidate.rect.isEmpty()))
    446         return;
    447 
    448     // Ignore off screen child nodes of containers that do not scroll (overflow:hidden)
    449     if (candidate.isOffscreen && !canBeScrolledIntoView(direction, candidate))
    450         return;
    451 
    452     distanceDataForNode(direction, current, candidate);
    453     if (candidate.distance == maxDistance())
    454         return;
    455 
    456     if (candidate.isOffscreenAfterScrolling && candidate.alignment < Full)
    457         return;
    458 
    459     if (closest.isNull()) {
    460         closest = candidate;
    461         return;
    462     }
    463 
    464     IntRect intersectionRect = intersection(candidate.rect, closest.rect);
    465     if (!intersectionRect.isEmpty() && !areElementsOnSameLine(closest, candidate)) {
    466         // If 2 nodes are intersecting, do hit test to find which node in on top.
    467         int x = intersectionRect.x() + intersectionRect.width() / 2;
    468         int y = intersectionRect.y() + intersectionRect.height() / 2;
    469         HitTestResult result = candidate.visibleNode->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, true);
    470         if (candidate.visibleNode->contains(result.innerNode())) {
    471             closest = candidate;
    472             return;
    473         }
    474         if (closest.visibleNode->contains(result.innerNode()))
    475             return;
    476     }
    477 
    478     if (candidate.alignment == closest.alignment) {
    479         if (candidate.distance < closest.distance)
    480             closest = candidate;
    481         return;
    482     }
    483 
    484     if (candidate.alignment > closest.alignment)
    485         closest = candidate;
    486 }
    487 
    488 void FocusController::findFocusCandidateInContainer(Node* container, const IntRect& startingRect, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closest)
    489 {
    490     ASSERT(container);
    491     Node* focusedNode = (focusedFrame() && focusedFrame()->document()) ? focusedFrame()->document()->focusedNode() : 0;
    492 
    493     Node* node = container->firstChild();
    494     FocusCandidate current;
    495     current.rect = startingRect;
    496     current.focusableNode = focusedNode;
    497     current.visibleNode = focusedNode;
    498 
    499     for (; node; node = (node->isFrameOwnerElement() || canScrollInDirection(node, direction)) ? node->traverseNextSibling(container) : node->traverseNextNode(container)) {
    500         if (node == focusedNode)
    501             continue;
    502 
    503         if (!node->isElementNode())
    504             continue;
    505 
    506         if (!node->isKeyboardFocusable(event) && !node->isFrameOwnerElement() && !canScrollInDirection(node, direction))
    507             continue;
    508 
    509         FocusCandidate candidate = FocusCandidate(node, direction);
    510         if (candidate.isNull())
    511             continue;
    512 
    513         candidate.enclosingScrollableBox = container;
    514         updateFocusCandidateIfNeeded(direction, current, candidate, closest);
    515     }
    516 }
    517 
    518 bool FocusController::advanceFocusDirectionallyInContainer(Node* container, const IntRect& startingRect, FocusDirection direction, KeyboardEvent* event)
    519 {
    520     if (!container || !container->document())
    521         return false;
    522 
    523     IntRect newStartingRect = startingRect;
    524 
    525     if (startingRect.isEmpty())
    526         newStartingRect = virtualRectForDirection(direction, nodeRectInAbsoluteCoordinates(container));
    527 
    528     // Find the closest node within current container in the direction of the navigation.
    529     FocusCandidate focusCandidate;
    530     findFocusCandidateInContainer(container, newStartingRect, direction, event, focusCandidate);
    531 
    532     if (focusCandidate.isNull()) {
    533         // Nothing to focus, scroll if possible.
    534         // NOTE: If no scrolling is performed (i.e. scrollInDirection returns false), the
    535         // spatial navigation algorithm will skip this container.
    536         return scrollInDirection(container, direction);
    537     }
    538 
    539     if (HTMLFrameOwnerElement* frameElement = frameOwnerElement(focusCandidate)) {
    540         // If we have an iframe without the src attribute, it will not have a contentFrame().
    541         // We ASSERT here to make sure that
    542         // updateFocusCandidateIfNeeded() will never consider such an iframe as a candidate.
    543         ASSERT(frameElement->contentFrame());
    544 
    545         if (focusCandidate.isOffscreenAfterScrolling) {
    546             scrollInDirection(focusCandidate.visibleNode->document(), direction);
    547             return true;
    548         }
    549         // Navigate into a new frame.
    550         IntRect rect;
    551         Node* focusedNode = focusedOrMainFrame()->document()->focusedNode();
    552         if (focusedNode && !hasOffscreenRect(focusedNode))
    553             rect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */);
    554         frameElement->contentFrame()->document()->updateLayoutIgnorePendingStylesheets();
    555         if (!advanceFocusDirectionallyInContainer(frameElement->contentFrame()->document(), rect, direction, event)) {
    556             // The new frame had nothing interesting, need to find another candidate.
    557             return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.visibleNode, true), direction, event);
    558         }
    559         return true;
    560     }
    561 
    562     if (canScrollInDirection(focusCandidate.visibleNode, direction)) {
    563         if (focusCandidate.isOffscreenAfterScrolling) {
    564             scrollInDirection(focusCandidate.visibleNode, direction);
    565             return true;
    566         }
    567         // Navigate into a new scrollable container.
    568         IntRect startingRect;
    569         Node* focusedNode = focusedOrMainFrame()->document()->focusedNode();
    570         if (focusedNode && !hasOffscreenRect(focusedNode))
    571             startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true);
    572         return advanceFocusDirectionallyInContainer(focusCandidate.visibleNode, startingRect, direction, event);
    573     }
    574     if (focusCandidate.isOffscreenAfterScrolling) {
    575         Node* container = focusCandidate.enclosingScrollableBox;
    576         scrollInDirection(container, direction);
    577         return true;
    578     }
    579 
    580     // We found a new focus node, navigate to it.
    581     Element* element = toElement(focusCandidate.focusableNode);
    582     ASSERT(element);
    583 
    584     element->focus(false);
    585     return true;
    586 }
    587 
    588 bool FocusController::advanceFocusDirectionally(FocusDirection direction, KeyboardEvent* event)
    589 {
    590     Frame* curFrame = focusedOrMainFrame();
    591     ASSERT(curFrame);
    592 
    593     Document* focusedDocument = curFrame->document();
    594     if (!focusedDocument)
    595         return false;
    596 
    597     Node* focusedNode = focusedDocument->focusedNode();
    598     Node* container = focusedDocument;
    599 
    600     if (container->isDocumentNode())
    601         static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets();
    602 
    603     // Figure out the starting rect.
    604     IntRect startingRect;
    605     if (focusedNode) {
    606         if (!hasOffscreenRect(focusedNode)) {
    607             container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedNode);
    608             startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */);
    609         } else if (focusedNode->hasTagName(areaTag)) {
    610             HTMLAreaElement* area = static_cast<HTMLAreaElement*>(focusedNode);
    611             container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, area->imageElement());
    612             startingRect = virtualRectForAreaElementAndDirection(area, direction);
    613         }
    614     }
    615 
    616     bool consumed = false;
    617     do {
    618         consumed = advanceFocusDirectionallyInContainer(container, startingRect, direction, event);
    619         startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */);
    620         container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, container);
    621         if (container && container->isDocumentNode())
    622             static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets();
    623     } while (!consumed && container);
    624 
    625     return consumed;
    626 }
    627 
    628 } // namespace WebCore
    629