1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef nsFocusManager_h___
8 #define nsFocusManager_h___
9 
10 #include "nsCycleCollectionParticipant.h"
11 #include "nsIContent.h"
12 #include "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"
19 
20 #define FOCUSMANAGER_CONTRACTID "@mozilla.org/focus-manager;1"
21 
22 class nsIContent;
23 class nsPIDOMWindowOuter;
24 
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
35 
36 struct nsDelayedBlurOrFocusEvent;
37 
38 /**
39  * The focus manager keeps track of where the focus is, that is, the node
40  * which receives key events.
41  */
42 
43 class nsFocusManager final : public nsIFocusManager,
44                              public nsIObserver,
45                              public nsSupportsWeakReference {
46   typedef mozilla::widget::InputContextAction InputContextAction;
47   typedef mozilla::dom::Document Document;
48   friend class mozilla::dom::ContentChild;
49   friend class mozilla::dom::ContentParent;
50 
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
56 
57   // called to initialize and stop the focus manager at startup and shutdown
58   static nsresult Init();
59   static void Shutdown();
60 
61   // Simple helper to call SetFocusedWindow on the instance.
62   //
63   // This raises the window and switches to the tab as needed.
64   static void FocusWindow(nsPIDOMWindowOuter* aWindow,
65                           mozilla::dom::CallerType aCallerType);
66 
67   static void PrefChanged(const char* aPref, void* aSelf);
68   void PrefChanged(const char* aPref);
69 
70   /**
71    * Retrieve the single focus manager.
72    */
GetFocusManager()73   static nsFocusManager* GetFocusManager() { return sInstance; }
74 
75   /**
76    * A faster version of nsIFocusManager::GetFocusedElement, returning a
77    * raw Element pointer (instead of having AddRef-ed Element
78    * pointer filled in to an out-parameter).
79    */
GetFocusedElement()80   mozilla::dom::Element* GetFocusedElement() { return mFocusedElement; }
81 
82   /**
83    * Returns true if aContent currently has focus.
84    */
85   bool IsFocused(nsIContent* aContent);
86 
87   /**
88    * Returns true if test mode is enabled.
89    */
90   bool IsTestMode();
91 
92   /**
93    * Return a focused window. Version of nsIFocusManager::GetFocusedWindow.
94    */
GetFocusedWindow()95   nsPIDOMWindowOuter* GetFocusedWindow() const { return mFocusedWindow; }
96 
97   /**
98    * In the chrome process, retrieves the BrowsingContext corresponding
99    * to GetFocusedWindow(). In a content process, retrieves the
100    * focused BrowsingContext, which may not belong to this process.
101    */
GetFocusedBrowsingContext()102   mozilla::dom::BrowsingContext* GetFocusedBrowsingContext() const {
103     if (XRE_IsParentProcess()) {
104       if (mFocusedWindow) {
105         return mFocusedWindow->GetBrowsingContext();
106       }
107       return nullptr;
108     }
109     return mFocusedBrowsingContextInContent;
110   }
111 
112   /**
113    * Returns whether the given browsing context is in the active window.
114    */
115   bool IsInActiveWindow(mozilla::dom::BrowsingContext*) const;
116 
117   /**
118    * Return an active window. Version of nsIFocusManager::GetActiveWindow.
119    */
GetActiveWindow()120   nsPIDOMWindowOuter* GetActiveWindow() const { return mActiveWindow; }
121 
122   /**
123    * In the chrome process, retrieves the BrowsingContext corresponding
124    * to GetActiveWindow(). In a content process, retrieves the
125    * BrowsingContext of the top-level Web content in the active tab if
126    * in the same process as the caller or nullptr otherwise.
127    */
GetActiveBrowsingContext()128   mozilla::dom::BrowsingContext* GetActiveBrowsingContext() const {
129     if (XRE_IsParentProcess()) {
130       if (mActiveWindow) {
131         return mActiveWindow->GetBrowsingContext();
132       }
133       return nullptr;
134     }
135     return mActiveBrowsingContextInContent;
136   }
137 
138   /**
139    * Called when content has been removed.
140    */
141   nsresult ContentRemoved(Document* aDocument, nsIContent* aContent);
142 
NeedsFlushBeforeEventHandling(mozilla::dom::Element * aElement)143   void NeedsFlushBeforeEventHandling(mozilla::dom::Element* aElement) {
144     if (mFocusedElement == aElement) {
145       mEventHandlingNeedsFlush = true;
146     }
147   }
148 
149   bool CanSkipFocus(nsIContent* aContent);
150 
FlushBeforeEventHandlingIfNeeded(nsIContent * aContent)151   void FlushBeforeEventHandlingIfNeeded(nsIContent* aContent) {
152     if (mEventHandlingNeedsFlush) {
153       nsCOMPtr<Document> doc = aContent->GetComposedDoc();
154       if (doc) {
155         mEventHandlingNeedsFlush = false;
156         doc->FlushPendingNotifications(mozilla::FlushType::Layout);
157       }
158     }
159   }
160 
161   /**
162    * Update the caret with current mode (whether in caret browsing mode or not).
163    */
164   void UpdateCaretForCaretBrowsingMode();
165 
166   /**
167    * Returns the content node that would be focused if aWindow was in an
168    * active window. This will traverse down the frame hierarchy, starting at
169    * the given window aWindow. Sets aFocusedWindow to the window with the
170    * document containing aFocusedContent. If no element is focused,
171    * aFocusedWindow may be still be set -- this means that the document is
172    * focused but no element within it is focused.
173    *
174    * aWindow, aFocusIsOutOfProcess, aFocusedWindow must all be non-null.
175    */
176   enum SearchRange {
177     // Return focused content in aWindow.  So, aFocusedWindow is always aWindow.
178     eOnlyCurrentWindow,
179     // Return focused content in aWindow or one of all sub windows.
180     eIncludeAllDescendants,
181     // Return focused content in aWindow or one of visible sub windows.
182     eIncludeVisibleDescendants,
183   };
184   static mozilla::dom::Element* GetFocusedDescendant(
185       nsPIDOMWindowOuter* aWindow, SearchRange aSearchRange,
186       nsPIDOMWindowOuter** aFocusedWindow);
187 
188   /**
189    * Helper function for MoveFocus which determines the next element
190    * to move the focus to and returns it in aNextContent.
191    *
192    * aWindow is the window to adjust the focus within, and aStart is
193    * the element to start navigation from. For tab key navigation,
194    * this should be the currently focused element.
195    *
196    * aType is the type passed to MoveFocus. If aNoParentTraversal is set,
197    * navigation is not done to parent documents and iteration returns to the
198    * beginning (or end) of the starting document.
199    *
200    * aNavigateByKey to move focus by keyboard as a side effect of computing the
201    * next target.
202    */
203   nsresult DetermineElementToMoveFocus(nsPIDOMWindowOuter* aWindow,
204                                        nsIContent* aStart, int32_t aType,
205                                        bool aNoParentTraversal,
206                                        bool aNavigateByKey,
207                                        nsIContent** aNextContent);
208 
209   /**
210    * Setter for focusedWindow with CallerType
211    */
212   MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult SetFocusedWindowWithCallerType(
213       mozIDOMWindowProxy* aWindowToFocus, mozilla::dom::CallerType aCallerType,
214       uint64_t aActionId);
215 
216   /**
217    * Given an element, which must be the focused element, activate the remote
218    * frame it embeds, if any.
219    */
220   void ActivateRemoteFrameIfNeeded(mozilla::dom::Element&, uint64_t aActionId);
221 
222   /**
223    * Raises the top-level window aWindow at the widget level.
224    */
225   void RaiseWindow(nsPIDOMWindowOuter* aWindow,
226                    mozilla::dom::CallerType aCallerType, uint64_t aActionId);
227 
228   /**
229    * Called when a window has been raised.
230    */
231   void WindowRaised(mozIDOMWindowProxy* aWindow, uint64_t aActionId);
232 
233   /**
234    * Called when a window has been lowered.
235    */
236   MOZ_CAN_RUN_SCRIPT_BOUNDARY void WindowLowered(mozIDOMWindowProxy* aWindow,
237                                                  uint64_t aActionId);
238 
239   /**
240    * Called when a new document in a window is shown.
241    *
242    * If aNeedsFocus is true, then focus events are expected to be fired on the
243    * window if this window is in the focused window chain.
244    */
245   void WindowShown(mozIDOMWindowProxy* aWindow, bool aNeedsFocus);
246 
247   /**
248    * Called when a document in a window has been hidden or otherwise can no
249    * longer accept focus.
250    */
251   void WindowHidden(mozIDOMWindowProxy* aWindow, uint64_t aActionId);
252 
253   /**
254    * Fire any events that have been delayed due to synchronized actions.
255    */
256   void FireDelayedEvents(Document* aDocument);
257 
258   void WasNuked(nsPIDOMWindowOuter* aWindow);
259 
260   /**
261    * Indicate that a plugin wishes to take the focus. This is similar to a
262    * normal focus except that the widget focus is not changed. Updating the
263    * widget focus state is the responsibility of the caller.
264    */
265   MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
266   FocusPlugin(mozilla::dom::Element* aPlugin);
267 
268   static uint32_t ProgrammaticFocusFlags(
269       const mozilla::dom::FocusOptions& aOptions);
270 
271   /**
272    * Returns the content node that focus will be redirected to if aContent was
273    * focused. This is used for the special case of certain XUL elements such
274    * as textboxes or input number which redirect focus to an anonymous child.
275    *
276    * aContent must be non-null.
277    *
278    * XXXndeakin this should be removed eventually but I want to do that as
279    * followup work.
280    */
281   static mozilla::dom::Element* GetRedirectedFocus(nsIContent* aContent);
282 
283   /**
284    * Returns an InputContextAction cause for aFlags.
285    */
286   static InputContextAction::Cause GetFocusMoveActionCause(uint32_t aFlags);
287 
288   /**
289    * Notify of re-focus to same content.
290    *
291    * aContent is focused content.
292    */
293   void NotifyOfReFocus(nsIContent& aContent);
294 
295   static void MarkUncollectableForCCGeneration(uint32_t aGeneration);
296 
297   struct BlurredElementInfo {
298     const mozilla::OwningNonNull<mozilla::dom::Element> mElement;
299 
300     explicit BlurredElementInfo(mozilla::dom::Element&);
301     ~BlurredElementInfo();
302   };
303 
304  protected:
305   nsFocusManager();
306   ~nsFocusManager();
307 
308   /**
309    * Ensure that the widget associated with the currently focused window is
310    * focused at the widget level.
311    */
312   void EnsureCurrentWidgetFocused(mozilla::dom::CallerType aCallerType);
313 
314   /**
315    * Activate or deactivate the window and send the activate/deactivate events.
316    */
317   void ActivateOrDeactivate(nsPIDOMWindowOuter* aWindow, bool aActive);
318 
319   /**
320    * Blur whatever is currently focused and focus aNewContent. aFlags is a
321    * bitmask of the flags defined in nsIFocusManager. If aFocusChanged is
322    * true, then the focus has actually shifted and the caret position will be
323    * updated to the new focus, aNewContent will be scrolled into view (unless
324    * a flag disables this) and the focus method for the window will be updated.
325    * If aAdjustWidget is false, don't change the widget focus state.
326    *
327    * All actual focus changes must use this method to do so. (as opposed
328    * to those that update the focus in an inactive window for instance).
329    */
330   MOZ_CAN_RUN_SCRIPT void SetFocusInner(mozilla::dom::Element* aNewContent,
331                                         int32_t aFlags, bool aFocusChanged,
332                                         bool aAdjustWidget, uint64_t aActionId);
333 
334   /**
335    * Returns true if aPossibleAncestor is the same as aWindow or an
336    * ancestor of aWindow.
337    */
338   bool IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor,
339                         nsPIDOMWindowOuter* aWindow) const;
340   bool IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor,
341                         mozilla::dom::BrowsingContext* aContext) const;
342   bool IsSameOrAncestor(mozilla::dom::BrowsingContext* aPossibleAncestor,
343                         nsPIDOMWindowOuter* aWindow) const;
344 
345  public:
346   bool IsSameOrAncestor(mozilla::dom::BrowsingContext* aPossibleAncestor,
347                         mozilla::dom::BrowsingContext* aContext) const;
348 
349  protected:
350   /**
351    * Returns the window that is the lowest common ancestor of both aWindow
352    * and aContext, or null if they share no common ancestor.
353    */
354   mozilla::dom::BrowsingContext* GetCommonAncestor(
355       nsPIDOMWindowOuter* aWindow, mozilla::dom::BrowsingContext* aContext);
356 
357   /**
358    * When aBrowsingContext is focused, adjust the ancestors of aBrowsingContext
359    * so that they also have their corresponding frames focused. Thus, one can
360    * start at the active top-level window and navigate down the currently
361    * focused elements for each frame in the tree to get to aBrowsingContext.
362    */
363   bool AdjustInProcessWindowFocus(
364       mozilla::dom::BrowsingContext* aBrowsingContext, bool aCheckPermission,
365       bool aIsVisible, uint64_t aActionId);
366   void AdjustWindowFocus(mozilla::dom::BrowsingContext* aBrowsingContext,
367                          bool aCheckPermission, bool aIsVisible,
368                          uint64_t aActionId);
369 
370   /**
371    * Returns true if aWindow is visible.
372    */
373   bool IsWindowVisible(nsPIDOMWindowOuter* aWindow);
374 
375   /**
376    * Returns true if aContent is a root element and not focusable.
377    * I.e., even if aContent is editable root element, this returns true when
378    * the document is in designMode.
379    *
380    * @param aContent must not be null and must be in a document.
381    */
382   bool IsNonFocusableRoot(nsIContent* aContent);
383 
384   /**
385    * First flushes the pending notifications to ensure the PresShell and frames
386    * are updated.
387    * Checks and returns aElement if it may be focused, another element node if
388    * the focus should be retargeted at another node, or null if the node
389    * cannot be focused. aFlags are the flags passed to SetFocus and similar
390    * methods.
391    *
392    * An element is focusable if it is in a document, the document isn't in
393    * print preview mode and the element has an nsIFrame where the
394    * IsFocusable method returns true. For <area> elements, there is no
395    * frame, so only the IsFocusable method on the content node must be
396    * true.
397    */
398   mozilla::dom::Element* FlushAndCheckIfFocusable(
399       mozilla::dom::Element* aElement, uint32_t aFlags);
400 
401   /**
402    * Blurs the currently focused element. Returns false if another element was
403    * focused as a result. This would mean that the caller should not proceed
404    * with a pending call to Focus. Normally, true would be returned.
405    *
406    * The currently focused element within aBrowsingContextToClear will be
407    * cleared. aBrowsingContextToClear may be null, which means that no window is
408    * cleared. This will be the case, for example, when lowering a window, as we
409    * want to fire a blur, but not actually change what element would be focused,
410    * so that the same element will be focused again when the window is raised.
411    *
412    * aAncestorBrowsingContextToFocus should be set to the common ancestor of the
413    * window that is being blurred and the window that is going to focused, when
414    * switching focus to a sibling window.
415    *
416    * aIsLeavingDocument should be set to true if the document/window is being
417    * blurred as well. Document/window blur events will be fired. It should be
418    * false if an element is the same document is about to be focused.
419    *
420    * If aAdjustWidget is false, don't change the widget focus state.
421    */
422   // MOZ_CAN_RUN_SCRIPT_BOUNDARY for now, until we annotate callers.
423   MOZ_CAN_RUN_SCRIPT_BOUNDARY
424   bool Blur(mozilla::dom::BrowsingContext* aBrowsingContextToClear,
425             mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus,
426             bool aIsLeavingDocument, bool aAdjustWidget, uint64_t aActionId,
427             mozilla::dom::Element* aElementToFocus = nullptr);
428   MOZ_CAN_RUN_SCRIPT_BOUNDARY
429   void BlurFromOtherProcess(
430       mozilla::dom::BrowsingContext* aFocusedBrowsingContext,
431       mozilla::dom::BrowsingContext* aBrowsingContextToClear,
432       mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus,
433       bool aIsLeavingDocument, bool aAdjustWidget, uint64_t aActionId);
434   MOZ_CAN_RUN_SCRIPT_BOUNDARY
435   bool BlurImpl(mozilla::dom::BrowsingContext* aBrowsingContextToClear,
436                 mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus,
437                 bool aIsLeavingDocument, bool aAdjustWidget,
438                 mozilla::dom::Element* aElementToFocus, uint64_t aActionId);
439 
440   /**
441    * Focus an element in the active window and child frame.
442    *
443    * aWindow is the window containing the element aContent to focus.
444    *
445    * aFlags is the flags passed to the various focus methods in
446    * nsIFocusManager.
447    *
448    * aIsNewDocument should be true if a new document is being focused.
449    * Document/window focus events will be fired.
450    *
451    * aFocusChanged should be true if a new content node is being focused, so
452    * the focused content will be scrolled into view and the caret position
453    * will be updated. If false is passed, then a window is simply being
454    * refocused, for instance, due to a window being raised, or a tab is being
455    * switched to.
456    *
457    * If aFocusChanged is true, then the focus has moved to a new location.
458    * Otherwise, the focus is just being updated because the window was
459    * raised.
460    *
461    * aWindowRaised should be true if the window is being raised. In this case,
462    * command updaters will not be called.
463    *
464    * If aAdjustWidget is false, don't change the widget focus state.
465    */
466   MOZ_CAN_RUN_SCRIPT_BOUNDARY
467   void Focus(nsPIDOMWindowOuter* aWindow, mozilla::dom::Element* aContent,
468              uint32_t aFlags, bool aIsNewDocument, bool aFocusChanged,
469              bool aWindowRaised, bool aAdjustWidget, uint64_t aActionId,
470              const mozilla::Maybe<BlurredElementInfo>& = mozilla::Nothing());
471 
472   /**
473    * Send a focus or blur event at aTarget. It may be added to the delayed
474    * event queue if the document is suppressing events.
475    *
476    * aEventMessage should be either eFocus or eBlur.
477    *
478    * aWindowRaised should only be true if called from WindowRaised.
479    */
480   void SendFocusOrBlurEvent(
481       mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
482       Document* aDocument, nsISupports* aTarget, bool aWindowRaised,
483       bool aIsRefocus = false,
484       mozilla::dom::EventTarget* aRelatedTarget = nullptr);
485   /**
486    * Fire a focus or blur event at aTarget.
487    *
488    * aEventMessage should be either eFocus or eBlur.
489    * For blur events, aFocusMethod should normally be non-zero.
490    *
491    * aWindowRaised should only be true if called from WindowRaised.
492    */
493   void FireFocusOrBlurEvent(
494       mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
495       nsISupports* aTarget, bool aWindowRaised, bool aIsRefocus = false,
496       mozilla::dom::EventTarget* aRelatedTarget = nullptr);
497 
498   /**
499    *  Fire a focusin or focusout event
500    *
501    *  aEventMessage should be either eFocusIn or eFocusOut.
502    *
503    *  aTarget is the content the event will fire on (the object that gained
504    *  focus for focusin, the object blurred for focusout).
505    *
506    *  aCurrentFocusedWindow is the window focused before the focus/blur event
507    *  was fired.
508    *
509    *  aCurrentFocusedContent is the content focused before the focus/blur event
510    *  was fired.
511    *
512    *  aRelatedTarget is the content related to the event (the object
513    *  losing focus for focusin, the object getting focus for focusout).
514    */
515   void FireFocusInOrOutEvent(
516       mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
517       nsISupports* aTarget, nsPIDOMWindowOuter* aCurrentFocusedWindow,
518       nsIContent* aCurrentFocusedContent,
519       mozilla::dom::EventTarget* aRelatedTarget = nullptr);
520 
521   /**
522    * Scrolls aContent into view unless the FLAG_NOSCROLL flag is set.
523    */
524   MOZ_CAN_RUN_SCRIPT
525   void ScrollIntoView(mozilla::PresShell* aPresShell, nsIContent* aContent,
526                       uint32_t aFlags);
527 
528   /**
529    * Updates the caret positon and visibility to match the focus.
530    *
531    * aMoveCaretToFocus should be true to move the caret to aContent.
532    *
533    * aUpdateVisibility should be true to update whether the caret is
534    * visible or not.
535    */
536   void UpdateCaret(bool aMoveCaretToFocus, bool aUpdateVisibility,
537                    nsIContent* aContent);
538 
539   /**
540    * Helper method to move the caret to the focused element aContent.
541    */
542   MOZ_CAN_RUN_SCRIPT_BOUNDARY void MoveCaretToFocus(
543       mozilla::PresShell* aPresShell, nsIContent* aContent);
544 
545   /**
546    * Makes the caret visible or not, depending on aVisible.
547    */
548   nsresult SetCaretVisible(mozilla::PresShell* aPresShell, bool aVisible,
549                            nsIContent* aContent);
550 
551   // the remaining functions are used for tab key and document-navigation
552 
553   /**
554    * Retrieves the start and end points of the current selection for
555    * aDocument and stores them in aStartContent and aEndContent.
556    */
557   nsresult GetSelectionLocation(Document* aDocument,
558                                 mozilla::PresShell* aPresShell,
559                                 nsIContent** aStartContent,
560                                 nsIContent** aEndContent);
561 
562   /**
563    * Retrieve the next tabbable element in scope owned by aOwner, using
564    * focusability and tabindex to determine the tab order.
565    *
566    * aOwner is the owner of scope to search in.
567    *
568    * aStartContent is the starting point for this call of this method.
569    *
570    * aOriginalStartContent is the initial starting point for sequential
571    * navigation.
572    *
573    * aForward should be true for forward navigation or false for backward
574    * navigation.
575    *
576    * aCurrentTabIndex is the current tabindex.
577    *
578    * aIgnoreTabIndex to ignore the current tabindex and find the element
579    * irrespective or the tab index.
580    *
581    * aForDocumentNavigation informs whether we're navigating only through
582    * documents.
583    *
584    * aSkipOwner to skip owner while searching. The flag is set when caller is
585    * |GetNextTabbableContent| in order to let caller handle owner.
586    *
587    * NOTE:
588    *   Consider the method searches downwards in flattened subtree
589    *   rooted at aOwner.
590    */
591   nsIContent* GetNextTabbableContentInScope(
592       nsIContent* aOwner, nsIContent* aStartContent,
593       nsIContent* aOriginalStartContent, bool aForward,
594       int32_t aCurrentTabIndex, bool aIgnoreTabIndex,
595       bool aForDocumentNavigation, bool aNavigateByKey, bool aSkipOwner);
596 
597   /**
598    * Retrieve the next tabbable element in scope including aStartContent
599    * and the scope's ancestor scopes, using focusability and tabindex to
600    * determine the tab order.
601    *
602    * aStartOwner is the scope owner of the aStartContent.
603    *
604    * aStartContent an in/out paremeter. It as input is the starting point
605    * for this call of this method; as output it is the shadow host in
606    * light DOM if the next tabbable element is not found in shadow DOM,
607    * in order to continue searching in light DOM.
608    *
609    * aOriginalStartContent is the initial starting point for sequential
610    * navigation.
611    *
612    * aForward should be true for forward navigation or false for backward
613    * navigation.
614    *
615    * aCurrentTabIndex returns tab index of shadow host in light DOM if the
616    * next tabbable element is not found in shadow DOM, in order to continue
617    * searching in light DOM.
618    *
619    * aIgnoreTabIndex to ignore the current tabindex and find the element
620    * irrespective or the tab index.
621    *
622    * aForDocumentNavigation informs whether we're navigating only through
623    * documents.
624    *
625    * aNavigateByKey to move focus by keyboard as a side effect of computing the
626    * next target.
627    *
628    * NOTE:
629    *   Consider the method searches upwards in all shadow host- or slot-rooted
630    *   flattened subtrees that contains aStartContent as non-root, except
631    *   the flattened subtree rooted at shadow host in light DOM.
632    */
633   nsIContent* GetNextTabbableContentInAncestorScopes(
634       nsIContent* aStartOwner, nsIContent** aStartContent,
635       nsIContent* aOriginalStartContent, bool aForward,
636       int32_t* aCurrentTabIndex, bool aIgnoreTabIndex,
637       bool aForDocumentNavigation, bool aNavigateByKey);
638 
639   /**
640    * Retrieve the next tabbable element within a document, using focusability
641    * and tabindex to determine the tab order. The element is returned in
642    * aResultContent.
643    *
644    * aRootContent is the root node -- nodes above this will not be examined.
645    * Typically this will be the root node of a document, but could also be
646    * a popup node.
647    *
648    * aOriginalStartContent is the content which was originally the starting
649    * node, in the case of recursive or looping calls.
650    *
651    * aStartContent is the starting point for this call of this method.
652    * If aStartContent doesn't have visual representation, the next content
653    * object, which does have a primary frame, will be used as a start.
654    * If that content object is focusable, the method may return it.
655    *
656    * aForward should be true for forward navigation or false for backward
657    * navigation.
658    *
659    * aCurrentTabIndex is the current tabindex.
660    *
661    * aIgnoreTabIndex to ignore the current tabindex and find the element
662    * irrespective or the tab index. This will be true when a selection is
663    * active, since we just want to focus the next element in tree order
664    * from where the selection is. Similarly, if the starting element isn't
665    * focusable, since it doesn't really have a defined tab index.
666    *
667    * aNavigateByKey to move focus by keyboard as a side effect of computing the
668    * next target.
669    */
670   nsresult GetNextTabbableContent(
671       mozilla::PresShell* aPresShell, nsIContent* aRootContent,
672       nsIContent* aOriginalStartContent, nsIContent* aStartContent,
673       bool aForward, int32_t aCurrentTabIndex, bool aIgnoreTabIndex,
674       bool aForDocumentNavigation, bool aNavigateByKey,
675       nsIContent** aResultContent);
676 
677   /**
678    * Get the next tabbable image map area and returns it.
679    *
680    * aForward should be true for forward navigation or false for backward
681    * navigation.
682    *
683    * aCurrentTabIndex is the current tabindex.
684    *
685    * aImageContent is the image.
686    *
687    * aStartContent is the current image map area.
688    */
689   nsIContent* GetNextTabbableMapArea(bool aForward, int32_t aCurrentTabIndex,
690                                      mozilla::dom::Element* aImageContent,
691                                      nsIContent* aStartContent);
692 
693   /**
694    * Return the next valid tabindex value after aCurrentTabIndex, if aForward
695    * is true, or the previous tabindex value if aForward is false. aParent is
696    * the node from which to start looking for tab indicies.
697    */
698   int32_t GetNextTabIndex(nsIContent* aParent, int32_t aCurrentTabIndex,
699                           bool aForward);
700 
701   /**
702    * Focus the first focusable content within the document with a root node of
703    * aRootContent. For content documents, this will be aRootContent itself, but
704    * for chrome documents, this will locate the next focusable content.
705    */
706   nsresult FocusFirst(mozilla::dom::Element* aRootContent,
707                       nsIContent** aNextContent);
708 
709   /**
710    * Retrieves and returns the root node from aDocument to be focused. Will
711    * return null if the root node cannot be focused. There are several reasons
712    * for this:
713    *
714    * - if aForDocumentNavigation is false and aWindow is a chrome shell.
715    * - if aCheckVisibility is true and the aWindow is not visible.
716    * - if aDocument is a frameset document.
717    */
718   mozilla::dom::Element* GetRootForFocus(nsPIDOMWindowOuter* aWindow,
719                                          Document* aDocument,
720                                          bool aForDocumentNavigation,
721                                          bool aCheckVisibility);
722 
723   /**
724    * Retrieves and returns the root node as with GetRootForFocus but only if
725    * aContent is a frame with a valid child document.
726    */
727   mozilla::dom::Element* GetRootForChildDocument(nsIContent* aContent);
728 
729   /**
730    * Retreives a focusable element within the current selection of aWindow.
731    * Currently, this only detects links.
732    *
733    * This is used when MoveFocus is called with a type of MOVEFOCUS_CARET,
734    * which is used, for example, to focus links as the caret is moved over
735    * them.
736    */
737   void GetFocusInSelection(nsPIDOMWindowOuter* aWindow,
738                            nsIContent* aStartSelection,
739                            nsIContent* aEndSelection,
740                            nsIContent** aFocusedContent);
741 
742  private:
743   // Notify that the focus state of aElement has changed.  Note that we need to
744   // pass in whether the window should show a focus ring before the
745   // SetFocusedNode call on it happened when losing focus and after the
746   // SetFocusedNode call when gaining focus, which is why that information needs
747   // to be an explicit argument instead of just passing in the window and asking
748   // it whether it should show focus rings: in the losing focus case that
749   // information could be wrong.
750   //
751   // aShouldShowFocusRing is only relevant if aGettingFocus is true.
752   static void NotifyFocusStateChange(mozilla::dom::Element* aElement,
753                                      mozilla::dom::Element* aElementToFocus,
754                                      int32_t aFlags, bool aGettingFocus,
755                                      bool aShouldShowFocusRing);
756 
757   void SetFocusedWindowInternal(nsPIDOMWindowOuter* aWindow, uint64_t aActionId,
758                                 bool aSyncBrowsingContext = true);
759 
760   bool TryDocumentNavigation(nsIContent* aCurrentContent,
761                              bool* aCheckSubDocument,
762                              nsIContent** aResultContent);
763 
764   bool TryToMoveFocusToSubDocument(nsIContent* aCurrentContent,
765                                    nsIContent* aOriginalStartContent,
766                                    bool aForward, bool aForDocumentNavigation,
767                                    bool aNavigateByKey,
768                                    nsIContent** aResultContent);
769 
770   // Sets the focused BrowsingContext and, if appropriate, syncs it to
771   // other processes.
772   void SetFocusedBrowsingContext(mozilla::dom::BrowsingContext* aContext,
773                                  uint64_t aActionId);
774 
775   // Content-only
776   // Called when receiving an IPC message about another process setting
777   // the focused BrowsingContext.
778   void SetFocusedBrowsingContextFromOtherProcess(
779       mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
780 
781   // Chrome-only
782   // When returning true, sets the chrome process notion of what
783   // BrowsingContext is focused in content. When returning false,
784   // ignores the attempt to set as out-of-sequence.
785   bool SetFocusedBrowsingContextInChrome(
786       mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
787 
788   void InsertNewFocusActionId(uint64_t aActionId);
789 
790   bool ProcessPendingActiveBrowsingContextActionId(uint64_t aActionId,
791                                                    bool aSettingToNonNull);
792 
793   bool ProcessPendingFocusedBrowsingContextActionId(uint64_t aActionId);
794 
795  public:
796   // Chrome-only
797   // Gets the chrome process notion of what BrowsingContext is focused
798   // in content.
799   mozilla::dom::BrowsingContext* GetFocusedBrowsingContextInChrome();
800 
801   // Chrome-only
802   // Notifies the focus manager that BrowsingContext::Detach was called
803   // on a BrowsingContext so that pointers to it can be forgotten.
804   void BrowsingContextDetached(mozilla::dom::BrowsingContext* aContext);
805 
806  private:
807   // Content-only
808   // Sets the BrowsingContext corresponding to top-level Web content
809   // in the frontmost tab if focus is in Web content.
810   void SetActiveBrowsingContextInContent(
811       mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
812 
813   // Content-only
814   // Receives notification of another process setting the top-level Web
815   // content as being in the frontmost tab with focus in Web content.
816   void SetActiveBrowsingContextFromOtherProcess(
817       mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
818 
819   // Content-only
820   // Receives notification that another process determined that focus
821   // moved to chrome so a particular BrowsingContext is no longer the
822   // "active" one.
823   void UnsetActiveBrowsingContextFromOtherProcess(
824       mozilla::dom::BrowsingContext* aContext, uint64_t aActionId);
825 
826   // Content-only
827   // Receives a notification from parent that this content process's
828   // attempt to set the active browsing context was late and the
829   // prevailing browsing context is instead the second argument of
830   // this method call. This should be ignored if the first argument
831   // doesn't match the latest action id associated with setting the
832   // active browsing context in this process, because in that case,
833   // this revision is late.
834   void ReviseActiveBrowsingContext(uint64_t aOldActionId,
835                                    mozilla::dom::BrowsingContext* aContext,
836                                    uint64_t aNewActionId);
837 
838   // Receives a notification from parent that this content process's
839   // attempt to set the focused browsing context was late and the
840   // prevailing browsing context is instead the second argument of
841   // this method call. This should be ignored if the first argument
842   // doesn't match the latest action id associated with setting the
843   // active browsing context in this process, because in that case,
844   // this revision is late.
845   void ReviseFocusedBrowsingContext(uint64_t aOldActionId,
846                                     mozilla::dom::BrowsingContext* aContext,
847                                     uint64_t aNewActionId);
848 
849   // Chrome-only
850   // Sets the chrome process notion of what content believes to be
851   // the top-level BrowsingContext in the frontmost tab when focus
852   // is in Web content.
853   // Returns true if set and false if ignored.
854   bool SetActiveBrowsingContextInChrome(mozilla::dom::BrowsingContext* aContext,
855                                         uint64_t aActionId);
856 
857  public:
858   // Chrome-only
859   // Gets the chrome process notion of what content believes to be
860   // the top-level BrowsingContext in the frontmost tab when focus
861   // is in Web content.
862   mozilla::dom::BrowsingContext* GetActiveBrowsingContextInChrome();
863 
864   uint64_t GetActionIdForActiveBrowsingContextInChrome() const;
865 
866   uint64_t GetActionIdForFocusedBrowsingContextInChrome() const;
867 
868   static uint64_t GenerateFocusActionId();
869 
870  private:
871   // In the chrome process, the currently active and front-most top-most
872   // window. Not supposed to be used in a meaningful way in content
873   // processes. For legacy reasons, this exists as a separate field
874   // instead of being derived from mFocusedWindow when needed, because
875   // the defined relation that mActiveWindow is supposed to be the same
876   // as or ancestor of mFocusedWindow is temporarily broken when a
877   // window is being raised or lowered.
878   nsCOMPtr<nsPIDOMWindowOuter> mActiveWindow;
879 
880   // In a content process, the BrowsingContext corresponding to top-level
881   // Web content in the active tab or nullptr if focus is not in a
882   // BrowsingContextGroup that this process participates in. Synced
883   // across processes in a BrowsingContextGroup. This field exists
884   // separately from mFocusedBrowsingContextInContent instead of being being
885   // derived from it, because for legacy reasons the relation
886   // mFocusedBrowsingContextInContent->Top() == mActiveBrowsingContextInContent
887   // is temporarily broken when a window is being raised or lowered.
888   // Not supposed to be used in a meaningful way in the chrome process.
889   RefPtr<mozilla::dom::BrowsingContext> mActiveBrowsingContextInContent;
890 
891   // If this content process set mActiveBrowsingContextInContent, this
892   // field holds the corresponding actionId so that
893   // mActiveBrowsingContextInContent can be revised of the parent rejects
894   // the update. This field is used for accepting revisions only if nothing
895   // else has updated mActiveBrowsingContextInContent before the revision
896   // arrives.
897   uint64_t mActionIdForActiveBrowsingContextInContent;
898 
899   uint64_t mActionIdForActiveBrowsingContextInChrome;
900 
901   // If this content process set mFocusedBrowsingContextInContent, this
902   // field holds the corresponding actionId so that
903   // mFocusedBrowsingContextInContent can be revised of the parent rejects
904   // the update. This field is used for accepting revisions only if nothing
905   // else has updated mFocusedBrowsingContextInContent before the revision
906   // arrives.
907   uint64_t mActionIdForFocusedBrowsingContextInContent;
908 
909   uint64_t mActionIdForFocusedBrowsingContextInChrome;
910 
911   // Whether or not mActiveBrowsingContextInContent was set from another process
912   // or from this process.
913   bool mActiveBrowsingContextInContentSetFromOtherProcess;
914 
915   // This is the chrome process notion of content's
916   // mActiveBrowsingContextInContent. Avoiding field reuse for different
917   // semantics in different process types to make it easier to catch bugs.
918   RefPtr<mozilla::dom::BrowsingContext> mActiveBrowsingContextInChrome;
919 
920   // the child or top-level window that is currently focused. In the chrome
921   // process, when a window isn't being raised or lowered, this window will
922   // either be the same window as mActiveWindow or a descendant of it.
923   // Except during shutdown use SetFocusedWindowInternal to set mFocusedWindow!
924   nsCOMPtr<nsPIDOMWindowOuter> mFocusedWindow;
925 
926   // The focused BrowsingContext if this is a chrome process and focus is
927   // in chrome or if this is a content process and focus is in Web content
928   // in this BrowsingContextGroup. nullptr otherwise.
929   // Except during shutdown, must be set via SetFocusedWindowInternal which
930   // calls SetFocusedBrowsingContext or if the value is coming in via IPC
931   // via SetFocusedBrowsingContextFromOtherProcess.
932   RefPtr<mozilla::dom::BrowsingContext> mFocusedBrowsingContextInContent;
933 
934   // This is the chrome process notion of content's
935   // mFocusedBrowsingContextInContent. Avoiding field reuse for different
936   // semantics in different process types to make it easier to catch bugs.
937   RefPtr<mozilla::dom::BrowsingContext> mFocusedBrowsingContextInChrome;
938 
939   // the currently focused content if in-process or the XUL browser in which
940   // Web content focus resides. Always inside mFocusedWindow. When a window
941   // isn't being raised or lowered, this is a cached copy of the
942   // mFocusedWindow's current content. This may be null if no content is
943   // focused.
944   RefPtr<mozilla::dom::Element> mFocusedElement;
945 
946   // these fields store a content node temporarily while it is being focused
947   // or blurred to ensure that a recursive call doesn't refire the same event.
948   // They will always be cleared afterwards.
949   RefPtr<mozilla::dom::Element> mFirstBlurEvent;
950   RefPtr<mozilla::dom::Element> mFirstFocusEvent;
951 
952   // keep track of a window while it is being lowered
953   nsCOMPtr<nsPIDOMWindowOuter> mWindowBeingLowered;
954 
955   // synchronized actions cannot be interrupted with events, so queue these up
956   // and fire them later.
957   nsTArray<nsDelayedBlurOrFocusEvent> mDelayedBlurFocusEvents;
958 
959   // Array of focus action ids for which we haven't seen an active browsing
960   // context set yet. As set is allowed to overwrite an unset. Therefore,
961   // an unset removes earlier ids but not the matching id. A set removes
962   // earlier ids and the matching id.
963   //
964   // Conceptually, active browsing context shouldn't have to exist as a
965   // field, because it should be possible to always derive it from the
966   // focused browsing context. Unfortunately, for legacy reasons, this
967   // is not the case while a window is being raised or lowered.
968   //
969   // Conceptually, it should be possible for the parent to manage the
970   // active browsing context. Unfortunately, for legacy reasons, the
971   // code for setting the active browsing context needs to reside in
972   // the content process to retain the existing and test-passing code
973   // flow.
974   //
975   // This, obviously, raises the issue of content processes racing to
976   // set the active browsing context. In particular, there is a pattern
977   // that the parent initiates actions that cause multiple content
978   // processes to mutate the active browsing context at almost the
979   // same time. When two native browser windows change order, the
980   // lowering isn't distinguished from the case of lowering the
981   // entire app. For this reason, the owner of the previous active
982   // browsing context tries to unset it and at almost the same time
983   // the another content process sets a new active browsing context.
984   // If the IPC messages for these unset and set actions were to
985   // arrive in the wrong order, this could get in the wrong state.
986   //
987   // To address this issue, the parent manages an authortative order
988   // of attempts to (un)set the active browsing context using the
989   // array mPendingActiveBrowsingContextActions.
990   //
991   // A process reserves a slot in the order by calling
992   // GenerateFocusActionId(). Per one call to GenerateFocusActionId(),
993   // there may be at most one action to set the active browsing context
994   // to a new value. There may be logically prior attempts to unset it
995   // (i.e. set it to nullptr). That is, if there are both attempts to
996   // unset and set the active browsing context with the same action id,
997   // the attempt to set to a non-null value wins.
998   //
999   // The completion of an action from reserting the slot in the order
1000   // and actually performing the setting of the active browsing context
1001   // may span multiple processes and IPC messages.
1002   //
1003   // The at-most-once property is not asserted, because the process
1004   // claiming the position in the order and the process setting the
1005   // active browsing context with that actionId may be different, and
1006   // the act of using an actionId to set the active browsing context
1007   // is used to delete stale items from the array to avoid excessive
1008   // growth of the array.
1009   nsTArray<uint64_t> mPendingActiveBrowsingContextActions;
1010 
1011   // Like mPendingActiveBrowsingContextActions but for the focused
1012   // browsing context.
1013   nsTArray<uint64_t> mPendingFocusedBrowsingContextActions;
1014 
1015   // If set to true, layout of the document of the event target should be
1016   // flushed before handling focus depending events.
1017   bool mEventHandlingNeedsFlush;
1018 
1019   static bool sTestMode;
1020 
1021   // Process-specific counter for maintaining the prosess-specific
1022   // uniqueness of actionIds.
1023   static uint64_t sFocusActionCounter;
1024 
1025   // the single focus manager
1026   static mozilla::StaticRefPtr<nsFocusManager> sInstance;
1027 };
1028 
1029 nsresult NS_NewFocusManager(nsIFocusManager** aResult);
1030 
1031 #endif
1032