Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsFocusManager.h
Line
Count
Source (jump to first uncovered line)
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 "nsIDocument.h"
13
#include "nsIFocusManager.h"
14
#include "nsIObserver.h"
15
#include "nsIWidget.h"
16
#include "nsWeakReference.h"
17
#include "mozilla/Attributes.h"
18
#include "mozilla/RefPtr.h"
19
20
0
#define FOCUSMETHOD_MASK 0xF000
21
0
#define FOCUSMETHODANDRING_MASK 0xF0F000
22
23
0
#define FOCUSMANAGER_CONTRACTID "@mozilla.org/focus-manager;1"
24
25
class nsIContent;
26
class nsIDocShellTreeItem;
27
class nsPIDOMWindowOuter;
28
29
namespace mozilla {
30
namespace dom {
31
class Element;
32
class TabParent;
33
}
34
}
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
{
47
  typedef mozilla::widget::InputContextAction InputContextAction;
48
49
public:
50
51
  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFocusManager, nsIFocusManager)
52
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
53
  NS_DECL_NSIOBSERVER
54
  NS_DECL_NSIFOCUSMANAGER
55
56
  // called to initialize and stop the focus manager at startup and shutdown
57
  static nsresult Init();
58
  static void Shutdown();
59
60
  void PrefChanged(const char* aPref);
61
62
  /**
63
   * Retrieve the single focus manager.
64
   */
65
0
  static nsFocusManager* GetFocusManager() { return sInstance; }
66
67
  /**
68
   * A faster version of nsIFocusManager::GetFocusedElement, returning a
69
   * raw Element pointer (instead of having AddRef-ed Element
70
   * pointer filled in to an out-parameter).
71
   */
72
0
  mozilla::dom::Element* GetFocusedElement() { return mFocusedElement; }
73
74
  /**
75
   * Returns true if aContent currently has focus.
76
   */
77
  bool IsFocused(nsIContent* aContent);
78
79
  /**
80
   * Returns true if test mode is enabled.
81
   */
82
  bool IsTestMode();
83
84
  /**
85
   * Return a focused window. Version of nsIFocusManager::GetFocusedWindow.
86
   */
87
0
  nsPIDOMWindowOuter* GetFocusedWindow() const { return mFocusedWindow; }
88
89
  /**
90
   * Return an active window. Version of nsIFocusManager::GetActiveWindow.
91
   */
92
0
  nsPIDOMWindowOuter* GetActiveWindow() const { return mActiveWindow; }
93
94
  /**
95
   * Called when content has been removed.
96
   */
97
  nsresult ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
98
99
  /**
100
   * Called when mouse button event handling is started and finished.
101
   */
102
  already_AddRefed<nsIDocument>
103
    SetMouseButtonHandlingDocument(nsIDocument* aDocument)
104
0
  {
105
0
    nsCOMPtr<nsIDocument> handlingDocument = mMouseButtonEventHandlingDocument;
106
0
    mMouseButtonEventHandlingDocument = aDocument;
107
0
    return handlingDocument.forget();
108
0
  }
109
110
  void NeedsFlushBeforeEventHandling(mozilla::dom::Element* aElement)
111
0
  {
112
0
    if (mFocusedElement == aElement) {
113
0
      mEventHandlingNeedsFlush = true;
114
0
    }
115
0
  }
116
117
  bool CanSkipFocus(nsIContent* aContent);
118
119
  void FlushBeforeEventHandlingIfNeeded(nsIContent* aContent)
120
0
  {
121
0
    if (mEventHandlingNeedsFlush) {
122
0
      nsCOMPtr<nsIDocument> doc = aContent->GetComposedDoc();
123
0
      if (doc) {
124
0
        mEventHandlingNeedsFlush = false;
125
0
        doc->FlushPendingNotifications(mozilla::FlushType::Layout);
126
0
      }
127
0
    }
128
0
  }
129
130
  /**
131
   * Update the caret with current mode (whether in caret browsing mode or not).
132
   */
133
  void UpdateCaretForCaretBrowsingMode();
134
135
  /**
136
   * Returns the content node that would be focused if aWindow was in an
137
   * active window. This will traverse down the frame hierarchy, starting at
138
   * the given window aWindow. Sets aFocusedWindow to the window with the
139
   * document containing aFocusedContent. If no element is focused,
140
   * aFocusedWindow may be still be set -- this means that the document is
141
   * focused but no element within it is focused.
142
   *
143
   * aWindow and aFocusedWindow must both be non-null.
144
   */
145
  enum SearchRange
146
  {
147
    // Return focused content in aWindow.  So, aFocusedWindow is always aWindow.
148
    eOnlyCurrentWindow,
149
    // Return focused content in aWindow or one of all sub windows.
150
    eIncludeAllDescendants,
151
    // Return focused content in aWindow or one of visible sub windows.
152
    eIncludeVisibleDescendants,
153
  };
154
  static mozilla::dom::Element*
155
  GetFocusedDescendant(nsPIDOMWindowOuter* aWindow,
156
                       SearchRange aSearchRange,
157
                       nsPIDOMWindowOuter** aFocusedWindow);
158
159
  /**
160
   * Returns the content node that focus will be redirected to if aContent was
161
   * focused. This is used for the special case of certain XUL elements such
162
   * as textboxes or input number which redirect focus to an anonymous child.
163
   *
164
   * aContent must be non-null.
165
   *
166
   * XXXndeakin this should be removed eventually but I want to do that as
167
   * followup work.
168
   */
169
  static mozilla::dom::Element* GetRedirectedFocus(nsIContent* aContent);
170
171
  /**
172
   * Returns an InputContextAction cause for aFlags.
173
   */
174
  static InputContextAction::Cause GetFocusMoveActionCause(uint32_t aFlags);
175
176
  static bool sMouseFocusesFormControl;
177
178
  static void MarkUncollectableForCCGeneration(uint32_t aGeneration);
179
protected:
180
181
  nsFocusManager();
182
  ~nsFocusManager();
183
184
  /**
185
   * Ensure that the widget associated with the currently focused window is
186
   * focused at the widget level.
187
   */
188
  void EnsureCurrentWidgetFocused();
189
190
  /**
191
   * Activate or deactivate the window and send the activate/deactivate events.
192
   */
193
  void ActivateOrDeactivate(nsPIDOMWindowOuter* aWindow, bool aActive);
194
195
  /**
196
   * Blur whatever is currently focused and focus aNewContent. aFlags is a
197
   * bitmask of the flags defined in nsIFocusManager. If aFocusChanged is
198
   * true, then the focus has actually shifted and the caret position will be
199
   * updated to the new focus, aNewContent will be scrolled into view (unless
200
   * a flag disables this) and the focus method for the window will be updated.
201
   * If aAdjustWidget is false, don't change the widget focus state.
202
   *
203
   * All actual focus changes must use this method to do so. (as opposed
204
   * to those that update the focus in an inactive window for instance).
205
   */
206
  void SetFocusInner(mozilla::dom::Element* aNewContent, int32_t aFlags,
207
                     bool aFocusChanged, bool aAdjustWidget);
208
209
  /**
210
   * Returns true if aPossibleAncestor is the same as aWindow or an
211
   * ancestor of aWindow.
212
   */
213
  bool IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor,
214
                        nsPIDOMWindowOuter* aWindow);
215
216
  /**
217
   * Returns the window that is the lowest common ancestor of both aWindow1
218
   * and aWindow2, or null if they share no common ancestor.
219
   */
220
  already_AddRefed<nsPIDOMWindowOuter>
221
  GetCommonAncestor(nsPIDOMWindowOuter* aWindow1, nsPIDOMWindowOuter* aWindow2);
222
223
  /**
224
   * When aNewWindow is focused, adjust the ancestors of aNewWindow so that they
225
   * also have their corresponding frames focused. Thus, one can start at
226
   * the active top-level window and navigate down the currently focused
227
   * elements for each frame in the tree to get to aNewWindow.
228
   */
229
  void AdjustWindowFocus(nsPIDOMWindowOuter* aNewWindow, bool aCheckPermission);
230
231
  /**
232
   * Returns true if aWindow is visible.
233
   */
234
  bool IsWindowVisible(nsPIDOMWindowOuter* aWindow);
235
236
  /**
237
   * Returns true if aContent is a root element and not focusable.
238
   * I.e., even if aContent is editable root element, this returns true when
239
   * the document is in designMode.
240
   *
241
   * @param aContent must not be null and must be in a document.
242
   */
243
  bool IsNonFocusableRoot(nsIContent* aContent);
244
245
  /**
246
   * Checks and returns aContent if it may be focused, another content node if
247
   * the focus should be retargeted at another node, or null if the node
248
   * cannot be focused. aFlags are the flags passed to SetFocus and similar
249
   * methods.
250
   *
251
   * An element is focusable if it is in a document, the document isn't in
252
   * print preview mode and the element has an nsIFrame where the
253
   * CheckIfFocusable method returns true. For <area> elements, there is no
254
   * frame, so only the IsFocusable method on the content node must be
255
   * true.
256
   */
257
  mozilla::dom::Element* CheckIfFocusable(mozilla::dom::Element* aContent,
258
                                          uint32_t aFlags);
259
260
  /**
261
   * Blurs the currently focused element. Returns false if another element was
262
   * focused as a result. This would mean that the caller should not proceed
263
   * with a pending call to Focus. Normally, true would be returned.
264
   *
265
   * The currently focused element within aWindowToClear will be cleared.
266
   * aWindowToClear may be null, which means that no window is cleared. This
267
   * will be the case, for example, when lowering a window, as we want to fire
268
   * a blur, but not actually change what element would be focused, so that
269
   * the same element will be focused again when the window is raised.
270
   *
271
   * aAncestorWindowToFocus should be set to the common ancestor of the window
272
   * that is being blurred and the window that is going to focused, when
273
   * switching focus to a sibling window.
274
   *
275
   * aIsLeavingDocument should be set to true if the document/window is being
276
   * blurred as well. Document/window blur events will be fired. It should be
277
   * false if an element is the same document is about to be focused.
278
   *
279
   * If aAdjustWidget is false, don't change the widget focus state.
280
   */
281
  // MOZ_CAN_RUN_SCRIPT_BOUNDARY for now, until we annotate callers.
282
  MOZ_CAN_RUN_SCRIPT_BOUNDARY
283
  bool Blur(nsPIDOMWindowOuter* aWindowToClear,
284
            nsPIDOMWindowOuter* aAncestorWindowToFocus,
285
            bool aIsLeavingDocument,
286
            bool aAdjustWidget,
287
            nsIContent* aContentToFocus = nullptr);
288
289
  /**
290
   * Focus an element in the active window and child frame.
291
   *
292
   * aWindow is the window containing the element aContent to focus.
293
   *
294
   * aFlags is the flags passed to the various focus methods in
295
   * nsIFocusManager.
296
   *
297
   * aIsNewDocument should be true if a new document is being focused.
298
   * Document/window focus events will be fired.
299
   *
300
   * aFocusChanged should be true if a new content node is being focused, so
301
   * the focused content will be scrolled into view and the caret position
302
   * will be updated. If false is passed, then a window is simply being
303
   * refocused, for instance, due to a window being raised, or a tab is being
304
   * switched to.
305
   *
306
   * If aFocusChanged is true, then the focus has moved to a new location.
307
   * Otherwise, the focus is just being updated because the window was
308
   * raised.
309
   *
310
   * aWindowRaised should be true if the window is being raised. In this case,
311
   * command updaters will not be called.
312
   *
313
   * If aAdjustWidget is false, don't change the widget focus state.
314
   */
315
  void Focus(nsPIDOMWindowOuter* aWindow,
316
             mozilla::dom::Element* aContent,
317
             uint32_t aFlags,
318
             bool aIsNewDocument,
319
             bool aFocusChanged,
320
             bool aWindowRaised,
321
             bool aAdjustWidget,
322
             nsIContent* aContentLostFocus = nullptr);
323
324
  /**
325
   * Send a focus or blur event at aTarget. It may be added to the delayed
326
   * event queue if the document is suppressing events.
327
   *
328
   * aEventMessage should be either eFocus or eBlur.
329
   * For blur events, aFocusMethod should normally be non-zero.
330
   *
331
   * aWindowRaised should only be true if called from WindowRaised.
332
   */
333
  void SendFocusOrBlurEvent(mozilla::EventMessage aEventMessage,
334
                            nsIPresShell* aPresShell,
335
                            nsIDocument* aDocument,
336
                            nsISupports* aTarget,
337
                            uint32_t aFocusMethod,
338
                            bool aWindowRaised,
339
                            bool aIsRefocus = false,
340
                            mozilla::dom::EventTarget* aRelatedTarget = nullptr);
341
342
  /**
343
   * Fire a focus or blur event at aTarget.
344
   *
345
   * aEventMessage should be either eFocus or eBlur.
346
   * For blur events, aFocusMethod should normally be non-zero.
347
   *
348
   * aWindowRaised should only be true if called from WindowRaised.
349
   */
350
  void FireFocusOrBlurEvent(mozilla::EventMessage aEventMessage,
351
                            nsIPresShell* aPresShell,
352
                            nsISupports* aTarget,
353
                            bool aWindowRaised,
354
                            bool aIsRefocus = false,
355
                            mozilla::dom::EventTarget* aRelatedTarget = nullptr);
356
357
  /**
358
   *  Fire a focusin or focusout event
359
   *
360
   *  aEventMessage should be either eFocusIn or eFocusOut.
361
   *
362
   *  aTarget is the content the event will fire on (the object that gained
363
   *  focus for focusin, the object blurred for focusout).
364
   *
365
   *  aCurrentFocusedWindow is the window focused before the focus/blur event
366
   *  was fired.
367
   *
368
   *  aCurrentFocusedContent is the content focused before the focus/blur event
369
   *  was fired.
370
   *
371
   *  aRelatedTarget is the content related to the event (the object
372
   *  losing focus for focusin, the object getting focus for focusout).
373
   */
374
  void FireFocusInOrOutEvent(mozilla::EventMessage aEventMessage,
375
                             nsIPresShell* aPresShell,
376
                             nsISupports* aTarget,
377
                             nsPIDOMWindowOuter* aCurrentFocusedWindow,
378
                             nsIContent* aCurrentFocusedContent,
379
                             mozilla::dom::EventTarget* aRelatedTarget = nullptr);
380
381
  /**
382
   * Scrolls aContent into view unless the FLAG_NOSCROLL flag is set.
383
   */
384
  void ScrollIntoView(nsIPresShell* aPresShell,
385
                      nsIContent* aContent,
386
                      uint32_t aFlags);
387
388
  /**
389
   * Raises the top-level window aWindow at the widget level.
390
   */
391
  void RaiseWindow(nsPIDOMWindowOuter* aWindow);
392
393
  /**
394
   * Updates the caret positon and visibility to match the focus.
395
   *
396
   * aMoveCaretToFocus should be true to move the caret to aContent.
397
   *
398
   * aUpdateVisibility should be true to update whether the caret is
399
   * visible or not.
400
   */
401
  void UpdateCaret(bool aMoveCaretToFocus,
402
                   bool aUpdateVisibility,
403
                   nsIContent* aContent);
404
405
  /**
406
   * Helper method to move the caret to the focused element aContent.
407
   */
408
  void MoveCaretToFocus(nsIPresShell* aPresShell, nsIContent* aContent);
409
410
  /**
411
   * Makes the caret visible or not, depending on aVisible.
412
   */
413
  nsresult SetCaretVisible(nsIPresShell* aPresShell,
414
                           bool aVisible,
415
                           nsIContent* aContent);
416
417
418
  // the remaining functions are used for tab key and document-navigation
419
420
  /**
421
   * Retrieves the start and end points of the current selection for
422
   * aDocument and stores them in aStartContent and aEndContent.
423
   */
424
  nsresult GetSelectionLocation(nsIDocument* aDocument,
425
                                nsIPresShell* aPresShell,
426
                                nsIContent **aStartContent,
427
                                nsIContent **aEndContent);
428
429
  /**
430
   * Helper function for MoveFocus which determines the next element
431
   * to move the focus to and returns it in aNextContent.
432
   *
433
   * aWindow is the window to adjust the focus within, and aStart is
434
   * the element to start navigation from. For tab key navigation,
435
   * this should be the currently focused element.
436
   *
437
   * aType is the type passed to MoveFocus. If aNoParentTraversal is set,
438
   * navigation is not done to parent documents and iteration returns to the
439
   * beginning (or end) of the starting document.
440
   */
441
  nsresult DetermineElementToMoveFocus(nsPIDOMWindowOuter* aWindow,
442
                                       nsIContent* aStart,
443
                                       int32_t aType, bool aNoParentTraversal,
444
                                       nsIContent** aNextContent);
445
446
  /**
447
   * Returns scope owner of aContent.
448
   * A scope owner is either a document root, shadow host, or slot.
449
   */
450
  nsIContent* FindOwner(nsIContent* aContent);
451
452
  /**
453
   * Returns true if aContent is a shadow host or slot
454
   */
455
  bool IsHostOrSlot(nsIContent* aContent);
456
457
  /**
458
   * Host and Slot elements need to be handled as if they had tabindex 0 even
459
   * when they don't have the attribute. This is a helper method to get the right
460
   * value for focus navigation.
461
   * If aIsFocusable is passed, it is set to true if the element itself is
462
   * focusable.
463
   */
464
  int32_t HostOrSlotTabIndexValue(nsIContent* aContent,
465
                                  bool* aIsFocusable = nullptr);
466
467
  /**
468
   * Retrieve the next tabbable element in scope owned by aOwner, using
469
   * focusability and tabindex to determine the tab order.
470
   *
471
   * aOwner is the owner of scope to search in.
472
   *
473
   * aStartContent is the starting point for this call of this method.
474
   *
475
   * aOriginalStartContent is the initial starting point for sequential
476
   * navigation.
477
   *
478
   * aForward should be true for forward navigation or false for backward
479
   * navigation.
480
   *
481
   * aCurrentTabIndex is the current tabindex.
482
   *
483
   * aIgnoreTabIndex to ignore the current tabindex and find the element
484
   * irrespective or the tab index.
485
   *
486
   * aForDocumentNavigation informs whether we're navigating only through
487
   * documents.
488
   *
489
   * aSkipOwner to skip owner while searching. The flag is set when caller is
490
   * |GetNextTabbableContent| in order to let caller handle owner.
491
   *
492
   * NOTE:
493
   *   Consider the method searches downwards in flattened subtree
494
   *   rooted at aOwner.
495
   */
496
  nsIContent* GetNextTabbableContentInScope(nsIContent* aOwner,
497
                                            nsIContent* aStartContent,
498
                                            nsIContent* aOriginalStartContent,
499
                                            bool aForward,
500
                                            int32_t aCurrentTabIndex,
501
                                            bool aIgnoreTabIndex,
502
                                            bool aForDocumentNavigation,
503
                                            bool aSkipOwner);
504
505
  /**
506
   * Retrieve the next tabbable element in scope including aStartContent
507
   * and the scope's ancestor scopes, using focusability and tabindex to
508
   * determine the tab order.
509
   *
510
   * aStartContent an in/out paremeter. It as input is the starting point
511
   * for this call of this method; as output it is the shadow host in
512
   * light DOM if the next tabbable element is not found in shadow DOM,
513
   * in order to continue searching in light DOM.
514
   *
515
   * aOriginalStartContent is the initial starting point for sequential
516
   * navigation.
517
   *
518
   * aForward should be true for forward navigation or false for backward
519
   * navigation.
520
   *
521
   * aCurrentTabIndex returns tab index of shadow host in light DOM if the
522
   * next tabbable element is not found in shadow DOM, in order to continue
523
   * searching in light DOM.
524
   *
525
   * aIgnoreTabIndex to ignore the current tabindex and find the element
526
   * irrespective or the tab index.
527
   *
528
   * aForDocumentNavigation informs whether we're navigating only through
529
   * documents.
530
   *
531
   * NOTE:
532
   *   Consider the method searches upwards in all shadow host- or slot-rooted
533
   *   flattened subtrees that contains aStartContent as non-root, except
534
   *   the flattened subtree rooted at shadow host in light DOM.
535
   */
536
  nsIContent* GetNextTabbableContentInAncestorScopes(nsIContent** aStartContent,
537
                                                     nsIContent* aOriginalStartContent,
538
                                                     bool aForward,
539
                                                     int32_t* aCurrentTabIndex,
540
                                                     bool aIgnoreTabIndex,
541
                                                     bool aForDocumentNavigation);
542
543
  /**
544
   * Retrieve the next tabbable element within a document, using focusability
545
   * and tabindex to determine the tab order. The element is returned in
546
   * aResultContent.
547
   *
548
   * aRootContent is the root node -- nodes above this will not be examined.
549
   * Typically this will be the root node of a document, but could also be
550
   * a popup node.
551
   *
552
   * aOriginalStartContent is the content which was originally the starting
553
   * node, in the case of recursive or looping calls.
554
   *
555
   * aStartContent is the starting point for this call of this method.
556
   * If aStartContent doesn't have visual representation, the next content
557
   * object, which does have a primary frame, will be used as a start.
558
   * If that content object is focusable, the method may return it.
559
   *
560
   * aForward should be true for forward navigation or false for backward
561
   * navigation.
562
   *
563
   * aCurrentTabIndex is the current tabindex.
564
   *
565
   * aIgnoreTabIndex to ignore the current tabindex and find the element
566
   * irrespective or the tab index. This will be true when a selection is
567
   * active, since we just want to focus the next element in tree order
568
   * from where the selection is. Similarly, if the starting element isn't
569
   * focusable, since it doesn't really have a defined tab index.
570
   */
571
  nsresult GetNextTabbableContent(nsIPresShell* aPresShell,
572
                                  nsIContent* aRootContent,
573
                                  nsIContent* aOriginalStartContent,
574
                                  nsIContent* aStartContent,
575
                                  bool aForward,
576
                                  int32_t aCurrentTabIndex,
577
                                  bool aIgnoreTabIndex,
578
                                  bool aForDocumentNavigation,
579
                                  nsIContent** aResultContent);
580
581
  /**
582
   * Get the next tabbable image map area and returns it.
583
   *
584
   * aForward should be true for forward navigation or false for backward
585
   * navigation.
586
   *
587
   * aCurrentTabIndex is the current tabindex.
588
   *
589
   * aImageContent is the image.
590
   *
591
   * aStartContent is the current image map area.
592
   */
593
  nsIContent* GetNextTabbableMapArea(bool aForward,
594
                                     int32_t aCurrentTabIndex,
595
                                     mozilla::dom::Element* aImageContent,
596
                                     nsIContent* aStartContent);
597
598
  /**
599
   * Return the next valid tabindex value after aCurrentTabIndex, if aForward
600
   * is true, or the previous tabindex value if aForward is false. aParent is
601
   * the node from which to start looking for tab indicies.
602
   */
603
  int32_t GetNextTabIndex(nsIContent* aParent,
604
                          int32_t aCurrentTabIndex,
605
                          bool aForward);
606
607
  /**
608
   * Focus the first focusable content within the document with a root node of
609
   * aRootContent. For content documents, this will be aRootContent itself, but
610
   * for chrome documents, this will locate the next focusable content.
611
   */
612
  nsresult FocusFirst(mozilla::dom::Element* aRootContent, nsIContent** aNextContent);
613
614
  /**
615
   * Retrieves and returns the root node from aDocument to be focused. Will
616
   * return null if the root node cannot be focused. There are several reasons
617
   * for this:
618
   *
619
   * - if aForDocumentNavigation is false and aWindow is a chrome shell.
620
   * - if aCheckVisibility is true and the aWindow is not visible.
621
   * - if aDocument is a frameset document.
622
   */
623
  mozilla::dom::Element* GetRootForFocus(nsPIDOMWindowOuter* aWindow,
624
                                         nsIDocument* aDocument,
625
                                         bool aForDocumentNavigation,
626
                                         bool aCheckVisibility);
627
628
  /**
629
   * Retrieves and returns the root node as with GetRootForFocus but only if
630
   * aContent is a frame with a valid child document.
631
   */
632
  mozilla::dom::Element* GetRootForChildDocument(nsIContent* aContent);
633
634
  /**
635
   * Retreives a focusable element within the current selection of aWindow.
636
   * Currently, this only detects links.
637
   *
638
   * This is used when MoveFocus is called with a type of MOVEFOCUS_CARET,
639
   * which is used, for example, to focus links as the caret is moved over
640
   * them.
641
   */
642
  void GetFocusInSelection(nsPIDOMWindowOuter* aWindow,
643
                           nsIContent* aStartSelection,
644
                           nsIContent* aEndSelection,
645
                           nsIContent** aFocusedContent);
646
647
private:
648
  // Notify that the focus state of aContent has changed.  Note that
649
  // we need to pass in whether the window should show a focus ring
650
  // before the SetFocusedNode call on it happened when losing focus
651
  // and after the SetFocusedNode call when gaining focus, which is
652
  // why that information needs to be an explicit argument instead of
653
  // just passing in the window and asking it whether it should show
654
  // focus rings: in the losing focus case that information could be
655
  // wrong..
656
  static void NotifyFocusStateChange(nsIContent* aContent,
657
                                     nsIContent* aContentToFocus,
658
                                     bool aWindowShouldShowFocusRing,
659
                                     bool aGettingFocus);
660
661
  void SetFocusedWindowInternal(nsPIDOMWindowOuter* aWindow);
662
663
  bool TryDocumentNavigation(nsIContent* aCurrentContent,
664
                             bool* aCheckSubDocument,
665
                             nsIContent** aResultContent);
666
667
  bool TryToMoveFocusToSubDocument(nsIContent* aCurrentContent,
668
                                   nsIContent* aOriginalStartContent,
669
                                   bool aForward,
670
                                   bool aForDocumentNavigation,
671
                                   nsIContent** aResultContent);
672
673
  // the currently active and front-most top-most window
674
  nsCOMPtr<nsPIDOMWindowOuter> mActiveWindow;
675
676
  // the child or top-level window that is currently focused. This window will
677
  // either be the same window as mActiveWindow or a descendant of it.
678
  // Except during shutdown use SetFocusedWindowInternal to set mFocusedWindow!
679
  nsCOMPtr<nsPIDOMWindowOuter> mFocusedWindow;
680
681
  // the currently focused content, which is always inside mFocusedWindow. This
682
  // is a cached copy of the mFocusedWindow's current content. This may be null
683
  // if no content is focused.
684
  RefPtr<mozilla::dom::Element> mFocusedElement;
685
686
  // these fields store a content node temporarily while it is being focused
687
  // or blurred to ensure that a recursive call doesn't refire the same event.
688
  // They will always be cleared afterwards.
689
  nsCOMPtr<nsIContent> mFirstBlurEvent;
690
  nsCOMPtr<nsIContent> mFirstFocusEvent;
691
692
  // keep track of a window while it is being lowered
693
  nsCOMPtr<nsPIDOMWindowOuter> mWindowBeingLowered;
694
695
  // synchronized actions cannot be interrupted with events, so queue these up
696
  // and fire them later.
697
  nsTArray<nsDelayedBlurOrFocusEvent> mDelayedBlurFocusEvents;
698
699
  // A document which is handling a mouse button event.
700
  // When a mouse down event process is finished, ESM sets focus to the target
701
  // content if it's not consumed.  Therefore, while DOM event handlers are
702
  // handling mouse down events or preceding mosue down event is consumed but
703
  // handling mouse up events, they should be able to steal focus from any
704
  // elements even if focus is in chrome content.  So, if this isn't nullptr
705
  // and the caller can access the document node, the caller should succeed in
706
  // moving focus.
707
  nsCOMPtr<nsIDocument> mMouseButtonEventHandlingDocument;
708
709
  // If set to true, layout of the document of the event target should be
710
  // flushed before handling focus depending events.
711
  bool mEventHandlingNeedsFlush;
712
713
  static bool sTestMode;
714
715
  // the single focus manager
716
  static nsFocusManager* sInstance;
717
};
718
719
nsresult
720
NS_NewFocusManager(nsIFocusManager** aResult);
721
722
#endif