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