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