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 "core/page/FocusController.h"
     29 
     30 #include "core/HTMLNames.h"
     31 #include "core/accessibility/AXObjectCache.h"
     32 #include "core/dom/Document.h"
     33 #include "core/dom/Element.h"
     34 #include "core/dom/ElementTraversal.h"
     35 #include "core/dom/NodeTraversal.h"
     36 #include "core/dom/Range.h"
     37 #include "core/dom/shadow/ElementShadow.h"
     38 #include "core/dom/shadow/ShadowRoot.h"
     39 #include "core/editing/Editor.h"
     40 #include "core/editing/FrameSelection.h"
     41 #include "core/editing/htmlediting.h" // For firstPositionInOrBeforeNode
     42 #include "core/events/Event.h"
     43 #include "core/frame/LocalDOMWindow.h"
     44 #include "core/frame/FrameView.h"
     45 #include "core/frame/LocalFrame.h"
     46 #include "core/html/HTMLAreaElement.h"
     47 #include "core/html/HTMLImageElement.h"
     48 #include "core/html/HTMLPlugInElement.h"
     49 #include "core/html/HTMLShadowElement.h"
     50 #include "core/html/HTMLTextFormControlElement.h"
     51 #include "core/page/Chrome.h"
     52 #include "core/page/ChromeClient.h"
     53 #include "core/page/EventHandler.h"
     54 #include "core/page/FrameTree.h"
     55 #include "core/page/Page.h"
     56 #include "core/frame/Settings.h"
     57 #include "core/page/SpatialNavigation.h"
     58 #include "core/rendering/HitTestResult.h"
     59 #include "core/rendering/RenderLayer.h"
     60 #include <limits>
     61 
     62 namespace WebCore {
     63 
     64 using namespace HTMLNames;
     65 
     66 static inline bool isShadowInsertionPointFocusScopeOwner(Node& node)
     67 {
     68     return isActiveShadowInsertionPoint(node) && toHTMLShadowElement(node).olderShadowRoot();
     69 }
     70 
     71 // FIXME: Some of Node* return values and Node* arguments should be Element*.
     72 
     73 FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope)
     74     : m_rootTreeScope(treeScope)
     75 {
     76     ASSERT(treeScope);
     77 }
     78 
     79 Node* FocusNavigationScope::rootNode() const
     80 {
     81     return &m_rootTreeScope->rootNode();
     82 }
     83 
     84 Element* FocusNavigationScope::owner() const
     85 {
     86     Node* root = rootNode();
     87     if (root->isShadowRoot()) {
     88         ShadowRoot* shadowRoot = toShadowRoot(root);
     89         return shadowRoot->isYoungest() ? shadowRoot->host() : shadowRoot->shadowInsertionPointOfYoungerShadowRoot();
     90     }
     91     // FIXME: Figure out the right thing for OOPI here.
     92     if (Frame* frame = root->document().frame())
     93         return frame->deprecatedLocalOwner();
     94     return 0;
     95 }
     96 
     97 FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(Node* node)
     98 {
     99     ASSERT(node);
    100     Node* root = node;
    101     for (Node* n = node; n; n = n->parentNode())
    102         root = n;
    103     // The result is not always a ShadowRoot nor a DocumentNode since
    104     // a starting node is in an orphaned tree in composed shadow tree.
    105     return FocusNavigationScope(&root->treeScope());
    106 }
    107 
    108 FocusNavigationScope FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(Node* node)
    109 {
    110     ASSERT(node);
    111     if (isShadowHost(node))
    112         return FocusNavigationScope::ownedByShadowHost(node);
    113     ASSERT(isShadowInsertionPointFocusScopeOwner(*node));
    114     return FocusNavigationScope::ownedByShadowInsertionPoint(toHTMLShadowElement(node));
    115 }
    116 
    117 FocusNavigationScope FocusNavigationScope::ownedByShadowHost(Node* node)
    118 {
    119     ASSERT(isShadowHost(node));
    120     return FocusNavigationScope(toElement(node)->shadow()->youngestShadowRoot());
    121 }
    122 
    123 FocusNavigationScope FocusNavigationScope::ownedByIFrame(HTMLFrameOwnerElement* frame)
    124 {
    125     ASSERT(frame && frame->contentFrame() && frame->contentFrame()->isLocalFrame());
    126     return FocusNavigationScope(toLocalFrame(frame->contentFrame())->document());
    127 }
    128 
    129 FocusNavigationScope FocusNavigationScope::ownedByShadowInsertionPoint(HTMLShadowElement* shadowInsertionPoint)
    130 {
    131     ASSERT(isShadowInsertionPointFocusScopeOwner(*shadowInsertionPoint));
    132     return FocusNavigationScope(shadowInsertionPoint->olderShadowRoot());
    133 }
    134 
    135 static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused)
    136 {
    137     // If we have a focused node we should dispatch blur on it before we blur the window.
    138     // If we have a focused node we should dispatch focus on it after we focus the window.
    139     // https://bugs.webkit.org/show_bug.cgi?id=27105
    140 
    141     // Do not fire events while modal dialogs are up.  See https://bugs.webkit.org/show_bug.cgi?id=33962
    142     if (Page* page = document->page()) {
    143         if (page->defersLoading())
    144             return;
    145     }
    146 
    147     if (!focused && document->focusedElement()) {
    148         RefPtrWillBeRawPtr<Element> focusedElement(document->focusedElement());
    149         focusedElement->setFocus(false);
    150         focusedElement->dispatchBlurEvent(0);
    151         if (focusedElement == document->focusedElement()) {
    152             focusedElement->dispatchFocusOutEvent(EventTypeNames::focusout, 0);
    153             if (focusedElement == document->focusedElement())
    154                 focusedElement->dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, 0);
    155         }
    156     }
    157 
    158     if (LocalDOMWindow* window = document->domWindow())
    159         window->dispatchEvent(Event::create(focused ? EventTypeNames::focus : EventTypeNames::blur));
    160     if (focused && document->focusedElement()) {
    161         RefPtrWillBeRawPtr<Element> focusedElement(document->focusedElement());
    162         focusedElement->setFocus(true);
    163         focusedElement->dispatchFocusEvent(0, FocusTypePage);
    164         if (focusedElement == document->focusedElement()) {
    165             document->focusedElement()->dispatchFocusInEvent(EventTypeNames::focusin, 0);
    166             if (focusedElement == document->focusedElement())
    167                 document->focusedElement()->dispatchFocusInEvent(EventTypeNames::DOMFocusIn, 0);
    168         }
    169     }
    170 }
    171 
    172 static inline bool hasCustomFocusLogic(Element* element)
    173 {
    174     return element->isHTMLElement() && toHTMLElement(element)->hasCustomFocusLogic();
    175 }
    176 
    177 #if ASSERT_ENABLED
    178 static inline bool isNonFocusableShadowHost(Node* node)
    179 {
    180     ASSERT(node);
    181     if (!node->isElementNode())
    182         return false;
    183     Element* element = toElement(node);
    184     return !element->isFocusable() && isShadowHost(element) && !hasCustomFocusLogic(element);
    185 }
    186 #endif
    187 
    188 static inline bool isNonKeyboardFocusableShadowHost(Node* node)
    189 {
    190     ASSERT(node);
    191     if (!node->isElementNode())
    192         return false;
    193     Element* element = toElement(node);
    194     return !element->isKeyboardFocusable() && isShadowHost(element) && !hasCustomFocusLogic(element);
    195 }
    196 
    197 static inline bool isKeyboardFocusableShadowHost(Node* node)
    198 {
    199     ASSERT(node);
    200     if (!node->isElementNode())
    201         return false;
    202     Element* element = toElement(node);
    203     return element->isKeyboardFocusable() && isShadowHost(element) && !hasCustomFocusLogic(element);
    204 }
    205 
    206 static inline bool isNonFocusableFocusScopeOwner(Node* node)
    207 {
    208     ASSERT(node);
    209     return isNonKeyboardFocusableShadowHost(node) || isShadowInsertionPointFocusScopeOwner(*node);
    210 }
    211 
    212 static inline int adjustedTabIndex(Node* node)
    213 {
    214     ASSERT(node);
    215     return isNonFocusableFocusScopeOwner(node) ? 0 : node->tabIndex();
    216 }
    217 
    218 static inline bool shouldVisit(Node* node)
    219 {
    220     ASSERT(node);
    221     return (node->isElementNode() && toElement(node)->isKeyboardFocusable()) || isNonFocusableFocusScopeOwner(node);
    222 }
    223 
    224 FocusController::FocusController(Page* page)
    225     : m_page(page)
    226     , m_isActive(false)
    227     , m_isFocused(false)
    228     , m_isChangingFocusedFrame(false)
    229 {
    230 }
    231 
    232 PassOwnPtr<FocusController> FocusController::create(Page* page)
    233 {
    234     return adoptPtr(new FocusController(page));
    235 }
    236 
    237 void FocusController::setFocusedFrame(PassRefPtr<Frame> frame)
    238 {
    239     ASSERT(!frame || frame->page() == m_page);
    240     if (m_focusedFrame == frame || m_isChangingFocusedFrame)
    241         return;
    242 
    243     m_isChangingFocusedFrame = true;
    244 
    245     RefPtr<LocalFrame> oldFrame = (m_focusedFrame && m_focusedFrame->isLocalFrame()) ? toLocalFrame(m_focusedFrame.get()) : 0;
    246     RefPtr<LocalFrame> newFrame = (frame && frame->isLocalFrame()) ? toLocalFrame(frame.get()) : 0;
    247 
    248     m_focusedFrame = frame.get();
    249 
    250     // Now that the frame is updated, fire events and update the selection focused states of both frames.
    251     if (oldFrame && oldFrame->view()) {
    252         oldFrame->selection().setFocused(false);
    253         oldFrame->domWindow()->dispatchEvent(Event::create(EventTypeNames::blur));
    254     }
    255 
    256     if (newFrame && newFrame->view() && isFocused()) {
    257         newFrame->selection().setFocused(true);
    258         newFrame->domWindow()->dispatchEvent(Event::create(EventTypeNames::focus));
    259     }
    260 
    261     m_isChangingFocusedFrame = false;
    262 
    263     m_page->chrome().client().focusedFrameChanged(newFrame.get());
    264 }
    265 
    266 void FocusController::focusDocumentView(PassRefPtr<Frame> frame)
    267 {
    268     ASSERT(!frame || frame->page() == m_page);
    269     if (m_focusedFrame == frame)
    270         return;
    271 
    272     RefPtr<LocalFrame> focusedFrame = (m_focusedFrame && m_focusedFrame->isLocalFrame()) ? toLocalFrame(m_focusedFrame.get()) : 0;
    273     if (focusedFrame && focusedFrame->view()) {
    274         RefPtrWillBeRawPtr<Document> document = focusedFrame->document();
    275         Element* focusedElement = document ? document->focusedElement() : 0;
    276         if (focusedElement) {
    277             focusedElement->dispatchBlurEvent(0);
    278             if (focusedElement == document->focusedElement()) {
    279                 focusedElement->dispatchFocusOutEvent(EventTypeNames::focusout, 0);
    280                 if (focusedElement == document->focusedElement())
    281                     focusedElement->dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, 0);
    282             }
    283         }
    284     }
    285 
    286     RefPtr<LocalFrame> newFocusedFrame = (frame && frame->isLocalFrame()) ? toLocalFrame(frame.get()) : 0;
    287     if (newFocusedFrame && newFocusedFrame->view()) {
    288         RefPtrWillBeRawPtr<Document> document = newFocusedFrame->document();
    289         Element* focusedElement = document ? document->focusedElement() : 0;
    290         if (focusedElement) {
    291             focusedElement->dispatchFocusEvent(0, FocusTypePage);
    292             if (focusedElement == document->focusedElement()) {
    293                 document->focusedElement()->dispatchFocusInEvent(EventTypeNames::focusin, 0);
    294                 if (focusedElement == document->focusedElement())
    295                     document->focusedElement()->dispatchFocusInEvent(EventTypeNames::DOMFocusIn, 0);
    296             }
    297         }
    298     }
    299 
    300     setFocusedFrame(frame);
    301 }
    302 
    303 Frame* FocusController::focusedOrMainFrame() const
    304 {
    305     if (Frame* frame = focusedFrame())
    306         return frame;
    307     return m_page->mainFrame();
    308 }
    309 
    310 void FocusController::setFocused(bool focused)
    311 {
    312     if (isFocused() == focused)
    313         return;
    314 
    315     m_isFocused = focused;
    316 
    317     if (!m_isFocused && focusedOrMainFrame()->isLocalFrame())
    318         toLocalFrame(focusedOrMainFrame())->eventHandler().stopAutoscroll();
    319 
    320     if (!m_focusedFrame)
    321         setFocusedFrame(m_page->mainFrame());
    322 
    323     // setFocusedFrame above might reject to update m_focusedFrame, or
    324     // m_focusedFrame might be changed by blur/focus event handlers.
    325     if (m_focusedFrame && m_focusedFrame->isLocalFrame() && toLocalFrame(m_focusedFrame.get())->view()) {
    326         toLocalFrame(m_focusedFrame.get())->selection().setFocused(focused);
    327         dispatchEventsOnWindowAndFocusedNode(toLocalFrame(m_focusedFrame.get())->document(), focused);
    328     }
    329 }
    330 
    331 Node* FocusController::findFocusableNodeDecendingDownIntoFrameDocument(FocusType type, Node* node)
    332 {
    333     // The node we found might be a HTMLFrameOwnerElement, so descend down the tree until we find either:
    334     // 1) a focusable node, or
    335     // 2) the deepest-nested HTMLFrameOwnerElement.
    336     while (node && node->isFrameOwnerElement()) {
    337         HTMLFrameOwnerElement* owner = toHTMLFrameOwnerElement(node);
    338         if (!owner->contentFrame() || !owner->contentFrame()->isLocalFrame())
    339             break;
    340         Node* foundNode = findFocusableNode(type, FocusNavigationScope::ownedByIFrame(owner), 0);
    341         if (!foundNode)
    342             break;
    343         ASSERT(node != foundNode);
    344         node = foundNode;
    345     }
    346     return node;
    347 }
    348 
    349 bool FocusController::setInitialFocus(FocusType type)
    350 {
    351     bool didAdvanceFocus = advanceFocus(type, true);
    352 
    353     // If focus is being set initially, accessibility needs to be informed that system focus has moved
    354     // into the web area again, even if focus did not change within WebCore. PostNotification is called instead
    355     // of handleFocusedUIElementChanged, because this will send the notification even if the element is the same.
    356     if (focusedOrMainFrame()->isLocalFrame()) {
    357         Document* document = toLocalFrame(focusedOrMainFrame())->document();
    358         if (AXObjectCache* cache = document->existingAXObjectCache())
    359             cache->postNotification(document, AXObjectCache::AXFocusedUIElementChanged, true);
    360     }
    361 
    362     return didAdvanceFocus;
    363 }
    364 
    365 bool FocusController::advanceFocus(FocusType type, bool initialFocus)
    366 {
    367     switch (type) {
    368     case FocusTypeForward:
    369     case FocusTypeBackward:
    370         return advanceFocusInDocumentOrder(type, initialFocus);
    371     case FocusTypeLeft:
    372     case FocusTypeRight:
    373     case FocusTypeUp:
    374     case FocusTypeDown:
    375         return advanceFocusDirectionally(type);
    376     default:
    377         ASSERT_NOT_REACHED();
    378     }
    379 
    380     return false;
    381 }
    382 
    383 bool FocusController::advanceFocusInDocumentOrder(FocusType type, bool initialFocus)
    384 {
    385     // FIXME: Focus advancement won't work with externally rendered frames until after
    386     // inter-frame focus control is moved out of Blink.
    387     if (!focusedOrMainFrame()->isLocalFrame())
    388         return false;
    389     LocalFrame* frame = toLocalFrame(focusedOrMainFrame());
    390     ASSERT(frame);
    391     Document* document = frame->document();
    392 
    393     Node* currentNode = document->focusedElement();
    394     // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself
    395     bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEnabled();
    396 
    397     if (caretBrowsing && !currentNode)
    398         currentNode = frame->selection().start().deprecatedNode();
    399 
    400     document->updateLayoutIgnorePendingStylesheets();
    401 
    402     RefPtrWillBeRawPtr<Node> node = findFocusableNodeAcrossFocusScope(type, FocusNavigationScope::focusNavigationScopeOf(currentNode ? currentNode : document), currentNode);
    403 
    404     if (!node) {
    405         // We didn't find a node to focus, so we should try to pass focus to Chrome.
    406         if (!initialFocus && m_page->chrome().canTakeFocus(type)) {
    407             document->setFocusedElement(nullptr);
    408             setFocusedFrame(nullptr);
    409             m_page->chrome().takeFocus(type);
    410             return true;
    411         }
    412 
    413         // Chrome doesn't want focus, so we should wrap focus.
    414         if (!m_page->mainFrame()->isLocalFrame())
    415             return false;
    416         node = findFocusableNodeRecursively(type, FocusNavigationScope::focusNavigationScopeOf(m_page->deprecatedLocalMainFrame()->document()), 0);
    417         node = findFocusableNodeDecendingDownIntoFrameDocument(type, node.get());
    418 
    419         if (!node)
    420             return false;
    421     }
    422 
    423     ASSERT(node);
    424 
    425     if (node == document->focusedElement())
    426         // Focus wrapped around to the same node.
    427         return true;
    428 
    429     if (!node->isElementNode())
    430         // FIXME: May need a way to focus a document here.
    431         return false;
    432 
    433     Element* element = toElement(node);
    434     if (element->isFrameOwnerElement() && (!isHTMLPlugInElement(*element) || !element->isKeyboardFocusable())) {
    435         // We focus frames rather than frame owners.
    436         // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user.
    437         HTMLFrameOwnerElement* owner = toHTMLFrameOwnerElement(element);
    438         if (!owner->contentFrame())
    439             return false;
    440 
    441         document->setFocusedElement(nullptr);
    442         setFocusedFrame(owner->contentFrame());
    443         return true;
    444     }
    445 
    446     // FIXME: It would be nice to just be able to call setFocusedElement(node)
    447     // here, but we can't do that because some elements (e.g. HTMLInputElement
    448     // and HTMLTextAreaElement) do extra work in their focus() methods.
    449     Document& newDocument = element->document();
    450 
    451     if (&newDocument != document) {
    452         // Focus is going away from this document, so clear the focused node.
    453         document->setFocusedElement(nullptr);
    454     }
    455 
    456     setFocusedFrame(newDocument.frame());
    457 
    458     if (caretBrowsing) {
    459         Position position = firstPositionInOrBeforeNode(element);
    460         VisibleSelection newSelection(position, position, DOWNSTREAM);
    461         frame->selection().setSelection(newSelection);
    462     }
    463 
    464     element->focus(false, type);
    465     return true;
    466 }
    467 
    468 Node* FocusController::findFocusableNodeAcrossFocusScope(FocusType type, FocusNavigationScope scope, Node* currentNode)
    469 {
    470     ASSERT(!currentNode || !isNonFocusableShadowHost(currentNode));
    471     Node* found;
    472     if (currentNode && type == FocusTypeForward && isKeyboardFocusableShadowHost(currentNode)) {
    473         Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByShadowHost(currentNode), 0);
    474         found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableNodeRecursively(type, scope, currentNode);
    475     } else {
    476         found = findFocusableNodeRecursively(type, scope, currentNode);
    477     }
    478 
    479     // If there's no focusable node to advance to, move up the focus scopes until we find one.
    480     while (!found) {
    481         Node* owner = scope.owner();
    482         if (!owner)
    483             break;
    484         scope = FocusNavigationScope::focusNavigationScopeOf(owner);
    485         if (type == FocusTypeBackward && isKeyboardFocusableShadowHost(owner)) {
    486             found = owner;
    487             break;
    488         }
    489         found = findFocusableNodeRecursively(type, scope, owner);
    490     }
    491     found = findFocusableNodeDecendingDownIntoFrameDocument(type, found);
    492     return found;
    493 }
    494 
    495 Node* FocusController::findFocusableNodeRecursively(FocusType type, FocusNavigationScope scope, Node* start)
    496 {
    497     // Starting node is exclusive.
    498     Node* found = findFocusableNode(type, scope, start);
    499     if (!found)
    500         return 0;
    501     if (type == FocusTypeForward) {
    502         if (!isNonFocusableFocusScopeOwner(found))
    503             return found;
    504         Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(found), 0);
    505         return foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableNodeRecursively(type, scope, found);
    506     }
    507     ASSERT(type == FocusTypeBackward);
    508     if (isKeyboardFocusableShadowHost(found)) {
    509         Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByShadowHost(found), 0);
    510         return foundInInnerFocusScope ? foundInInnerFocusScope : found;
    511     }
    512     if (isNonFocusableFocusScopeOwner(found)) {
    513         Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(found), 0);
    514         return foundInInnerFocusScope ? foundInInnerFocusScope :findFocusableNodeRecursively(type, scope, found);
    515     }
    516     return found;
    517 }
    518 
    519 Node* FocusController::findFocusableNode(FocusType type, FocusNavigationScope scope, Node* node)
    520 {
    521     return type == FocusTypeForward ? nextFocusableNode(scope, node) : previousFocusableNode(scope, node);
    522 }
    523 
    524 Node* FocusController::findNodeWithExactTabIndex(Node* start, int tabIndex, FocusType type)
    525 {
    526     // Search is inclusive of start
    527     for (Node* node = start; node; node = type == FocusTypeForward ? NodeTraversal::next(*node) : NodeTraversal::previous(*node)) {
    528         if (shouldVisit(node) && adjustedTabIndex(node) == tabIndex)
    529             return node;
    530     }
    531     return 0;
    532 }
    533 
    534 static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex)
    535 {
    536     // Search is inclusive of start
    537     int winningTabIndex = std::numeric_limits<short>::max() + 1;
    538     Node* winner = 0;
    539     for (Node* node = start; node; node = NodeTraversal::next(*node)) {
    540         if (shouldVisit(node) && node->tabIndex() > tabIndex && node->tabIndex() < winningTabIndex) {
    541             winner = node;
    542             winningTabIndex = node->tabIndex();
    543         }
    544     }
    545 
    546     return winner;
    547 }
    548 
    549 static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex)
    550 {
    551     // Search is inclusive of start
    552     int winningTabIndex = 0;
    553     Node* winner = 0;
    554     for (Node* node = start; node; node = NodeTraversal::previous(*node)) {
    555         int currentTabIndex = adjustedTabIndex(node);
    556         if ((shouldVisit(node) || isNonKeyboardFocusableShadowHost(node)) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) {
    557             winner = node;
    558             winningTabIndex = currentTabIndex;
    559         }
    560     }
    561     return winner;
    562 }
    563 
    564 Node* FocusController::nextFocusableNode(FocusNavigationScope scope, Node* start)
    565 {
    566     if (start) {
    567         int tabIndex = adjustedTabIndex(start);
    568         // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order
    569         if (tabIndex < 0) {
    570             for (Node* node = NodeTraversal::next(*start); node; node = NodeTraversal::next(*node)) {
    571                 if (shouldVisit(node) && adjustedTabIndex(node) >= 0)
    572                     return node;
    573             }
    574         }
    575 
    576         // First try to find a node with the same tabindex as start that comes after start in the scope.
    577         if (Node* winner = findNodeWithExactTabIndex(NodeTraversal::next(*start), tabIndex, FocusTypeForward))
    578             return winner;
    579 
    580         if (!tabIndex)
    581             // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order.
    582             return 0;
    583     }
    584 
    585     // Look for the first node in the scope that:
    586     // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and
    587     // 2) comes first in the scope, if there's a tie.
    588     if (Node* winner = nextNodeWithGreaterTabIndex(scope.rootNode(), start ? adjustedTabIndex(start) : 0))
    589         return winner;
    590 
    591     // There are no nodes with a tabindex greater than start's tabindex,
    592     // so find the first node with a tabindex of 0.
    593     return findNodeWithExactTabIndex(scope.rootNode(), 0, FocusTypeForward);
    594 }
    595 
    596 Node* FocusController::previousFocusableNode(FocusNavigationScope scope, Node* start)
    597 {
    598     Node* last = 0;
    599     for (Node* node = scope.rootNode(); node; node = node->lastChild())
    600         last = node;
    601     ASSERT(last);
    602 
    603     // First try to find the last node in the scope that comes before start and has the same tabindex as start.
    604     // If start is null, find the last node in the scope with a tabindex of 0.
    605     Node* startingNode;
    606     int startingTabIndex;
    607     if (start) {
    608         startingNode = NodeTraversal::previous(*start);
    609         startingTabIndex = adjustedTabIndex(start);
    610     } else {
    611         startingNode = last;
    612         startingTabIndex = 0;
    613     }
    614 
    615     // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order
    616     if (startingTabIndex < 0) {
    617         for (Node* node = startingNode; node; node = NodeTraversal::previous(*node)) {
    618             if (shouldVisit(node) && adjustedTabIndex(node) >= 0)
    619                 return node;
    620         }
    621     }
    622 
    623     if (Node* winner = findNodeWithExactTabIndex(startingNode, startingTabIndex, FocusTypeBackward))
    624         return winner;
    625 
    626     // There are no nodes before start with the same tabindex as start, so look for a node that:
    627     // 1) has the highest non-zero tabindex (that is less than start's tabindex), and
    628     // 2) comes last in the scope, if there's a tie.
    629     startingTabIndex = (start && startingTabIndex) ? startingTabIndex : std::numeric_limits<short>::max();
    630     return previousNodeWithLowerTabIndex(last, startingTabIndex);
    631 }
    632 
    633 static bool relinquishesEditingFocus(Node *node)
    634 {
    635     ASSERT(node);
    636     ASSERT(node->rendererIsEditable());
    637     return node->document().frame() && node->rootEditableElement();
    638 }
    639 
    640 static void clearSelectionIfNeeded(LocalFrame* oldFocusedFrame, LocalFrame* newFocusedFrame, Node* newFocusedNode)
    641 {
    642     if (!oldFocusedFrame || !newFocusedFrame)
    643         return;
    644 
    645     if (oldFocusedFrame->document() != newFocusedFrame->document())
    646         return;
    647 
    648     FrameSelection& selection = oldFocusedFrame->selection();
    649     if (selection.isNone())
    650         return;
    651 
    652     bool caretBrowsing = oldFocusedFrame->settings()->caretBrowsingEnabled();
    653     if (caretBrowsing)
    654         return;
    655 
    656     Node* selectionStartNode = selection.selection().start().deprecatedNode();
    657     if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->deprecatedShadowAncestorNode() == newFocusedNode)
    658         return;
    659 
    660     if (Node* mousePressNode = newFocusedFrame->eventHandler().mousePressNode()) {
    661         if (mousePressNode->renderer() && !mousePressNode->canStartSelection()) {
    662             // Don't clear the selection for contentEditable elements, but do
    663             // clear it for input and textarea. See bug 38696.
    664             if (!enclosingTextFormControl(selection.start()))
    665                 return;
    666         }
    667     }
    668 
    669     selection.clear();
    670 }
    671 
    672 bool FocusController::setFocusedElement(Element* element, PassRefPtr<Frame> newFocusedFrame, FocusType type)
    673 {
    674     RefPtr<LocalFrame> oldFocusedFrame = toLocalFrame(focusedFrame());
    675     RefPtrWillBeRawPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0;
    676 
    677     Element* oldFocusedElement = oldDocument ? oldDocument->focusedElement() : 0;
    678     if (element && oldFocusedElement == element)
    679         return true;
    680 
    681     // FIXME: Might want to disable this check for caretBrowsing
    682     if (oldFocusedElement && oldFocusedElement->isRootEditableElement() && !relinquishesEditingFocus(oldFocusedElement))
    683         return false;
    684 
    685     m_page->chrome().client().willSetInputMethodState();
    686 
    687     RefPtrWillBeRawPtr<Document> newDocument = nullptr;
    688     if (element)
    689         newDocument = &element->document();
    690     else if (newFocusedFrame && newFocusedFrame->isLocalFrame())
    691         newDocument = toLocalFrame(newFocusedFrame.get())->document();
    692 
    693     if (newDocument && oldDocument == newDocument && newDocument->focusedElement() == element)
    694         return true;
    695 
    696     clearSelectionIfNeeded(oldFocusedFrame.get(), toLocalFrame(newFocusedFrame.get()), element);
    697 
    698     if (oldDocument && oldDocument != newDocument)
    699         oldDocument->setFocusedElement(nullptr);
    700 
    701     if (newFocusedFrame && !newFocusedFrame->page()) {
    702         setFocusedFrame(nullptr);
    703         return false;
    704     }
    705     setFocusedFrame(newFocusedFrame);
    706 
    707     // Setting the focused node can result in losing our last reft to node when JS event handlers fire.
    708     RefPtrWillBeRawPtr<Element> protect ALLOW_UNUSED = element;
    709     if (newDocument) {
    710         bool successfullyFocused = newDocument->setFocusedElement(element, type);
    711         if (!successfullyFocused)
    712             return false;
    713     }
    714 
    715     return true;
    716 }
    717 
    718 void FocusController::setActive(bool active)
    719 {
    720     if (m_isActive == active)
    721         return;
    722 
    723     m_isActive = active;
    724 
    725     if (m_page->mainFrame()->isLocalFrame()) {
    726         if (FrameView* view = m_page->deprecatedLocalMainFrame()->view())
    727             view->updateControlTints();
    728     }
    729 
    730     toLocalFrame(focusedOrMainFrame())->selection().pageActivationChanged();
    731 }
    732 
    733 static void updateFocusCandidateIfNeeded(FocusType type, const FocusCandidate& current, FocusCandidate& candidate, FocusCandidate& closest)
    734 {
    735     ASSERT(candidate.visibleNode->isElementNode());
    736     ASSERT(candidate.visibleNode->renderer());
    737 
    738     // Ignore iframes that don't have a src attribute
    739     if (frameOwnerElement(candidate) && (!frameOwnerElement(candidate)->contentFrame() || candidate.rect.isEmpty()))
    740         return;
    741 
    742     // Ignore off screen child nodes of containers that do not scroll (overflow:hidden)
    743     if (candidate.isOffscreen && !canBeScrolledIntoView(type, candidate))
    744         return;
    745 
    746     distanceDataForNode(type, current, candidate);
    747     if (candidate.distance == maxDistance())
    748         return;
    749 
    750     if (candidate.isOffscreenAfterScrolling && candidate.alignment < Full)
    751         return;
    752 
    753     if (closest.isNull()) {
    754         closest = candidate;
    755         return;
    756     }
    757 
    758     LayoutRect intersectionRect = intersection(candidate.rect, closest.rect);
    759     if (!intersectionRect.isEmpty() && !areElementsOnSameLine(closest, candidate)
    760         && intersectionRect == candidate.rect) {
    761         // If 2 nodes are intersecting, do hit test to find which node in on top.
    762         LayoutUnit x = intersectionRect.x() + intersectionRect.width() / 2;
    763         LayoutUnit y = intersectionRect.y() + intersectionRect.height() / 2;
    764         if (!candidate.visibleNode->document().page()->mainFrame()->isLocalFrame())
    765             return;
    766         HitTestResult result = candidate.visibleNode->document().page()->deprecatedLocalMainFrame()->eventHandler().hitTestResultAtPoint(IntPoint(x, y), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
    767         if (candidate.visibleNode->contains(result.innerNode())) {
    768             closest = candidate;
    769             return;
    770         }
    771         if (closest.visibleNode->contains(result.innerNode()))
    772             return;
    773     }
    774 
    775     if (candidate.alignment == closest.alignment) {
    776         if (candidate.distance < closest.distance)
    777             closest = candidate;
    778         return;
    779     }
    780 
    781     if (candidate.alignment > closest.alignment)
    782         closest = candidate;
    783 }
    784 
    785 void FocusController::findFocusCandidateInContainer(Node& container, const LayoutRect& startingRect, FocusType type, FocusCandidate& closest)
    786 {
    787     Element* focusedElement = (focusedFrame() && toLocalFrame(focusedFrame())->document()) ? toLocalFrame(focusedFrame())->document()->focusedElement() : 0;
    788 
    789     Element* element = ElementTraversal::firstWithin(container);
    790     FocusCandidate current;
    791     current.rect = startingRect;
    792     current.focusableNode = focusedElement;
    793     current.visibleNode = focusedElement;
    794 
    795     for (; element; element = (element->isFrameOwnerElement() || canScrollInDirection(element, type))
    796         ? ElementTraversal::nextSkippingChildren(*element, &container)
    797         : ElementTraversal::next(*element, &container)) {
    798         if (element == focusedElement)
    799             continue;
    800 
    801         if (!element->isKeyboardFocusable() && !element->isFrameOwnerElement() && !canScrollInDirection(element, type))
    802             continue;
    803 
    804         FocusCandidate candidate = FocusCandidate(element, type);
    805         if (candidate.isNull())
    806             continue;
    807 
    808         candidate.enclosingScrollableBox = &container;
    809         updateFocusCandidateIfNeeded(type, current, candidate, closest);
    810     }
    811 }
    812 
    813 bool FocusController::advanceFocusDirectionallyInContainer(Node* container, const LayoutRect& startingRect, FocusType type)
    814 {
    815     if (!container)
    816         return false;
    817 
    818     LayoutRect newStartingRect = startingRect;
    819 
    820     if (startingRect.isEmpty())
    821         newStartingRect = virtualRectForDirection(type, nodeRectInAbsoluteCoordinates(container));
    822 
    823     // Find the closest node within current container in the direction of the navigation.
    824     FocusCandidate focusCandidate;
    825     findFocusCandidateInContainer(*container, newStartingRect, type, focusCandidate);
    826 
    827     if (focusCandidate.isNull()) {
    828         // Nothing to focus, scroll if possible.
    829         // NOTE: If no scrolling is performed (i.e. scrollInDirection returns false), the
    830         // spatial navigation algorithm will skip this container.
    831         return scrollInDirection(container, type);
    832     }
    833 
    834     HTMLFrameOwnerElement* frameElement = frameOwnerElement(focusCandidate);
    835     // If we have an iframe without the src attribute, it will not have a contentFrame().
    836     // We ASSERT here to make sure that
    837     // updateFocusCandidateIfNeeded() will never consider such an iframe as a candidate.
    838     ASSERT(!frameElement || frameElement->contentFrame());
    839     if (frameElement && frameElement->contentFrame()->isLocalFrame()) {
    840         if (focusCandidate.isOffscreenAfterScrolling) {
    841             scrollInDirection(&focusCandidate.visibleNode->document(), type);
    842             return true;
    843         }
    844         // Navigate into a new frame.
    845         LayoutRect rect;
    846         Element* focusedElement = toLocalFrame(focusedOrMainFrame())->document()->focusedElement();
    847         if (focusedElement && !hasOffscreenRect(focusedElement))
    848             rect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */);
    849         toLocalFrame(frameElement->contentFrame())->document()->updateLayoutIgnorePendingStylesheets();
    850         if (!advanceFocusDirectionallyInContainer(toLocalFrame(frameElement->contentFrame())->document(), rect, type)) {
    851             // The new frame had nothing interesting, need to find another candidate.
    852             return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.visibleNode, true), type);
    853         }
    854         return true;
    855     }
    856 
    857     if (canScrollInDirection(focusCandidate.visibleNode, type)) {
    858         if (focusCandidate.isOffscreenAfterScrolling) {
    859             scrollInDirection(focusCandidate.visibleNode, type);
    860             return true;
    861         }
    862         // Navigate into a new scrollable container.
    863         LayoutRect startingRect;
    864         Element* focusedElement = toLocalFrame(focusedOrMainFrame())->document()->focusedElement();
    865         if (focusedElement && !hasOffscreenRect(focusedElement))
    866             startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true);
    867         return advanceFocusDirectionallyInContainer(focusCandidate.visibleNode, startingRect, type);
    868     }
    869     if (focusCandidate.isOffscreenAfterScrolling) {
    870         Node* container = focusCandidate.enclosingScrollableBox;
    871         scrollInDirection(container, type);
    872         return true;
    873     }
    874 
    875     // We found a new focus node, navigate to it.
    876     Element* element = toElement(focusCandidate.focusableNode);
    877     ASSERT(element);
    878 
    879     element->focus(false, type);
    880     return true;
    881 }
    882 
    883 bool FocusController::advanceFocusDirectionally(FocusType type)
    884 {
    885     // FIXME: Directional focus changes don't yet work with RemoteFrames.
    886     if (!focusedOrMainFrame()->isLocalFrame())
    887         return false;
    888     LocalFrame* curFrame = toLocalFrame(focusedOrMainFrame());
    889     ASSERT(curFrame);
    890 
    891     Document* focusedDocument = curFrame->document();
    892     if (!focusedDocument)
    893         return false;
    894 
    895     Element* focusedElement = focusedDocument->focusedElement();
    896     Node* container = focusedDocument;
    897 
    898     if (container->isDocumentNode())
    899         toDocument(container)->updateLayoutIgnorePendingStylesheets();
    900 
    901     // Figure out the starting rect.
    902     LayoutRect startingRect;
    903     if (focusedElement) {
    904         if (!hasOffscreenRect(focusedElement)) {
    905             container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(type, focusedElement);
    906             startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */);
    907         } else if (isHTMLAreaElement(*focusedElement)) {
    908             HTMLAreaElement& area = toHTMLAreaElement(*focusedElement);
    909             container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(type, area.imageElement());
    910             startingRect = virtualRectForAreaElementAndDirection(area, type);
    911         }
    912     }
    913 
    914     bool consumed = false;
    915     do {
    916         consumed = advanceFocusDirectionallyInContainer(container, startingRect, type);
    917         startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */);
    918         container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(type, container);
    919         if (container && container->isDocumentNode())
    920             toDocument(container)->updateLayoutIgnorePendingStylesheets();
    921     } while (!consumed && container);
    922 
    923     return consumed;
    924 }
    925 
    926 } // namespace WebCore
    927