/src/mozilla-central/dom/base/nsFocusManager.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef nsFocusManager_h___ |
8 | | #define nsFocusManager_h___ |
9 | | |
10 | | #include "nsCycleCollectionParticipant.h" |
11 | | #include "nsIContent.h" |
12 | | #include "nsIDocument.h" |
13 | | #include "nsIFocusManager.h" |
14 | | #include "nsIObserver.h" |
15 | | #include "nsIWidget.h" |
16 | | #include "nsWeakReference.h" |
17 | | #include "mozilla/Attributes.h" |
18 | | #include "mozilla/RefPtr.h" |
19 | | |
20 | 0 | #define FOCUSMETHOD_MASK 0xF000 |
21 | 0 | #define FOCUSMETHODANDRING_MASK 0xF0F000 |
22 | | |
23 | 0 | #define FOCUSMANAGER_CONTRACTID "@mozilla.org/focus-manager;1" |
24 | | |
25 | | class nsIContent; |
26 | | class nsIDocShellTreeItem; |
27 | | class nsPIDOMWindowOuter; |
28 | | |
29 | | namespace mozilla { |
30 | | namespace dom { |
31 | | class Element; |
32 | | class TabParent; |
33 | | } |
34 | | } |
35 | | |
36 | | struct nsDelayedBlurOrFocusEvent; |
37 | | |
38 | | /** |
39 | | * The focus manager keeps track of where the focus is, that is, the node |
40 | | * which receives key events. |
41 | | */ |
42 | | |
43 | | class nsFocusManager final : public nsIFocusManager, |
44 | | public nsIObserver, |
45 | | public nsSupportsWeakReference |
46 | | { |
47 | | typedef mozilla::widget::InputContextAction InputContextAction; |
48 | | |
49 | | public: |
50 | | |
51 | | NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFocusManager, nsIFocusManager) |
52 | | NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
53 | | NS_DECL_NSIOBSERVER |
54 | | NS_DECL_NSIFOCUSMANAGER |
55 | | |
56 | | // called to initialize and stop the focus manager at startup and shutdown |
57 | | static nsresult Init(); |
58 | | static void Shutdown(); |
59 | | |
60 | | void PrefChanged(const char* aPref); |
61 | | |
62 | | /** |
63 | | * Retrieve the single focus manager. |
64 | | */ |
65 | 0 | static nsFocusManager* GetFocusManager() { return sInstance; } |
66 | | |
67 | | /** |
68 | | * A faster version of nsIFocusManager::GetFocusedElement, returning a |
69 | | * raw Element pointer (instead of having AddRef-ed Element |
70 | | * pointer filled in to an out-parameter). |
71 | | */ |
72 | 0 | mozilla::dom::Element* GetFocusedElement() { return mFocusedElement; } |
73 | | |
74 | | /** |
75 | | * Returns true if aContent currently has focus. |
76 | | */ |
77 | | bool IsFocused(nsIContent* aContent); |
78 | | |
79 | | /** |
80 | | * Returns true if test mode is enabled. |
81 | | */ |
82 | | bool IsTestMode(); |
83 | | |
84 | | /** |
85 | | * Return a focused window. Version of nsIFocusManager::GetFocusedWindow. |
86 | | */ |
87 | 0 | nsPIDOMWindowOuter* GetFocusedWindow() const { return mFocusedWindow; } |
88 | | |
89 | | /** |
90 | | * Return an active window. Version of nsIFocusManager::GetActiveWindow. |
91 | | */ |
92 | 0 | nsPIDOMWindowOuter* GetActiveWindow() const { return mActiveWindow; } |
93 | | |
94 | | /** |
95 | | * Called when content has been removed. |
96 | | */ |
97 | | nsresult ContentRemoved(nsIDocument* aDocument, nsIContent* aContent); |
98 | | |
99 | | /** |
100 | | * Called when mouse button event handling is started and finished. |
101 | | */ |
102 | | already_AddRefed<nsIDocument> |
103 | | SetMouseButtonHandlingDocument(nsIDocument* aDocument) |
104 | 0 | { |
105 | 0 | nsCOMPtr<nsIDocument> handlingDocument = mMouseButtonEventHandlingDocument; |
106 | 0 | mMouseButtonEventHandlingDocument = aDocument; |
107 | 0 | return handlingDocument.forget(); |
108 | 0 | } |
109 | | |
110 | | void NeedsFlushBeforeEventHandling(mozilla::dom::Element* aElement) |
111 | 0 | { |
112 | 0 | if (mFocusedElement == aElement) { |
113 | 0 | mEventHandlingNeedsFlush = true; |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | bool CanSkipFocus(nsIContent* aContent); |
118 | | |
119 | | void FlushBeforeEventHandlingIfNeeded(nsIContent* aContent) |
120 | 0 | { |
121 | 0 | if (mEventHandlingNeedsFlush) { |
122 | 0 | nsCOMPtr<nsIDocument> doc = aContent->GetComposedDoc(); |
123 | 0 | if (doc) { |
124 | 0 | mEventHandlingNeedsFlush = false; |
125 | 0 | doc->FlushPendingNotifications(mozilla::FlushType::Layout); |
126 | 0 | } |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | | /** |
131 | | * Update the caret with current mode (whether in caret browsing mode or not). |
132 | | */ |
133 | | void UpdateCaretForCaretBrowsingMode(); |
134 | | |
135 | | /** |
136 | | * Returns the content node that would be focused if aWindow was in an |
137 | | * active window. This will traverse down the frame hierarchy, starting at |
138 | | * the given window aWindow. Sets aFocusedWindow to the window with the |
139 | | * document containing aFocusedContent. If no element is focused, |
140 | | * aFocusedWindow may be still be set -- this means that the document is |
141 | | * focused but no element within it is focused. |
142 | | * |
143 | | * aWindow and aFocusedWindow must both be non-null. |
144 | | */ |
145 | | enum SearchRange |
146 | | { |
147 | | // Return focused content in aWindow. So, aFocusedWindow is always aWindow. |
148 | | eOnlyCurrentWindow, |
149 | | // Return focused content in aWindow or one of all sub windows. |
150 | | eIncludeAllDescendants, |
151 | | // Return focused content in aWindow or one of visible sub windows. |
152 | | eIncludeVisibleDescendants, |
153 | | }; |
154 | | static mozilla::dom::Element* |
155 | | GetFocusedDescendant(nsPIDOMWindowOuter* aWindow, |
156 | | SearchRange aSearchRange, |
157 | | nsPIDOMWindowOuter** aFocusedWindow); |
158 | | |
159 | | /** |
160 | | * Returns the content node that focus will be redirected to if aContent was |
161 | | * focused. This is used for the special case of certain XUL elements such |
162 | | * as textboxes or input number which redirect focus to an anonymous child. |
163 | | * |
164 | | * aContent must be non-null. |
165 | | * |
166 | | * XXXndeakin this should be removed eventually but I want to do that as |
167 | | * followup work. |
168 | | */ |
169 | | static mozilla::dom::Element* GetRedirectedFocus(nsIContent* aContent); |
170 | | |
171 | | /** |
172 | | * Returns an InputContextAction cause for aFlags. |
173 | | */ |
174 | | static InputContextAction::Cause GetFocusMoveActionCause(uint32_t aFlags); |
175 | | |
176 | | static bool sMouseFocusesFormControl; |
177 | | |
178 | | static void MarkUncollectableForCCGeneration(uint32_t aGeneration); |
179 | | protected: |
180 | | |
181 | | nsFocusManager(); |
182 | | ~nsFocusManager(); |
183 | | |
184 | | /** |
185 | | * Ensure that the widget associated with the currently focused window is |
186 | | * focused at the widget level. |
187 | | */ |
188 | | void EnsureCurrentWidgetFocused(); |
189 | | |
190 | | /** |
191 | | * Activate or deactivate the window and send the activate/deactivate events. |
192 | | */ |
193 | | void ActivateOrDeactivate(nsPIDOMWindowOuter* aWindow, bool aActive); |
194 | | |
195 | | /** |
196 | | * Blur whatever is currently focused and focus aNewContent. aFlags is a |
197 | | * bitmask of the flags defined in nsIFocusManager. If aFocusChanged is |
198 | | * true, then the focus has actually shifted and the caret position will be |
199 | | * updated to the new focus, aNewContent will be scrolled into view (unless |
200 | | * a flag disables this) and the focus method for the window will be updated. |
201 | | * If aAdjustWidget is false, don't change the widget focus state. |
202 | | * |
203 | | * All actual focus changes must use this method to do so. (as opposed |
204 | | * to those that update the focus in an inactive window for instance). |
205 | | */ |
206 | | void SetFocusInner(mozilla::dom::Element* aNewContent, int32_t aFlags, |
207 | | bool aFocusChanged, bool aAdjustWidget); |
208 | | |
209 | | /** |
210 | | * Returns true if aPossibleAncestor is the same as aWindow or an |
211 | | * ancestor of aWindow. |
212 | | */ |
213 | | bool IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor, |
214 | | nsPIDOMWindowOuter* aWindow); |
215 | | |
216 | | /** |
217 | | * Returns the window that is the lowest common ancestor of both aWindow1 |
218 | | * and aWindow2, or null if they share no common ancestor. |
219 | | */ |
220 | | already_AddRefed<nsPIDOMWindowOuter> |
221 | | GetCommonAncestor(nsPIDOMWindowOuter* aWindow1, nsPIDOMWindowOuter* aWindow2); |
222 | | |
223 | | /** |
224 | | * When aNewWindow is focused, adjust the ancestors of aNewWindow so that they |
225 | | * also have their corresponding frames focused. Thus, one can start at |
226 | | * the active top-level window and navigate down the currently focused |
227 | | * elements for each frame in the tree to get to aNewWindow. |
228 | | */ |
229 | | void AdjustWindowFocus(nsPIDOMWindowOuter* aNewWindow, bool aCheckPermission); |
230 | | |
231 | | /** |
232 | | * Returns true if aWindow is visible. |
233 | | */ |
234 | | bool IsWindowVisible(nsPIDOMWindowOuter* aWindow); |
235 | | |
236 | | /** |
237 | | * Returns true if aContent is a root element and not focusable. |
238 | | * I.e., even if aContent is editable root element, this returns true when |
239 | | * the document is in designMode. |
240 | | * |
241 | | * @param aContent must not be null and must be in a document. |
242 | | */ |
243 | | bool IsNonFocusableRoot(nsIContent* aContent); |
244 | | |
245 | | /** |
246 | | * Checks and returns aContent if it may be focused, another content node if |
247 | | * the focus should be retargeted at another node, or null if the node |
248 | | * cannot be focused. aFlags are the flags passed to SetFocus and similar |
249 | | * methods. |
250 | | * |
251 | | * An element is focusable if it is in a document, the document isn't in |
252 | | * print preview mode and the element has an nsIFrame where the |
253 | | * CheckIfFocusable method returns true. For <area> elements, there is no |
254 | | * frame, so only the IsFocusable method on the content node must be |
255 | | * true. |
256 | | */ |
257 | | mozilla::dom::Element* CheckIfFocusable(mozilla::dom::Element* aContent, |
258 | | uint32_t aFlags); |
259 | | |
260 | | /** |
261 | | * Blurs the currently focused element. Returns false if another element was |
262 | | * focused as a result. This would mean that the caller should not proceed |
263 | | * with a pending call to Focus. Normally, true would be returned. |
264 | | * |
265 | | * The currently focused element within aWindowToClear will be cleared. |
266 | | * aWindowToClear may be null, which means that no window is cleared. This |
267 | | * will be the case, for example, when lowering a window, as we want to fire |
268 | | * a blur, but not actually change what element would be focused, so that |
269 | | * the same element will be focused again when the window is raised. |
270 | | * |
271 | | * aAncestorWindowToFocus should be set to the common ancestor of the window |
272 | | * that is being blurred and the window that is going to focused, when |
273 | | * switching focus to a sibling window. |
274 | | * |
275 | | * aIsLeavingDocument should be set to true if the document/window is being |
276 | | * blurred as well. Document/window blur events will be fired. It should be |
277 | | * false if an element is the same document is about to be focused. |
278 | | * |
279 | | * If aAdjustWidget is false, don't change the widget focus state. |
280 | | */ |
281 | | // MOZ_CAN_RUN_SCRIPT_BOUNDARY for now, until we annotate callers. |
282 | | MOZ_CAN_RUN_SCRIPT_BOUNDARY |
283 | | bool Blur(nsPIDOMWindowOuter* aWindowToClear, |
284 | | nsPIDOMWindowOuter* aAncestorWindowToFocus, |
285 | | bool aIsLeavingDocument, |
286 | | bool aAdjustWidget, |
287 | | nsIContent* aContentToFocus = nullptr); |
288 | | |
289 | | /** |
290 | | * Focus an element in the active window and child frame. |
291 | | * |
292 | | * aWindow is the window containing the element aContent to focus. |
293 | | * |
294 | | * aFlags is the flags passed to the various focus methods in |
295 | | * nsIFocusManager. |
296 | | * |
297 | | * aIsNewDocument should be true if a new document is being focused. |
298 | | * Document/window focus events will be fired. |
299 | | * |
300 | | * aFocusChanged should be true if a new content node is being focused, so |
301 | | * the focused content will be scrolled into view and the caret position |
302 | | * will be updated. If false is passed, then a window is simply being |
303 | | * refocused, for instance, due to a window being raised, or a tab is being |
304 | | * switched to. |
305 | | * |
306 | | * If aFocusChanged is true, then the focus has moved to a new location. |
307 | | * Otherwise, the focus is just being updated because the window was |
308 | | * raised. |
309 | | * |
310 | | * aWindowRaised should be true if the window is being raised. In this case, |
311 | | * command updaters will not be called. |
312 | | * |
313 | | * If aAdjustWidget is false, don't change the widget focus state. |
314 | | */ |
315 | | void Focus(nsPIDOMWindowOuter* aWindow, |
316 | | mozilla::dom::Element* aContent, |
317 | | uint32_t aFlags, |
318 | | bool aIsNewDocument, |
319 | | bool aFocusChanged, |
320 | | bool aWindowRaised, |
321 | | bool aAdjustWidget, |
322 | | nsIContent* aContentLostFocus = nullptr); |
323 | | |
324 | | /** |
325 | | * Send a focus or blur event at aTarget. It may be added to the delayed |
326 | | * event queue if the document is suppressing events. |
327 | | * |
328 | | * aEventMessage should be either eFocus or eBlur. |
329 | | * For blur events, aFocusMethod should normally be non-zero. |
330 | | * |
331 | | * aWindowRaised should only be true if called from WindowRaised. |
332 | | */ |
333 | | void SendFocusOrBlurEvent(mozilla::EventMessage aEventMessage, |
334 | | nsIPresShell* aPresShell, |
335 | | nsIDocument* aDocument, |
336 | | nsISupports* aTarget, |
337 | | uint32_t aFocusMethod, |
338 | | bool aWindowRaised, |
339 | | bool aIsRefocus = false, |
340 | | mozilla::dom::EventTarget* aRelatedTarget = nullptr); |
341 | | |
342 | | /** |
343 | | * Fire a focus or blur event at aTarget. |
344 | | * |
345 | | * aEventMessage should be either eFocus or eBlur. |
346 | | * For blur events, aFocusMethod should normally be non-zero. |
347 | | * |
348 | | * aWindowRaised should only be true if called from WindowRaised. |
349 | | */ |
350 | | void FireFocusOrBlurEvent(mozilla::EventMessage aEventMessage, |
351 | | nsIPresShell* aPresShell, |
352 | | nsISupports* aTarget, |
353 | | bool aWindowRaised, |
354 | | bool aIsRefocus = false, |
355 | | mozilla::dom::EventTarget* aRelatedTarget = nullptr); |
356 | | |
357 | | /** |
358 | | * Fire a focusin or focusout event |
359 | | * |
360 | | * aEventMessage should be either eFocusIn or eFocusOut. |
361 | | * |
362 | | * aTarget is the content the event will fire on (the object that gained |
363 | | * focus for focusin, the object blurred for focusout). |
364 | | * |
365 | | * aCurrentFocusedWindow is the window focused before the focus/blur event |
366 | | * was fired. |
367 | | * |
368 | | * aCurrentFocusedContent is the content focused before the focus/blur event |
369 | | * was fired. |
370 | | * |
371 | | * aRelatedTarget is the content related to the event (the object |
372 | | * losing focus for focusin, the object getting focus for focusout). |
373 | | */ |
374 | | void FireFocusInOrOutEvent(mozilla::EventMessage aEventMessage, |
375 | | nsIPresShell* aPresShell, |
376 | | nsISupports* aTarget, |
377 | | nsPIDOMWindowOuter* aCurrentFocusedWindow, |
378 | | nsIContent* aCurrentFocusedContent, |
379 | | mozilla::dom::EventTarget* aRelatedTarget = nullptr); |
380 | | |
381 | | /** |
382 | | * Scrolls aContent into view unless the FLAG_NOSCROLL flag is set. |
383 | | */ |
384 | | void ScrollIntoView(nsIPresShell* aPresShell, |
385 | | nsIContent* aContent, |
386 | | uint32_t aFlags); |
387 | | |
388 | | /** |
389 | | * Raises the top-level window aWindow at the widget level. |
390 | | */ |
391 | | void RaiseWindow(nsPIDOMWindowOuter* aWindow); |
392 | | |
393 | | /** |
394 | | * Updates the caret positon and visibility to match the focus. |
395 | | * |
396 | | * aMoveCaretToFocus should be true to move the caret to aContent. |
397 | | * |
398 | | * aUpdateVisibility should be true to update whether the caret is |
399 | | * visible or not. |
400 | | */ |
401 | | void UpdateCaret(bool aMoveCaretToFocus, |
402 | | bool aUpdateVisibility, |
403 | | nsIContent* aContent); |
404 | | |
405 | | /** |
406 | | * Helper method to move the caret to the focused element aContent. |
407 | | */ |
408 | | void MoveCaretToFocus(nsIPresShell* aPresShell, nsIContent* aContent); |
409 | | |
410 | | /** |
411 | | * Makes the caret visible or not, depending on aVisible. |
412 | | */ |
413 | | nsresult SetCaretVisible(nsIPresShell* aPresShell, |
414 | | bool aVisible, |
415 | | nsIContent* aContent); |
416 | | |
417 | | |
418 | | // the remaining functions are used for tab key and document-navigation |
419 | | |
420 | | /** |
421 | | * Retrieves the start and end points of the current selection for |
422 | | * aDocument and stores them in aStartContent and aEndContent. |
423 | | */ |
424 | | nsresult GetSelectionLocation(nsIDocument* aDocument, |
425 | | nsIPresShell* aPresShell, |
426 | | nsIContent **aStartContent, |
427 | | nsIContent **aEndContent); |
428 | | |
429 | | /** |
430 | | * Helper function for MoveFocus which determines the next element |
431 | | * to move the focus to and returns it in aNextContent. |
432 | | * |
433 | | * aWindow is the window to adjust the focus within, and aStart is |
434 | | * the element to start navigation from. For tab key navigation, |
435 | | * this should be the currently focused element. |
436 | | * |
437 | | * aType is the type passed to MoveFocus. If aNoParentTraversal is set, |
438 | | * navigation is not done to parent documents and iteration returns to the |
439 | | * beginning (or end) of the starting document. |
440 | | */ |
441 | | nsresult DetermineElementToMoveFocus(nsPIDOMWindowOuter* aWindow, |
442 | | nsIContent* aStart, |
443 | | int32_t aType, bool aNoParentTraversal, |
444 | | nsIContent** aNextContent); |
445 | | |
446 | | /** |
447 | | * Returns scope owner of aContent. |
448 | | * A scope owner is either a document root, shadow host, or slot. |
449 | | */ |
450 | | nsIContent* FindOwner(nsIContent* aContent); |
451 | | |
452 | | /** |
453 | | * Returns true if aContent is a shadow host or slot |
454 | | */ |
455 | | bool IsHostOrSlot(nsIContent* aContent); |
456 | | |
457 | | /** |
458 | | * Host and Slot elements need to be handled as if they had tabindex 0 even |
459 | | * when they don't have the attribute. This is a helper method to get the right |
460 | | * value for focus navigation. |
461 | | * If aIsFocusable is passed, it is set to true if the element itself is |
462 | | * focusable. |
463 | | */ |
464 | | int32_t HostOrSlotTabIndexValue(nsIContent* aContent, |
465 | | bool* aIsFocusable = nullptr); |
466 | | |
467 | | /** |
468 | | * Retrieve the next tabbable element in scope owned by aOwner, using |
469 | | * focusability and tabindex to determine the tab order. |
470 | | * |
471 | | * aOwner is the owner of scope to search in. |
472 | | * |
473 | | * aStartContent is the starting point for this call of this method. |
474 | | * |
475 | | * aOriginalStartContent is the initial starting point for sequential |
476 | | * navigation. |
477 | | * |
478 | | * aForward should be true for forward navigation or false for backward |
479 | | * navigation. |
480 | | * |
481 | | * aCurrentTabIndex is the current tabindex. |
482 | | * |
483 | | * aIgnoreTabIndex to ignore the current tabindex and find the element |
484 | | * irrespective or the tab index. |
485 | | * |
486 | | * aForDocumentNavigation informs whether we're navigating only through |
487 | | * documents. |
488 | | * |
489 | | * aSkipOwner to skip owner while searching. The flag is set when caller is |
490 | | * |GetNextTabbableContent| in order to let caller handle owner. |
491 | | * |
492 | | * NOTE: |
493 | | * Consider the method searches downwards in flattened subtree |
494 | | * rooted at aOwner. |
495 | | */ |
496 | | nsIContent* GetNextTabbableContentInScope(nsIContent* aOwner, |
497 | | nsIContent* aStartContent, |
498 | | nsIContent* aOriginalStartContent, |
499 | | bool aForward, |
500 | | int32_t aCurrentTabIndex, |
501 | | bool aIgnoreTabIndex, |
502 | | bool aForDocumentNavigation, |
503 | | bool aSkipOwner); |
504 | | |
505 | | /** |
506 | | * Retrieve the next tabbable element in scope including aStartContent |
507 | | * and the scope's ancestor scopes, using focusability and tabindex to |
508 | | * determine the tab order. |
509 | | * |
510 | | * aStartContent an in/out paremeter. It as input is the starting point |
511 | | * for this call of this method; as output it is the shadow host in |
512 | | * light DOM if the next tabbable element is not found in shadow DOM, |
513 | | * in order to continue searching in light DOM. |
514 | | * |
515 | | * aOriginalStartContent is the initial starting point for sequential |
516 | | * navigation. |
517 | | * |
518 | | * aForward should be true for forward navigation or false for backward |
519 | | * navigation. |
520 | | * |
521 | | * aCurrentTabIndex returns tab index of shadow host in light DOM if the |
522 | | * next tabbable element is not found in shadow DOM, in order to continue |
523 | | * searching in light DOM. |
524 | | * |
525 | | * aIgnoreTabIndex to ignore the current tabindex and find the element |
526 | | * irrespective or the tab index. |
527 | | * |
528 | | * aForDocumentNavigation informs whether we're navigating only through |
529 | | * documents. |
530 | | * |
531 | | * NOTE: |
532 | | * Consider the method searches upwards in all shadow host- or slot-rooted |
533 | | * flattened subtrees that contains aStartContent as non-root, except |
534 | | * the flattened subtree rooted at shadow host in light DOM. |
535 | | */ |
536 | | nsIContent* GetNextTabbableContentInAncestorScopes(nsIContent** aStartContent, |
537 | | nsIContent* aOriginalStartContent, |
538 | | bool aForward, |
539 | | int32_t* aCurrentTabIndex, |
540 | | bool aIgnoreTabIndex, |
541 | | bool aForDocumentNavigation); |
542 | | |
543 | | /** |
544 | | * Retrieve the next tabbable element within a document, using focusability |
545 | | * and tabindex to determine the tab order. The element is returned in |
546 | | * aResultContent. |
547 | | * |
548 | | * aRootContent is the root node -- nodes above this will not be examined. |
549 | | * Typically this will be the root node of a document, but could also be |
550 | | * a popup node. |
551 | | * |
552 | | * aOriginalStartContent is the content which was originally the starting |
553 | | * node, in the case of recursive or looping calls. |
554 | | * |
555 | | * aStartContent is the starting point for this call of this method. |
556 | | * If aStartContent doesn't have visual representation, the next content |
557 | | * object, which does have a primary frame, will be used as a start. |
558 | | * If that content object is focusable, the method may return it. |
559 | | * |
560 | | * aForward should be true for forward navigation or false for backward |
561 | | * navigation. |
562 | | * |
563 | | * aCurrentTabIndex is the current tabindex. |
564 | | * |
565 | | * aIgnoreTabIndex to ignore the current tabindex and find the element |
566 | | * irrespective or the tab index. This will be true when a selection is |
567 | | * active, since we just want to focus the next element in tree order |
568 | | * from where the selection is. Similarly, if the starting element isn't |
569 | | * focusable, since it doesn't really have a defined tab index. |
570 | | */ |
571 | | nsresult GetNextTabbableContent(nsIPresShell* aPresShell, |
572 | | nsIContent* aRootContent, |
573 | | nsIContent* aOriginalStartContent, |
574 | | nsIContent* aStartContent, |
575 | | bool aForward, |
576 | | int32_t aCurrentTabIndex, |
577 | | bool aIgnoreTabIndex, |
578 | | bool aForDocumentNavigation, |
579 | | nsIContent** aResultContent); |
580 | | |
581 | | /** |
582 | | * Get the next tabbable image map area and returns it. |
583 | | * |
584 | | * aForward should be true for forward navigation or false for backward |
585 | | * navigation. |
586 | | * |
587 | | * aCurrentTabIndex is the current tabindex. |
588 | | * |
589 | | * aImageContent is the image. |
590 | | * |
591 | | * aStartContent is the current image map area. |
592 | | */ |
593 | | nsIContent* GetNextTabbableMapArea(bool aForward, |
594 | | int32_t aCurrentTabIndex, |
595 | | mozilla::dom::Element* aImageContent, |
596 | | nsIContent* aStartContent); |
597 | | |
598 | | /** |
599 | | * Return the next valid tabindex value after aCurrentTabIndex, if aForward |
600 | | * is true, or the previous tabindex value if aForward is false. aParent is |
601 | | * the node from which to start looking for tab indicies. |
602 | | */ |
603 | | int32_t GetNextTabIndex(nsIContent* aParent, |
604 | | int32_t aCurrentTabIndex, |
605 | | bool aForward); |
606 | | |
607 | | /** |
608 | | * Focus the first focusable content within the document with a root node of |
609 | | * aRootContent. For content documents, this will be aRootContent itself, but |
610 | | * for chrome documents, this will locate the next focusable content. |
611 | | */ |
612 | | nsresult FocusFirst(mozilla::dom::Element* aRootContent, nsIContent** aNextContent); |
613 | | |
614 | | /** |
615 | | * Retrieves and returns the root node from aDocument to be focused. Will |
616 | | * return null if the root node cannot be focused. There are several reasons |
617 | | * for this: |
618 | | * |
619 | | * - if aForDocumentNavigation is false and aWindow is a chrome shell. |
620 | | * - if aCheckVisibility is true and the aWindow is not visible. |
621 | | * - if aDocument is a frameset document. |
622 | | */ |
623 | | mozilla::dom::Element* GetRootForFocus(nsPIDOMWindowOuter* aWindow, |
624 | | nsIDocument* aDocument, |
625 | | bool aForDocumentNavigation, |
626 | | bool aCheckVisibility); |
627 | | |
628 | | /** |
629 | | * Retrieves and returns the root node as with GetRootForFocus but only if |
630 | | * aContent is a frame with a valid child document. |
631 | | */ |
632 | | mozilla::dom::Element* GetRootForChildDocument(nsIContent* aContent); |
633 | | |
634 | | /** |
635 | | * Retreives a focusable element within the current selection of aWindow. |
636 | | * Currently, this only detects links. |
637 | | * |
638 | | * This is used when MoveFocus is called with a type of MOVEFOCUS_CARET, |
639 | | * which is used, for example, to focus links as the caret is moved over |
640 | | * them. |
641 | | */ |
642 | | void GetFocusInSelection(nsPIDOMWindowOuter* aWindow, |
643 | | nsIContent* aStartSelection, |
644 | | nsIContent* aEndSelection, |
645 | | nsIContent** aFocusedContent); |
646 | | |
647 | | private: |
648 | | // Notify that the focus state of aContent has changed. Note that |
649 | | // we need to pass in whether the window should show a focus ring |
650 | | // before the SetFocusedNode call on it happened when losing focus |
651 | | // and after the SetFocusedNode call when gaining focus, which is |
652 | | // why that information needs to be an explicit argument instead of |
653 | | // just passing in the window and asking it whether it should show |
654 | | // focus rings: in the losing focus case that information could be |
655 | | // wrong.. |
656 | | static void NotifyFocusStateChange(nsIContent* aContent, |
657 | | nsIContent* aContentToFocus, |
658 | | bool aWindowShouldShowFocusRing, |
659 | | bool aGettingFocus); |
660 | | |
661 | | void SetFocusedWindowInternal(nsPIDOMWindowOuter* aWindow); |
662 | | |
663 | | bool TryDocumentNavigation(nsIContent* aCurrentContent, |
664 | | bool* aCheckSubDocument, |
665 | | nsIContent** aResultContent); |
666 | | |
667 | | bool TryToMoveFocusToSubDocument(nsIContent* aCurrentContent, |
668 | | nsIContent* aOriginalStartContent, |
669 | | bool aForward, |
670 | | bool aForDocumentNavigation, |
671 | | nsIContent** aResultContent); |
672 | | |
673 | | // the currently active and front-most top-most window |
674 | | nsCOMPtr<nsPIDOMWindowOuter> mActiveWindow; |
675 | | |
676 | | // the child or top-level window that is currently focused. This window will |
677 | | // either be the same window as mActiveWindow or a descendant of it. |
678 | | // Except during shutdown use SetFocusedWindowInternal to set mFocusedWindow! |
679 | | nsCOMPtr<nsPIDOMWindowOuter> mFocusedWindow; |
680 | | |
681 | | // the currently focused content, which is always inside mFocusedWindow. This |
682 | | // is a cached copy of the mFocusedWindow's current content. This may be null |
683 | | // if no content is focused. |
684 | | RefPtr<mozilla::dom::Element> mFocusedElement; |
685 | | |
686 | | // these fields store a content node temporarily while it is being focused |
687 | | // or blurred to ensure that a recursive call doesn't refire the same event. |
688 | | // They will always be cleared afterwards. |
689 | | nsCOMPtr<nsIContent> mFirstBlurEvent; |
690 | | nsCOMPtr<nsIContent> mFirstFocusEvent; |
691 | | |
692 | | // keep track of a window while it is being lowered |
693 | | nsCOMPtr<nsPIDOMWindowOuter> mWindowBeingLowered; |
694 | | |
695 | | // synchronized actions cannot be interrupted with events, so queue these up |
696 | | // and fire them later. |
697 | | nsTArray<nsDelayedBlurOrFocusEvent> mDelayedBlurFocusEvents; |
698 | | |
699 | | // A document which is handling a mouse button event. |
700 | | // When a mouse down event process is finished, ESM sets focus to the target |
701 | | // content if it's not consumed. Therefore, while DOM event handlers are |
702 | | // handling mouse down events or preceding mosue down event is consumed but |
703 | | // handling mouse up events, they should be able to steal focus from any |
704 | | // elements even if focus is in chrome content. So, if this isn't nullptr |
705 | | // and the caller can access the document node, the caller should succeed in |
706 | | // moving focus. |
707 | | nsCOMPtr<nsIDocument> mMouseButtonEventHandlingDocument; |
708 | | |
709 | | // If set to true, layout of the document of the event target should be |
710 | | // flushed before handling focus depending events. |
711 | | bool mEventHandlingNeedsFlush; |
712 | | |
713 | | static bool sTestMode; |
714 | | |
715 | | // the single focus manager |
716 | | static nsFocusManager* sInstance; |
717 | | }; |
718 | | |
719 | | nsresult |
720 | | NS_NewFocusManager(nsIFocusManager** aResult); |
721 | | |
722 | | #endif |