Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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;
26 struct nsDelayedBlurOrFocusEvent;
28 /**
29 * The focus manager keeps track of where the focus is, that is, the node
30 * which receives key events.
31 */
33 class nsFocusManager MOZ_FINAL : public nsIFocusManager,
34 public nsIObserver,
35 public nsSupportsWeakReference
36 {
37 typedef mozilla::widget::InputContextAction InputContextAction;
39 public:
41 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFocusManager, nsIFocusManager)
42 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
43 NS_DECL_NSIOBSERVER
44 NS_DECL_NSIFOCUSMANAGER
46 // called to initialize and stop the focus manager at startup and shutdown
47 static nsresult Init();
48 static void Shutdown();
50 /**
51 * Retrieve the single focus manager.
52 */
53 static nsFocusManager* GetFocusManager() { return sInstance; }
55 /**
56 * A faster version of nsIFocusManager::GetFocusedElement, returning a
57 * raw nsIContent pointer (instead of having AddRef-ed nsIDOMElement
58 * pointer filled in to an out-parameter).
59 */
60 nsIContent* GetFocusedContent() { return mFocusedContent; }
62 /**
63 * Return a focused window. Version of nsIFocusManager::GetFocusedWindow.
64 */
65 nsPIDOMWindow* GetFocusedWindow() const { return mFocusedWindow; }
67 /**
68 * Return an active window. Version of nsIFocusManager::GetActiveWindow.
69 */
70 nsPIDOMWindow* GetActiveWindow() const { return mActiveWindow; }
72 /**
73 * Called when content has been removed.
74 */
75 nsresult ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
77 /**
78 * Called when mouse button down event handling is started and finished.
79 */
80 void SetMouseButtonDownHandlingDocument(nsIDocument* aDocument)
81 {
82 NS_ASSERTION(!aDocument || !mMouseDownEventHandlingDocument,
83 "Some mouse button down events are nested?");
84 mMouseDownEventHandlingDocument = aDocument;
85 }
87 /**
88 * Update the caret with current mode (whether in caret browsing mode or not).
89 */
90 void UpdateCaretForCaretBrowsingMode();
92 /**
93 * Returns the content node that would be focused if aWindow was in an
94 * active window. This will traverse down the frame hierarchy, starting at
95 * the given window aWindow. Sets aFocusedWindow to the window with the
96 * document containing aFocusedContent. If no element is focused,
97 * aFocusedWindow may be still be set -- this means that the document is
98 * focused but no element within it is focused.
99 *
100 * aWindow and aFocusedWindow must both be non-null.
101 */
102 static nsIContent* GetFocusedDescendant(nsPIDOMWindow* aWindow, bool aDeep,
103 nsPIDOMWindow** aFocusedWindow);
105 /**
106 * Returns the content node that focus will be redirected to if aContent was
107 * focused. This is used for the special case of certain XUL elements such
108 * as textboxes which redirect focus to an anonymous child.
109 *
110 * aContent must be non-null.
111 *
112 * XXXndeakin this should be removed eventually but I want to do that as
113 * followup work.
114 */
115 static nsIContent* GetRedirectedFocus(nsIContent* aContent);
117 /**
118 * Returns an InputContextAction cause for aFlags.
119 */
120 static InputContextAction::Cause GetFocusMoveActionCause(uint32_t aFlags);
122 static bool sMouseFocusesFormControl;
124 static void MarkUncollectableForCCGeneration(uint32_t aGeneration);
125 protected:
127 nsFocusManager();
128 ~nsFocusManager();
130 /**
131 * Ensure that the widget associated with the currently focused window is
132 * focused at the widget level.
133 */
134 void EnsureCurrentWidgetFocused();
136 /**
137 * Blur whatever is currently focused and focus aNewContent. aFlags is a
138 * bitmask of the flags defined in nsIFocusManager. If aFocusChanged is
139 * true, then the focus has actually shifted and the caret position will be
140 * updated to the new focus, aNewContent will be scrolled into view (unless
141 * a flag disables this) and the focus method for the window will be updated.
142 * If aAdjustWidget is false, don't change the widget focus state.
143 *
144 * All actual focus changes must use this method to do so. (as opposed
145 * to those that update the focus in an inactive window for instance).
146 */
147 void SetFocusInner(nsIContent* aNewContent, int32_t aFlags,
148 bool aFocusChanged, bool aAdjustWidget);
150 /**
151 * Returns true if aPossibleAncestor is the same as aWindow or an
152 * ancestor of aWindow.
153 */
154 bool IsSameOrAncestor(nsPIDOMWindow* aPossibleAncestor,
155 nsPIDOMWindow* aWindow);
157 /**
158 * Returns the window that is the lowest common ancestor of both aWindow1
159 * and aWindow2, or null if they share no common ancestor.
160 */
161 already_AddRefed<nsPIDOMWindow> GetCommonAncestor(nsPIDOMWindow* aWindow1,
162 nsPIDOMWindow* aWindow2);
164 /**
165 * When aNewWindow is focused, adjust the ancestors of aNewWindow so that they
166 * also have their corresponding frames focused. Thus, one can start at
167 * the active top-level window and navigate down the currently focused
168 * elements for each frame in the tree to get to aNewWindow.
169 */
170 void AdjustWindowFocus(nsPIDOMWindow* aNewWindow, bool aCheckPermission);
172 /**
173 * Returns true if aWindow is visible.
174 */
175 bool IsWindowVisible(nsPIDOMWindow* aWindow);
177 /**
178 * Returns true if aContent is a root element and not focusable.
179 * I.e., even if aContent is editable root element, this returns true when
180 * the document is in designMode.
181 *
182 * @param aContent must not be null and must be in a document.
183 */
184 bool IsNonFocusableRoot(nsIContent* aContent);
186 /**
187 * Checks and returns aContent if it may be focused, another content node if
188 * the focus should be retargeted at another node, or null if the node
189 * cannot be focused. aFlags are the flags passed to SetFocus and similar
190 * methods.
191 *
192 * An element is focusable if it is in a document, the document isn't in
193 * print preview mode and the element has an nsIFrame where the
194 * CheckIfFocusable method returns true. For <area> elements, there is no
195 * frame, so only the IsFocusable method on the content node must be
196 * true.
197 */
198 nsIContent* CheckIfFocusable(nsIContent* aContent, uint32_t aFlags);
200 /**
201 * Blurs the currently focused element. Returns false if another element was
202 * focused as a result. This would mean that the caller should not proceed
203 * with a pending call to Focus. Normally, true would be returned.
204 *
205 * The currently focused element within aWindowToClear will be cleared.
206 * aWindowToClear may be null, which means that no window is cleared. This
207 * will be the case, for example, when lowering a window, as we want to fire
208 * a blur, but not actually change what element would be focused, so that
209 * the same element will be focused again when the window is raised.
210 *
211 * aAncestorWindowToFocus should be set to the common ancestor of the window
212 * that is being blurred and the window that is going to focused, when
213 * switching focus to a sibling window.
214 *
215 * aIsLeavingDocument should be set to true if the document/window is being
216 * blurred as well. Document/window blur events will be fired. It should be
217 * false if an element is the same document is about to be focused.
218 *
219 * If aAdjustWidget is false, don't change the widget focus state.
220 */
221 bool Blur(nsPIDOMWindow* aWindowToClear,
222 nsPIDOMWindow* aAncestorWindowToFocus,
223 bool aIsLeavingDocument,
224 bool aAdjustWidget);
226 /**
227 * Focus an element in the active window and child frame.
228 *
229 * aWindow is the window containing the element aContent to focus.
230 *
231 * aFlags is the flags passed to the various focus methods in
232 * nsIFocusManager.
233 *
234 * aIsNewDocument should be true if a new document is being focused.
235 * Document/window focus events will be fired.
236 *
237 * aFocusChanged should be true if a new content node is being focused, so
238 * the focused content will be scrolled into view and the caret position
239 * will be updated. If false is passed, then a window is simply being
240 * refocused, for instance, due to a window being raised, or a tab is being
241 * switched to.
242 *
243 * If aFocusChanged is true, then the focus has moved to a new location.
244 * Otherwise, the focus is just being updated because the window was
245 * raised.
246 *
247 * aWindowRaised should be true if the window is being raised. In this case,
248 * command updaters will not be called.
249 *
250 * If aAdjustWidget is false, don't change the widget focus state.
251 */
252 void Focus(nsPIDOMWindow* aWindow,
253 nsIContent* aContent,
254 uint32_t aFlags,
255 bool aIsNewDocument,
256 bool aFocusChanged,
257 bool aWindowRaised,
258 bool aAdjustWidget);
260 /**
261 * Fires a focus or blur event at aTarget.
262 *
263 * aType should be either NS_FOCUS_CONTENT or NS_BLUR_CONTENT. For blur
264 * events, aFocusMethod should normally be non-zero.
265 *
266 * aWindowRaised should only be true if called from WindowRaised.
267 */
268 void SendFocusOrBlurEvent(uint32_t aType,
269 nsIPresShell* aPresShell,
270 nsIDocument* aDocument,
271 nsISupports* aTarget,
272 uint32_t aFocusMethod,
273 bool aWindowRaised,
274 bool aIsRefocus = false);
276 /**
277 * Scrolls aContent into view unless the FLAG_NOSCROLL flag is set.
278 */
279 void ScrollIntoView(nsIPresShell* aPresShell,
280 nsIContent* aContent,
281 uint32_t aFlags);
283 /**
284 * Raises the top-level window aWindow at the widget level.
285 */
286 void RaiseWindow(nsPIDOMWindow* aWindow);
288 /**
289 * Updates the caret positon and visibility to match the focus.
290 *
291 * aMoveCaretToFocus should be true to move the caret to aContent.
292 *
293 * aUpdateVisibility should be true to update whether the caret is
294 * visible or not.
295 */
296 void UpdateCaret(bool aMoveCaretToFocus,
297 bool aUpdateVisibility,
298 nsIContent* aContent);
300 /**
301 * Helper method to move the caret to the focused element aContent.
302 */
303 void MoveCaretToFocus(nsIPresShell* aPresShell, nsIContent* aContent);
305 /**
306 * Makes the caret visible or not, depending on aVisible.
307 */
308 nsresult SetCaretVisible(nsIPresShell* aPresShell,
309 bool aVisible,
310 nsIContent* aContent);
313 // the remaining functions are used for tab key and document-navigation
315 /**
316 * Retrieves the start and end points of the current selection for
317 * aDocument and stores them in aStartContent and aEndContent.
318 */
319 nsresult GetSelectionLocation(nsIDocument* aDocument,
320 nsIPresShell* aPresShell,
321 nsIContent **aStartContent,
322 nsIContent **aEndContent);
324 /**
325 * Helper function for MoveFocus which determines the next element
326 * to move the focus to and returns it in aNextContent.
327 *
328 * aWindow is the window to adjust the focus within, and aStart is
329 * the element to start navigation from. For tab key navigation,
330 * this should be the currently focused element.
331 *
332 * aType is the type passed to MoveFocus. If aNoParentTraversal is set,
333 * navigation is not done to parent documents and iteration returns to the
334 * beginning (or end) of the starting document.
335 */
336 nsresult DetermineElementToMoveFocus(nsPIDOMWindow* aWindow,
337 nsIContent* aStart,
338 int32_t aType, bool aNoParentTraversal,
339 nsIContent** aNextContent);
341 /**
342 * Retrieve the next tabbable element within a document, using focusability
343 * and tabindex to determine the tab order. The element is returned in
344 * aResultContent.
345 *
346 * aRootContent is the root node -- nodes above this will not be examined.
347 * Typically this will be the root node of a document, but could also be
348 * a popup node.
349 *
350 * aOriginalStartContent is the content which was originally the starting
351 * node, in the case of recursive or looping calls.
352 *
353 * aStartContent is the starting point for this call of this method.
354 * If aStartContent doesn't have visual representation, the next content
355 * object, which does have a primary frame, will be used as a start.
356 * If that content object is focusable, the method may return it.
357 *
358 * aForward should be true for forward navigation or false for backward
359 * navigation.
360 *
361 * aCurrentTabIndex is the current tabindex.
362 *
363 * aIgnoreTabIndex to ignore the current tabindex and find the element
364 * irrespective or the tab index. This will be true when a selection is
365 * active, since we just want to focus the next element in tree order
366 * from where the selection is. Similarly, if the starting element isn't
367 * focusable, since it doesn't really have a defined tab index.
368 */
369 nsresult GetNextTabbableContent(nsIPresShell* aPresShell,
370 nsIContent* aRootContent,
371 nsIContent* aOriginalStartContent,
372 nsIContent* aStartContent,
373 bool aForward,
374 int32_t aCurrentTabIndex,
375 bool aIgnoreTabIndex,
376 nsIContent** aResultContent);
378 /**
379 * Get the next tabbable image map area and returns it.
380 *
381 * aForward should be true for forward navigation or false for backward
382 * navigation.
383 *
384 * aCurrentTabIndex is the current tabindex.
385 *
386 * aImageContent is the image.
387 *
388 * aStartContent is the current image map area.
389 */
390 nsIContent* GetNextTabbableMapArea(bool aForward,
391 int32_t aCurrentTabIndex,
392 nsIContent* aImageContent,
393 nsIContent* aStartContent);
395 /**
396 * Return the next valid tabindex value after aCurrentTabIndex, if aForward
397 * is true, or the previous tabindex value if aForward is false. aParent is
398 * the node from which to start looking for tab indicies.
399 */
400 int32_t GetNextTabIndex(nsIContent* aParent,
401 int32_t aCurrentTabIndex,
402 bool aForward);
404 /**
405 * Retrieves and returns the root node from aDocument to be focused. Will
406 * return null if the root node cannot be focused. There are several reasons
407 * for this:
408 *
409 * - if aIsForDocNavigation is true, and aWindow is in an <iframe>.
410 * - if aIsForDocNavigation is false, and aWindow is a chrome shell.
411 * - if aCheckVisibility is true and the aWindow is not visible.
412 * - if aDocument is a frameset document.
413 */
414 nsIContent* GetRootForFocus(nsPIDOMWindow* aWindow,
415 nsIDocument* aDocument,
416 bool aIsForDocNavigation,
417 bool aCheckVisibility);
419 /**
420 * Get the last docshell child of aItem and return it in aResult.
421 */
422 void GetLastDocShell(nsIDocShellTreeItem* aItem,
423 nsIDocShellTreeItem** aResult);
425 /**
426 * Get the next docshell child of aItem and return it in aResult.
427 */
428 void GetNextDocShell(nsIDocShellTreeItem* aItem,
429 nsIDocShellTreeItem** aResult);
431 /**
432 * Get the previous docshell child of aItem and return it in aResult.
433 */
434 void GetPreviousDocShell(nsIDocShellTreeItem* aItem,
435 nsIDocShellTreeItem** aResult);
437 /**
438 * Determine the first panel with focusable content in document tab order
439 * from the given document. aForward indicates the direction to scan. If
440 * aCurrentPopup is set to a panel, the next or previous popup after
441 * aCurrentPopup after it is used. If aCurrentPopup is null, then the first
442 * or last popup is used. If a panel has no focusable content, it is skipped.
443 * Null is returned if no panel is open or no open panel contains a focusable
444 * element.
445 */
446 nsIContent* GetNextTabbablePanel(nsIDocument* aDocument, nsIFrame* aCurrentPopup, bool aForward);
448 /**
449 * Get the tabbable next document from aStartContent or, if null, the
450 * currently focused frame if aForward is true, or the previously tabbable
451 * document if aForward is false. If this document is a chrome or frameset
452 * document, returns the first focusable element within this document,
453 * otherwise, returns the root node of the document.
454 *
455 *
456 * Panels with focusable content are also placed in the cycling order, just
457 * after the document containing that panel.
458 *
459 * This method would be used for document navigation, which is typically
460 * invoked by pressing F6.
461 */
462 nsIContent* GetNextTabbableDocument(nsIContent* aStartContent, bool aForward);
464 /**
465 * Retreives a focusable element within the current selection of aWindow.
466 * Currently, this only detects links.
467 *
468 * This is used when MoveFocus is called with a type of MOVEFOCUS_CARET,
469 * which is used, for example, to focus links as the caret is moved over
470 * them.
471 */
472 void GetFocusInSelection(nsPIDOMWindow* aWindow,
473 nsIContent* aStartSelection,
474 nsIContent* aEndSelection,
475 nsIContent** aFocusedContent);
477 private:
478 // Notify that the focus state of aContent has changed. Note that
479 // we need to pass in whether the window should show a focus ring
480 // before the SetFocusedNode call on it happened when losing focus
481 // and after the SetFocusedNode call when gaining focus, which is
482 // why that information needs to be an explicit argument instead of
483 // just passing in the window and asking it whether it should show
484 // focus rings: in the losing focus case that information could be
485 // wrong..
486 static void NotifyFocusStateChange(nsIContent* aContent,
487 bool aWindowShouldShowFocusRing,
488 bool aGettingFocus);
490 void SetFocusedWindowInternal(nsPIDOMWindow* aWindow);
492 // the currently active and front-most top-most window
493 nsCOMPtr<nsPIDOMWindow> mActiveWindow;
495 // the child or top-level window that is currently focused. This window will
496 // either be the same window as mActiveWindow or a descendant of it.
497 // Except during shutdown use SetFocusedWindowInternal to set mFocusedWindow!
498 nsCOMPtr<nsPIDOMWindow> mFocusedWindow;
500 // the currently focused content, which is always inside mFocusedWindow. This
501 // is a cached copy of the mFocusedWindow's current content. This may be null
502 // if no content is focused.
503 nsCOMPtr<nsIContent> mFocusedContent;
505 // these fields store a content node temporarily while it is being focused
506 // or blurred to ensure that a recursive call doesn't refire the same event.
507 // They will always be cleared afterwards.
508 nsCOMPtr<nsIContent> mFirstBlurEvent;
509 nsCOMPtr<nsIContent> mFirstFocusEvent;
511 // keep track of a window while it is being lowered
512 nsCOMPtr<nsPIDOMWindow> mWindowBeingLowered;
514 // synchronized actions cannot be interrupted with events, so queue these up
515 // and fire them later.
516 nsTArray<nsDelayedBlurOrFocusEvent> mDelayedBlurFocusEvents;
518 // A document which is handling a mouse button down event.
519 // When a mouse down event process is finished, ESM sets focus to the target
520 // content. Therefore, while DOM event handlers are handling mouse down
521 // events, the handlers should be able to steal focus from any elements even
522 // if focus is in chrome content. So, if this isn't nullptr and the caller
523 // can access the document node, the caller should succeed in moving focus.
524 nsCOMPtr<nsIDocument> mMouseDownEventHandlingDocument;
526 static bool sTestMode;
528 // the single focus manager
529 static nsFocusManager* sInstance;
530 };
532 nsresult
533 NS_NewFocusManager(nsIFocusManager** aResult);
535 #endif