Bumping manifests a=b2g-bump
[gecko.git] / dom / base / nsFocusManager.h
blob476440157606f97dfd42873fad1f3b5c6b1fa27f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef nsFocusManager_h___
7 #define nsFocusManager_h___
9 #include "nsCycleCollectionParticipant.h"
10 #include "nsIDocument.h"
11 #include "nsIFocusManager.h"
12 #include "nsIObserver.h"
13 #include "nsIWidget.h"
14 #include "nsWeakReference.h"
15 #include "mozilla/Attributes.h"
17 #define FOCUSMETHOD_MASK 0xF000
18 #define FOCUSMETHODANDRING_MASK 0xF0F000
20 #define FOCUSMANAGER_CONTRACTID "@mozilla.org/focus-manager;1"
22 class nsIContent;
23 class nsIDocShellTreeItem;
24 class nsPIDOMWindow;
25 class nsIMessageBroadcaster;
27 struct nsDelayedBlurOrFocusEvent;
29 enum ParentFocusType {
30 ParentFocusType_Ignore, // Parent or single process window or unknown
31 ParentFocusType_Active, // Child process window in active parent
32 ParentFocusType_Inactive, // Child process window in inactive parent
35 /**
36 * The focus manager keeps track of where the focus is, that is, the node
37 * which receives key events.
40 class nsFocusManager MOZ_FINAL : public nsIFocusManager,
41 public nsIObserver,
42 public nsSupportsWeakReference
44 typedef mozilla::widget::InputContextAction InputContextAction;
46 public:
48 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFocusManager, nsIFocusManager)
49 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
50 NS_DECL_NSIOBSERVER
51 NS_DECL_NSIFOCUSMANAGER
53 // called to initialize and stop the focus manager at startup and shutdown
54 static nsresult Init();
55 static void Shutdown();
57 /**
58 * Retrieve the single focus manager.
60 static nsFocusManager* GetFocusManager() { return sInstance; }
62 /**
63 * A faster version of nsIFocusManager::GetFocusedElement, returning a
64 * raw nsIContent pointer (instead of having AddRef-ed nsIDOMElement
65 * pointer filled in to an out-parameter).
67 nsIContent* GetFocusedContent() { return mFocusedContent; }
69 /**
70 * Return a focused window. Version of nsIFocusManager::GetFocusedWindow.
72 nsPIDOMWindow* GetFocusedWindow() const { return mFocusedWindow; }
74 /**
75 * Return an active window. Version of nsIFocusManager::GetActiveWindow.
77 nsPIDOMWindow* GetActiveWindow() const { return mActiveWindow; }
79 /**
80 * Called when content has been removed.
82 nsresult ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
84 /**
85 * Called when mouse button event handling is started and finished.
87 already_AddRefed<nsIDocument>
88 SetMouseButtonHandlingDocument(nsIDocument* aDocument)
90 nsCOMPtr<nsIDocument> handlingDocument = mMouseButtonEventHandlingDocument;
91 mMouseButtonEventHandlingDocument = aDocument;
92 return handlingDocument.forget();
95 /**
96 * Update the caret with current mode (whether in caret browsing mode or not).
98 void UpdateCaretForCaretBrowsingMode();
100 bool IsParentActivated()
102 return mParentFocusType == ParentFocusType_Active;
106 * Returns the content node that would be focused if aWindow was in an
107 * active window. This will traverse down the frame hierarchy, starting at
108 * the given window aWindow. Sets aFocusedWindow to the window with the
109 * document containing aFocusedContent. If no element is focused,
110 * aFocusedWindow may be still be set -- this means that the document is
111 * focused but no element within it is focused.
113 * aWindow and aFocusedWindow must both be non-null.
115 static nsIContent* GetFocusedDescendant(nsPIDOMWindow* aWindow, bool aDeep,
116 nsPIDOMWindow** aFocusedWindow);
119 * Returns the content node that focus will be redirected to if aContent was
120 * focused. This is used for the special case of certain XUL elements such
121 * as textboxes which redirect focus to an anonymous child.
123 * aContent must be non-null.
125 * XXXndeakin this should be removed eventually but I want to do that as
126 * followup work.
128 static nsIContent* GetRedirectedFocus(nsIContent* aContent);
131 * Returns an InputContextAction cause for aFlags.
133 static InputContextAction::Cause GetFocusMoveActionCause(uint32_t aFlags);
135 static bool sMouseFocusesFormControl;
137 static void MarkUncollectableForCCGeneration(uint32_t aGeneration);
138 protected:
140 nsFocusManager();
141 ~nsFocusManager();
144 * Ensure that the widget associated with the currently focused window is
145 * focused at the widget level.
147 void EnsureCurrentWidgetFocused();
150 * Iterate over the children of the message broadcaster and notify them
151 * of the activation change.
153 void ActivateOrDeactivateChildren(nsIMessageBroadcaster* aManager, bool aActive);
156 * Activate or deactivate the window and send the activate/deactivate events.
158 void ActivateOrDeactivate(nsPIDOMWindow* aWindow, bool aActive);
161 * Blur whatever is currently focused and focus aNewContent. aFlags is a
162 * bitmask of the flags defined in nsIFocusManager. If aFocusChanged is
163 * true, then the focus has actually shifted and the caret position will be
164 * updated to the new focus, aNewContent will be scrolled into view (unless
165 * a flag disables this) and the focus method for the window will be updated.
166 * If aAdjustWidget is false, don't change the widget focus state.
168 * All actual focus changes must use this method to do so. (as opposed
169 * to those that update the focus in an inactive window for instance).
171 void SetFocusInner(nsIContent* aNewContent, int32_t aFlags,
172 bool aFocusChanged, bool aAdjustWidget);
175 * Returns true if aPossibleAncestor is the same as aWindow or an
176 * ancestor of aWindow.
178 bool IsSameOrAncestor(nsPIDOMWindow* aPossibleAncestor,
179 nsPIDOMWindow* aWindow);
182 * Returns the window that is the lowest common ancestor of both aWindow1
183 * and aWindow2, or null if they share no common ancestor.
185 already_AddRefed<nsPIDOMWindow> GetCommonAncestor(nsPIDOMWindow* aWindow1,
186 nsPIDOMWindow* aWindow2);
189 * When aNewWindow is focused, adjust the ancestors of aNewWindow so that they
190 * also have their corresponding frames focused. Thus, one can start at
191 * the active top-level window and navigate down the currently focused
192 * elements for each frame in the tree to get to aNewWindow.
194 void AdjustWindowFocus(nsPIDOMWindow* aNewWindow, bool aCheckPermission);
197 * Returns true if aWindow is visible.
199 bool IsWindowVisible(nsPIDOMWindow* aWindow);
202 * Returns true if aContent is a root element and not focusable.
203 * I.e., even if aContent is editable root element, this returns true when
204 * the document is in designMode.
206 * @param aContent must not be null and must be in a document.
208 bool IsNonFocusableRoot(nsIContent* aContent);
211 * Checks and returns aContent if it may be focused, another content node if
212 * the focus should be retargeted at another node, or null if the node
213 * cannot be focused. aFlags are the flags passed to SetFocus and similar
214 * methods.
216 * An element is focusable if it is in a document, the document isn't in
217 * print preview mode and the element has an nsIFrame where the
218 * CheckIfFocusable method returns true. For <area> elements, there is no
219 * frame, so only the IsFocusable method on the content node must be
220 * true.
222 nsIContent* CheckIfFocusable(nsIContent* aContent, uint32_t aFlags);
225 * Blurs the currently focused element. Returns false if another element was
226 * focused as a result. This would mean that the caller should not proceed
227 * with a pending call to Focus. Normally, true would be returned.
229 * The currently focused element within aWindowToClear will be cleared.
230 * aWindowToClear may be null, which means that no window is cleared. This
231 * will be the case, for example, when lowering a window, as we want to fire
232 * a blur, but not actually change what element would be focused, so that
233 * the same element will be focused again when the window is raised.
235 * aAncestorWindowToFocus should be set to the common ancestor of the window
236 * that is being blurred and the window that is going to focused, when
237 * switching focus to a sibling window.
239 * aIsLeavingDocument should be set to true if the document/window is being
240 * blurred as well. Document/window blur events will be fired. It should be
241 * false if an element is the same document is about to be focused.
243 * If aAdjustWidget is false, don't change the widget focus state.
245 bool Blur(nsPIDOMWindow* aWindowToClear,
246 nsPIDOMWindow* aAncestorWindowToFocus,
247 bool aIsLeavingDocument,
248 bool aAdjustWidget);
251 * Focus an element in the active window and child frame.
253 * aWindow is the window containing the element aContent to focus.
255 * aFlags is the flags passed to the various focus methods in
256 * nsIFocusManager.
258 * aIsNewDocument should be true if a new document is being focused.
259 * Document/window focus events will be fired.
261 * aFocusChanged should be true if a new content node is being focused, so
262 * the focused content will be scrolled into view and the caret position
263 * will be updated. If false is passed, then a window is simply being
264 * refocused, for instance, due to a window being raised, or a tab is being
265 * switched to.
267 * If aFocusChanged is true, then the focus has moved to a new location.
268 * Otherwise, the focus is just being updated because the window was
269 * raised.
271 * aWindowRaised should be true if the window is being raised. In this case,
272 * command updaters will not be called.
274 * If aAdjustWidget is false, don't change the widget focus state.
276 void Focus(nsPIDOMWindow* aWindow,
277 nsIContent* aContent,
278 uint32_t aFlags,
279 bool aIsNewDocument,
280 bool aFocusChanged,
281 bool aWindowRaised,
282 bool aAdjustWidget);
285 * Fires a focus or blur event at aTarget.
287 * aType should be either NS_FOCUS_CONTENT or NS_BLUR_CONTENT. For blur
288 * events, aFocusMethod should normally be non-zero.
290 * aWindowRaised should only be true if called from WindowRaised.
292 void SendFocusOrBlurEvent(uint32_t aType,
293 nsIPresShell* aPresShell,
294 nsIDocument* aDocument,
295 nsISupports* aTarget,
296 uint32_t aFocusMethod,
297 bool aWindowRaised,
298 bool aIsRefocus = false);
301 * Scrolls aContent into view unless the FLAG_NOSCROLL flag is set.
303 void ScrollIntoView(nsIPresShell* aPresShell,
304 nsIContent* aContent,
305 uint32_t aFlags);
308 * Raises the top-level window aWindow at the widget level.
310 void RaiseWindow(nsPIDOMWindow* aWindow);
313 * Updates the caret positon and visibility to match the focus.
315 * aMoveCaretToFocus should be true to move the caret to aContent.
317 * aUpdateVisibility should be true to update whether the caret is
318 * visible or not.
320 void UpdateCaret(bool aMoveCaretToFocus,
321 bool aUpdateVisibility,
322 nsIContent* aContent);
325 * Helper method to move the caret to the focused element aContent.
327 void MoveCaretToFocus(nsIPresShell* aPresShell, nsIContent* aContent);
330 * Makes the caret visible or not, depending on aVisible.
332 nsresult SetCaretVisible(nsIPresShell* aPresShell,
333 bool aVisible,
334 nsIContent* aContent);
337 // the remaining functions are used for tab key and document-navigation
340 * Retrieves the start and end points of the current selection for
341 * aDocument and stores them in aStartContent and aEndContent.
343 nsresult GetSelectionLocation(nsIDocument* aDocument,
344 nsIPresShell* aPresShell,
345 nsIContent **aStartContent,
346 nsIContent **aEndContent);
349 * Helper function for MoveFocus which determines the next element
350 * to move the focus to and returns it in aNextContent.
352 * aWindow is the window to adjust the focus within, and aStart is
353 * the element to start navigation from. For tab key navigation,
354 * this should be the currently focused element.
356 * aType is the type passed to MoveFocus. If aNoParentTraversal is set,
357 * navigation is not done to parent documents and iteration returns to the
358 * beginning (or end) of the starting document.
360 nsresult DetermineElementToMoveFocus(nsPIDOMWindow* aWindow,
361 nsIContent* aStart,
362 int32_t aType, bool aNoParentTraversal,
363 nsIContent** aNextContent);
366 * Retrieve the next tabbable element within a document, using focusability
367 * and tabindex to determine the tab order. The element is returned in
368 * aResultContent.
370 * aRootContent is the root node -- nodes above this will not be examined.
371 * Typically this will be the root node of a document, but could also be
372 * a popup node.
374 * aOriginalStartContent is the content which was originally the starting
375 * node, in the case of recursive or looping calls.
377 * aStartContent is the starting point for this call of this method.
378 * If aStartContent doesn't have visual representation, the next content
379 * object, which does have a primary frame, will be used as a start.
380 * If that content object is focusable, the method may return it.
382 * aForward should be true for forward navigation or false for backward
383 * navigation.
385 * aCurrentTabIndex is the current tabindex.
387 * aIgnoreTabIndex to ignore the current tabindex and find the element
388 * irrespective or the tab index. This will be true when a selection is
389 * active, since we just want to focus the next element in tree order
390 * from where the selection is. Similarly, if the starting element isn't
391 * focusable, since it doesn't really have a defined tab index.
393 nsresult GetNextTabbableContent(nsIPresShell* aPresShell,
394 nsIContent* aRootContent,
395 nsIContent* aOriginalStartContent,
396 nsIContent* aStartContent,
397 bool aForward,
398 int32_t aCurrentTabIndex,
399 bool aIgnoreTabIndex,
400 nsIContent** aResultContent);
403 * Get the next tabbable image map area and returns it.
405 * aForward should be true for forward navigation or false for backward
406 * navigation.
408 * aCurrentTabIndex is the current tabindex.
410 * aImageContent is the image.
412 * aStartContent is the current image map area.
414 nsIContent* GetNextTabbableMapArea(bool aForward,
415 int32_t aCurrentTabIndex,
416 nsIContent* aImageContent,
417 nsIContent* aStartContent);
420 * Return the next valid tabindex value after aCurrentTabIndex, if aForward
421 * is true, or the previous tabindex value if aForward is false. aParent is
422 * the node from which to start looking for tab indicies.
424 int32_t GetNextTabIndex(nsIContent* aParent,
425 int32_t aCurrentTabIndex,
426 bool aForward);
429 * Retrieves and returns the root node from aDocument to be focused. Will
430 * return null if the root node cannot be focused. There are several reasons
431 * for this:
433 * - if aIsForDocNavigation is true, and aWindow is in an <iframe>.
434 * - if aIsForDocNavigation is false, and aWindow is a chrome shell.
435 * - if aCheckVisibility is true and the aWindow is not visible.
436 * - if aDocument is a frameset document.
438 nsIContent* GetRootForFocus(nsPIDOMWindow* aWindow,
439 nsIDocument* aDocument,
440 bool aIsForDocNavigation,
441 bool aCheckVisibility);
444 * Get the last docshell child of aItem and return it in aResult.
446 void GetLastDocShell(nsIDocShellTreeItem* aItem,
447 nsIDocShellTreeItem** aResult);
450 * Get the next docshell child of aItem and return it in aResult.
452 void GetNextDocShell(nsIDocShellTreeItem* aItem,
453 nsIDocShellTreeItem** aResult);
456 * Get the previous docshell child of aItem and return it in aResult.
458 void GetPreviousDocShell(nsIDocShellTreeItem* aItem,
459 nsIDocShellTreeItem** aResult);
462 * Determine the first panel with focusable content in document tab order
463 * from the given document. aForward indicates the direction to scan. If
464 * aCurrentPopup is set to a panel, the next or previous popup after
465 * aCurrentPopup after it is used. If aCurrentPopup is null, then the first
466 * or last popup is used. If a panel has no focusable content, it is skipped.
467 * Null is returned if no panel is open or no open panel contains a focusable
468 * element.
470 nsIContent* GetNextTabbablePanel(nsIDocument* aDocument, nsIFrame* aCurrentPopup, bool aForward);
473 * Get the tabbable next document from aStartContent or, if null, the
474 * currently focused frame if aForward is true, or the previously tabbable
475 * document if aForward is false. If this document is a chrome or frameset
476 * document, returns the first focusable element within this document,
477 * otherwise, returns the root node of the document.
480 * Panels with focusable content are also placed in the cycling order, just
481 * after the document containing that panel.
483 * This method would be used for document navigation, which is typically
484 * invoked by pressing F6.
486 nsIContent* GetNextTabbableDocument(nsIContent* aStartContent, bool aForward);
489 * Retreives a focusable element within the current selection of aWindow.
490 * Currently, this only detects links.
492 * This is used when MoveFocus is called with a type of MOVEFOCUS_CARET,
493 * which is used, for example, to focus links as the caret is moved over
494 * them.
496 void GetFocusInSelection(nsPIDOMWindow* aWindow,
497 nsIContent* aStartSelection,
498 nsIContent* aEndSelection,
499 nsIContent** aFocusedContent);
501 private:
502 // Notify that the focus state of aContent has changed. Note that
503 // we need to pass in whether the window should show a focus ring
504 // before the SetFocusedNode call on it happened when losing focus
505 // and after the SetFocusedNode call when gaining focus, which is
506 // why that information needs to be an explicit argument instead of
507 // just passing in the window and asking it whether it should show
508 // focus rings: in the losing focus case that information could be
509 // wrong..
510 static void NotifyFocusStateChange(nsIContent* aContent,
511 bool aWindowShouldShowFocusRing,
512 bool aGettingFocus);
514 void SetFocusedWindowInternal(nsPIDOMWindow* aWindow);
516 // the currently active and front-most top-most window
517 nsCOMPtr<nsPIDOMWindow> mActiveWindow;
519 // the child or top-level window that is currently focused. This window will
520 // either be the same window as mActiveWindow or a descendant of it.
521 // Except during shutdown use SetFocusedWindowInternal to set mFocusedWindow!
522 nsCOMPtr<nsPIDOMWindow> mFocusedWindow;
524 // the currently focused content, which is always inside mFocusedWindow. This
525 // is a cached copy of the mFocusedWindow's current content. This may be null
526 // if no content is focused.
527 nsCOMPtr<nsIContent> mFocusedContent;
529 // these fields store a content node temporarily while it is being focused
530 // or blurred to ensure that a recursive call doesn't refire the same event.
531 // They will always be cleared afterwards.
532 nsCOMPtr<nsIContent> mFirstBlurEvent;
533 nsCOMPtr<nsIContent> mFirstFocusEvent;
535 // keep track of a window while it is being lowered
536 nsCOMPtr<nsPIDOMWindow> mWindowBeingLowered;
538 // synchronized actions cannot be interrupted with events, so queue these up
539 // and fire them later.
540 nsTArray<nsDelayedBlurOrFocusEvent> mDelayedBlurFocusEvents;
542 // A document which is handling a mouse button event.
543 // When a mouse down event process is finished, ESM sets focus to the target
544 // content if it's not consumed. Therefore, while DOM event handlers are
545 // handling mouse down events or preceding mosue down event is consumed but
546 // handling mouse up events, they should be able to steal focus from any
547 // elements even if focus is in chrome content. So, if this isn't nullptr
548 // and the caller can access the document node, the caller should succeed in
549 // moving focus.
550 nsCOMPtr<nsIDocument> mMouseButtonEventHandlingDocument;
552 // Indicates a child process that is in an active window.
553 ParentFocusType mParentFocusType;
555 static bool sTestMode;
557 // the single focus manager
558 static nsFocusManager* sInstance;
561 nsresult
562 NS_NewFocusManager(nsIFocusManager** aResult);
564 #endif