2010-11-23 Yael Aharon <yael.aharon@nokia.com>
[WebKit-https.git] / WebCore / page / FocusController.cpp
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 "HitTestResult.h"
44 #include "HTMLFrameOwnerElement.h"
45 #include "HTMLNames.h"
46 #include "KeyboardEvent.h"
47 #include "Page.h"
48 #include "Range.h"
49 #include "RenderLayer.h"
50 #include "RenderObject.h"
51 #include "RenderWidget.h"
52 #include "SelectionController.h"
53 #include "Settings.h"
54 #include "SpatialNavigation.h"
55 #include "Widget.h"
56
57 namespace WebCore {
58
59 using namespace HTMLNames;
60 using namespace std;
61
62 static void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& startingRect, FocusCandidate& candidate, FocusCandidate& closest);
63 static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused)
64 {
65     // If we have a focused node we should dispatch blur on it before we blur the window.
66     // If we have a focused node we should dispatch focus on it after we focus the window.
67     // https://bugs.webkit.org/show_bug.cgi?id=27105
68
69     // Do not fire events while modal dialogs are up.  See https://bugs.webkit.org/show_bug.cgi?id=33962
70     if (Page* page = document->page()) {
71         if (page->defersLoading())
72             return;
73     }
74
75     if (!focused && document->focusedNode())
76         document->focusedNode()->dispatchBlurEvent();
77     document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false));
78     if (focused && document->focusedNode())
79         document->focusedNode()->dispatchFocusEvent();
80 }
81
82 FocusController::FocusController(Page* page)
83     : m_page(page)
84     , m_isActive(false)
85     , m_isFocused(false)
86     , m_isChangingFocusedFrame(false)
87 {
88 }
89
90 void FocusController::setFocusedFrame(PassRefPtr<Frame> frame)
91 {
92     ASSERT(!frame || frame->page() == m_page);
93     if (m_focusedFrame == frame || m_isChangingFocusedFrame)
94         return;
95
96     m_isChangingFocusedFrame = true;
97
98     RefPtr<Frame> oldFrame = m_focusedFrame;
99     RefPtr<Frame> newFrame = frame;
100
101     m_focusedFrame = newFrame;
102
103     // Now that the frame is updated, fire events and update the selection focused states of both frames.
104     if (oldFrame && oldFrame->view()) {
105         oldFrame->selection()->setFocused(false);
106         oldFrame->document()->dispatchWindowEvent(Event::create(eventNames().blurEvent, false, false));
107     }
108
109     if (newFrame && newFrame->view() && isFocused()) {
110         newFrame->selection()->setFocused(true);
111         newFrame->document()->dispatchWindowEvent(Event::create(eventNames().focusEvent, false, false));
112     }
113
114     m_page->chrome()->focusedFrameChanged(newFrame.get());
115
116     m_isChangingFocusedFrame = false;
117 }
118
119 Frame* FocusController::focusedOrMainFrame() const
120 {
121     if (Frame* frame = focusedFrame())
122         return frame;
123     return m_page->mainFrame();
124 }
125
126 void FocusController::setFocused(bool focused)
127 {
128     if (isFocused() == focused)
129         return;
130     
131     m_isFocused = focused;
132
133     if (!m_focusedFrame)
134         setFocusedFrame(m_page->mainFrame());
135
136     if (m_focusedFrame->view()) {
137         m_focusedFrame->selection()->setFocused(focused);
138         dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), focused);
139     }
140 }
141
142 static Node* deepFocusableNode(FocusDirection direction, Node* node, KeyboardEvent* event)
143 {
144     // The node we found might be a HTMLFrameOwnerElement, so descend down the frame tree until we find either:
145     // 1) a focusable node, or
146     // 2) the deepest-nested HTMLFrameOwnerElement
147     while (node && node->isFrameOwnerElement()) {
148         HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node);
149         if (!owner->contentFrame())
150             break;
151
152         Document* document = owner->contentFrame()->document();
153
154         node = (direction == FocusDirectionForward)
155             ? document->nextFocusableNode(0, event)
156             : document->previousFocusableNode(0, event);
157         if (!node) {
158             node = owner;
159             break;
160         }
161     }
162
163     return node;
164 }
165
166 bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* event)
167 {
168     return advanceFocus(direction, event, true);
169 }
170
171 bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* event, bool initialFocus)
172 {
173     switch (direction) {
174     case FocusDirectionForward:
175     case FocusDirectionBackward:
176         return advanceFocusInDocumentOrder(direction, event, initialFocus);
177     case FocusDirectionLeft:
178     case FocusDirectionRight:
179     case FocusDirectionUp:
180     case FocusDirectionDown:
181         return advanceFocusDirectionally(direction, event);
182     default:
183         ASSERT_NOT_REACHED();
184     }
185
186     return false;
187 }
188
189 bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, KeyboardEvent* event, bool initialFocus)
190 {
191     Frame* frame = focusedOrMainFrame();
192     ASSERT(frame);
193     Document* document = frame->document();
194
195     Node* currentNode = document->focusedNode();
196     // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself
197     bool caretBrowsing = focusedOrMainFrame()->settings()->caretBrowsingEnabled();
198
199     if (caretBrowsing && !currentNode)
200         currentNode = frame->selection()->start().node();
201
202     document->updateLayoutIgnorePendingStylesheets();
203
204     Node* node = (direction == FocusDirectionForward)
205         ? document->nextFocusableNode(currentNode, event)
206         : document->previousFocusableNode(currentNode, event);
207             
208     // If there's no focusable node to advance to, move up the frame tree until we find one.
209     while (!node && frame) {
210         Frame* parentFrame = frame->tree()->parent();
211         if (!parentFrame)
212             break;
213
214         Document* parentDocument = parentFrame->document();
215
216         HTMLFrameOwnerElement* owner = frame->ownerElement();
217         if (!owner)
218             break;
219
220         node = (direction == FocusDirectionForward)
221             ? parentDocument->nextFocusableNode(owner, event)
222             : parentDocument->previousFocusableNode(owner, event);
223
224         frame = parentFrame;
225     }
226
227     node = deepFocusableNode(direction, node, event);
228
229     if (!node) {
230         // We didn't find a node to focus, so we should try to pass focus to Chrome.
231         if (!initialFocus && m_page->chrome()->canTakeFocus(direction)) {
232             document->setFocusedNode(0);
233             setFocusedFrame(0);
234             m_page->chrome()->takeFocus(direction);
235             return true;
236         }
237
238         // Chrome doesn't want focus, so we should wrap focus.
239         Document* d = m_page->mainFrame()->document();
240         node = (direction == FocusDirectionForward)
241             ? d->nextFocusableNode(0, event)
242             : d->previousFocusableNode(0, event);
243
244         node = deepFocusableNode(direction, node, event);
245
246         if (!node)
247             return false;
248     }
249
250     ASSERT(node);
251
252     if (node == document->focusedNode())
253         // Focus wrapped around to the same node.
254         return true;
255
256     if (!node->isElementNode())
257         // FIXME: May need a way to focus a document here.
258         return false;
259
260     if (node->isFrameOwnerElement()) {
261         // We focus frames rather than frame owners.
262         // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user.
263         HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node);
264         if (!owner->contentFrame())
265             return false;
266
267         document->setFocusedNode(0);
268         setFocusedFrame(owner->contentFrame());
269         return true;
270     }
271     
272     // FIXME: It would be nice to just be able to call setFocusedNode(node) here, but we can't do
273     // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in
274     // their focus() methods.
275
276     Document* newDocument = node->document();
277
278     if (newDocument != document)
279         // Focus is going away from this document, so clear the focused node.
280         document->setFocusedNode(0);
281
282     if (newDocument)
283         setFocusedFrame(newDocument->frame());
284
285     if (caretBrowsing) {
286         VisibleSelection newSelection(Position(node, 0), Position(node, 0), DOWNSTREAM);
287         if (frame->selection()->shouldChangeSelection(newSelection))
288             frame->selection()->setSelection(newSelection);
289     }
290
291     static_cast<Element*>(node)->focus(false);
292     return true;
293 }
294
295 static bool relinquishesEditingFocus(Node *node)
296 {
297     ASSERT(node);
298     ASSERT(node->isContentEditable());
299
300     Node* root = node->rootEditableElement();
301     Frame* frame = node->document()->frame();
302     if (!frame || !root)
303         return false;
304
305     return frame->editor()->shouldEndEditing(rangeOfContents(root).get());
306 }
307
308 static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode)
309 {
310     if (!oldFocusedFrame || !newFocusedFrame)
311         return;
312         
313     if (oldFocusedFrame->document() != newFocusedFrame->document())
314         return;
315     
316     SelectionController* s = oldFocusedFrame->selection();
317     if (s->isNone())
318         return;
319
320     bool caretBrowsing = oldFocusedFrame->settings()->caretBrowsingEnabled();
321     if (caretBrowsing)
322         return;
323
324     Node* selectionStartNode = s->selection().start().node();
325     if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode)
326         return;
327         
328     if (Node* mousePressNode = newFocusedFrame->eventHandler()->mousePressNode()) {
329         if (mousePressNode->renderer() && !mousePressNode->canStartSelection()) {
330             // Don't clear the selection for contentEditable elements, but do clear it for input and textarea. See bug 38696.
331             Node * root = s->rootEditableElement();
332             if (!root)
333                 return;
334
335             if (Node* shadowAncestorNode = root->shadowAncestorNode()) {
336                 if (!shadowAncestorNode->hasTagName(inputTag) && !shadowAncestorNode->hasTagName(textareaTag))
337                     return;
338             }
339         }
340     }
341     
342     s->clear();
343 }
344
345 bool FocusController::setFocusedNode(Node* node, PassRefPtr<Frame> newFocusedFrame)
346 {
347     RefPtr<Frame> oldFocusedFrame = focusedFrame();
348     RefPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0;
349     
350     Node* oldFocusedNode = oldDocument ? oldDocument->focusedNode() : 0;
351     if (oldFocusedNode == node)
352         return true;
353
354     // FIXME: Might want to disable this check for caretBrowsing
355     if (oldFocusedNode && oldFocusedNode->rootEditableElement() == oldFocusedNode && !relinquishesEditingFocus(oldFocusedNode))
356         return false;
357
358     m_page->editorClient()->willSetInputMethodState();
359
360     clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), node);
361
362     if (!node) {
363         if (oldDocument)
364             oldDocument->setFocusedNode(0);
365         m_page->editorClient()->setInputMethodState(false);
366         return true;
367     }
368
369     RefPtr<Document> newDocument = node->document();
370
371     if (newDocument && newDocument->focusedNode() == node) {
372         m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod());
373         return true;
374     }
375     
376     if (oldDocument && oldDocument != newDocument)
377         oldDocument->setFocusedNode(0);
378     
379     setFocusedFrame(newFocusedFrame);
380
381     // Setting the focused node can result in losing our last reft to node when JS event handlers fire.
382     RefPtr<Node> protect = node;
383     if (newDocument) {
384         bool successfullyFocused = newDocument->setFocusedNode(node);
385         if (!successfullyFocused)
386             return false;
387     }
388
389     if (newDocument->focusedNode() == node)
390         m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod());
391
392     return true;
393 }
394
395 void FocusController::setActive(bool active)
396 {
397     if (m_isActive == active)
398         return;
399
400     m_isActive = active;
401
402     if (FrameView* view = m_page->mainFrame()->view()) {
403         if (!view->platformWidget()) {
404             view->updateLayoutAndStyleIfNeededRecursive();
405             view->updateControlTints();
406         }
407     }
408
409     focusedOrMainFrame()->selection()->pageActivationChanged();
410     
411     if (m_focusedFrame && isFocused())
412         dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), active);
413 }
414
415 void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& startingRect, FocusCandidate& candidate, FocusCandidate& closest)
416 {
417     if (!candidate.node->isElementNode() || !candidate.node->renderer())
418         return;
419
420     // Ignore iframes that don't have a src attribute
421     if (candidate.node->isFrameOwnerElement() && !static_cast<HTMLFrameOwnerElement*>(candidate.node)->contentFrame())
422         return;
423
424     // Ignore off screen child nodes of containers that do not scroll (overflow:hidden)
425     if (hasOffscreenRect(candidate.node) && !canBeScrolledIntoView(direction, candidate))
426         return;
427
428     FocusCandidate current;
429     current.rect = startingRect;
430     distanceDataForNode(direction, current, candidate);
431     if (candidate.distance == maxDistance())
432         return;
433
434     if (hasOffscreenRect(candidate.node, direction) && candidate.alignment < Full)
435         return;
436
437     if (closest.isNull()) {
438         closest = candidate;
439         return;
440     }
441
442     IntRect intersectionRect = intersection(nodeRectInAbsoluteCoordinates(candidate.node, true), nodeRectInAbsoluteCoordinates(closest.node, true));
443     if (!intersectionRect.isEmpty()) {
444         // If 2 nodes are intersecting, do hit test to find which node in on top.
445         int x = intersectionRect.x() + intersectionRect.width() / 2;
446         int y = intersectionRect.y() + intersectionRect.height() / 2;
447         HitTestResult result = candidate.node->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, true);
448         if (candidate.node->contains(result.innerNode())) {
449             closest = candidate;
450             return;
451         }
452         if (closest.node->contains(result.innerNode()))
453             return;
454     }
455
456     if (candidate.alignment == closest.alignment) {
457         if (candidate.distance < closest.distance)
458             closest = candidate;
459         return;
460     }
461
462     if (candidate.alignment > closest.alignment)
463         closest = candidate;
464 }
465
466 void FocusController::findFocusCandidateInContainer(Node* container, const IntRect& startingRect, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closest)
467 {
468     ASSERT(container);
469     Node* focusedNode = (focusedFrame() && focusedFrame()->document()) ? focusedFrame()->document()->focusedNode() : 0;
470
471     Node* node = container->firstChild();
472     for (; node; node = (node->isFrameOwnerElement() || canScrollInDirection(direction, node)) ? node->traverseNextSibling(container) : node->traverseNextNode(container)) {
473         if (node == focusedNode)
474             continue;
475
476         if (!node->renderer())
477             continue;
478
479         if (!node->isKeyboardFocusable(event) && !node->isFrameOwnerElement() && !canScrollInDirection(direction, node))
480             continue;
481
482         FocusCandidate candidate(node);
483         candidate.enclosingScrollableBox = container;
484         updateFocusCandidateIfNeeded(direction, startingRect, candidate, closest);
485     }
486 }
487
488 bool FocusController::advanceFocusDirectionallyInContainer(Node* container, const IntRect& startingRect, FocusDirection direction, KeyboardEvent* event)
489 {
490     if (!container || !container->document())
491         return false;
492
493     IntRect newStartingRect = startingRect;
494
495     if (startingRect.isEmpty())
496         newStartingRect = virtualRectForDirection(direction, nodeRectInAbsoluteCoordinates(container));
497
498     // Find the closest node within current container in the direction of the navigation.
499     FocusCandidate focusCandidate;
500     findFocusCandidateInContainer(container, newStartingRect, direction, event, focusCandidate);
501
502     if (focusCandidate.isNull()) {
503         if (canScrollInDirection(direction, container)) {
504             // Nothing to focus, scroll if possible.
505             scrollInDirection(container, direction);
506             return true;
507         }
508         // Return false will cause a re-try, skipping this container.
509         return false;
510     }
511     if (focusCandidate.node->isFrameOwnerElement()) {
512         HTMLFrameOwnerElement* frameElement = static_cast<HTMLFrameOwnerElement*>(focusCandidate.node);
513         // If we have an iframe without the src attribute, it will not have a contentFrame().
514         // We ASSERT here to make sure that
515         // updateFocusCandidateIfNeeded() will never consider such an iframe as a candidate.
516         ASSERT(frameElement->contentFrame());
517
518         if (hasOffscreenRect(focusCandidate.node, direction)) {
519             scrollInDirection(focusCandidate.node->document(), direction);
520             return true;
521         }
522         // Navigate into a new frame.
523         IntRect rect;
524         Node* focusedNode = focusedOrMainFrame()->document()->focusedNode();
525         if (focusedNode && !hasOffscreenRect(focusedNode))
526             rect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */);
527         frameElement->contentFrame()->document()->updateLayoutIgnorePendingStylesheets();
528         if (!advanceFocusDirectionallyInContainer(frameElement->contentFrame()->document(), rect, direction, event)) {
529             // The new frame had nothing interesting, need to find another candidate.
530             return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.node, true), direction, event);
531         }
532         return true;
533     }
534     if (canScrollInDirection(direction, focusCandidate.node)) {
535         if (hasOffscreenRect(focusCandidate.node, direction)) {
536             scrollInDirection(focusCandidate.node, direction);
537             return true;
538         }
539         // Navigate into a new scrollable container.
540         IntRect startingRect;
541         Node* focusedNode = focusedOrMainFrame()->document()->focusedNode();
542         if (focusedNode && !hasOffscreenRect(focusedNode))
543             startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true);
544         return advanceFocusDirectionallyInContainer(focusCandidate.node, startingRect, direction, event);
545     }
546     if (hasOffscreenRect(focusCandidate.node, direction)) {
547         Node* container = focusCandidate.enclosingScrollableBox;
548         scrollInDirection(container, direction);
549         return true;
550     }
551
552     // We found a new focus node, navigate to it.
553     Element* element = toElement(focusCandidate.node);
554     ASSERT(element);
555
556     element->focus(false);
557     return true;
558 }
559
560 bool FocusController::advanceFocusDirectionally(FocusDirection direction, KeyboardEvent* event)
561 {
562     Frame* curFrame = focusedOrMainFrame();
563     ASSERT(curFrame);
564
565     Document* focusedDocument = curFrame->document();
566     if (!focusedDocument)
567         return false;
568
569     Node* focusedNode = focusedDocument->focusedNode();
570     Node* container = focusedDocument;
571
572     // Figure out the starting rect.
573     IntRect startingRect;
574     if (focusedNode && !hasOffscreenRect(focusedNode)) {
575         container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedNode);
576         startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */);
577     }
578
579     bool consumed = false;
580     do {
581         if (container->isDocumentNode())
582             static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets();
583         consumed = advanceFocusDirectionallyInContainer(container, startingRect, direction, event);
584         startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */);
585         container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, container);
586     } while (!consumed && container);
587
588     return consumed;
589 }
590
591 } // namespace WebCore