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 
dispatchEventsOnWindowAndFocusedNode(Document * document,bool focused)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 
FocusController(Page * page)84 FocusController::FocusController(Page* page)
85     : m_page(page)
86     , m_isActive(false)
87     , m_isFocused(false)
88     , m_isChangingFocusedFrame(false)
89 {
90 }
91 
setFocusedFrame(PassRefPtr<Frame> frame)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 
focusedOrMainFrame() const121 Frame* FocusController::focusedOrMainFrame() const
122 {
123     if (Frame* frame = focusedFrame())
124         return frame;
125     return m_page->mainFrame();
126 }
127 
setFocused(bool focused)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 
deepFocusableNode(FocusDirection direction,Node * node,KeyboardEvent * event)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 
setInitialFocus(FocusDirection direction,KeyboardEvent * event)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 
advanceFocus(FocusDirection direction,KeyboardEvent * event,bool initialFocus)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 
advanceFocusInDocumentOrder(FocusDirection direction,KeyboardEvent * event,bool initialFocus)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     RefPtr<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.get(), 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.get(), 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.get());
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.get());
300         VisibleSelection newSelection(position, position, DOWNSTREAM);
301         if (frame->selection()->shouldChangeSelection(newSelection))
302             frame->selection()->setSelection(newSelection);
303     }
304 
305     static_cast<Element*>(node.get())->focus(false);
306     return true;
307 }
308 
relinquishesEditingFocus(Node * node)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 
clearSelectionIfNeeded(Frame * oldFocusedFrame,Frame * newFocusedFrame,Node * newFocusedNode)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 
setFocusedNode(Node * node,PassRefPtr<Frame> newFocusedFrame)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 
setActive(bool active)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 
updateFocusCandidateIfNeeded(FocusDirection direction,const FocusCandidate & current,FocusCandidate & candidate,FocusCandidate & closest)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 
findFocusCandidateInContainer(Node * container,const IntRect & startingRect,FocusDirection direction,KeyboardEvent * event,FocusCandidate & closest)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 
advanceFocusDirectionallyInContainer(Node * container,const IntRect & startingRect,FocusDirection direction,KeyboardEvent * event)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 
advanceFocusDirectionally(FocusDirection direction,KeyboardEvent * event)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