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 "HTMLFrameOwnerElement.h"
     44 #include "HTMLNames.h"
     45 #include "KeyboardEvent.h"
     46 #include "Page.h"
     47 #include "Range.h"
     48 #include "RenderObject.h"
     49 #include "RenderWidget.h"
     50 #include "SelectionController.h"
     51 #include "Settings.h"
     52 #include "Widget.h"
     53 #include <wtf/Platform.h>
     54 
     55 namespace WebCore {
     56 
     57 using namespace HTMLNames;
     58 
     59 static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused)
     60 {
     61     // If we have a focused node we should dispatch blur on it before we blur the window.
     62     // If we have a focused node we should dispatch focus on it after we focus the window.
     63     // https://bugs.webkit.org/show_bug.cgi?id=27105
     64     if (!focused && document->focusedNode())
     65         document->focusedNode()->dispatchBlurEvent();
     66     document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false));
     67     if (focused && document->focusedNode())
     68         document->focusedNode()->dispatchFocusEvent();
     69 }
     70 
     71 FocusController::FocusController(Page* page)
     72     : m_page(page)
     73     , m_isActive(false)
     74     , m_isFocused(false)
     75     , m_isChangingFocusedFrame(false)
     76 {
     77 }
     78 
     79 void FocusController::setFocusedFrame(PassRefPtr<Frame> frame)
     80 {
     81     if (m_focusedFrame == frame || m_isChangingFocusedFrame)
     82         return;
     83 
     84     m_isChangingFocusedFrame = true;
     85 
     86     RefPtr<Frame> oldFrame = m_focusedFrame;
     87     RefPtr<Frame> newFrame = frame;
     88 
     89     m_focusedFrame = newFrame;
     90 
     91     // Now that the frame is updated, fire events and update the selection focused states of both frames.
     92     if (oldFrame && oldFrame->view()) {
     93         oldFrame->selection()->setFocused(false);
     94         oldFrame->document()->dispatchWindowEvent(Event::create(eventNames().blurEvent, false, false));
     95     }
     96 
     97     if (newFrame && newFrame->view() && isFocused()) {
     98         newFrame->selection()->setFocused(true);
     99         newFrame->document()->dispatchWindowEvent(Event::create(eventNames().focusEvent, false, false));
    100     }
    101 
    102     m_isChangingFocusedFrame = false;
    103 }
    104 
    105 Frame* FocusController::focusedOrMainFrame()
    106 {
    107     if (Frame* frame = focusedFrame())
    108         return frame;
    109     return m_page->mainFrame();
    110 }
    111 
    112 void FocusController::setFocused(bool focused)
    113 {
    114     if (isFocused() == focused)
    115         return;
    116 
    117     m_isFocused = focused;
    118 
    119     if (m_focusedFrame && m_focusedFrame->view()) {
    120         m_focusedFrame->selection()->setFocused(focused);
    121         dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), focused);
    122     }
    123 }
    124 
    125 static Node* deepFocusableNode(FocusDirection direction, Node* node, KeyboardEvent* event)
    126 {
    127     // The node we found might be a HTMLFrameOwnerElement, so descend down the frame tree until we find either:
    128     // 1) a focusable node, or
    129     // 2) the deepest-nested HTMLFrameOwnerElement
    130     while (node && node->isFrameOwnerElement()) {
    131         HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node);
    132         if (!owner->contentFrame())
    133             break;
    134 
    135         Document* document = owner->contentFrame()->document();
    136 
    137         node = (direction == FocusDirectionForward)
    138             ? document->nextFocusableNode(0, event)
    139             : document->previousFocusableNode(0, event);
    140         if (!node) {
    141             node = owner;
    142             break;
    143         }
    144     }
    145 
    146     return node;
    147 }
    148 
    149 bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* event)
    150 {
    151     return advanceFocus(direction, event, true);
    152 }
    153 
    154 bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* event, bool initialFocus)
    155 {
    156     Frame* frame = focusedOrMainFrame();
    157     ASSERT(frame);
    158     Document* document = frame->document();
    159 
    160     Node* currentNode = document->focusedNode();
    161     // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself
    162     bool caretBrowsing = focusedOrMainFrame()->settings()->caretBrowsingEnabled();
    163 
    164     if (caretBrowsing && !currentNode)
    165         currentNode = frame->selection()->start().node();
    166 
    167     document->updateLayoutIgnorePendingStylesheets();
    168 
    169     Node* node = (direction == FocusDirectionForward)
    170         ? document->nextFocusableNode(currentNode, event)
    171         : document->previousFocusableNode(currentNode, event);
    172 
    173     // If there's no focusable node to advance to, move up the frame tree until we find one.
    174     while (!node && frame) {
    175         Frame* parentFrame = frame->tree()->parent();
    176         if (!parentFrame)
    177             break;
    178 
    179         Document* parentDocument = parentFrame->document();
    180 
    181         HTMLFrameOwnerElement* owner = frame->ownerElement();
    182         if (!owner)
    183             break;
    184 
    185         node = (direction == FocusDirectionForward)
    186             ? parentDocument->nextFocusableNode(owner, event)
    187             : parentDocument->previousFocusableNode(owner, event);
    188 
    189         frame = parentFrame;
    190     }
    191 
    192     node = deepFocusableNode(direction, node, event);
    193 
    194     if (!node) {
    195         // We didn't find a node to focus, so we should try to pass focus to Chrome.
    196         if (!initialFocus && m_page->chrome()->canTakeFocus(direction)) {
    197             document->setFocusedNode(0);
    198             setFocusedFrame(0);
    199             m_page->chrome()->takeFocus(direction);
    200             return true;
    201         }
    202 
    203         // Chrome doesn't want focus, so we should wrap focus.
    204         Document* d = m_page->mainFrame()->document();
    205         node = (direction == FocusDirectionForward)
    206             ? d->nextFocusableNode(0, event)
    207             : d->previousFocusableNode(0, event);
    208 
    209         node = deepFocusableNode(direction, node, event);
    210 
    211         if (!node)
    212             return false;
    213     }
    214 
    215     ASSERT(node);
    216 
    217     if (node == document->focusedNode())
    218         // Focus wrapped around to the same node.
    219         return true;
    220 
    221     if (!node->isElementNode())
    222         // FIXME: May need a way to focus a document here.
    223         return false;
    224 
    225     if (node->isFrameOwnerElement()) {
    226         // We focus frames rather than frame owners.
    227         // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user.
    228         HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node);
    229         if (!owner->contentFrame())
    230             return false;
    231 
    232         document->setFocusedNode(0);
    233         setFocusedFrame(owner->contentFrame());
    234         return true;
    235     }
    236 
    237     // FIXME: It would be nice to just be able to call setFocusedNode(node) here, but we can't do
    238     // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in
    239     // their focus() methods.
    240 
    241     Document* newDocument = node->document();
    242 
    243     if (newDocument != document)
    244         // Focus is going away from this document, so clear the focused node.
    245         document->setFocusedNode(0);
    246 
    247     if (newDocument)
    248         setFocusedFrame(newDocument->frame());
    249 
    250     if (caretBrowsing) {
    251         VisibleSelection newSelection(Position(node, 0), Position(node, 0), DOWNSTREAM);
    252         if (frame->shouldChangeSelection(newSelection))
    253             frame->selection()->setSelection(newSelection);
    254     }
    255 
    256     static_cast<Element*>(node)->focus(false);
    257     return true;
    258 }
    259 
    260 static bool relinquishesEditingFocus(Node *node)
    261 {
    262     ASSERT(node);
    263     ASSERT(node->isContentEditable());
    264 
    265     Node* root = node->rootEditableElement();
    266     Frame* frame = node->document()->frame();
    267     if (!frame || !root)
    268         return false;
    269 
    270     return frame->editor()->shouldEndEditing(rangeOfContents(root).get());
    271 }
    272 
    273 static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode)
    274 {
    275     if (!oldFocusedFrame || !newFocusedFrame)
    276         return;
    277 
    278     if (oldFocusedFrame->document() != newFocusedFrame->document())
    279         return;
    280 
    281     SelectionController* s = oldFocusedFrame->selection();
    282     if (s->isNone())
    283         return;
    284 
    285     bool caretBrowsing = oldFocusedFrame->settings()->caretBrowsingEnabled();
    286     if (caretBrowsing)
    287         return;
    288 
    289     Node* selectionStartNode = s->selection().start().node();
    290     if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode)
    291         return;
    292 
    293     if (Node* mousePressNode = newFocusedFrame->eventHandler()->mousePressNode())
    294         if (mousePressNode->renderer() && !mousePressNode->canStartSelection())
    295             if (Node* root = s->rootEditableElement())
    296                 if (Node* shadowAncestorNode = root->shadowAncestorNode())
    297                     // Don't do this for textareas and text fields, when they lose focus their selections should be cleared
    298                     // and then restored when they regain focus, to match other browsers.
    299                     if (!shadowAncestorNode->hasTagName(inputTag) && !shadowAncestorNode->hasTagName(textareaTag))
    300                         return;
    301 
    302     s->clear();
    303 }
    304 
    305 bool FocusController::setFocusedNode(Node* node, PassRefPtr<Frame> newFocusedFrame)
    306 {
    307     RefPtr<Frame> oldFocusedFrame = focusedFrame();
    308     RefPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0;
    309 
    310     Node* oldFocusedNode = oldDocument ? oldDocument->focusedNode() : 0;
    311     if (oldFocusedNode == node)
    312         return true;
    313 
    314     // FIXME: Might want to disable this check for caretBrowsing
    315     if (oldFocusedNode && oldFocusedNode->rootEditableElement() == oldFocusedNode && !relinquishesEditingFocus(oldFocusedNode))
    316         return false;
    317 
    318     clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), node);
    319 
    320     if (!node) {
    321         if (oldDocument)
    322             oldDocument->setFocusedNode(0);
    323         m_page->editorClient()->setInputMethodState(false);
    324         return true;
    325     }
    326 
    327     RefPtr<Document> newDocument = node->document();
    328 
    329     if (newDocument && newDocument->focusedNode() == node) {
    330         m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod());
    331         return true;
    332     }
    333 
    334     if (oldDocument && oldDocument != newDocument)
    335         oldDocument->setFocusedNode(0);
    336 
    337     setFocusedFrame(newFocusedFrame);
    338 
    339     if (newDocument)
    340         newDocument->setFocusedNode(node);
    341 
    342     m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod());
    343 
    344     return true;
    345 }
    346 
    347 void FocusController::setActive(bool active)
    348 {
    349     if (m_isActive == active)
    350         return;
    351 
    352     m_isActive = active;
    353 
    354     if (FrameView* view = m_page->mainFrame()->view()) {
    355         if (!view->platformWidget()) {
    356             view->layoutIfNeededRecursive();
    357             view->updateControlTints();
    358         }
    359     }
    360 
    361     focusedOrMainFrame()->selection()->pageActivationChanged();
    362 
    363     if (m_focusedFrame && isFocused())
    364         dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), active);
    365 }
    366 
    367 } // namespace WebCore
    368