author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Tue, 06 Jul 2010 15:10:48 +0300 | |
changeset 30 | 5dc02b23752f |
parent 0 | 1918ee327afb |
child 33 | 3e2da88830cd |
permissions | -rw-r--r-- |
0 | 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" |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
41 |
#include "FrameTree.h" |
0 | 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" |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
52 |
#include "SpatialNavigation.h" |
0 | 53 |
#include "Widget.h" |
54 |
||
55 |
namespace WebCore { |
|
56 |
||
57 |
using namespace HTMLNames; |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
58 |
using namespace std; |
0 | 59 |
|
60 |
static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused) |
|
61 |
{ |
|
62 |
// If we have a focused node we should dispatch blur on it before we blur the window. |
|
63 |
// If we have a focused node we should dispatch focus on it after we focus the window. |
|
64 |
// https://bugs.webkit.org/show_bug.cgi?id=27105 |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
65 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
66 |
// Do not fire events while modal dialogs are up. See https://bugs.webkit.org/show_bug.cgi?id=33962 |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
67 |
if (Page* page = document->page()) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
68 |
if (page->defersLoading()) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
69 |
return; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
70 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
71 |
|
0 | 72 |
if (!focused && document->focusedNode()) |
73 |
document->focusedNode()->dispatchBlurEvent(); |
|
74 |
document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false)); |
|
75 |
if (focused && document->focusedNode()) |
|
76 |
document->focusedNode()->dispatchFocusEvent(); |
|
77 |
} |
|
78 |
||
79 |
FocusController::FocusController(Page* page) |
|
80 |
: m_page(page) |
|
81 |
, m_isActive(false) |
|
82 |
, m_isFocused(false) |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
83 |
, m_isChangingFocusedFrame(false) |
0 | 84 |
{ |
85 |
} |
|
86 |
||
87 |
void FocusController::setFocusedFrame(PassRefPtr<Frame> frame) |
|
88 |
{ |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
89 |
if (m_focusedFrame == frame || m_isChangingFocusedFrame) |
0 | 90 |
return; |
91 |
||
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
92 |
m_isChangingFocusedFrame = true; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
93 |
|
0 | 94 |
RefPtr<Frame> oldFrame = m_focusedFrame; |
95 |
RefPtr<Frame> newFrame = frame; |
|
96 |
||
97 |
m_focusedFrame = newFrame; |
|
98 |
||
99 |
// Now that the frame is updated, fire events and update the selection focused states of both frames. |
|
100 |
if (oldFrame && oldFrame->view()) { |
|
101 |
oldFrame->selection()->setFocused(false); |
|
102 |
oldFrame->document()->dispatchWindowEvent(Event::create(eventNames().blurEvent, false, false)); |
|
103 |
} |
|
104 |
||
105 |
if (newFrame && newFrame->view() && isFocused()) { |
|
106 |
newFrame->selection()->setFocused(true); |
|
107 |
newFrame->document()->dispatchWindowEvent(Event::create(eventNames().focusEvent, false, false)); |
|
108 |
} |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
109 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
110 |
m_isChangingFocusedFrame = false; |
0 | 111 |
} |
112 |
||
113 |
Frame* FocusController::focusedOrMainFrame() |
|
114 |
{ |
|
115 |
if (Frame* frame = focusedFrame()) |
|
116 |
return frame; |
|
117 |
return m_page->mainFrame(); |
|
118 |
} |
|
119 |
||
120 |
void FocusController::setFocused(bool focused) |
|
121 |
{ |
|
122 |
if (isFocused() == focused) |
|
123 |
return; |
|
124 |
||
125 |
m_isFocused = focused; |
|
126 |
||
127 |
if (m_focusedFrame && m_focusedFrame->view()) { |
|
128 |
m_focusedFrame->selection()->setFocused(focused); |
|
129 |
dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), focused); |
|
130 |
} |
|
131 |
} |
|
132 |
||
133 |
static Node* deepFocusableNode(FocusDirection direction, Node* node, KeyboardEvent* event) |
|
134 |
{ |
|
135 |
// The node we found might be a HTMLFrameOwnerElement, so descend down the frame tree until we find either: |
|
136 |
// 1) a focusable node, or |
|
137 |
// 2) the deepest-nested HTMLFrameOwnerElement |
|
138 |
while (node && node->isFrameOwnerElement()) { |
|
139 |
HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); |
|
140 |
if (!owner->contentFrame()) |
|
141 |
break; |
|
142 |
||
143 |
Document* document = owner->contentFrame()->document(); |
|
144 |
||
145 |
node = (direction == FocusDirectionForward) |
|
146 |
? document->nextFocusableNode(0, event) |
|
147 |
: document->previousFocusableNode(0, event); |
|
148 |
if (!node) { |
|
149 |
node = owner; |
|
150 |
break; |
|
151 |
} |
|
152 |
} |
|
153 |
||
154 |
return node; |
|
155 |
} |
|
156 |
||
157 |
bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* event) |
|
158 |
{ |
|
159 |
return advanceFocus(direction, event, true); |
|
160 |
} |
|
161 |
||
162 |
bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* event, bool initialFocus) |
|
163 |
{ |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
164 |
switch (direction) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
165 |
case FocusDirectionForward: |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
166 |
case FocusDirectionBackward: |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
167 |
return advanceFocusInDocumentOrder(direction, event, initialFocus); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
168 |
case FocusDirectionLeft: |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
169 |
case FocusDirectionRight: |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
170 |
case FocusDirectionUp: |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
171 |
case FocusDirectionDown: |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
172 |
return advanceFocusDirectionally(direction, event); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
173 |
default: |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
174 |
ASSERT_NOT_REACHED(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
175 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
176 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
177 |
return false; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
178 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
179 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
180 |
bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, KeyboardEvent* event, bool initialFocus) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
181 |
{ |
0 | 182 |
Frame* frame = focusedOrMainFrame(); |
183 |
ASSERT(frame); |
|
184 |
Document* document = frame->document(); |
|
185 |
||
186 |
Node* currentNode = document->focusedNode(); |
|
187 |
// FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself |
|
188 |
bool caretBrowsing = focusedOrMainFrame()->settings()->caretBrowsingEnabled(); |
|
189 |
||
190 |
if (caretBrowsing && !currentNode) |
|
191 |
currentNode = frame->selection()->start().node(); |
|
192 |
||
193 |
document->updateLayoutIgnorePendingStylesheets(); |
|
194 |
||
195 |
Node* node = (direction == FocusDirectionForward) |
|
196 |
? document->nextFocusableNode(currentNode, event) |
|
197 |
: document->previousFocusableNode(currentNode, event); |
|
198 |
||
199 |
// If there's no focusable node to advance to, move up the frame tree until we find one. |
|
200 |
while (!node && frame) { |
|
201 |
Frame* parentFrame = frame->tree()->parent(); |
|
202 |
if (!parentFrame) |
|
203 |
break; |
|
204 |
||
205 |
Document* parentDocument = parentFrame->document(); |
|
206 |
||
207 |
HTMLFrameOwnerElement* owner = frame->ownerElement(); |
|
208 |
if (!owner) |
|
209 |
break; |
|
210 |
||
211 |
node = (direction == FocusDirectionForward) |
|
212 |
? parentDocument->nextFocusableNode(owner, event) |
|
213 |
: parentDocument->previousFocusableNode(owner, event); |
|
214 |
||
215 |
frame = parentFrame; |
|
216 |
} |
|
217 |
||
218 |
node = deepFocusableNode(direction, node, event); |
|
219 |
||
220 |
if (!node) { |
|
221 |
// We didn't find a node to focus, so we should try to pass focus to Chrome. |
|
222 |
if (!initialFocus && m_page->chrome()->canTakeFocus(direction)) { |
|
223 |
document->setFocusedNode(0); |
|
224 |
setFocusedFrame(0); |
|
225 |
m_page->chrome()->takeFocus(direction); |
|
226 |
return true; |
|
227 |
} |
|
228 |
||
229 |
// Chrome doesn't want focus, so we should wrap focus. |
|
230 |
Document* d = m_page->mainFrame()->document(); |
|
231 |
node = (direction == FocusDirectionForward) |
|
232 |
? d->nextFocusableNode(0, event) |
|
233 |
: d->previousFocusableNode(0, event); |
|
234 |
||
235 |
node = deepFocusableNode(direction, node, event); |
|
236 |
||
237 |
if (!node) |
|
238 |
return false; |
|
239 |
} |
|
240 |
||
241 |
ASSERT(node); |
|
242 |
||
243 |
if (node == document->focusedNode()) |
|
244 |
// Focus wrapped around to the same node. |
|
245 |
return true; |
|
246 |
||
247 |
if (!node->isElementNode()) |
|
248 |
// FIXME: May need a way to focus a document here. |
|
249 |
return false; |
|
250 |
||
251 |
if (node->isFrameOwnerElement()) { |
|
252 |
// We focus frames rather than frame owners. |
|
253 |
// FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user. |
|
254 |
HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); |
|
255 |
if (!owner->contentFrame()) |
|
256 |
return false; |
|
257 |
||
258 |
document->setFocusedNode(0); |
|
259 |
setFocusedFrame(owner->contentFrame()); |
|
260 |
return true; |
|
261 |
} |
|
262 |
||
263 |
// FIXME: It would be nice to just be able to call setFocusedNode(node) here, but we can't do |
|
264 |
// that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in |
|
265 |
// their focus() methods. |
|
266 |
||
267 |
Document* newDocument = node->document(); |
|
268 |
||
269 |
if (newDocument != document) |
|
270 |
// Focus is going away from this document, so clear the focused node. |
|
271 |
document->setFocusedNode(0); |
|
272 |
||
273 |
if (newDocument) |
|
274 |
setFocusedFrame(newDocument->frame()); |
|
275 |
||
276 |
if (caretBrowsing) { |
|
277 |
VisibleSelection newSelection(Position(node, 0), Position(node, 0), DOWNSTREAM); |
|
278 |
if (frame->shouldChangeSelection(newSelection)) |
|
279 |
frame->selection()->setSelection(newSelection); |
|
280 |
} |
|
281 |
||
282 |
static_cast<Element*>(node)->focus(false); |
|
283 |
return true; |
|
284 |
} |
|
285 |
||
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
286 |
bool FocusController::advanceFocusDirectionally(FocusDirection direction, KeyboardEvent* event) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
287 |
{ |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
288 |
Frame* frame = focusedOrMainFrame(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
289 |
ASSERT(frame); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
290 |
Document* focusedDocument = frame->document(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
291 |
if (!focusedDocument) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
292 |
return false; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
293 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
294 |
Node* focusedNode = focusedDocument->focusedNode(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
295 |
if (!focusedNode) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
296 |
// Just move to the first focusable node. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
297 |
FocusDirection tabDirection = (direction == FocusDirectionUp || direction == FocusDirectionLeft) ? |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
298 |
FocusDirectionForward : FocusDirectionBackward; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
299 |
// 'initialFocus' is set to true so the chrome is not focused. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
300 |
return advanceFocusInDocumentOrder(tabDirection, event, true); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
301 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
302 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
303 |
// Move up in the chain of nested frames. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
304 |
frame = frame->tree()->top(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
305 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
306 |
FocusCandidate focusCandidate; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
307 |
findFocusableNodeInDirection(frame->document()->firstChild(), focusedNode, direction, event, focusCandidate); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
308 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
309 |
Node* node = focusCandidate.node; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
310 |
if (!node || !node->isElementNode()) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
311 |
// FIXME: May need a way to focus a document here. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
312 |
Frame* frame = focusedOrMainFrame(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
313 |
scrollInDirection(frame, direction); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
314 |
return false; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
315 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
316 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
317 |
// In order to avoid crazy jump between links that are either far away from each other, |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
318 |
// or just not currently visible, lets do a scroll in the given direction and bail out |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
319 |
// if |node| element is not in the viewport. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
320 |
if (hasOffscreenRect(node)) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
321 |
Frame* frame = node->document()->view()->frame(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
322 |
scrollInDirection(frame, direction); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
323 |
return true; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
324 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
325 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
326 |
Document* newDocument = node->document(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
327 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
328 |
if (newDocument != focusedDocument) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
329 |
// Focus is going away from the originally focused document, so clear the focused node. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
330 |
focusedDocument->setFocusedNode(0); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
331 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
332 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
333 |
if (newDocument) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
334 |
setFocusedFrame(newDocument->frame()); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
335 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
336 |
Element* element = static_cast<Element*>(node); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
337 |
ASSERT(element); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
338 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
339 |
scrollIntoView(element); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
340 |
element->focus(false); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
341 |
return true; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
342 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
343 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
344 |
// FIXME: Make this method more modular, and simpler to understand and maintain. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
345 |
static void updateFocusCandidateIfCloser(Node* focusedNode, const FocusCandidate& candidate, FocusCandidate& closest) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
346 |
{ |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
347 |
bool sameDocument = candidate.document() == closest.document(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
348 |
if (sameDocument) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
349 |
if (closest.alignment > candidate.alignment |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
350 |
|| (closest.parentAlignment && candidate.alignment > closest.parentAlignment)) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
351 |
return; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
352 |
} else if (closest.alignment > candidate.alignment |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
353 |
&& (closest.parentAlignment && candidate.alignment > closest.parentAlignment)) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
354 |
return; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
355 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
356 |
if (candidate.alignment != None |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
357 |
|| (closest.parentAlignment >= candidate.alignment |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
358 |
&& closest.document() == candidate.document())) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
359 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
360 |
// If we are now in an higher precedent case, lets reset the current closest's |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
361 |
// distance so we force it to be bigger than any result we will get from |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
362 |
// spatialDistance(). |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
363 |
if (closest.alignment < candidate.alignment |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
364 |
&& closest.parentAlignment < candidate.alignment) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
365 |
closest.distance = maxDistance(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
366 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
367 |
closest.alignment = candidate.alignment; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
368 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
369 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
370 |
// Bail out if candidate's distance is larger than that of the closest candidate. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
371 |
if (candidate.distance >= closest.distance) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
372 |
return; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
373 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
374 |
if (closest.isNull()) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
375 |
closest = candidate; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
376 |
return; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
377 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
378 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
379 |
// If the focused node and the candadate are in the same document and current |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
380 |
// closest candidate is not in an {i}frame that is preferable to get focused ... |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
381 |
if (focusedNode->document() == candidate.document() |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
382 |
&& candidate.distance < closest.parentDistance) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
383 |
closest = candidate; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
384 |
else if (focusedNode->document() != candidate.document()) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
385 |
// If the focusedNode is in an inner document and candidate is in a |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
386 |
// different document, we only consider to change focus if there is not |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
387 |
// another already good focusable candidate in the same document as focusedNode. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
388 |
if (!((isInRootDocument(candidate.node) && !isInRootDocument(focusedNode)) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
389 |
&& focusedNode->document() == closest.document())) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
390 |
closest = candidate; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
391 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
392 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
393 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
394 |
void FocusController::findFocusableNodeInDirection(Node* outer, Node* focusedNode, |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
395 |
FocusDirection direction, KeyboardEvent* event, |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
396 |
FocusCandidate& closestFocusCandidate, |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
397 |
const FocusCandidate& candidateParent) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
398 |
{ |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
399 |
ASSERT(outer); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
400 |
ASSERT(candidateParent.isNull() |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
401 |
|| candidateParent.node->hasTagName(frameTag) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
402 |
|| candidateParent.node->hasTagName(iframeTag)); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
403 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
404 |
// Walk all the child nodes and update closestFocusCandidate if we find a nearer node. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
405 |
Node* candidate = outer; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
406 |
while (candidate) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
407 |
// Inner documents case. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
408 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
409 |
if (candidate->isFrameOwnerElement()) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
410 |
deepFindFocusableNodeInDirection(candidate, focusedNode, direction, event, closestFocusCandidate); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
411 |
else if (candidate != focusedNode && candidate->isKeyboardFocusable(event)) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
412 |
FocusCandidate currentFocusCandidate(candidate); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
413 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
414 |
// Get distance and alignment from current candidate. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
415 |
distanceDataForNode(direction, focusedNode, currentFocusCandidate); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
416 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
417 |
// Bail out if distance is maximum. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
418 |
if (currentFocusCandidate.distance == maxDistance()) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
419 |
candidate = candidate->traverseNextNode(outer->parent()); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
420 |
continue; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
421 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
422 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
423 |
// If candidateParent is not null, it means that we are in a recursive call |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
424 |
// from deepFineFocusableNodeInDirection (i.e. processing an element in an iframe), |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
425 |
// and holds the distance and alignment data of the iframe element itself. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
426 |
if (!candidateParent.isNull()) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
427 |
currentFocusCandidate.parentAlignment = candidateParent.alignment; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
428 |
currentFocusCandidate.parentDistance = candidateParent.distance; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
429 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
430 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
431 |
updateFocusCandidateIfCloser(focusedNode, currentFocusCandidate, closestFocusCandidate); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
432 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
433 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
434 |
candidate = candidate->traverseNextNode(outer->parent()); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
435 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
436 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
437 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
438 |
void FocusController::deepFindFocusableNodeInDirection(Node* container, Node* focusedNode, |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
439 |
FocusDirection direction, KeyboardEvent* event, |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
440 |
FocusCandidate& closestFocusCandidate) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
441 |
{ |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
442 |
ASSERT(container->hasTagName(frameTag) || container->hasTagName(iframeTag)); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
443 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
444 |
// Track if focusedNode is a descendant of the current container node being processed. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
445 |
bool descendantOfContainer = false; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
446 |
Node* firstChild = 0; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
447 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
448 |
// Iframe or Frame. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
449 |
if (container->hasTagName(frameTag) || container->hasTagName(iframeTag)) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
450 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
451 |
HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(container); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
452 |
if (!owner->contentFrame()) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
453 |
return; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
454 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
455 |
Document* innerDocument = owner->contentFrame()->document(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
456 |
if (!innerDocument) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
457 |
return; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
458 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
459 |
descendantOfContainer = innerDocument == focusedNode->document(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
460 |
firstChild = innerDocument->firstChild(); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
461 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
462 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
463 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
464 |
if (descendantOfContainer) { |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
465 |
findFocusableNodeInDirection(firstChild, focusedNode, direction, event, closestFocusCandidate); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
466 |
return; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
467 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
468 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
469 |
// Check if the current container element itself is a good candidate |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
470 |
// to move focus to. If it is, then we traverse its inner nodes. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
471 |
FocusCandidate candidateParent = FocusCandidate(container); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
472 |
distanceDataForNode(direction, focusedNode, candidateParent); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
473 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
474 |
// Bail out if distance is maximum. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
475 |
if (candidateParent.distance == maxDistance()) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
476 |
return; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
477 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
478 |
// FIXME: Consider alignment? |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
479 |
if (candidateParent.distance < closestFocusCandidate.distance) |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
480 |
findFocusableNodeInDirection(firstChild, focusedNode, direction, event, closestFocusCandidate, candidateParent); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
481 |
} |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
482 |
|
0 | 483 |
static bool relinquishesEditingFocus(Node *node) |
484 |
{ |
|
485 |
ASSERT(node); |
|
486 |
ASSERT(node->isContentEditable()); |
|
487 |
||
488 |
Node* root = node->rootEditableElement(); |
|
489 |
Frame* frame = node->document()->frame(); |
|
490 |
if (!frame || !root) |
|
491 |
return false; |
|
492 |
||
493 |
return frame->editor()->shouldEndEditing(rangeOfContents(root).get()); |
|
494 |
} |
|
495 |
||
496 |
static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode) |
|
497 |
{ |
|
498 |
if (!oldFocusedFrame || !newFocusedFrame) |
|
499 |
return; |
|
500 |
||
501 |
if (oldFocusedFrame->document() != newFocusedFrame->document()) |
|
502 |
return; |
|
503 |
||
504 |
SelectionController* s = oldFocusedFrame->selection(); |
|
505 |
if (s->isNone()) |
|
506 |
return; |
|
507 |
||
508 |
bool caretBrowsing = oldFocusedFrame->settings()->caretBrowsingEnabled(); |
|
509 |
if (caretBrowsing) |
|
510 |
return; |
|
511 |
||
512 |
Node* selectionStartNode = s->selection().start().node(); |
|
513 |
if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode) |
|
514 |
return; |
|
515 |
||
516 |
if (Node* mousePressNode = newFocusedFrame->eventHandler()->mousePressNode()) |
|
517 |
if (mousePressNode->renderer() && !mousePressNode->canStartSelection()) |
|
518 |
if (Node* root = s->rootEditableElement()) |
|
519 |
if (Node* shadowAncestorNode = root->shadowAncestorNode()) |
|
520 |
// Don't do this for textareas and text fields, when they lose focus their selections should be cleared |
|
521 |
// and then restored when they regain focus, to match other browsers. |
|
522 |
if (!shadowAncestorNode->hasTagName(inputTag) && !shadowAncestorNode->hasTagName(textareaTag)) |
|
523 |
return; |
|
524 |
||
525 |
s->clear(); |
|
526 |
} |
|
527 |
||
528 |
bool FocusController::setFocusedNode(Node* node, PassRefPtr<Frame> newFocusedFrame) |
|
529 |
{ |
|
530 |
RefPtr<Frame> oldFocusedFrame = focusedFrame(); |
|
531 |
RefPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0; |
|
532 |
||
533 |
Node* oldFocusedNode = oldDocument ? oldDocument->focusedNode() : 0; |
|
534 |
if (oldFocusedNode == node) |
|
535 |
return true; |
|
536 |
||
537 |
// FIXME: Might want to disable this check for caretBrowsing |
|
538 |
if (oldFocusedNode && oldFocusedNode->rootEditableElement() == oldFocusedNode && !relinquishesEditingFocus(oldFocusedNode)) |
|
539 |
return false; |
|
540 |
||
541 |
clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), node); |
|
542 |
||
543 |
if (!node) { |
|
544 |
if (oldDocument) |
|
545 |
oldDocument->setFocusedNode(0); |
|
546 |
m_page->editorClient()->setInputMethodState(false); |
|
547 |
return true; |
|
548 |
} |
|
549 |
||
550 |
RefPtr<Document> newDocument = node->document(); |
|
551 |
||
552 |
if (newDocument && newDocument->focusedNode() == node) { |
|
553 |
m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod()); |
|
554 |
return true; |
|
555 |
} |
|
556 |
||
557 |
if (oldDocument && oldDocument != newDocument) |
|
558 |
oldDocument->setFocusedNode(0); |
|
559 |
||
560 |
setFocusedFrame(newFocusedFrame); |
|
561 |
||
562 |
if (newDocument) |
|
563 |
newDocument->setFocusedNode(node); |
|
564 |
||
565 |
m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod()); |
|
566 |
||
567 |
return true; |
|
568 |
} |
|
569 |
||
570 |
void FocusController::setActive(bool active) |
|
571 |
{ |
|
572 |
if (m_isActive == active) |
|
573 |
return; |
|
574 |
||
575 |
m_isActive = active; |
|
576 |
||
577 |
if (FrameView* view = m_page->mainFrame()->view()) { |
|
578 |
if (!view->platformWidget()) { |
|
579 |
view->layoutIfNeededRecursive(); |
|
580 |
view->updateControlTints(); |
|
581 |
} |
|
582 |
} |
|
583 |
||
584 |
focusedOrMainFrame()->selection()->pageActivationChanged(); |
|
585 |
||
586 |
if (m_focusedFrame && isFocused()) |
|
587 |
dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), active); |
|
588 |
} |
|
589 |
||
590 |
} // namespace WebCore |