Backed out changeset 9d8b4c0b99ed (bug 1945683) for causing btime failures. CLOSED...
[gecko.git] / dom / base / nsFocusManager.h
blob1c5504d29a8fb10ec593d3a9eb9e5eef258b4e65
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 class HTMLAreaElement;
30 struct FocusOptions;
31 class BrowserParent;
32 class ContentChild;
33 class ContentParent;
34 } // namespace dom
35 } // namespace mozilla
37 struct nsDelayedBlurOrFocusEvent;
39 /**
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,
45 public nsIObserver,
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;
52 public:
53 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFocusManager, nsIFocusManager)
54 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
55 NS_DECL_NSIOBSERVER
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,
69 void* aSelf);
70 MOZ_CAN_RUN_SCRIPT void PrefChanged(const char* aPref);
72 /**
73 * Retrieve the single focus manager.
75 static nsFocusManager* GetFocusManager() { return sInstance; }
77 /**
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;
87 /**
88 * Returns true if aContent currently has focus.
90 bool IsFocused(nsIContent* aContent);
92 /**
93 * Returns true if test mode is enabled.
95 bool IsTestMode();
97 /**
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();
112 return nullptr;
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()) {
135 if (mActiveWindow) {
136 return mActiveWindow->GetBrowsingContext();
138 return nullptr;
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();
161 if (doc) {
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.
186 enum SearchRange {
187 // Return focused content in aWindow. So, aFocusedWindow is always aWindow.
188 eOnlyCurrentWindow,
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
211 * next target.
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);
223 /** Given a focused frame loader owner, fix up the focus to be consistent */
224 MOZ_CAN_RUN_SCRIPT void FixUpFocusAfterFrameLoaderChange(
225 mozilla::dom::Element&);
227 * Keep track of whether the focused window is about to go away, and if so fix
228 * up the focus state so that we can know if we're still focused by the time
229 * the frame loader swap ends.
231 void FixUpFocusBeforeFrameLoaderChange(mozilla::dom::Element&,
232 mozilla::dom::BrowsingContext* aBc);
235 * Raises the top-level window aWindow at the widget level.
237 MOZ_CAN_RUN_SCRIPT void RaiseWindow(nsPIDOMWindowOuter* aWindow,
238 mozilla::dom::CallerType aCallerType,
239 uint64_t aActionId);
242 * Called when a window has been raised.
244 MOZ_CAN_RUN_SCRIPT void WindowRaised(mozIDOMWindowProxy* aWindow,
245 uint64_t aActionId);
248 * Called when a window has been lowered.
250 MOZ_CAN_RUN_SCRIPT void WindowLowered(mozIDOMWindowProxy* aWindow,
251 uint64_t aActionId);
254 * Called when a new document in a window is shown.
256 * If aNeedsFocus is true, then focus events are expected to be fired on the
257 * window if this window is in the focused window chain.
259 MOZ_CAN_RUN_SCRIPT void WindowShown(mozIDOMWindowProxy* aWindow,
260 bool aNeedsFocus);
263 * Called when a document in a window has been hidden or otherwise can no
264 * longer accept focus.
266 MOZ_CAN_RUN_SCRIPT void WindowHidden(mozIDOMWindowProxy* aWindow,
267 uint64_t aActionId,
268 bool aIsEnteringBFCache);
271 * Fire any events that have been delayed due to synchronized actions.
273 MOZ_CAN_RUN_SCRIPT void FireDelayedEvents(Document* aDocument);
275 void WasNuked(nsPIDOMWindowOuter* aWindow);
277 static uint32_t ProgrammaticFocusFlags(
278 const mozilla::dom::FocusOptions& aOptions);
281 * Returns an InputContextAction cause for aFlags.
283 static InputContextAction::Cause GetFocusMoveActionCause(uint32_t aFlags);
286 * Notify of re-focus to same element.
288 * aElement is focused element.
290 MOZ_CAN_RUN_SCRIPT void NotifyOfReFocus(mozilla::dom::Element& aElement);
292 static void MarkUncollectableForCCGeneration(uint32_t aGeneration);
294 struct BlurredElementInfo {
295 const mozilla::OwningNonNull<mozilla::dom::Element> mElement;
297 explicit BlurredElementInfo(mozilla::dom::Element&);
298 ~BlurredElementInfo();
301 protected:
302 nsFocusManager();
303 ~nsFocusManager();
306 * Ensure that the widget associated with the currently focused window is
307 * focused at the widget level.
309 void EnsureCurrentWidgetFocused(mozilla::dom::CallerType aCallerType);
312 * Focus the last focused element in aWindow, after aWindow was raised (or if
313 * aWindow was already raised).
315 MOZ_CAN_RUN_SCRIPT void MoveFocusToWindowAfterRaise(nsPIDOMWindowOuter*,
316 uint64_t aActionId);
319 * Activate or deactivate the window and send the activate/deactivate events.
321 void ActivateOrDeactivate(nsPIDOMWindowOuter* aWindow, bool aActive);
324 * Blur whatever is currently focused and focus aNewContent. aFlags is a
325 * bitmask of the flags defined in nsIFocusManager. If aFocusChanged is
326 * true, then the focus has actually shifted and the caret position will be
327 * updated to the new focus, aNewContent will be scrolled into view (unless
328 * a flag disables this) and the focus method for the window will be updated.
329 * If aAdjustWidget is false, don't change the widget focus state.
331 * All actual focus changes must use this method to do so. (as opposed
332 * to those that update the focus in an inactive window for instance).
334 * Returns Nothing() if we end up not trying to focus the element,
335 * otherwise returns the generated action id.
337 MOZ_CAN_RUN_SCRIPT mozilla::Maybe<uint64_t> SetFocusInner(
338 mozilla::dom::Element* aNewContent, int32_t aFlags, bool aFocusChanged,
339 bool aAdjustWidget);
342 * Returns true if aPossibleAncestor is the same as aWindow or an
343 * ancestor of aWindow.
345 bool IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor,
346 nsPIDOMWindowOuter* aWindow) const;
347 bool IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor,
348 mozilla::dom::BrowsingContext* aContext) const;
349 bool IsSameOrAncestor(mozilla::dom::BrowsingContext* aPossibleAncestor,
350 nsPIDOMWindowOuter* aWindow) const;
352 public:
353 bool IsSameOrAncestor(mozilla::dom::BrowsingContext* aPossibleAncestor,
354 mozilla::dom::BrowsingContext* aContext) const;
356 protected:
358 * Returns the window that is the lowest common ancestor of both aWindow
359 * and aContext, or null if they share no common ancestor.
361 mozilla::dom::BrowsingContext* GetCommonAncestor(
362 nsPIDOMWindowOuter* aWindow, mozilla::dom::BrowsingContext* aContext);
365 * When aBrowsingContext is focused or blurred, adjust the ancestors of
366 * aBrowsingContext so that they also have their corresponding frames focused
367 * or blurred. Thus, one can start at the active top-level window and navigate
368 * down the currently focused elements for each frame in the tree to get to
369 * aBrowsingContext.
371 MOZ_CAN_RUN_SCRIPT bool AdjustInProcessWindowFocus(
372 mozilla::dom::BrowsingContext* aBrowsingContext, bool aCheckPermission,
373 bool aIsVisible, uint64_t aActionId, bool aShouldClearAncestorFocus,
374 mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus);
376 MOZ_CAN_RUN_SCRIPT void AdjustWindowFocus(
377 mozilla::dom::BrowsingContext* aBrowsingContext, bool aCheckPermission,
378 bool aIsVisible, uint64_t aActionId, bool aShouldClearAncestorFocus,
379 mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus);
382 * Returns true if aWindow is visible.
384 bool IsWindowVisible(nsPIDOMWindowOuter* aWindow);
387 * Returns true if aContent is a root element and not focusable.
388 * I.e., even if aContent is editable root element, this returns true when
389 * the document is in designMode.
391 * @param aContent must not be null and must be in a document.
393 bool IsNonFocusableRoot(nsIContent* aContent);
396 * First flushes the pending notifications to ensure the PresShell and frames
397 * are updated.
398 * Checks and returns aElement if it may be focused, another element node if
399 * the focus should be retargeted at another node, or null if the node
400 * cannot be focused. aFlags are the flags passed to SetFocus and similar
401 * methods.
403 * An element is focusable if it is in a document, the document isn't in
404 * print preview mode and the element has an nsIFrame where the
405 * IsFocusable method returns true. For <area> elements, there is no
406 * frame, so only the IsFocusable method on the content node must be
407 * true.
409 MOZ_CAN_RUN_SCRIPT mozilla::dom::Element* FlushAndCheckIfFocusable(
410 mozilla::dom::Element* aElement, uint32_t aFlags);
413 * Blurs the currently focused element. Returns false if another element was
414 * focused as a result. This would mean that the caller should not proceed
415 * with a pending call to Focus. Normally, true would be returned.
417 * The currently focused element within aBrowsingContextToClear will be
418 * cleared. aBrowsingContextToClear may be null, which means that no window is
419 * cleared. This will be the case, for example, when lowering a window, as we
420 * want to fire a blur, but not actually change what element would be focused,
421 * so that the same element will be focused again when the window is raised.
423 * aAncestorBrowsingContextToFocus should be set to the common ancestor of the
424 * window that is being blurred and the window that is going to focused, when
425 * switching focus to a sibling window.
427 * aIsLeavingDocument should be set to true if the document/window is being
428 * blurred as well. Document/window blur events will be fired. It should be
429 * false if an element is the same document is about to be focused.
431 * If aAdjustWidget is false, don't change the widget focus state.
433 MOZ_CAN_RUN_SCRIPT bool Blur(
434 mozilla::dom::BrowsingContext* aBrowsingContextToClear,
435 mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus,
436 bool aIsLeavingDocument, bool aAdjustWidget, bool aRemainActive,
437 uint64_t aActionId, mozilla::dom::Element* aElementToFocus = nullptr);
438 MOZ_CAN_RUN_SCRIPT void BlurFromOtherProcess(
439 mozilla::dom::BrowsingContext* aFocusedBrowsingContext,
440 mozilla::dom::BrowsingContext* aBrowsingContextToClear,
441 mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus,
442 bool aIsLeavingDocument, bool aAdjustWidget, uint64_t aActionId);
443 MOZ_CAN_RUN_SCRIPT bool BlurImpl(
444 mozilla::dom::BrowsingContext* aBrowsingContextToClear,
445 mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus,
446 bool aIsLeavingDocument, bool aAdjustWidget, bool aRemainActive,
447 mozilla::dom::Element* aElementToFocus, uint64_t aActionId);
450 * Focus an element in the active window and child frame.
452 * aWindow is the window containing the element aContent to focus.
454 * aFlags is the flags passed to the various focus methods in
455 * nsIFocusManager.
457 * aIsNewDocument should be true if a new document is being focused.
458 * Document/window focus events will be fired.
460 * aFocusChanged should be true if a new content node is being focused, so
461 * the focused content will be scrolled into view and the caret position
462 * will be updated. If false is passed, then a window is simply being
463 * refocused, for instance, due to a window being raised, or a tab is being
464 * switched to.
466 * If aFocusChanged is true, then the focus has moved to a new location.
467 * Otherwise, the focus is just being updated because the window was
468 * raised.
470 * aWindowRaised should be true if the window is being raised. In this case,
471 * command updaters will not be called.
473 * If aAdjustWidget is false, don't change the widget focus state.
475 MOZ_CAN_RUN_SCRIPT void Focus(
476 nsPIDOMWindowOuter* aWindow, mozilla::dom::Element* aContent,
477 uint32_t aFlags, bool aIsNewDocument, bool aFocusChanged,
478 bool aWindowRaised, bool aAdjustWidget, uint64_t aActionId,
479 const mozilla::Maybe<BlurredElementInfo>& = mozilla::Nothing());
482 * Send a focus or blur event at aTarget. It may be added to the delayed
483 * event queue if the document is suppressing events.
485 * aEventMessage should be either eFocus or eBlur.
487 * aWindowRaised should only be true if called from WindowRaised.
489 MOZ_CAN_RUN_SCRIPT void SendFocusOrBlurEvent(
490 mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
491 Document* aDocument, mozilla::dom::EventTarget* aTarget,
492 bool aWindowRaised, bool aIsRefocus = false,
493 mozilla::dom::EventTarget* aRelatedTarget = nullptr);
495 * Fire a focus or blur event at aTarget.
497 * aEventMessage should be either eFocus or eBlur.
498 * For blur events, aFocusMethod should normally be non-zero.
500 * aWindowRaised should only be true if called from WindowRaised.
502 MOZ_CAN_RUN_SCRIPT void FireFocusOrBlurEvent(
503 mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
504 mozilla::dom::EventTarget* aTarget, bool aWindowRaised,
505 bool aIsRefocus = false,
506 mozilla::dom::EventTarget* aRelatedTarget = nullptr);
509 * Fire a focusin or focusout event
511 * aEventMessage should be either eFocusIn or eFocusOut.
513 * aTarget is the content the event will fire on (the object that gained
514 * focus for focusin, the object blurred for focusout).
516 * aCurrentFocusedWindow is the window focused before the focus/blur event
517 * was fired.
519 * aCurrentFocusedContent is the content focused before the focus/blur event
520 * was fired.
522 * aRelatedTarget is the content related to the event (the object
523 * losing focus for focusin, the object getting focus for focusout).
525 MOZ_CAN_RUN_SCRIPT void FireFocusInOrOutEvent(
526 mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
527 mozilla::dom::EventTarget* aTarget,
528 nsPIDOMWindowOuter* aCurrentFocusedWindow,
529 nsIContent* aCurrentFocusedContent,
530 mozilla::dom::EventTarget* aRelatedTarget = nullptr);
533 * Scrolls aContent into view unless the FLAG_NOSCROLL flag is set.
535 MOZ_CAN_RUN_SCRIPT
536 void ScrollIntoView(mozilla::PresShell* aPresShell, nsIContent* aContent,
537 uint32_t aFlags);
540 * Updates the caret positon and visibility to match the focus.
542 * aMoveCaretToFocus should be true to move the caret to aContent.
544 * aUpdateVisibility should be true to update whether the caret is
545 * visible or not.
547 MOZ_CAN_RUN_SCRIPT void UpdateCaret(bool aMoveCaretToFocus,
548 bool aUpdateVisibility,
549 nsIContent* aContent);
552 * Helper method to move the caret to the focused element aContent.
554 MOZ_CAN_RUN_SCRIPT void MoveCaretToFocus(mozilla::PresShell* aPresShell,
555 nsIContent* aContent);
558 * Makes the caret visible or not, depending on aVisible.
560 nsresult SetCaretVisible(mozilla::PresShell* aPresShell, bool aVisible,
561 nsIContent* aContent);
563 // the remaining functions are used for tab key and document-navigation
566 * Retrieves the start and end points of the current selection for
567 * aDocument and stores them in aStartContent and aEndContent.
569 void GetSelectionLocation(Document* aDocument, mozilla::PresShell* aPresShell,
570 nsIContent** aStartContent,
571 nsIContent** aEndContent);
574 * Retrieve the next tabbable element in scope owned by aOwner, using
575 * focusability and tabindex to determine the tab order.
577 * aOwner is the owner of scope to search in.
579 * aStartContent is the starting point for this call of this method.
581 * aOriginalStartContent is the initial starting point for sequential
582 * navigation.
584 * aForward should be true for forward navigation or false for backward
585 * navigation.
587 * aCurrentTabIndex is the current tabindex.
589 * aIgnoreTabIndex to ignore the current tabindex and find the element
590 * irrespective or the tab index.
592 * aForDocumentNavigation informs whether we're navigating only through
593 * documents.
595 * aSkipOwner to skip owner while searching. The flag is set when caller is
596 * |GetNextTabbableContent| in order to let caller handle owner.
598 * aReachedToEndForDocumentNavigation is true when this is a document
599 * navigation and the focus algorithm has reached to the end of the top-level
600 * document.
602 * NOTE:
603 * Consider the method searches downwards in flattened subtree
604 * rooted at aOwner.
606 MOZ_CAN_RUN_SCRIPT nsIContent* GetNextTabbableContentInScope(
607 nsIContent* aOwner, nsIContent* aStartContent,
608 nsIContent* aOriginalStartContent, bool aForward,
609 int32_t aCurrentTabIndex, bool aIgnoreTabIndex,
610 bool aForDocumentNavigation, bool aNavigateByKey, bool aSkipOwner,
611 bool aReachedToEndForDocumentNavigation);
614 * Retrieve the next tabbable element in scope including aStartContent
615 * and the scope's ancestor scopes, using focusability and tabindex to
616 * determine the tab order.
618 * aStartOwner is the scope owner of the aStartContent.
620 * aStartContent an in/out paremeter. It as input is the starting point
621 * for this call of this method; as output it is the shadow host in
622 * light DOM if the next tabbable element is not found in shadow DOM,
623 * in order to continue searching in light DOM.
625 * aOriginalStartContent is the initial starting point for sequential
626 * navigation.
628 * aForward should be true for forward navigation or false for backward
629 * navigation.
631 * aCurrentTabIndex returns tab index of shadow host in light DOM if the
632 * next tabbable element is not found in shadow DOM, in order to continue
633 * searching in light DOM.
635 * aIgnoreTabIndex to ignore the current tabindex and find the element
636 * irrespective or the tab index.
638 * aForDocumentNavigation informs whether we're navigating only through
639 * documents.
641 * aNavigateByKey to move focus by keyboard as a side effect of computing the
642 * next target.
644 * aReachedToEndForDocumentNavigation is true when this is a document
645 * navigation and the focus algorithm has reached to the end of the top-level
646 * document.
648 * NOTE:
649 * Consider the method searches upwards in all shadow host- or slot-rooted
650 * flattened subtrees that contains aStartContent as non-root, except
651 * the flattened subtree rooted at shadow host in light DOM.
653 MOZ_CAN_RUN_SCRIPT nsIContent* GetNextTabbableContentInAncestorScopes(
654 nsIContent* aStartOwner, nsCOMPtr<nsIContent>& aStartContent /* inout */,
655 nsIContent* aOriginalStartContent, bool aForward,
656 int32_t* aCurrentTabIndex, bool* aIgnoreTabIndex,
657 bool aForDocumentNavigation, bool aNavigateByKey,
658 bool aReachedToEndForDocumentNavigation);
661 * Retrieve the next tabbable element within a document, using focusability
662 * and tabindex to determine the tab order. The element is returned in
663 * aResultContent.
665 * aRootContent is the root node -- nodes above this will not be examined.
666 * Typically this will be the root node of a document, but could also be
667 * a popup node.
669 * aOriginalStartContent is the content which was originally the starting
670 * node, in the case of recursive or looping calls.
672 * aStartContent is the starting point for this call of this method.
673 * If aStartContent doesn't have visual representation, the next content
674 * object, which does have a primary frame, will be used as a start.
675 * If that content object is focusable, the method may return it.
677 * aForward should be true for forward navigation or false for backward
678 * navigation.
680 * aCurrentTabIndex is the current tabindex.
682 * aIgnoreTabIndex to ignore the current tabindex and find the element
683 * irrespective or the tab index. This will be true when a selection is
684 * active, since we just want to focus the next element in tree order
685 * from where the selection is. Similarly, if the starting element isn't
686 * focusable, since it doesn't really have a defined tab index.
688 * aSkipPopover should be true to avoid an invoker triggering to step into
689 * the popover that was already been visited again.
691 * aNavigateByKey to move focus by keyboard as a side effect of computing the
692 * next target.
694 * aReachedToEndForDocumentNavigation is true when this is a document
695 * navigation and the focus algorithm has reached to the end of the top-level
696 * document.
698 MOZ_CAN_RUN_SCRIPT nsresult GetNextTabbableContent(
699 mozilla::PresShell* aPresShell, nsIContent* aRootContent,
700 nsIContent* aOriginalStartContent, nsIContent* aStartContent,
701 bool aForward, int32_t aCurrentTabIndex, bool aIgnoreTabIndex,
702 bool aForDocumentNavigation, bool aNavigateByKey, bool aSkipPopover,
703 bool aReachedToEndForDocumentNavigation, nsIContent** aResultContent);
706 * Get the next tabbable image map area and returns it.
708 * aForward should be true for forward navigation or false for backward
709 * navigation.
711 * aCurrentTabIndex is the current tabindex.
713 * aImageContent is the image.
715 * aStartContent is the current image map area.
717 nsIContent* GetNextTabbableMapArea(bool aForward, int32_t aCurrentTabIndex,
718 mozilla::dom::Element* aImageContent,
719 nsIContent* aStartContent);
722 * Return the next valid tabindex value after aCurrentTabIndex, if aForward
723 * is true, or the previous tabindex value if aForward is false. aParent is
724 * the node from which to start looking for tab indicies.
726 int32_t GetNextTabIndex(nsIContent* aParent, int32_t aCurrentTabIndex,
727 bool aForward);
730 * Focus the first focusable content within the document with a root node of
731 * aRootContent. For content documents, this will be aRootContent itself, but
732 * for chrome documents, this will locate the next focusable content.
734 * aReachedToEndForDocumentNavigation is true when the focus algorithm has
735 * reached to the end of the top-level document.
737 MOZ_CAN_RUN_SCRIPT nsresult
738 FocusFirst(mozilla::dom::Element* aRootContent, nsIContent** aNextContent,
739 bool aReachedToEndForDocumentNavigation);
742 * Retrieves and returns the root node from aDocument to be focused. Will
743 * return null if the root node cannot be focused. There are several reasons
744 * for this:
746 * - if aForDocumentNavigation is false and aWindow is a chrome shell.
747 * - if aCheckVisibility is true and the aWindow is not visible.
748 * - if aDocument is a frameset document.
750 mozilla::dom::Element* GetRootForFocus(nsPIDOMWindowOuter* aWindow,
751 Document* aDocument,
752 bool aForDocumentNavigation,
753 bool aCheckVisibility);
756 * Retrieves and returns the root node as with GetRootForFocus but only if
757 * aContent is a frame with a valid child document.
759 mozilla::dom::Element* GetRootForChildDocument(nsIContent* aContent);
762 * Retreives a focusable element within the current selection of aWindow.
763 * Currently, this only detects links.
765 * This is used when MoveFocus is called with a type of MOVEFOCUS_CARET,
766 * which is used, for example, to focus links as the caret is moved over
767 * them.
769 void GetFocusInSelection(nsPIDOMWindowOuter* aWindow,
770 nsIContent* aStartSelection,
771 nsIContent* aEndSelection,
772 nsIContent** aFocusedContent);
774 private:
776 * Given an element, which must be the focused element, activate the remote
777 * frame it embeds, if any.
779 void ActivateRemoteFrameIfNeeded(mozilla::dom::Element&, uint64_t aActionId);
781 // Notify that the focus state of aElement has changed. Note that we need to
782 // pass in whether the window should show a focus ring before the
783 // SetFocusedNode call on it happened when losing focus and after the
784 // SetFocusedNode call when gaining focus, which is why that information needs
785 // to be an explicit argument instead of just passing in the window and asking
786 // it whether it should show focus rings: in the losing focus case that
787 // information could be wrong.
789 // aShouldShowFocusRing is only relevant if aGettingFocus is true.
790 static void NotifyFocusStateChange(mozilla::dom::Element* aElement,
791 mozilla::dom::Element* aElementToFocus,
792 int32_t aFlags, bool aGettingFocus,
793 bool aShouldShowFocusRing);
795 void SetFocusedWindowInternal(nsPIDOMWindowOuter* aWindow, uint64_t aActionId,
796 bool aSyncBrowsingContext = true);
798 MOZ_CAN_RUN_SCRIPT bool TryDocumentNavigation(nsIContent* aCurrentContent,
799 bool* aCheckSubDocument,
800 nsIContent** aResultContent);
802 MOZ_CAN_RUN_SCRIPT bool TryToMoveFocusToSubDocument(
803 nsIContent* aCurrentContent, nsIContent* aOriginalStartContent,
804 bool aForward, bool aForDocumentNavigation, bool aNavigateByKey,
805 bool aReachedToEndForDocumentNavigation, nsIContent** aResultContent);
807 // Sets the focused BrowsingContext and, if appropriate, syncs it to
808 // other processes.
809 void SetFocusedBrowsingContext(mozilla::dom::BrowsingContext* aContext,
810 uint64_t aActionId);
812 // Content-only
813 // Called when receiving an IPC message about another process setting
814 // the focused BrowsingContext.
815 void SetFocusedBrowsingContextFromOtherProcess(
816 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
818 // Chrome-only
819 // When returning true, sets the chrome process notion of what
820 // BrowsingContext is focused in content. When returning false,
821 // ignores the attempt to set as out-of-sequence.
822 bool SetFocusedBrowsingContextInChrome(
823 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
825 void InsertNewFocusActionId(uint64_t aActionId);
827 bool ProcessPendingActiveBrowsingContextActionId(uint64_t aActionId,
828 bool aSettingToNonNull);
830 bool ProcessPendingFocusedBrowsingContextActionId(uint64_t aActionId);
832 public:
833 // Chrome-only
834 // Gets the chrome process notion of what BrowsingContext is focused
835 // in content.
836 mozilla::dom::BrowsingContext* GetFocusedBrowsingContextInChrome();
838 // Chrome-only
839 // Notifies the focus manager that BrowsingContext::Detach was called
840 // on a BrowsingContext so that pointers to it can be forgotten.
841 void BrowsingContextDetached(mozilla::dom::BrowsingContext* aContext);
843 private:
844 // Content-only
845 // Sets the BrowsingContext corresponding to top-level Web content
846 // in the frontmost tab if focus is in Web content.
847 void SetActiveBrowsingContextInContent(
848 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId,
849 bool aIsEnteringBFCache);
851 // Content-only
852 // Receives notification of another process setting the top-level Web
853 // content as being in the frontmost tab with focus in Web content.
854 void SetActiveBrowsingContextFromOtherProcess(
855 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
857 // Content-only
858 // Receives notification that another process determined that focus
859 // moved to chrome so a particular BrowsingContext is no longer the
860 // "active" one.
861 void UnsetActiveBrowsingContextFromOtherProcess(
862 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
864 // Content-only
865 // Receives a notification from parent that this content process's
866 // attempt to set the active browsing context was late and the
867 // prevailing browsing context is instead the second argument of
868 // this method call. This should be ignored if the first argument
869 // doesn't match the latest action id associated with setting the
870 // active browsing context in this process, because in that case,
871 // this revision is late.
872 void ReviseActiveBrowsingContext(uint64_t aOldActionId,
873 mozilla::dom::BrowsingContext* aContext,
874 uint64_t aNewActionId);
876 // Receives a notification from parent that this content process's
877 // attempt to set the focused browsing context was late and the
878 // prevailing browsing context is instead the second argument of
879 // this method call. This should be ignored if the first argument
880 // doesn't match the latest action id associated with setting the
881 // active browsing context in this process, because in that case,
882 // this revision is late.
883 void ReviseFocusedBrowsingContext(uint64_t aOldActionId,
884 mozilla::dom::BrowsingContext* aContext,
885 uint64_t aNewActionId);
887 // Chrome-only
888 // Sets the chrome process notion of what content believes to be
889 // the top-level BrowsingContext in the frontmost tab when focus
890 // is in Web content.
891 // Returns true if set and false if ignored.
892 bool SetActiveBrowsingContextInChrome(mozilla::dom::BrowsingContext* aContext,
893 uint64_t aActionId);
895 public:
896 // Chrome-only
897 // Gets the chrome process notion of what content believes to be
898 // the top-level BrowsingContext in the frontmost tab when focus
899 // is in Web content.
900 mozilla::dom::BrowsingContext* GetActiveBrowsingContextInChrome();
902 uint64_t GetActionIdForActiveBrowsingContextInChrome() const;
904 uint64_t GetActionIdForFocusedBrowsingContextInChrome() const;
906 static uint64_t GenerateFocusActionId();
908 // This function works very similar to
909 // https://html.spec.whatwg.org/#get-the-focusable-area
910 static mozilla::dom::Element* GetTheFocusableArea(
911 mozilla::dom::Element* aTarget, uint32_t aFlags);
913 // Returns true if it's an area element with one or more shapes that are
914 // focusable areas.
915 static bool IsAreaElementFocusable(mozilla::dom::HTMLAreaElement& aArea);
917 private:
918 // In the chrome process, the currently active and front-most top-most
919 // window. Not supposed to be used in a meaningful way in content
920 // processes. For legacy reasons, this exists as a separate field
921 // instead of being derived from mFocusedWindow when needed, because
922 // the defined relation that mActiveWindow is supposed to be the same
923 // as or ancestor of mFocusedWindow is temporarily broken when a
924 // window is being raised or lowered.
925 nsCOMPtr<nsPIDOMWindowOuter> mActiveWindow;
927 // In a content process, the BrowsingContext corresponding to top-level
928 // Web content in the active tab or nullptr if focus is not in a
929 // BrowsingContextGroup that this process participates in. Synced
930 // across processes in a BrowsingContextGroup. This field exists
931 // separately from mFocusedBrowsingContextInContent instead of being being
932 // derived from it, because for legacy reasons the relation
933 // mFocusedBrowsingContextInContent->Top() == mActiveBrowsingContextInContent
934 // is temporarily broken when a window is being raised or lowered.
935 // Not supposed to be used in a meaningful way in the chrome process.
936 RefPtr<mozilla::dom::BrowsingContext> mActiveBrowsingContextInContent;
938 // If this content process set mActiveBrowsingContextInContent, this
939 // field holds the corresponding actionId so that
940 // mActiveBrowsingContextInContent can be revised of the parent rejects
941 // the update. This field is used for accepting revisions only if nothing
942 // else has updated mActiveBrowsingContextInContent before the revision
943 // arrives.
944 uint64_t mActionIdForActiveBrowsingContextInContent;
946 uint64_t mActionIdForActiveBrowsingContextInChrome;
948 // If this content process set mFocusedBrowsingContextInContent, this
949 // field holds the corresponding actionId so that
950 // mFocusedBrowsingContextInContent can be revised of the parent rejects
951 // the update. This field is used for accepting revisions only if nothing
952 // else has updated mFocusedBrowsingContextInContent before the revision
953 // arrives.
954 uint64_t mActionIdForFocusedBrowsingContextInContent;
956 uint64_t mActionIdForFocusedBrowsingContextInChrome;
958 // Whether or not mActiveBrowsingContextInContent was set from another process
959 // or from this process.
960 bool mActiveBrowsingContextInContentSetFromOtherProcess;
962 // This is the chrome process notion of content's
963 // mActiveBrowsingContextInContent. Avoiding field reuse for different
964 // semantics in different process types to make it easier to catch bugs.
965 RefPtr<mozilla::dom::BrowsingContext> mActiveBrowsingContextInChrome;
967 // the child or top-level window that is currently focused. In the chrome
968 // process, when a window isn't being raised or lowered, this window will
969 // either be the same window as mActiveWindow or a descendant of it.
970 // Except during shutdown use SetFocusedWindowInternal to set mFocusedWindow!
971 nsCOMPtr<nsPIDOMWindowOuter> mFocusedWindow;
973 // The focused BrowsingContext if this is a chrome process and focus is
974 // in chrome or if this is a content process and focus is in Web content
975 // in this BrowsingContextGroup. nullptr otherwise.
976 // Except during shutdown, must be set via SetFocusedWindowInternal which
977 // calls SetFocusedBrowsingContext or if the value is coming in via IPC
978 // via SetFocusedBrowsingContextFromOtherProcess.
979 RefPtr<mozilla::dom::BrowsingContext> mFocusedBrowsingContextInContent;
981 // This is the chrome process notion of content's
982 // mFocusedBrowsingContextInContent. Avoiding field reuse for different
983 // semantics in different process types to make it easier to catch bugs.
984 RefPtr<mozilla::dom::BrowsingContext> mFocusedBrowsingContextInChrome;
986 // the currently focused content if in-process or the XUL browser in which
987 // Web content focus resides. Always inside mFocusedWindow. When a window
988 // isn't being raised or lowered, this is a cached copy of the
989 // mFocusedWindow's current content. This may be null if no content is
990 // focused.
991 RefPtr<mozilla::dom::Element> mFocusedElement;
993 // these fields store a content node temporarily while it is being focused
994 // or blurred to ensure that a recursive call doesn't refire the same event.
995 // They will always be cleared afterwards.
996 RefPtr<mozilla::dom::Element> mFirstBlurEvent;
997 RefPtr<mozilla::dom::Element> mFirstFocusEvent;
999 // keep track of a window while it is being lowered
1000 nsCOMPtr<nsPIDOMWindowOuter> mWindowBeingLowered;
1002 // synchronized actions cannot be interrupted with events, so queue these up
1003 // and fire them later.
1004 nsTArray<nsDelayedBlurOrFocusEvent> mDelayedBlurFocusEvents;
1006 // Array of focus action ids for which we haven't seen an active browsing
1007 // context set yet. As set is allowed to overwrite an unset. Therefore,
1008 // an unset removes earlier ids but not the matching id. A set removes
1009 // earlier ids and the matching id.
1011 // Conceptually, active browsing context shouldn't have to exist as a
1012 // field, because it should be possible to always derive it from the
1013 // focused browsing context. Unfortunately, for legacy reasons, this
1014 // is not the case while a window is being raised or lowered.
1016 // Conceptually, it should be possible for the parent to manage the
1017 // active browsing context. Unfortunately, for legacy reasons, the
1018 // code for setting the active browsing context needs to reside in
1019 // the content process to retain the existing and test-passing code
1020 // flow.
1022 // This, obviously, raises the issue of content processes racing to
1023 // set the active browsing context. In particular, there is a pattern
1024 // that the parent initiates actions that cause multiple content
1025 // processes to mutate the active browsing context at almost the
1026 // same time. When two native browser windows change order, the
1027 // lowering isn't distinguished from the case of lowering the
1028 // entire app. For this reason, the owner of the previous active
1029 // browsing context tries to unset it and at almost the same time
1030 // the another content process sets a new active browsing context.
1031 // If the IPC messages for these unset and set actions were to
1032 // arrive in the wrong order, this could get in the wrong state.
1034 // To address this issue, the parent manages an authortative order
1035 // of attempts to (un)set the active browsing context using the
1036 // array mPendingActiveBrowsingContextActions.
1038 // A process reserves a slot in the order by calling
1039 // GenerateFocusActionId(). Per one call to GenerateFocusActionId(),
1040 // there may be at most one action to set the active browsing context
1041 // to a new value. There may be logically prior attempts to unset it
1042 // (i.e. set it to nullptr). That is, if there are both attempts to
1043 // unset and set the active browsing context with the same action id,
1044 // the attempt to set to a non-null value wins.
1046 // The completion of an action from reserting the slot in the order
1047 // and actually performing the setting of the active browsing context
1048 // may span multiple processes and IPC messages.
1050 // The at-most-once property is not asserted, because the process
1051 // claiming the position in the order and the process setting the
1052 // active browsing context with that actionId may be different, and
1053 // the act of using an actionId to set the active browsing context
1054 // is used to delete stale items from the array to avoid excessive
1055 // growth of the array.
1056 nsTArray<uint64_t> mPendingActiveBrowsingContextActions;
1058 // Like mPendingActiveBrowsingContextActions but for the focused
1059 // browsing context.
1060 nsTArray<uint64_t> mPendingFocusedBrowsingContextActions;
1062 // If set to true, layout of the document of the event target should be
1063 // flushed before handling focus depending events.
1064 bool mEventHandlingNeedsFlush;
1066 static bool sTestMode;
1068 // Process-specific counter for maintaining the prosess-specific
1069 // uniqueness of actionIds.
1070 static uint64_t sFocusActionCounter;
1072 // the single focus manager
1073 static mozilla::StaticRefPtr<nsFocusManager> sInstance;
1076 nsresult NS_NewFocusManager(nsIFocusManager** aResult);
1078 #endif