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/. */
7 #ifndef nsFocusManager_h___
8 #define nsFocusManager_h___
10 #include "nsCycleCollectionParticipant.h"
11 #include "nsIContent.h"
12 #include "mozilla/dom/Document.h"
13 #include "nsIFocusManager.h"
14 #include "nsIObserver.h"
15 #include "nsWeakReference.h"
16 #include "mozilla/Attributes.h"
17 #include "mozilla/RefPtr.h"
18 #include "mozilla/StaticPtr.h"
20 #define FOCUSMANAGER_CONTRACTID "@mozilla.org/focus-manager;1"
23 class nsPIDOMWindowOuter
;
29 class HTMLAreaElement
;
35 } // namespace mozilla
37 struct nsDelayedBlurOrFocusEvent
;
40 * The focus manager keeps track of where the focus is, that is, the node
41 * which receives key events.
44 class nsFocusManager final
: public nsIFocusManager
,
46 public nsSupportsWeakReference
{
47 using InputContextAction
= mozilla::widget::InputContextAction
;
48 using Document
= mozilla::dom::Document
;
49 friend class mozilla::dom::ContentChild
;
50 friend class mozilla::dom::ContentParent
;
53 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFocusManager
, nsIFocusManager
)
54 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
56 NS_DECL_NSIFOCUSMANAGER
58 // called to initialize and stop the focus manager at startup and shutdown
59 static nsresult
Init();
60 static void Shutdown();
62 // Simple helper to call SetFocusedWindow on the instance.
64 // This raises the window and switches to the tab as needed.
65 MOZ_CAN_RUN_SCRIPT
static void FocusWindow(
66 nsPIDOMWindowOuter
* aWindow
, mozilla::dom::CallerType aCallerType
);
68 MOZ_CAN_RUN_SCRIPT_BOUNDARY
static void PrefChanged(const char* aPref
,
70 MOZ_CAN_RUN_SCRIPT
void PrefChanged(const char* aPref
);
73 * Retrieve the single focus manager.
75 static nsFocusManager
* GetFocusManager() { return sInstance
; }
78 * A faster version of nsIFocusManager::GetFocusedElement, returning a
79 * raw Element pointer (instead of having AddRef-ed Element
80 * pointer filled in to an out-parameter).
82 mozilla::dom::Element
* GetFocusedElement() { return mFocusedElement
; }
83 static mozilla::dom::Element
* GetFocusedElementStatic() {
84 return sInstance
? sInstance
->GetFocusedElement() : nullptr;
88 * Returns true if aContent currently has focus.
90 bool IsFocused(nsIContent
* aContent
);
93 * Returns true if test mode is enabled.
98 * Return a focused window. Version of nsIFocusManager::GetFocusedWindow.
100 nsPIDOMWindowOuter
* GetFocusedWindow() const { return mFocusedWindow
; }
103 * In the chrome process, retrieves the BrowsingContext corresponding
104 * to GetFocusedWindow(). In a content process, retrieves the
105 * focused BrowsingContext, which may not belong to this process.
107 mozilla::dom::BrowsingContext
* GetFocusedBrowsingContext() const {
108 if (XRE_IsParentProcess()) {
109 if (mFocusedWindow
) {
110 return mFocusedWindow
->GetBrowsingContext();
114 return mFocusedBrowsingContextInContent
;
118 * Returns whether the given browsing context is in the active window.
120 bool IsInActiveWindow(mozilla::dom::BrowsingContext
*) const;
123 * Return an active window. Version of nsIFocusManager::GetActiveWindow.
125 nsPIDOMWindowOuter
* GetActiveWindow() const { return mActiveWindow
; }
128 * In the chrome process, retrieves the BrowsingContext corresponding
129 * to GetActiveWindow(). In a content process, retrieves the
130 * BrowsingContext of the top-level Web content in the active tab if
131 * in the same process as the caller or nullptr otherwise.
133 mozilla::dom::BrowsingContext
* GetActiveBrowsingContext() const {
134 if (XRE_IsParentProcess()) {
136 return mActiveWindow
->GetBrowsingContext();
140 return mActiveBrowsingContextInContent
;
144 * Called when content has been removed.
146 MOZ_CAN_RUN_SCRIPT nsresult
ContentRemoved(Document
* aDocument
,
147 nsIContent
* aContent
);
149 void NeedsFlushBeforeEventHandling(mozilla::dom::Element
* aElement
) {
150 if (mFocusedElement
== aElement
) {
151 mEventHandlingNeedsFlush
= true;
155 bool CanSkipFocus(nsIContent
* aContent
);
157 MOZ_CAN_RUN_SCRIPT
void FlushBeforeEventHandlingIfNeeded(
158 nsIContent
* aContent
) {
159 if (mEventHandlingNeedsFlush
) {
160 nsCOMPtr
<Document
> doc
= aContent
->GetComposedDoc();
162 mEventHandlingNeedsFlush
= false;
163 doc
->FlushPendingNotifications(mozilla::FlushType::Layout
);
169 * Update the caret with current mode (whether in caret browsing mode or not).
171 MOZ_CAN_RUN_SCRIPT
void UpdateCaretForCaretBrowsingMode();
173 /** @see nsIFocusManager.getLastFocusMethod() */
174 uint32_t GetLastFocusMethod(nsPIDOMWindowOuter
*) const;
177 * Returns the content node that would be focused if aWindow was in an
178 * active window. This will traverse down the frame hierarchy, starting at
179 * the given window aWindow. Sets aFocusedWindow to the window with the
180 * document containing aFocusedContent. If no element is focused,
181 * aFocusedWindow may be still be set -- this means that the document is
182 * focused but no element within it is focused.
184 * aWindow, aFocusIsOutOfProcess, aFocusedWindow must all be non-null.
187 // Return focused content in aWindow. So, aFocusedWindow is always aWindow.
189 // Return focused content in aWindow or one of all sub windows.
190 eIncludeAllDescendants
,
191 // Return focused content in aWindow or one of visible sub windows.
192 eIncludeVisibleDescendants
,
194 static mozilla::dom::Element
* GetFocusedDescendant(
195 nsPIDOMWindowOuter
* aWindow
, SearchRange aSearchRange
,
196 nsPIDOMWindowOuter
** aFocusedWindow
);
199 * Helper function for MoveFocus which determines the next element
200 * to move the focus to and returns it in aNextContent.
202 * aWindow is the window to adjust the focus within, and aStart is
203 * the element to start navigation from. For tab key navigation,
204 * this should be the currently focused element.
206 * aType is the type passed to MoveFocus. If aNoParentTraversal is set,
207 * navigation is not done to parent documents and iteration returns to the
208 * beginning (or end) of the starting document.
210 * aNavigateByKey to move focus by keyboard as a side effect of computing the
213 MOZ_CAN_RUN_SCRIPT nsresult
DetermineElementToMoveFocus(
214 nsPIDOMWindowOuter
* aWindow
, nsIContent
* aStart
, int32_t aType
,
215 bool aNoParentTraversal
, bool aNavigateByKey
, nsIContent
** aNextContent
);
218 * Setter for focusedWindow with CallerType
220 MOZ_CAN_RUN_SCRIPT nsresult
SetFocusedWindowWithCallerType(
221 mozIDOMWindowProxy
* aWindowToFocus
, mozilla::dom::CallerType aCallerType
);
224 * Given an element, which must be the focused element, activate the remote
225 * frame it embeds, if any.
227 void ActivateRemoteFrameIfNeeded(mozilla::dom::Element
&, uint64_t aActionId
);
230 * Raises the top-level window aWindow at the widget level.
232 MOZ_CAN_RUN_SCRIPT
void RaiseWindow(nsPIDOMWindowOuter
* aWindow
,
233 mozilla::dom::CallerType aCallerType
,
237 * Called when a window has been raised.
239 MOZ_CAN_RUN_SCRIPT
void WindowRaised(mozIDOMWindowProxy
* aWindow
,
243 * Called when a window has been lowered.
245 MOZ_CAN_RUN_SCRIPT
void WindowLowered(mozIDOMWindowProxy
* aWindow
,
249 * Called when a new document in a window is shown.
251 * If aNeedsFocus is true, then focus events are expected to be fired on the
252 * window if this window is in the focused window chain.
254 MOZ_CAN_RUN_SCRIPT
void WindowShown(mozIDOMWindowProxy
* aWindow
,
258 * Called when a document in a window has been hidden or otherwise can no
259 * longer accept focus.
261 MOZ_CAN_RUN_SCRIPT
void WindowHidden(mozIDOMWindowProxy
* aWindow
,
265 * Fire any events that have been delayed due to synchronized actions.
267 MOZ_CAN_RUN_SCRIPT
void FireDelayedEvents(Document
* aDocument
);
269 void WasNuked(nsPIDOMWindowOuter
* aWindow
);
271 static uint32_t ProgrammaticFocusFlags(
272 const mozilla::dom::FocusOptions
& aOptions
);
275 * Returns an InputContextAction cause for aFlags.
277 static InputContextAction::Cause
GetFocusMoveActionCause(uint32_t aFlags
);
280 * Notify of re-focus to same element.
282 * aElement is focused element.
284 MOZ_CAN_RUN_SCRIPT
void NotifyOfReFocus(mozilla::dom::Element
& aElement
);
286 static void MarkUncollectableForCCGeneration(uint32_t aGeneration
);
288 struct BlurredElementInfo
{
289 const mozilla::OwningNonNull
<mozilla::dom::Element
> mElement
;
291 explicit BlurredElementInfo(mozilla::dom::Element
&);
292 ~BlurredElementInfo();
300 * Ensure that the widget associated with the currently focused window is
301 * focused at the widget level.
303 void EnsureCurrentWidgetFocused(mozilla::dom::CallerType aCallerType
);
306 * Activate or deactivate the window and send the activate/deactivate events.
308 void ActivateOrDeactivate(nsPIDOMWindowOuter
* aWindow
, bool aActive
);
311 * Blur whatever is currently focused and focus aNewContent. aFlags is a
312 * bitmask of the flags defined in nsIFocusManager. If aFocusChanged is
313 * true, then the focus has actually shifted and the caret position will be
314 * updated to the new focus, aNewContent will be scrolled into view (unless
315 * a flag disables this) and the focus method for the window will be updated.
316 * If aAdjustWidget is false, don't change the widget focus state.
318 * All actual focus changes must use this method to do so. (as opposed
319 * to those that update the focus in an inactive window for instance).
321 * Returns Nothing() if we end up not trying to focus the element,
322 * otherwise returns the generated action id.
324 MOZ_CAN_RUN_SCRIPT
mozilla::Maybe
<uint64_t> SetFocusInner(
325 mozilla::dom::Element
* aNewContent
, int32_t aFlags
, bool aFocusChanged
,
329 * Returns true if aPossibleAncestor is the same as aWindow or an
330 * ancestor of aWindow.
332 bool IsSameOrAncestor(nsPIDOMWindowOuter
* aPossibleAncestor
,
333 nsPIDOMWindowOuter
* aWindow
) const;
334 bool IsSameOrAncestor(nsPIDOMWindowOuter
* aPossibleAncestor
,
335 mozilla::dom::BrowsingContext
* aContext
) const;
336 bool IsSameOrAncestor(mozilla::dom::BrowsingContext
* aPossibleAncestor
,
337 nsPIDOMWindowOuter
* aWindow
) const;
340 bool IsSameOrAncestor(mozilla::dom::BrowsingContext
* aPossibleAncestor
,
341 mozilla::dom::BrowsingContext
* aContext
) const;
345 * Returns the window that is the lowest common ancestor of both aWindow
346 * and aContext, or null if they share no common ancestor.
348 mozilla::dom::BrowsingContext
* GetCommonAncestor(
349 nsPIDOMWindowOuter
* aWindow
, mozilla::dom::BrowsingContext
* aContext
);
352 * When aBrowsingContext is focused or blurred, adjust the ancestors of
353 * aBrowsingContext so that they also have their corresponding frames focused
354 * or blurred. Thus, one can start at the active top-level window and navigate
355 * down the currently focused elements for each frame in the tree to get to
358 MOZ_CAN_RUN_SCRIPT
bool AdjustInProcessWindowFocus(
359 mozilla::dom::BrowsingContext
* aBrowsingContext
, bool aCheckPermission
,
360 bool aIsVisible
, uint64_t aActionId
, bool aShouldClearAncestorFocus
,
361 mozilla::dom::BrowsingContext
* aAncestorBrowsingContextToFocus
);
363 MOZ_CAN_RUN_SCRIPT
void AdjustWindowFocus(
364 mozilla::dom::BrowsingContext
* aBrowsingContext
, bool aCheckPermission
,
365 bool aIsVisible
, uint64_t aActionId
, bool aShouldClearAncestorFocus
,
366 mozilla::dom::BrowsingContext
* aAncestorBrowsingContextToFocus
);
369 * Returns true if aWindow is visible.
371 bool IsWindowVisible(nsPIDOMWindowOuter
* aWindow
);
374 * Returns true if aContent is a root element and not focusable.
375 * I.e., even if aContent is editable root element, this returns true when
376 * the document is in designMode.
378 * @param aContent must not be null and must be in a document.
380 bool IsNonFocusableRoot(nsIContent
* aContent
);
383 * First flushes the pending notifications to ensure the PresShell and frames
385 * Checks and returns aElement if it may be focused, another element node if
386 * the focus should be retargeted at another node, or null if the node
387 * cannot be focused. aFlags are the flags passed to SetFocus and similar
390 * An element is focusable if it is in a document, the document isn't in
391 * print preview mode and the element has an nsIFrame where the
392 * IsFocusable method returns true. For <area> elements, there is no
393 * frame, so only the IsFocusable method on the content node must be
396 MOZ_CAN_RUN_SCRIPT
mozilla::dom::Element
* FlushAndCheckIfFocusable(
397 mozilla::dom::Element
* aElement
, uint32_t aFlags
);
400 * Blurs the currently focused element. Returns false if another element was
401 * focused as a result. This would mean that the caller should not proceed
402 * with a pending call to Focus. Normally, true would be returned.
404 * The currently focused element within aBrowsingContextToClear will be
405 * cleared. aBrowsingContextToClear may be null, which means that no window is
406 * cleared. This will be the case, for example, when lowering a window, as we
407 * want to fire a blur, but not actually change what element would be focused,
408 * so that the same element will be focused again when the window is raised.
410 * aAncestorBrowsingContextToFocus should be set to the common ancestor of the
411 * window that is being blurred and the window that is going to focused, when
412 * switching focus to a sibling window.
414 * aIsLeavingDocument should be set to true if the document/window is being
415 * blurred as well. Document/window blur events will be fired. It should be
416 * false if an element is the same document is about to be focused.
418 * If aAdjustWidget is false, don't change the widget focus state.
420 MOZ_CAN_RUN_SCRIPT
bool Blur(
421 mozilla::dom::BrowsingContext
* aBrowsingContextToClear
,
422 mozilla::dom::BrowsingContext
* aAncestorBrowsingContextToFocus
,
423 bool aIsLeavingDocument
, bool aAdjustWidget
, bool aRemainActive
,
424 uint64_t aActionId
, mozilla::dom::Element
* aElementToFocus
= nullptr);
425 MOZ_CAN_RUN_SCRIPT
void BlurFromOtherProcess(
426 mozilla::dom::BrowsingContext
* aFocusedBrowsingContext
,
427 mozilla::dom::BrowsingContext
* aBrowsingContextToClear
,
428 mozilla::dom::BrowsingContext
* aAncestorBrowsingContextToFocus
,
429 bool aIsLeavingDocument
, bool aAdjustWidget
, uint64_t aActionId
);
430 MOZ_CAN_RUN_SCRIPT
bool BlurImpl(
431 mozilla::dom::BrowsingContext
* aBrowsingContextToClear
,
432 mozilla::dom::BrowsingContext
* aAncestorBrowsingContextToFocus
,
433 bool aIsLeavingDocument
, bool aAdjustWidget
, bool aRemainActive
,
434 mozilla::dom::Element
* aElementToFocus
, uint64_t aActionId
);
437 * Focus an element in the active window and child frame.
439 * aWindow is the window containing the element aContent to focus.
441 * aFlags is the flags passed to the various focus methods in
444 * aIsNewDocument should be true if a new document is being focused.
445 * Document/window focus events will be fired.
447 * aFocusChanged should be true if a new content node is being focused, so
448 * the focused content will be scrolled into view and the caret position
449 * will be updated. If false is passed, then a window is simply being
450 * refocused, for instance, due to a window being raised, or a tab is being
453 * If aFocusChanged is true, then the focus has moved to a new location.
454 * Otherwise, the focus is just being updated because the window was
457 * aWindowRaised should be true if the window is being raised. In this case,
458 * command updaters will not be called.
460 * If aAdjustWidget is false, don't change the widget focus state.
462 MOZ_CAN_RUN_SCRIPT
void Focus(
463 nsPIDOMWindowOuter
* aWindow
, mozilla::dom::Element
* aContent
,
464 uint32_t aFlags
, bool aIsNewDocument
, bool aFocusChanged
,
465 bool aWindowRaised
, bool aAdjustWidget
, uint64_t aActionId
,
466 const mozilla::Maybe
<BlurredElementInfo
>& = mozilla::Nothing());
469 * Send a focus or blur event at aTarget. It may be added to the delayed
470 * event queue if the document is suppressing events.
472 * aEventMessage should be either eFocus or eBlur.
474 * aWindowRaised should only be true if called from WindowRaised.
476 MOZ_CAN_RUN_SCRIPT
void SendFocusOrBlurEvent(
477 mozilla::EventMessage aEventMessage
, mozilla::PresShell
* aPresShell
,
478 Document
* aDocument
, mozilla::dom::EventTarget
* aTarget
,
479 bool aWindowRaised
, bool aIsRefocus
= false,
480 mozilla::dom::EventTarget
* aRelatedTarget
= nullptr);
482 * Fire a focus or blur event at aTarget.
484 * aEventMessage should be either eFocus or eBlur.
485 * For blur events, aFocusMethod should normally be non-zero.
487 * aWindowRaised should only be true if called from WindowRaised.
489 MOZ_CAN_RUN_SCRIPT
void FireFocusOrBlurEvent(
490 mozilla::EventMessage aEventMessage
, mozilla::PresShell
* aPresShell
,
491 mozilla::dom::EventTarget
* aTarget
, bool aWindowRaised
,
492 bool aIsRefocus
= false,
493 mozilla::dom::EventTarget
* aRelatedTarget
= nullptr);
496 * Fire a focusin or focusout event
498 * aEventMessage should be either eFocusIn or eFocusOut.
500 * aTarget is the content the event will fire on (the object that gained
501 * focus for focusin, the object blurred for focusout).
503 * aCurrentFocusedWindow is the window focused before the focus/blur event
506 * aCurrentFocusedContent is the content focused before the focus/blur event
509 * aRelatedTarget is the content related to the event (the object
510 * losing focus for focusin, the object getting focus for focusout).
512 MOZ_CAN_RUN_SCRIPT
void FireFocusInOrOutEvent(
513 mozilla::EventMessage aEventMessage
, mozilla::PresShell
* aPresShell
,
514 mozilla::dom::EventTarget
* aTarget
,
515 nsPIDOMWindowOuter
* aCurrentFocusedWindow
,
516 nsIContent
* aCurrentFocusedContent
,
517 mozilla::dom::EventTarget
* aRelatedTarget
= nullptr);
520 * Scrolls aContent into view unless the FLAG_NOSCROLL flag is set.
523 void ScrollIntoView(mozilla::PresShell
* aPresShell
, nsIContent
* aContent
,
527 * Updates the caret positon and visibility to match the focus.
529 * aMoveCaretToFocus should be true to move the caret to aContent.
531 * aUpdateVisibility should be true to update whether the caret is
534 MOZ_CAN_RUN_SCRIPT
void UpdateCaret(bool aMoveCaretToFocus
,
535 bool aUpdateVisibility
,
536 nsIContent
* aContent
);
539 * Helper method to move the caret to the focused element aContent.
541 MOZ_CAN_RUN_SCRIPT
void MoveCaretToFocus(mozilla::PresShell
* aPresShell
,
542 nsIContent
* aContent
);
545 * Makes the caret visible or not, depending on aVisible.
547 nsresult
SetCaretVisible(mozilla::PresShell
* aPresShell
, bool aVisible
,
548 nsIContent
* aContent
);
550 // the remaining functions are used for tab key and document-navigation
553 * Retrieves the start and end points of the current selection for
554 * aDocument and stores them in aStartContent and aEndContent.
556 void GetSelectionLocation(Document
* aDocument
, mozilla::PresShell
* aPresShell
,
557 nsIContent
** aStartContent
,
558 nsIContent
** aEndContent
);
561 * Retrieve the next tabbable element in scope owned by aOwner, using
562 * focusability and tabindex to determine the tab order.
564 * aOwner is the owner of scope to search in.
566 * aStartContent is the starting point for this call of this method.
568 * aOriginalStartContent is the initial starting point for sequential
571 * aForward should be true for forward navigation or false for backward
574 * aCurrentTabIndex is the current tabindex.
576 * aIgnoreTabIndex to ignore the current tabindex and find the element
577 * irrespective or the tab index.
579 * aForDocumentNavigation informs whether we're navigating only through
582 * aSkipOwner to skip owner while searching. The flag is set when caller is
583 * |GetNextTabbableContent| in order to let caller handle owner.
585 * aReachedToEndForDocumentNavigation is true when this is a document
586 * navigation and the focus algorithm has reached to the end of the top-level
590 * Consider the method searches downwards in flattened subtree
593 MOZ_CAN_RUN_SCRIPT nsIContent
* GetNextTabbableContentInScope(
594 nsIContent
* aOwner
, nsIContent
* aStartContent
,
595 nsIContent
* aOriginalStartContent
, bool aForward
,
596 int32_t aCurrentTabIndex
, bool aIgnoreTabIndex
,
597 bool aForDocumentNavigation
, bool aNavigateByKey
, bool aSkipOwner
,
598 bool aReachedToEndForDocumentNavigation
);
601 * Retrieve the next tabbable element in scope including aStartContent
602 * and the scope's ancestor scopes, using focusability and tabindex to
603 * determine the tab order.
605 * aStartOwner is the scope owner of the aStartContent.
607 * aStartContent an in/out paremeter. It as input is the starting point
608 * for this call of this method; as output it is the shadow host in
609 * light DOM if the next tabbable element is not found in shadow DOM,
610 * in order to continue searching in light DOM.
612 * aOriginalStartContent is the initial starting point for sequential
615 * aForward should be true for forward navigation or false for backward
618 * aCurrentTabIndex returns tab index of shadow host in light DOM if the
619 * next tabbable element is not found in shadow DOM, in order to continue
620 * searching in light DOM.
622 * aIgnoreTabIndex to ignore the current tabindex and find the element
623 * irrespective or the tab index.
625 * aForDocumentNavigation informs whether we're navigating only through
628 * aNavigateByKey to move focus by keyboard as a side effect of computing the
631 * aReachedToEndForDocumentNavigation is true when this is a document
632 * navigation and the focus algorithm has reached to the end of the top-level
636 * Consider the method searches upwards in all shadow host- or slot-rooted
637 * flattened subtrees that contains aStartContent as non-root, except
638 * the flattened subtree rooted at shadow host in light DOM.
640 MOZ_CAN_RUN_SCRIPT nsIContent
* GetNextTabbableContentInAncestorScopes(
641 nsIContent
* aStartOwner
, nsCOMPtr
<nsIContent
>& aStartContent
/* inout */,
642 nsIContent
* aOriginalStartContent
, bool aForward
,
643 int32_t* aCurrentTabIndex
, bool* aIgnoreTabIndex
,
644 bool aForDocumentNavigation
, bool aNavigateByKey
,
645 bool aReachedToEndForDocumentNavigation
);
648 * Retrieve the next tabbable element within a document, using focusability
649 * and tabindex to determine the tab order. The element is returned in
652 * aRootContent is the root node -- nodes above this will not be examined.
653 * Typically this will be the root node of a document, but could also be
656 * aOriginalStartContent is the content which was originally the starting
657 * node, in the case of recursive or looping calls.
659 * aStartContent is the starting point for this call of this method.
660 * If aStartContent doesn't have visual representation, the next content
661 * object, which does have a primary frame, will be used as a start.
662 * If that content object is focusable, the method may return it.
664 * aForward should be true for forward navigation or false for backward
667 * aCurrentTabIndex is the current tabindex.
669 * aIgnoreTabIndex to ignore the current tabindex and find the element
670 * irrespective or the tab index. This will be true when a selection is
671 * active, since we just want to focus the next element in tree order
672 * from where the selection is. Similarly, if the starting element isn't
673 * focusable, since it doesn't really have a defined tab index.
675 * aSkipPopover should be true to avoid an invoker triggering to step into
676 * the popover that was already been visited again.
678 * aNavigateByKey to move focus by keyboard as a side effect of computing the
681 * aReachedToEndForDocumentNavigation is true when this is a document
682 * navigation and the focus algorithm has reached to the end of the top-level
685 MOZ_CAN_RUN_SCRIPT nsresult
GetNextTabbableContent(
686 mozilla::PresShell
* aPresShell
, nsIContent
* aRootContent
,
687 nsIContent
* aOriginalStartContent
, nsIContent
* aStartContent
,
688 bool aForward
, int32_t aCurrentTabIndex
, bool aIgnoreTabIndex
,
689 bool aForDocumentNavigation
, bool aNavigateByKey
, bool aSkipPopover
,
690 bool aReachedToEndForDocumentNavigation
, nsIContent
** aResultContent
);
693 * Get the next tabbable image map area and returns it.
695 * aForward should be true for forward navigation or false for backward
698 * aCurrentTabIndex is the current tabindex.
700 * aImageContent is the image.
702 * aStartContent is the current image map area.
704 nsIContent
* GetNextTabbableMapArea(bool aForward
, int32_t aCurrentTabIndex
,
705 mozilla::dom::Element
* aImageContent
,
706 nsIContent
* aStartContent
);
709 * Return the next valid tabindex value after aCurrentTabIndex, if aForward
710 * is true, or the previous tabindex value if aForward is false. aParent is
711 * the node from which to start looking for tab indicies.
713 int32_t GetNextTabIndex(nsIContent
* aParent
, int32_t aCurrentTabIndex
,
717 * Focus the first focusable content within the document with a root node of
718 * aRootContent. For content documents, this will be aRootContent itself, but
719 * for chrome documents, this will locate the next focusable content.
721 * aReachedToEndForDocumentNavigation is true when the focus algorithm has
722 * reached to the end of the top-level document.
724 MOZ_CAN_RUN_SCRIPT nsresult
725 FocusFirst(mozilla::dom::Element
* aRootContent
, nsIContent
** aNextContent
,
726 bool aReachedToEndForDocumentNavigation
);
729 * Retrieves and returns the root node from aDocument to be focused. Will
730 * return null if the root node cannot be focused. There are several reasons
733 * - if aForDocumentNavigation is false and aWindow is a chrome shell.
734 * - if aCheckVisibility is true and the aWindow is not visible.
735 * - if aDocument is a frameset document.
737 mozilla::dom::Element
* GetRootForFocus(nsPIDOMWindowOuter
* aWindow
,
739 bool aForDocumentNavigation
,
740 bool aCheckVisibility
);
743 * Retrieves and returns the root node as with GetRootForFocus but only if
744 * aContent is a frame with a valid child document.
746 mozilla::dom::Element
* GetRootForChildDocument(nsIContent
* aContent
);
749 * Retreives a focusable element within the current selection of aWindow.
750 * Currently, this only detects links.
752 * This is used when MoveFocus is called with a type of MOVEFOCUS_CARET,
753 * which is used, for example, to focus links as the caret is moved over
756 void GetFocusInSelection(nsPIDOMWindowOuter
* aWindow
,
757 nsIContent
* aStartSelection
,
758 nsIContent
* aEndSelection
,
759 nsIContent
** aFocusedContent
);
762 // Notify that the focus state of aElement has changed. Note that we need to
763 // pass in whether the window should show a focus ring before the
764 // SetFocusedNode call on it happened when losing focus and after the
765 // SetFocusedNode call when gaining focus, which is why that information needs
766 // to be an explicit argument instead of just passing in the window and asking
767 // it whether it should show focus rings: in the losing focus case that
768 // information could be wrong.
770 // aShouldShowFocusRing is only relevant if aGettingFocus is true.
771 static void NotifyFocusStateChange(mozilla::dom::Element
* aElement
,
772 mozilla::dom::Element
* aElementToFocus
,
773 int32_t aFlags
, bool aGettingFocus
,
774 bool aShouldShowFocusRing
);
776 void SetFocusedWindowInternal(nsPIDOMWindowOuter
* aWindow
, uint64_t aActionId
,
777 bool aSyncBrowsingContext
= true);
779 MOZ_CAN_RUN_SCRIPT
bool TryDocumentNavigation(nsIContent
* aCurrentContent
,
780 bool* aCheckSubDocument
,
781 nsIContent
** aResultContent
);
783 MOZ_CAN_RUN_SCRIPT
bool TryToMoveFocusToSubDocument(
784 nsIContent
* aCurrentContent
, nsIContent
* aOriginalStartContent
,
785 bool aForward
, bool aForDocumentNavigation
, bool aNavigateByKey
,
786 bool aReachedToEndForDocumentNavigation
, nsIContent
** aResultContent
);
788 // Sets the focused BrowsingContext and, if appropriate, syncs it to
790 void SetFocusedBrowsingContext(mozilla::dom::BrowsingContext
* aContext
,
794 // Called when receiving an IPC message about another process setting
795 // the focused BrowsingContext.
796 void SetFocusedBrowsingContextFromOtherProcess(
797 mozilla::dom::BrowsingContext
* aContext
, uint64_t aActionId
);
800 // When returning true, sets the chrome process notion of what
801 // BrowsingContext is focused in content. When returning false,
802 // ignores the attempt to set as out-of-sequence.
803 bool SetFocusedBrowsingContextInChrome(
804 mozilla::dom::BrowsingContext
* aContext
, uint64_t aActionId
);
806 void InsertNewFocusActionId(uint64_t aActionId
);
808 bool ProcessPendingActiveBrowsingContextActionId(uint64_t aActionId
,
809 bool aSettingToNonNull
);
811 bool ProcessPendingFocusedBrowsingContextActionId(uint64_t aActionId
);
815 // Gets the chrome process notion of what BrowsingContext is focused
817 mozilla::dom::BrowsingContext
* GetFocusedBrowsingContextInChrome();
820 // Notifies the focus manager that BrowsingContext::Detach was called
821 // on a BrowsingContext so that pointers to it can be forgotten.
822 void BrowsingContextDetached(mozilla::dom::BrowsingContext
* aContext
);
826 // Sets the BrowsingContext corresponding to top-level Web content
827 // in the frontmost tab if focus is in Web content.
828 void SetActiveBrowsingContextInContent(
829 mozilla::dom::BrowsingContext
* aContext
, uint64_t aActionId
);
832 // Receives notification of another process setting the top-level Web
833 // content as being in the frontmost tab with focus in Web content.
834 void SetActiveBrowsingContextFromOtherProcess(
835 mozilla::dom::BrowsingContext
* aContext
, uint64_t aActionId
);
838 // Receives notification that another process determined that focus
839 // moved to chrome so a particular BrowsingContext is no longer the
841 void UnsetActiveBrowsingContextFromOtherProcess(
842 mozilla::dom::BrowsingContext
* aContext
, uint64_t aActionId
);
845 // Receives a notification from parent that this content process's
846 // attempt to set the active browsing context was late and the
847 // prevailing browsing context is instead the second argument of
848 // this method call. This should be ignored if the first argument
849 // doesn't match the latest action id associated with setting the
850 // active browsing context in this process, because in that case,
851 // this revision is late.
852 void ReviseActiveBrowsingContext(uint64_t aOldActionId
,
853 mozilla::dom::BrowsingContext
* aContext
,
854 uint64_t aNewActionId
);
856 // Receives a notification from parent that this content process's
857 // attempt to set the focused browsing context was late and the
858 // prevailing browsing context is instead the second argument of
859 // this method call. This should be ignored if the first argument
860 // doesn't match the latest action id associated with setting the
861 // active browsing context in this process, because in that case,
862 // this revision is late.
863 void ReviseFocusedBrowsingContext(uint64_t aOldActionId
,
864 mozilla::dom::BrowsingContext
* aContext
,
865 uint64_t aNewActionId
);
868 // Sets the chrome process notion of what content believes to be
869 // the top-level BrowsingContext in the frontmost tab when focus
870 // is in Web content.
871 // Returns true if set and false if ignored.
872 bool SetActiveBrowsingContextInChrome(mozilla::dom::BrowsingContext
* aContext
,
877 // Gets the chrome process notion of what content believes to be
878 // the top-level BrowsingContext in the frontmost tab when focus
879 // is in Web content.
880 mozilla::dom::BrowsingContext
* GetActiveBrowsingContextInChrome();
882 uint64_t GetActionIdForActiveBrowsingContextInChrome() const;
884 uint64_t GetActionIdForFocusedBrowsingContextInChrome() const;
886 static uint64_t GenerateFocusActionId();
888 // This function works very similar to
889 // https://html.spec.whatwg.org/#get-the-focusable-area
890 static mozilla::dom::Element
* GetTheFocusableArea(
891 mozilla::dom::Element
* aTarget
, uint32_t aFlags
);
893 // Returns true if it's an area element with one or more shapes that are
895 static bool IsAreaElementFocusable(mozilla::dom::HTMLAreaElement
& aArea
);
898 // In the chrome process, the currently active and front-most top-most
899 // window. Not supposed to be used in a meaningful way in content
900 // processes. For legacy reasons, this exists as a separate field
901 // instead of being derived from mFocusedWindow when needed, because
902 // the defined relation that mActiveWindow is supposed to be the same
903 // as or ancestor of mFocusedWindow is temporarily broken when a
904 // window is being raised or lowered.
905 nsCOMPtr
<nsPIDOMWindowOuter
> mActiveWindow
;
907 // In a content process, the BrowsingContext corresponding to top-level
908 // Web content in the active tab or nullptr if focus is not in a
909 // BrowsingContextGroup that this process participates in. Synced
910 // across processes in a BrowsingContextGroup. This field exists
911 // separately from mFocusedBrowsingContextInContent instead of being being
912 // derived from it, because for legacy reasons the relation
913 // mFocusedBrowsingContextInContent->Top() == mActiveBrowsingContextInContent
914 // is temporarily broken when a window is being raised or lowered.
915 // Not supposed to be used in a meaningful way in the chrome process.
916 RefPtr
<mozilla::dom::BrowsingContext
> mActiveBrowsingContextInContent
;
918 // If this content process set mActiveBrowsingContextInContent, this
919 // field holds the corresponding actionId so that
920 // mActiveBrowsingContextInContent can be revised of the parent rejects
921 // the update. This field is used for accepting revisions only if nothing
922 // else has updated mActiveBrowsingContextInContent before the revision
924 uint64_t mActionIdForActiveBrowsingContextInContent
;
926 uint64_t mActionIdForActiveBrowsingContextInChrome
;
928 // If this content process set mFocusedBrowsingContextInContent, this
929 // field holds the corresponding actionId so that
930 // mFocusedBrowsingContextInContent can be revised of the parent rejects
931 // the update. This field is used for accepting revisions only if nothing
932 // else has updated mFocusedBrowsingContextInContent before the revision
934 uint64_t mActionIdForFocusedBrowsingContextInContent
;
936 uint64_t mActionIdForFocusedBrowsingContextInChrome
;
938 // Whether or not mActiveBrowsingContextInContent was set from another process
939 // or from this process.
940 bool mActiveBrowsingContextInContentSetFromOtherProcess
;
942 // This is the chrome process notion of content's
943 // mActiveBrowsingContextInContent. Avoiding field reuse for different
944 // semantics in different process types to make it easier to catch bugs.
945 RefPtr
<mozilla::dom::BrowsingContext
> mActiveBrowsingContextInChrome
;
947 // the child or top-level window that is currently focused. In the chrome
948 // process, when a window isn't being raised or lowered, this window will
949 // either be the same window as mActiveWindow or a descendant of it.
950 // Except during shutdown use SetFocusedWindowInternal to set mFocusedWindow!
951 nsCOMPtr
<nsPIDOMWindowOuter
> mFocusedWindow
;
953 // The focused BrowsingContext if this is a chrome process and focus is
954 // in chrome or if this is a content process and focus is in Web content
955 // in this BrowsingContextGroup. nullptr otherwise.
956 // Except during shutdown, must be set via SetFocusedWindowInternal which
957 // calls SetFocusedBrowsingContext or if the value is coming in via IPC
958 // via SetFocusedBrowsingContextFromOtherProcess.
959 RefPtr
<mozilla::dom::BrowsingContext
> mFocusedBrowsingContextInContent
;
961 // This is the chrome process notion of content's
962 // mFocusedBrowsingContextInContent. Avoiding field reuse for different
963 // semantics in different process types to make it easier to catch bugs.
964 RefPtr
<mozilla::dom::BrowsingContext
> mFocusedBrowsingContextInChrome
;
966 // the currently focused content if in-process or the XUL browser in which
967 // Web content focus resides. Always inside mFocusedWindow. When a window
968 // isn't being raised or lowered, this is a cached copy of the
969 // mFocusedWindow's current content. This may be null if no content is
971 RefPtr
<mozilla::dom::Element
> mFocusedElement
;
973 // these fields store a content node temporarily while it is being focused
974 // or blurred to ensure that a recursive call doesn't refire the same event.
975 // They will always be cleared afterwards.
976 RefPtr
<mozilla::dom::Element
> mFirstBlurEvent
;
977 RefPtr
<mozilla::dom::Element
> mFirstFocusEvent
;
979 // keep track of a window while it is being lowered
980 nsCOMPtr
<nsPIDOMWindowOuter
> mWindowBeingLowered
;
982 // synchronized actions cannot be interrupted with events, so queue these up
983 // and fire them later.
984 nsTArray
<nsDelayedBlurOrFocusEvent
> mDelayedBlurFocusEvents
;
986 // Array of focus action ids for which we haven't seen an active browsing
987 // context set yet. As set is allowed to overwrite an unset. Therefore,
988 // an unset removes earlier ids but not the matching id. A set removes
989 // earlier ids and the matching id.
991 // Conceptually, active browsing context shouldn't have to exist as a
992 // field, because it should be possible to always derive it from the
993 // focused browsing context. Unfortunately, for legacy reasons, this
994 // is not the case while a window is being raised or lowered.
996 // Conceptually, it should be possible for the parent to manage the
997 // active browsing context. Unfortunately, for legacy reasons, the
998 // code for setting the active browsing context needs to reside in
999 // the content process to retain the existing and test-passing code
1002 // This, obviously, raises the issue of content processes racing to
1003 // set the active browsing context. In particular, there is a pattern
1004 // that the parent initiates actions that cause multiple content
1005 // processes to mutate the active browsing context at almost the
1006 // same time. When two native browser windows change order, the
1007 // lowering isn't distinguished from the case of lowering the
1008 // entire app. For this reason, the owner of the previous active
1009 // browsing context tries to unset it and at almost the same time
1010 // the another content process sets a new active browsing context.
1011 // If the IPC messages for these unset and set actions were to
1012 // arrive in the wrong order, this could get in the wrong state.
1014 // To address this issue, the parent manages an authortative order
1015 // of attempts to (un)set the active browsing context using the
1016 // array mPendingActiveBrowsingContextActions.
1018 // A process reserves a slot in the order by calling
1019 // GenerateFocusActionId(). Per one call to GenerateFocusActionId(),
1020 // there may be at most one action to set the active browsing context
1021 // to a new value. There may be logically prior attempts to unset it
1022 // (i.e. set it to nullptr). That is, if there are both attempts to
1023 // unset and set the active browsing context with the same action id,
1024 // the attempt to set to a non-null value wins.
1026 // The completion of an action from reserting the slot in the order
1027 // and actually performing the setting of the active browsing context
1028 // may span multiple processes and IPC messages.
1030 // The at-most-once property is not asserted, because the process
1031 // claiming the position in the order and the process setting the
1032 // active browsing context with that actionId may be different, and
1033 // the act of using an actionId to set the active browsing context
1034 // is used to delete stale items from the array to avoid excessive
1035 // growth of the array.
1036 nsTArray
<uint64_t> mPendingActiveBrowsingContextActions
;
1038 // Like mPendingActiveBrowsingContextActions but for the focused
1039 // browsing context.
1040 nsTArray
<uint64_t> mPendingFocusedBrowsingContextActions
;
1042 // If set to true, layout of the document of the event target should be
1043 // flushed before handling focus depending events.
1044 bool mEventHandlingNeedsFlush
;
1046 static bool sTestMode
;
1048 // Process-specific counter for maintaining the prosess-specific
1049 // uniqueness of actionIds.
1050 static uint64_t sFocusActionCounter
;
1052 // the single focus manager
1053 static mozilla::StaticRefPtr
<nsFocusManager
> sInstance
;
1056 nsresult
NS_NewFocusManager(nsIFocusManager
** aResult
);