Bug 1850713: remove duplicated setting of early hint preloader id in `ScriptLoader...
[gecko.git] / dom / base / nsFocusManager.h
blob9309bde0d6b79bce8c15ca4152954b0f3261c4a6
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"
22 class nsIContent;
23 class nsPIDOMWindowOuter;
25 namespace mozilla {
26 class PresShell;
27 namespace dom {
28 class Element;
29 struct FocusOptions;
30 class BrowserParent;
31 class ContentChild;
32 class ContentParent;
33 } // namespace dom
34 } // namespace mozilla
36 struct nsDelayedBlurOrFocusEvent;
38 /**
39 * The focus manager keeps track of where the focus is, that is, the node
40 * which receives key events.
43 class nsFocusManager final : public nsIFocusManager,
44 public nsIObserver,
45 public nsSupportsWeakReference {
46 using InputContextAction = mozilla::widget::InputContextAction;
47 using Document = mozilla::dom::Document;
48 friend class mozilla::dom::ContentChild;
49 friend class mozilla::dom::ContentParent;
51 public:
52 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFocusManager, nsIFocusManager)
53 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
54 NS_DECL_NSIOBSERVER
55 NS_DECL_NSIFOCUSMANAGER
57 // called to initialize and stop the focus manager at startup and shutdown
58 static nsresult Init();
59 static void Shutdown();
61 // Simple helper to call SetFocusedWindow on the instance.
63 // This raises the window and switches to the tab as needed.
64 MOZ_CAN_RUN_SCRIPT static void FocusWindow(
65 nsPIDOMWindowOuter* aWindow, mozilla::dom::CallerType aCallerType);
67 MOZ_CAN_RUN_SCRIPT_BOUNDARY static void PrefChanged(const char* aPref,
68 void* aSelf);
69 MOZ_CAN_RUN_SCRIPT void PrefChanged(const char* aPref);
71 /**
72 * Retrieve the single focus manager.
74 static nsFocusManager* GetFocusManager() { return sInstance; }
76 /**
77 * A faster version of nsIFocusManager::GetFocusedElement, returning a
78 * raw Element pointer (instead of having AddRef-ed Element
79 * pointer filled in to an out-parameter).
81 mozilla::dom::Element* GetFocusedElement() { return mFocusedElement; }
82 static mozilla::dom::Element* GetFocusedElementStatic() {
83 return sInstance ? sInstance->GetFocusedElement() : nullptr;
86 /**
87 * Returns true if aContent currently has focus.
89 bool IsFocused(nsIContent* aContent);
91 /**
92 * Returns true if test mode is enabled.
94 bool IsTestMode();
96 /**
97 * Return a focused window. Version of nsIFocusManager::GetFocusedWindow.
99 nsPIDOMWindowOuter* GetFocusedWindow() const { return mFocusedWindow; }
102 * In the chrome process, retrieves the BrowsingContext corresponding
103 * to GetFocusedWindow(). In a content process, retrieves the
104 * focused BrowsingContext, which may not belong to this process.
106 mozilla::dom::BrowsingContext* GetFocusedBrowsingContext() const {
107 if (XRE_IsParentProcess()) {
108 if (mFocusedWindow) {
109 return mFocusedWindow->GetBrowsingContext();
111 return nullptr;
113 return mFocusedBrowsingContextInContent;
117 * Returns whether the given browsing context is in the active window.
119 bool IsInActiveWindow(mozilla::dom::BrowsingContext*) const;
122 * Return an active window. Version of nsIFocusManager::GetActiveWindow.
124 nsPIDOMWindowOuter* GetActiveWindow() const { return mActiveWindow; }
127 * In the chrome process, retrieves the BrowsingContext corresponding
128 * to GetActiveWindow(). In a content process, retrieves the
129 * BrowsingContext of the top-level Web content in the active tab if
130 * in the same process as the caller or nullptr otherwise.
132 mozilla::dom::BrowsingContext* GetActiveBrowsingContext() const {
133 if (XRE_IsParentProcess()) {
134 if (mActiveWindow) {
135 return mActiveWindow->GetBrowsingContext();
137 return nullptr;
139 return mActiveBrowsingContextInContent;
143 * Called when content has been removed.
145 MOZ_CAN_RUN_SCRIPT nsresult ContentRemoved(Document* aDocument,
146 nsIContent* aContent);
148 void NeedsFlushBeforeEventHandling(mozilla::dom::Element* aElement) {
149 if (mFocusedElement == aElement) {
150 mEventHandlingNeedsFlush = true;
154 bool CanSkipFocus(nsIContent* aContent);
156 MOZ_CAN_RUN_SCRIPT void FlushBeforeEventHandlingIfNeeded(
157 nsIContent* aContent) {
158 if (mEventHandlingNeedsFlush) {
159 nsCOMPtr<Document> doc = aContent->GetComposedDoc();
160 if (doc) {
161 mEventHandlingNeedsFlush = false;
162 doc->FlushPendingNotifications(mozilla::FlushType::Layout);
168 * Update the caret with current mode (whether in caret browsing mode or not).
170 MOZ_CAN_RUN_SCRIPT void UpdateCaretForCaretBrowsingMode();
172 /** @see nsIFocusManager.getLastFocusMethod() */
173 uint32_t GetLastFocusMethod(nsPIDOMWindowOuter*) const;
176 * Returns the content node that would be focused if aWindow was in an
177 * active window. This will traverse down the frame hierarchy, starting at
178 * the given window aWindow. Sets aFocusedWindow to the window with the
179 * document containing aFocusedContent. If no element is focused,
180 * aFocusedWindow may be still be set -- this means that the document is
181 * focused but no element within it is focused.
183 * aWindow, aFocusIsOutOfProcess, aFocusedWindow must all be non-null.
185 enum SearchRange {
186 // Return focused content in aWindow. So, aFocusedWindow is always aWindow.
187 eOnlyCurrentWindow,
188 // Return focused content in aWindow or one of all sub windows.
189 eIncludeAllDescendants,
190 // Return focused content in aWindow or one of visible sub windows.
191 eIncludeVisibleDescendants,
193 static mozilla::dom::Element* GetFocusedDescendant(
194 nsPIDOMWindowOuter* aWindow, SearchRange aSearchRange,
195 nsPIDOMWindowOuter** aFocusedWindow);
198 * Helper function for MoveFocus which determines the next element
199 * to move the focus to and returns it in aNextContent.
201 * aWindow is the window to adjust the focus within, and aStart is
202 * the element to start navigation from. For tab key navigation,
203 * this should be the currently focused element.
205 * aType is the type passed to MoveFocus. If aNoParentTraversal is set,
206 * navigation is not done to parent documents and iteration returns to the
207 * beginning (or end) of the starting document.
209 * aNavigateByKey to move focus by keyboard as a side effect of computing the
210 * next target.
212 MOZ_CAN_RUN_SCRIPT nsresult DetermineElementToMoveFocus(
213 nsPIDOMWindowOuter* aWindow, nsIContent* aStart, int32_t aType,
214 bool aNoParentTraversal, bool aNavigateByKey, nsIContent** aNextContent);
217 * Setter for focusedWindow with CallerType
219 MOZ_CAN_RUN_SCRIPT nsresult SetFocusedWindowWithCallerType(
220 mozIDOMWindowProxy* aWindowToFocus, mozilla::dom::CallerType aCallerType);
223 * Given an element, which must be the focused element, activate the remote
224 * frame it embeds, if any.
226 void ActivateRemoteFrameIfNeeded(mozilla::dom::Element&, uint64_t aActionId);
229 * Raises the top-level window aWindow at the widget level.
231 MOZ_CAN_RUN_SCRIPT void RaiseWindow(nsPIDOMWindowOuter* aWindow,
232 mozilla::dom::CallerType aCallerType,
233 uint64_t aActionId);
236 * Called when a window has been raised.
238 MOZ_CAN_RUN_SCRIPT void WindowRaised(mozIDOMWindowProxy* aWindow,
239 uint64_t aActionId);
242 * Called when a window has been lowered.
244 MOZ_CAN_RUN_SCRIPT void WindowLowered(mozIDOMWindowProxy* aWindow,
245 uint64_t aActionId);
248 * Called when a new document in a window is shown.
250 * If aNeedsFocus is true, then focus events are expected to be fired on the
251 * window if this window is in the focused window chain.
253 MOZ_CAN_RUN_SCRIPT void WindowShown(mozIDOMWindowProxy* aWindow,
254 bool aNeedsFocus);
257 * Called when a document in a window has been hidden or otherwise can no
258 * longer accept focus.
260 MOZ_CAN_RUN_SCRIPT void WindowHidden(mozIDOMWindowProxy* aWindow,
261 uint64_t aActionId);
264 * Fire any events that have been delayed due to synchronized actions.
266 MOZ_CAN_RUN_SCRIPT void FireDelayedEvents(Document* aDocument);
268 void WasNuked(nsPIDOMWindowOuter* aWindow);
270 static uint32_t ProgrammaticFocusFlags(
271 const mozilla::dom::FocusOptions& aOptions);
274 * Returns an InputContextAction cause for aFlags.
276 static InputContextAction::Cause GetFocusMoveActionCause(uint32_t aFlags);
279 * Notify of re-focus to same element.
281 * aElement is focused element.
283 MOZ_CAN_RUN_SCRIPT void NotifyOfReFocus(mozilla::dom::Element& aElement);
285 static void MarkUncollectableForCCGeneration(uint32_t aGeneration);
287 struct BlurredElementInfo {
288 const mozilla::OwningNonNull<mozilla::dom::Element> mElement;
290 explicit BlurredElementInfo(mozilla::dom::Element&);
291 ~BlurredElementInfo();
294 protected:
295 nsFocusManager();
296 ~nsFocusManager();
299 * Ensure that the widget associated with the currently focused window is
300 * focused at the widget level.
302 void EnsureCurrentWidgetFocused(mozilla::dom::CallerType aCallerType);
305 * Activate or deactivate the window and send the activate/deactivate events.
307 void ActivateOrDeactivate(nsPIDOMWindowOuter* aWindow, bool aActive);
310 * Blur whatever is currently focused and focus aNewContent. aFlags is a
311 * bitmask of the flags defined in nsIFocusManager. If aFocusChanged is
312 * true, then the focus has actually shifted and the caret position will be
313 * updated to the new focus, aNewContent will be scrolled into view (unless
314 * a flag disables this) and the focus method for the window will be updated.
315 * If aAdjustWidget is false, don't change the widget focus state.
317 * All actual focus changes must use this method to do so. (as opposed
318 * to those that update the focus in an inactive window for instance).
320 * Returns Nothing() if we end up not trying to focus the element,
321 * otherwise returns the generated action id.
323 MOZ_CAN_RUN_SCRIPT mozilla::Maybe<uint64_t> SetFocusInner(
324 mozilla::dom::Element* aNewContent, int32_t aFlags, bool aFocusChanged,
325 bool aAdjustWidget);
328 * Returns true if aPossibleAncestor is the same as aWindow or an
329 * ancestor of aWindow.
331 bool IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor,
332 nsPIDOMWindowOuter* aWindow) const;
333 bool IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor,
334 mozilla::dom::BrowsingContext* aContext) const;
335 bool IsSameOrAncestor(mozilla::dom::BrowsingContext* aPossibleAncestor,
336 nsPIDOMWindowOuter* aWindow) const;
338 public:
339 bool IsSameOrAncestor(mozilla::dom::BrowsingContext* aPossibleAncestor,
340 mozilla::dom::BrowsingContext* aContext) const;
342 protected:
344 * Returns the window that is the lowest common ancestor of both aWindow
345 * and aContext, or null if they share no common ancestor.
347 mozilla::dom::BrowsingContext* GetCommonAncestor(
348 nsPIDOMWindowOuter* aWindow, mozilla::dom::BrowsingContext* aContext);
351 * When aBrowsingContext is focused, adjust the ancestors of aBrowsingContext
352 * so that they also have their corresponding frames focused. Thus, one can
353 * start at the active top-level window and navigate down the currently
354 * focused elements for each frame in the tree to get to aBrowsingContext.
356 MOZ_CAN_RUN_SCRIPT bool AdjustInProcessWindowFocus(
357 mozilla::dom::BrowsingContext* aBrowsingContext, bool aCheckPermission,
358 bool aIsVisible, uint64_t aActionId);
359 MOZ_CAN_RUN_SCRIPT void AdjustWindowFocus(
360 mozilla::dom::BrowsingContext* aBrowsingContext, bool aCheckPermission,
361 bool aIsVisible, uint64_t aActionId);
364 * Returns true if aWindow is visible.
366 bool IsWindowVisible(nsPIDOMWindowOuter* aWindow);
369 * Returns true if aContent is a root element and not focusable.
370 * I.e., even if aContent is editable root element, this returns true when
371 * the document is in designMode.
373 * @param aContent must not be null and must be in a document.
375 bool IsNonFocusableRoot(nsIContent* aContent);
378 * First flushes the pending notifications to ensure the PresShell and frames
379 * are updated.
380 * Checks and returns aElement if it may be focused, another element node if
381 * the focus should be retargeted at another node, or null if the node
382 * cannot be focused. aFlags are the flags passed to SetFocus and similar
383 * methods.
385 * An element is focusable if it is in a document, the document isn't in
386 * print preview mode and the element has an nsIFrame where the
387 * IsFocusable method returns true. For <area> elements, there is no
388 * frame, so only the IsFocusable method on the content node must be
389 * true.
391 MOZ_CAN_RUN_SCRIPT mozilla::dom::Element* FlushAndCheckIfFocusable(
392 mozilla::dom::Element* aElement, uint32_t aFlags);
395 * Blurs the currently focused element. Returns false if another element was
396 * focused as a result. This would mean that the caller should not proceed
397 * with a pending call to Focus. Normally, true would be returned.
399 * The currently focused element within aBrowsingContextToClear will be
400 * cleared. aBrowsingContextToClear may be null, which means that no window is
401 * cleared. This will be the case, for example, when lowering a window, as we
402 * want to fire a blur, but not actually change what element would be focused,
403 * so that the same element will be focused again when the window is raised.
405 * aAncestorBrowsingContextToFocus should be set to the common ancestor of the
406 * window that is being blurred and the window that is going to focused, when
407 * switching focus to a sibling window.
409 * aIsLeavingDocument should be set to true if the document/window is being
410 * blurred as well. Document/window blur events will be fired. It should be
411 * false if an element is the same document is about to be focused.
413 * If aAdjustWidget is false, don't change the widget focus state.
415 MOZ_CAN_RUN_SCRIPT bool Blur(
416 mozilla::dom::BrowsingContext* aBrowsingContextToClear,
417 mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus,
418 bool aIsLeavingDocument, bool aAdjustWidget, bool aRemainActive,
419 uint64_t aActionId, mozilla::dom::Element* aElementToFocus = nullptr);
420 MOZ_CAN_RUN_SCRIPT void BlurFromOtherProcess(
421 mozilla::dom::BrowsingContext* aFocusedBrowsingContext,
422 mozilla::dom::BrowsingContext* aBrowsingContextToClear,
423 mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus,
424 bool aIsLeavingDocument, bool aAdjustWidget, uint64_t aActionId);
425 MOZ_CAN_RUN_SCRIPT bool BlurImpl(
426 mozilla::dom::BrowsingContext* aBrowsingContextToClear,
427 mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus,
428 bool aIsLeavingDocument, bool aAdjustWidget, bool aRemainActive,
429 mozilla::dom::Element* aElementToFocus, uint64_t aActionId);
432 * Focus an element in the active window and child frame.
434 * aWindow is the window containing the element aContent to focus.
436 * aFlags is the flags passed to the various focus methods in
437 * nsIFocusManager.
439 * aIsNewDocument should be true if a new document is being focused.
440 * Document/window focus events will be fired.
442 * aFocusChanged should be true if a new content node is being focused, so
443 * the focused content will be scrolled into view and the caret position
444 * will be updated. If false is passed, then a window is simply being
445 * refocused, for instance, due to a window being raised, or a tab is being
446 * switched to.
448 * If aFocusChanged is true, then the focus has moved to a new location.
449 * Otherwise, the focus is just being updated because the window was
450 * raised.
452 * aWindowRaised should be true if the window is being raised. In this case,
453 * command updaters will not be called.
455 * If aAdjustWidget is false, don't change the widget focus state.
457 MOZ_CAN_RUN_SCRIPT void Focus(
458 nsPIDOMWindowOuter* aWindow, mozilla::dom::Element* aContent,
459 uint32_t aFlags, bool aIsNewDocument, bool aFocusChanged,
460 bool aWindowRaised, bool aAdjustWidget, uint64_t aActionId,
461 const mozilla::Maybe<BlurredElementInfo>& = mozilla::Nothing());
464 * Send a focus or blur event at aTarget. It may be added to the delayed
465 * event queue if the document is suppressing events.
467 * aEventMessage should be either eFocus or eBlur.
469 * aWindowRaised should only be true if called from WindowRaised.
471 MOZ_CAN_RUN_SCRIPT void SendFocusOrBlurEvent(
472 mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
473 Document* aDocument, mozilla::dom::EventTarget* aTarget,
474 bool aWindowRaised, bool aIsRefocus = false,
475 mozilla::dom::EventTarget* aRelatedTarget = nullptr);
477 * Fire a focus or blur event at aTarget.
479 * aEventMessage should be either eFocus or eBlur.
480 * For blur events, aFocusMethod should normally be non-zero.
482 * aWindowRaised should only be true if called from WindowRaised.
484 MOZ_CAN_RUN_SCRIPT void FireFocusOrBlurEvent(
485 mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
486 mozilla::dom::EventTarget* aTarget, bool aWindowRaised,
487 bool aIsRefocus = false,
488 mozilla::dom::EventTarget* aRelatedTarget = nullptr);
491 * Fire a focusin or focusout event
493 * aEventMessage should be either eFocusIn or eFocusOut.
495 * aTarget is the content the event will fire on (the object that gained
496 * focus for focusin, the object blurred for focusout).
498 * aCurrentFocusedWindow is the window focused before the focus/blur event
499 * was fired.
501 * aCurrentFocusedContent is the content focused before the focus/blur event
502 * was fired.
504 * aRelatedTarget is the content related to the event (the object
505 * losing focus for focusin, the object getting focus for focusout).
507 MOZ_CAN_RUN_SCRIPT void FireFocusInOrOutEvent(
508 mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
509 mozilla::dom::EventTarget* aTarget,
510 nsPIDOMWindowOuter* aCurrentFocusedWindow,
511 nsIContent* aCurrentFocusedContent,
512 mozilla::dom::EventTarget* aRelatedTarget = nullptr);
515 * Scrolls aContent into view unless the FLAG_NOSCROLL flag is set.
517 MOZ_CAN_RUN_SCRIPT
518 void ScrollIntoView(mozilla::PresShell* aPresShell, nsIContent* aContent,
519 uint32_t aFlags);
522 * Updates the caret positon and visibility to match the focus.
524 * aMoveCaretToFocus should be true to move the caret to aContent.
526 * aUpdateVisibility should be true to update whether the caret is
527 * visible or not.
529 MOZ_CAN_RUN_SCRIPT void UpdateCaret(bool aMoveCaretToFocus,
530 bool aUpdateVisibility,
531 nsIContent* aContent);
534 * Helper method to move the caret to the focused element aContent.
536 MOZ_CAN_RUN_SCRIPT void MoveCaretToFocus(mozilla::PresShell* aPresShell,
537 nsIContent* aContent);
540 * Makes the caret visible or not, depending on aVisible.
542 nsresult SetCaretVisible(mozilla::PresShell* aPresShell, bool aVisible,
543 nsIContent* aContent);
545 // the remaining functions are used for tab key and document-navigation
548 * Retrieves the start and end points of the current selection for
549 * aDocument and stores them in aStartContent and aEndContent.
551 nsresult GetSelectionLocation(Document* aDocument,
552 mozilla::PresShell* aPresShell,
553 nsIContent** aStartContent,
554 nsIContent** aEndContent);
557 * Retrieve the next tabbable element in scope owned by aOwner, using
558 * focusability and tabindex to determine the tab order.
560 * aOwner is the owner of scope to search in.
562 * aStartContent is the starting point for this call of this method.
564 * aOriginalStartContent is the initial starting point for sequential
565 * navigation.
567 * aForward should be true for forward navigation or false for backward
568 * navigation.
570 * aCurrentTabIndex is the current tabindex.
572 * aIgnoreTabIndex to ignore the current tabindex and find the element
573 * irrespective or the tab index.
575 * aForDocumentNavigation informs whether we're navigating only through
576 * documents.
578 * aSkipOwner to skip owner while searching. The flag is set when caller is
579 * |GetNextTabbableContent| in order to let caller handle owner.
581 * NOTE:
582 * Consider the method searches downwards in flattened subtree
583 * rooted at aOwner.
585 MOZ_CAN_RUN_SCRIPT nsIContent* GetNextTabbableContentInScope(
586 nsIContent* aOwner, nsIContent* aStartContent,
587 nsIContent* aOriginalStartContent, bool aForward,
588 int32_t aCurrentTabIndex, bool aIgnoreTabIndex,
589 bool aForDocumentNavigation, bool aNavigateByKey, bool aSkipOwner);
592 * Retrieve the next tabbable element in scope including aStartContent
593 * and the scope's ancestor scopes, using focusability and tabindex to
594 * determine the tab order.
596 * aStartOwner is the scope owner of the aStartContent.
598 * aStartContent an in/out paremeter. It as input is the starting point
599 * for this call of this method; as output it is the shadow host in
600 * light DOM if the next tabbable element is not found in shadow DOM,
601 * in order to continue searching in light DOM.
603 * aOriginalStartContent is the initial starting point for sequential
604 * navigation.
606 * aForward should be true for forward navigation or false for backward
607 * navigation.
609 * aCurrentTabIndex returns tab index of shadow host in light DOM if the
610 * next tabbable element is not found in shadow DOM, in order to continue
611 * searching in light DOM.
613 * aIgnoreTabIndex to ignore the current tabindex and find the element
614 * irrespective or the tab index.
616 * aForDocumentNavigation informs whether we're navigating only through
617 * documents.
619 * aNavigateByKey to move focus by keyboard as a side effect of computing the
620 * next target.
622 * NOTE:
623 * Consider the method searches upwards in all shadow host- or slot-rooted
624 * flattened subtrees that contains aStartContent as non-root, except
625 * the flattened subtree rooted at shadow host in light DOM.
627 MOZ_CAN_RUN_SCRIPT nsIContent* GetNextTabbableContentInAncestorScopes(
628 nsIContent* aStartOwner, nsCOMPtr<nsIContent>& aStartContent /* inout */,
629 nsIContent* aOriginalStartContent, bool aForward,
630 int32_t* aCurrentTabIndex, bool* aIgnoreTabIndex,
631 bool aForDocumentNavigation, bool aNavigateByKey);
634 * Retrieve the next tabbable element within a document, using focusability
635 * and tabindex to determine the tab order. The element is returned in
636 * aResultContent.
638 * aRootContent is the root node -- nodes above this will not be examined.
639 * Typically this will be the root node of a document, but could also be
640 * a popup node.
642 * aOriginalStartContent is the content which was originally the starting
643 * node, in the case of recursive or looping calls.
645 * aStartContent is the starting point for this call of this method.
646 * If aStartContent doesn't have visual representation, the next content
647 * object, which does have a primary frame, will be used as a start.
648 * If that content object is focusable, the method may return it.
650 * aForward should be true for forward navigation or false for backward
651 * navigation.
653 * aCurrentTabIndex is the current tabindex.
655 * aIgnoreTabIndex to ignore the current tabindex and find the element
656 * irrespective or the tab index. This will be true when a selection is
657 * active, since we just want to focus the next element in tree order
658 * from where the selection is. Similarly, if the starting element isn't
659 * focusable, since it doesn't really have a defined tab index.
661 * aNavigateByKey to move focus by keyboard as a side effect of computing the
662 * next target.
664 MOZ_CAN_RUN_SCRIPT nsresult GetNextTabbableContent(
665 mozilla::PresShell* aPresShell, nsIContent* aRootContent,
666 nsIContent* aOriginalStartContent, nsIContent* aStartContent,
667 bool aForward, int32_t aCurrentTabIndex, bool aIgnoreTabIndex,
668 bool aForDocumentNavigation, bool aNavigateByKey,
669 nsIContent** aResultContent);
672 * Get the next tabbable image map area and returns it.
674 * aForward should be true for forward navigation or false for backward
675 * navigation.
677 * aCurrentTabIndex is the current tabindex.
679 * aImageContent is the image.
681 * aStartContent is the current image map area.
683 nsIContent* GetNextTabbableMapArea(bool aForward, int32_t aCurrentTabIndex,
684 mozilla::dom::Element* aImageContent,
685 nsIContent* aStartContent);
688 * Return the next valid tabindex value after aCurrentTabIndex, if aForward
689 * is true, or the previous tabindex value if aForward is false. aParent is
690 * the node from which to start looking for tab indicies.
692 int32_t GetNextTabIndex(nsIContent* aParent, int32_t aCurrentTabIndex,
693 bool aForward);
696 * Focus the first focusable content within the document with a root node of
697 * aRootContent. For content documents, this will be aRootContent itself, but
698 * for chrome documents, this will locate the next focusable content.
700 MOZ_CAN_RUN_SCRIPT nsresult FocusFirst(mozilla::dom::Element* aRootContent,
701 nsIContent** aNextContent);
704 * Retrieves and returns the root node from aDocument to be focused. Will
705 * return null if the root node cannot be focused. There are several reasons
706 * for this:
708 * - if aForDocumentNavigation is false and aWindow is a chrome shell.
709 * - if aCheckVisibility is true and the aWindow is not visible.
710 * - if aDocument is a frameset document.
712 mozilla::dom::Element* GetRootForFocus(nsPIDOMWindowOuter* aWindow,
713 Document* aDocument,
714 bool aForDocumentNavigation,
715 bool aCheckVisibility);
718 * Retrieves and returns the root node as with GetRootForFocus but only if
719 * aContent is a frame with a valid child document.
721 mozilla::dom::Element* GetRootForChildDocument(nsIContent* aContent);
724 * Retreives a focusable element within the current selection of aWindow.
725 * Currently, this only detects links.
727 * This is used when MoveFocus is called with a type of MOVEFOCUS_CARET,
728 * which is used, for example, to focus links as the caret is moved over
729 * them.
731 void GetFocusInSelection(nsPIDOMWindowOuter* aWindow,
732 nsIContent* aStartSelection,
733 nsIContent* aEndSelection,
734 nsIContent** aFocusedContent);
736 private:
737 // Notify that the focus state of aElement has changed. Note that we need to
738 // pass in whether the window should show a focus ring before the
739 // SetFocusedNode call on it happened when losing focus and after the
740 // SetFocusedNode call when gaining focus, which is why that information needs
741 // to be an explicit argument instead of just passing in the window and asking
742 // it whether it should show focus rings: in the losing focus case that
743 // information could be wrong.
745 // aShouldShowFocusRing is only relevant if aGettingFocus is true.
746 static void NotifyFocusStateChange(mozilla::dom::Element* aElement,
747 mozilla::dom::Element* aElementToFocus,
748 int32_t aFlags, bool aGettingFocus,
749 bool aShouldShowFocusRing);
751 void SetFocusedWindowInternal(nsPIDOMWindowOuter* aWindow, uint64_t aActionId,
752 bool aSyncBrowsingContext = true);
754 MOZ_CAN_RUN_SCRIPT bool TryDocumentNavigation(nsIContent* aCurrentContent,
755 bool* aCheckSubDocument,
756 nsIContent** aResultContent);
758 MOZ_CAN_RUN_SCRIPT bool TryToMoveFocusToSubDocument(
759 nsIContent* aCurrentContent, nsIContent* aOriginalStartContent,
760 bool aForward, bool aForDocumentNavigation, bool aNavigateByKey,
761 nsIContent** aResultContent);
763 // Sets the focused BrowsingContext and, if appropriate, syncs it to
764 // other processes.
765 void SetFocusedBrowsingContext(mozilla::dom::BrowsingContext* aContext,
766 uint64_t aActionId);
768 // Content-only
769 // Called when receiving an IPC message about another process setting
770 // the focused BrowsingContext.
771 void SetFocusedBrowsingContextFromOtherProcess(
772 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
774 // Chrome-only
775 // When returning true, sets the chrome process notion of what
776 // BrowsingContext is focused in content. When returning false,
777 // ignores the attempt to set as out-of-sequence.
778 bool SetFocusedBrowsingContextInChrome(
779 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
781 void InsertNewFocusActionId(uint64_t aActionId);
783 bool ProcessPendingActiveBrowsingContextActionId(uint64_t aActionId,
784 bool aSettingToNonNull);
786 bool ProcessPendingFocusedBrowsingContextActionId(uint64_t aActionId);
788 public:
789 // Chrome-only
790 // Gets the chrome process notion of what BrowsingContext is focused
791 // in content.
792 mozilla::dom::BrowsingContext* GetFocusedBrowsingContextInChrome();
794 // Chrome-only
795 // Notifies the focus manager that BrowsingContext::Detach was called
796 // on a BrowsingContext so that pointers to it can be forgotten.
797 void BrowsingContextDetached(mozilla::dom::BrowsingContext* aContext);
799 private:
800 // Content-only
801 // Sets the BrowsingContext corresponding to top-level Web content
802 // in the frontmost tab if focus is in Web content.
803 void SetActiveBrowsingContextInContent(
804 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
806 // Content-only
807 // Receives notification of another process setting the top-level Web
808 // content as being in the frontmost tab with focus in Web content.
809 void SetActiveBrowsingContextFromOtherProcess(
810 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
812 // Content-only
813 // Receives notification that another process determined that focus
814 // moved to chrome so a particular BrowsingContext is no longer the
815 // "active" one.
816 void UnsetActiveBrowsingContextFromOtherProcess(
817 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
819 // Content-only
820 // Receives a notification from parent that this content process's
821 // attempt to set the active browsing context was late and the
822 // prevailing browsing context is instead the second argument of
823 // this method call. This should be ignored if the first argument
824 // doesn't match the latest action id associated with setting the
825 // active browsing context in this process, because in that case,
826 // this revision is late.
827 void ReviseActiveBrowsingContext(uint64_t aOldActionId,
828 mozilla::dom::BrowsingContext* aContext,
829 uint64_t aNewActionId);
831 // Receives a notification from parent that this content process's
832 // attempt to set the focused browsing context was late and the
833 // prevailing browsing context is instead the second argument of
834 // this method call. This should be ignored if the first argument
835 // doesn't match the latest action id associated with setting the
836 // active browsing context in this process, because in that case,
837 // this revision is late.
838 void ReviseFocusedBrowsingContext(uint64_t aOldActionId,
839 mozilla::dom::BrowsingContext* aContext,
840 uint64_t aNewActionId);
842 // Chrome-only
843 // Sets the chrome process notion of what content believes to be
844 // the top-level BrowsingContext in the frontmost tab when focus
845 // is in Web content.
846 // Returns true if set and false if ignored.
847 bool SetActiveBrowsingContextInChrome(mozilla::dom::BrowsingContext* aContext,
848 uint64_t aActionId);
850 public:
851 // Chrome-only
852 // Gets the chrome process notion of what content believes to be
853 // the top-level BrowsingContext in the frontmost tab when focus
854 // is in Web content.
855 mozilla::dom::BrowsingContext* GetActiveBrowsingContextInChrome();
857 uint64_t GetActionIdForActiveBrowsingContextInChrome() const;
859 uint64_t GetActionIdForFocusedBrowsingContextInChrome() const;
861 static uint64_t GenerateFocusActionId();
863 // This function works very similar to
864 // https://html.spec.whatwg.org/#get-the-focusable-area
865 static mozilla::dom::Element* GetTheFocusableArea(
866 mozilla::dom::Element* aTarget, uint32_t aFlags);
868 private:
869 // In the chrome process, the currently active and front-most top-most
870 // window. Not supposed to be used in a meaningful way in content
871 // processes. For legacy reasons, this exists as a separate field
872 // instead of being derived from mFocusedWindow when needed, because
873 // the defined relation that mActiveWindow is supposed to be the same
874 // as or ancestor of mFocusedWindow is temporarily broken when a
875 // window is being raised or lowered.
876 nsCOMPtr<nsPIDOMWindowOuter> mActiveWindow;
878 // In a content process, the BrowsingContext corresponding to top-level
879 // Web content in the active tab or nullptr if focus is not in a
880 // BrowsingContextGroup that this process participates in. Synced
881 // across processes in a BrowsingContextGroup. This field exists
882 // separately from mFocusedBrowsingContextInContent instead of being being
883 // derived from it, because for legacy reasons the relation
884 // mFocusedBrowsingContextInContent->Top() == mActiveBrowsingContextInContent
885 // is temporarily broken when a window is being raised or lowered.
886 // Not supposed to be used in a meaningful way in the chrome process.
887 RefPtr<mozilla::dom::BrowsingContext> mActiveBrowsingContextInContent;
889 // If this content process set mActiveBrowsingContextInContent, this
890 // field holds the corresponding actionId so that
891 // mActiveBrowsingContextInContent can be revised of the parent rejects
892 // the update. This field is used for accepting revisions only if nothing
893 // else has updated mActiveBrowsingContextInContent before the revision
894 // arrives.
895 uint64_t mActionIdForActiveBrowsingContextInContent;
897 uint64_t mActionIdForActiveBrowsingContextInChrome;
899 // If this content process set mFocusedBrowsingContextInContent, this
900 // field holds the corresponding actionId so that
901 // mFocusedBrowsingContextInContent can be revised of the parent rejects
902 // the update. This field is used for accepting revisions only if nothing
903 // else has updated mFocusedBrowsingContextInContent before the revision
904 // arrives.
905 uint64_t mActionIdForFocusedBrowsingContextInContent;
907 uint64_t mActionIdForFocusedBrowsingContextInChrome;
909 // Whether or not mActiveBrowsingContextInContent was set from another process
910 // or from this process.
911 bool mActiveBrowsingContextInContentSetFromOtherProcess;
913 // This is the chrome process notion of content's
914 // mActiveBrowsingContextInContent. Avoiding field reuse for different
915 // semantics in different process types to make it easier to catch bugs.
916 RefPtr<mozilla::dom::BrowsingContext> mActiveBrowsingContextInChrome;
918 // the child or top-level window that is currently focused. In the chrome
919 // process, when a window isn't being raised or lowered, this window will
920 // either be the same window as mActiveWindow or a descendant of it.
921 // Except during shutdown use SetFocusedWindowInternal to set mFocusedWindow!
922 nsCOMPtr<nsPIDOMWindowOuter> mFocusedWindow;
924 // The focused BrowsingContext if this is a chrome process and focus is
925 // in chrome or if this is a content process and focus is in Web content
926 // in this BrowsingContextGroup. nullptr otherwise.
927 // Except during shutdown, must be set via SetFocusedWindowInternal which
928 // calls SetFocusedBrowsingContext or if the value is coming in via IPC
929 // via SetFocusedBrowsingContextFromOtherProcess.
930 RefPtr<mozilla::dom::BrowsingContext> mFocusedBrowsingContextInContent;
932 // This is the chrome process notion of content's
933 // mFocusedBrowsingContextInContent. Avoiding field reuse for different
934 // semantics in different process types to make it easier to catch bugs.
935 RefPtr<mozilla::dom::BrowsingContext> mFocusedBrowsingContextInChrome;
937 // the currently focused content if in-process or the XUL browser in which
938 // Web content focus resides. Always inside mFocusedWindow. When a window
939 // isn't being raised or lowered, this is a cached copy of the
940 // mFocusedWindow's current content. This may be null if no content is
941 // focused.
942 RefPtr<mozilla::dom::Element> mFocusedElement;
944 // these fields store a content node temporarily while it is being focused
945 // or blurred to ensure that a recursive call doesn't refire the same event.
946 // They will always be cleared afterwards.
947 RefPtr<mozilla::dom::Element> mFirstBlurEvent;
948 RefPtr<mozilla::dom::Element> mFirstFocusEvent;
950 // keep track of a window while it is being lowered
951 nsCOMPtr<nsPIDOMWindowOuter> mWindowBeingLowered;
953 // synchronized actions cannot be interrupted with events, so queue these up
954 // and fire them later.
955 nsTArray<nsDelayedBlurOrFocusEvent> mDelayedBlurFocusEvents;
957 // Array of focus action ids for which we haven't seen an active browsing
958 // context set yet. As set is allowed to overwrite an unset. Therefore,
959 // an unset removes earlier ids but not the matching id. A set removes
960 // earlier ids and the matching id.
962 // Conceptually, active browsing context shouldn't have to exist as a
963 // field, because it should be possible to always derive it from the
964 // focused browsing context. Unfortunately, for legacy reasons, this
965 // is not the case while a window is being raised or lowered.
967 // Conceptually, it should be possible for the parent to manage the
968 // active browsing context. Unfortunately, for legacy reasons, the
969 // code for setting the active browsing context needs to reside in
970 // the content process to retain the existing and test-passing code
971 // flow.
973 // This, obviously, raises the issue of content processes racing to
974 // set the active browsing context. In particular, there is a pattern
975 // that the parent initiates actions that cause multiple content
976 // processes to mutate the active browsing context at almost the
977 // same time. When two native browser windows change order, the
978 // lowering isn't distinguished from the case of lowering the
979 // entire app. For this reason, the owner of the previous active
980 // browsing context tries to unset it and at almost the same time
981 // the another content process sets a new active browsing context.
982 // If the IPC messages for these unset and set actions were to
983 // arrive in the wrong order, this could get in the wrong state.
985 // To address this issue, the parent manages an authortative order
986 // of attempts to (un)set the active browsing context using the
987 // array mPendingActiveBrowsingContextActions.
989 // A process reserves a slot in the order by calling
990 // GenerateFocusActionId(). Per one call to GenerateFocusActionId(),
991 // there may be at most one action to set the active browsing context
992 // to a new value. There may be logically prior attempts to unset it
993 // (i.e. set it to nullptr). That is, if there are both attempts to
994 // unset and set the active browsing context with the same action id,
995 // the attempt to set to a non-null value wins.
997 // The completion of an action from reserting the slot in the order
998 // and actually performing the setting of the active browsing context
999 // may span multiple processes and IPC messages.
1001 // The at-most-once property is not asserted, because the process
1002 // claiming the position in the order and the process setting the
1003 // active browsing context with that actionId may be different, and
1004 // the act of using an actionId to set the active browsing context
1005 // is used to delete stale items from the array to avoid excessive
1006 // growth of the array.
1007 nsTArray<uint64_t> mPendingActiveBrowsingContextActions;
1009 // Like mPendingActiveBrowsingContextActions but for the focused
1010 // browsing context.
1011 nsTArray<uint64_t> mPendingFocusedBrowsingContextActions;
1013 // If set to true, layout of the document of the event target should be
1014 // flushed before handling focus depending events.
1015 bool mEventHandlingNeedsFlush;
1017 static bool sTestMode;
1019 // Process-specific counter for maintaining the prosess-specific
1020 // uniqueness of actionIds.
1021 static uint64_t sFocusActionCounter;
1023 // the single focus manager
1024 static mozilla::StaticRefPtr<nsFocusManager> sInstance;
1027 nsresult NS_NewFocusManager(nsIFocusManager** aResult);
1029 #endif