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