Bug 1700051: part 26) Correct typo in comment of `mozInlineSpellWordUtil::BuildSoftTe...
[gecko.git] / dom / base / nsWindowRoot.cpp
blob4b5831d8653991e0c5a67a9aafc7a7a7b3777ecc
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/. */
7 #include "mozilla/BasicEvents.h"
8 #include "mozilla/EventDispatcher.h"
9 #include "mozilla/EventListenerManager.h"
10 #include "mozilla/StaticPrefs_browser.h"
11 #include "mozilla/dom/WindowRootBinding.h"
12 #include "nsCOMPtr.h"
13 #include "nsWindowRoot.h"
14 #include "nsPIDOMWindow.h"
15 #include "nsPresContext.h"
16 #include "nsLayoutCID.h"
17 #include "nsContentCID.h"
18 #include "nsString.h"
19 #include "nsFrameLoaderOwner.h"
20 #include "nsFrameLoader.h"
21 #include "nsQueryActor.h"
22 #include "nsGlobalWindow.h"
23 #include "nsFocusManager.h"
24 #include "nsIContent.h"
25 #include "nsIControllers.h"
26 #include "nsIController.h"
27 #include "nsQueryObject.h"
28 #include "xpcpublic.h"
29 #include "nsCycleCollectionParticipant.h"
30 #include "mozilla/dom/BrowserParent.h"
31 #include "mozilla/dom/CanonicalBrowsingContext.h"
32 #include "mozilla/dom/HTMLTextAreaElement.h"
33 #include "mozilla/dom/HTMLInputElement.h"
34 #include "mozilla/dom/JSActorService.h"
35 #include "mozilla/dom/WindowGlobalParent.h"
37 #ifdef MOZ_XUL
38 # include "nsXULElement.h"
39 #endif
41 using namespace mozilla;
42 using namespace mozilla::dom;
44 nsWindowRoot::nsWindowRoot(nsPIDOMWindowOuter* aWindow) {
45 mWindow = aWindow;
46 mShowFocusRings = StaticPrefs::browser_display_show_focus_rings();
49 nsWindowRoot::~nsWindowRoot() {
50 if (mListenerManager) {
51 mListenerManager->Disconnect();
54 if (XRE_IsContentProcess()) {
55 JSActorService::UnregisterChromeEventTarget(this);
59 NS_IMPL_CYCLE_COLLECTION_CLASS(nsWindowRoot)
61 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsWindowRoot)
62 if (XRE_IsContentProcess()) {
63 JSActorService::UnregisterChromeEventTarget(tmp);
66 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
67 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
68 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
69 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
70 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
72 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsWindowRoot)
73 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
74 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
75 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
76 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
78 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsWindowRoot)
80 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot)
81 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
82 NS_INTERFACE_MAP_ENTRY(nsISupports)
83 NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
84 NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
85 NS_INTERFACE_MAP_END
87 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWindowRoot)
88 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWindowRoot)
90 bool nsWindowRoot::DispatchEvent(Event& aEvent, CallerType aCallerType,
91 ErrorResult& aRv) {
92 nsEventStatus status = nsEventStatus_eIgnore;
93 nsresult rv = EventDispatcher::DispatchDOMEvent(
94 static_cast<EventTarget*>(this), nullptr, &aEvent, nullptr, &status);
95 bool retval = !aEvent.DefaultPrevented(aCallerType);
96 if (NS_FAILED(rv)) {
97 aRv.Throw(rv);
99 return retval;
102 bool nsWindowRoot::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
103 return false;
106 EventListenerManager* nsWindowRoot::GetOrCreateListenerManager() {
107 if (!mListenerManager) {
108 mListenerManager =
109 new EventListenerManager(static_cast<EventTarget*>(this));
112 return mListenerManager;
115 EventListenerManager* nsWindowRoot::GetExistingListenerManager() const {
116 return mListenerManager;
119 void nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
120 aVisitor.mCanHandle = true;
121 aVisitor.mForceContentDispatch = true; // FIXME! Bug 329119
122 // To keep mWindow alive
123 aVisitor.mItemData = static_cast<nsISupports*>(mWindow);
124 aVisitor.SetParentTarget(mParent, false);
127 nsresult nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor) {
128 return NS_OK;
131 nsPIDOMWindowOuter* nsWindowRoot::GetOwnerGlobalForBindingsInternal() {
132 return mWindow;
135 nsIGlobalObject* nsWindowRoot::GetOwnerGlobal() const {
136 nsCOMPtr<nsIGlobalObject> global =
137 do_QueryInterface(mWindow->GetCurrentInnerWindow());
138 // We're still holding a ref to it, so returning the raw pointer is ok...
139 return global;
142 nsPIDOMWindowOuter* nsWindowRoot::GetWindow() { return mWindow; }
144 nsresult nsWindowRoot::GetControllers(bool aForVisibleWindow,
145 nsIControllers** aResult) {
146 *aResult = nullptr;
148 // XXX: we should fix this so there's a generic interface that
149 // describes controllers, so this code would have no special
150 // knowledge of what object might have controllers.
152 nsFocusManager::SearchRange searchRange =
153 aForVisibleWindow ? nsFocusManager::eIncludeVisibleDescendants
154 : nsFocusManager::eIncludeAllDescendants;
155 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
156 nsIContent* focusedContent = nsFocusManager::GetFocusedDescendant(
157 mWindow, searchRange, getter_AddRefs(focusedWindow));
158 if (focusedContent) {
159 #ifdef MOZ_XUL
160 RefPtr<nsXULElement> xulElement = nsXULElement::FromNode(focusedContent);
161 if (xulElement) {
162 ErrorResult rv;
163 *aResult = xulElement->GetControllers(rv);
164 NS_IF_ADDREF(*aResult);
165 return rv.StealNSResult();
167 #endif
169 HTMLTextAreaElement* htmlTextArea =
170 HTMLTextAreaElement::FromNode(focusedContent);
171 if (htmlTextArea) return htmlTextArea->GetControllers(aResult);
173 HTMLInputElement* htmlInputElement =
174 HTMLInputElement::FromNode(focusedContent);
175 if (htmlInputElement) return htmlInputElement->GetControllers(aResult);
177 if (focusedContent->IsEditable() && focusedWindow)
178 return focusedWindow->GetControllers(aResult);
179 } else {
180 return focusedWindow->GetControllers(aResult);
183 return NS_OK;
186 nsresult nsWindowRoot::GetControllerForCommand(const char* aCommand,
187 bool aForVisibleWindow,
188 nsIController** _retval) {
189 NS_ENSURE_ARG_POINTER(_retval);
190 *_retval = nullptr;
192 // If this is the parent process, check if a child browsing context from
193 // another process is focused, and ask if it has a controller actor that
194 // supports the command.
195 if (XRE_IsParentProcess()) {
196 nsFocusManager* fm = nsFocusManager::GetFocusManager();
197 if (!fm) {
198 return NS_ERROR_FAILURE;
201 // Unfortunately, messages updating the active/focus state in the focus
202 // manager don't happen fast enough in the case when switching focus between
203 // processes when clicking on a chrome UI element while a child tab is
204 // focused, so we need to check whether the focus manager thinks a child
205 // frame is focused as well.
206 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
207 nsIContent* focusedContent = nsFocusManager::GetFocusedDescendant(
208 mWindow, nsFocusManager::eIncludeAllDescendants,
209 getter_AddRefs(focusedWindow));
210 RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(focusedContent);
211 if (loaderOwner) {
212 // Only check browsing contexts if a remote frame is focused. If chrome is
213 // focused, just check the controllers directly below.
214 RefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
215 if (frameLoader && frameLoader->IsRemoteFrame()) {
216 // GetActiveBrowsingContextInChrome actually returns the top-level
217 // browsing context if the focus is in a child process tab, or null if
218 // the focus is in chrome.
219 BrowsingContext* focusedBC =
220 fm->GetActiveBrowsingContextInChrome()
221 ? fm->GetFocusedBrowsingContextInChrome()
222 : nullptr;
223 if (focusedBC) {
224 // At this point, it is known that a child process is focused, so ask
225 // its Controllers actor if the command is supported.
226 nsCOMPtr<nsIController> controller = do_QueryActor(
227 "Controllers", focusedBC->Canonical()->GetCurrentWindowGlobal());
228 if (controller) {
229 bool supported;
230 controller->SupportsCommand(aCommand, &supported);
231 if (supported) {
232 controller.forget(_retval);
233 return NS_OK;
242 nsCOMPtr<nsIControllers> controllers;
243 GetControllers(aForVisibleWindow, getter_AddRefs(controllers));
244 if (controllers) {
245 nsCOMPtr<nsIController> controller;
246 controllers->GetControllerForCommand(aCommand,
247 getter_AddRefs(controller));
248 if (controller) {
249 controller.forget(_retval);
250 return NS_OK;
255 nsFocusManager::SearchRange searchRange =
256 aForVisibleWindow ? nsFocusManager::eIncludeVisibleDescendants
257 : nsFocusManager::eIncludeAllDescendants;
258 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
259 nsFocusManager::GetFocusedDescendant(mWindow, searchRange,
260 getter_AddRefs(focusedWindow));
261 while (focusedWindow) {
262 nsCOMPtr<nsIControllers> controllers;
263 focusedWindow->GetControllers(getter_AddRefs(controllers));
264 if (controllers) {
265 nsCOMPtr<nsIController> controller;
266 controllers->GetControllerForCommand(aCommand,
267 getter_AddRefs(controller));
268 if (controller) {
269 controller.forget(_retval);
270 return NS_OK;
274 // XXXndeakin P3 is this casting safe?
275 nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(focusedWindow);
276 focusedWindow = win->GetPrivateParent();
279 return NS_OK;
282 void nsWindowRoot::GetEnabledDisabledCommandsForControllers(
283 nsIControllers* aControllers, nsTHashSet<nsCString>& aCommandsHandled,
284 nsTArray<nsCString>& aEnabledCommands,
285 nsTArray<nsCString>& aDisabledCommands) {
286 uint32_t controllerCount;
287 aControllers->GetControllerCount(&controllerCount);
288 for (uint32_t c = 0; c < controllerCount; c++) {
289 nsCOMPtr<nsIController> controller;
290 aControllers->GetControllerAt(c, getter_AddRefs(controller));
292 nsCOMPtr<nsICommandController> commandController(
293 do_QueryInterface(controller));
294 if (commandController) {
295 // All of our default command controllers have 20-60 commands. Let's just
296 // leave enough space here for all of them so we probably don't need to
297 // heap-allocate.
298 AutoTArray<nsCString, 64> commands;
299 if (NS_SUCCEEDED(commandController->GetSupportedCommands(commands))) {
300 for (auto& commandStr : commands) {
301 // Use a hash to determine which commands have already been handled by
302 // earlier controllers, as the earlier controller's result should get
303 // priority.
304 if (aCommandsHandled.EnsureInserted(commandStr)) {
305 // We inserted a new entry into aCommandsHandled.
306 bool enabled = false;
307 controller->IsCommandEnabled(commandStr.get(), &enabled);
309 if (enabled) {
310 aEnabledCommands.AppendElement(commandStr);
311 } else {
312 aDisabledCommands.AppendElement(commandStr);
321 void nsWindowRoot::GetEnabledDisabledCommands(
322 nsTArray<nsCString>& aEnabledCommands,
323 nsTArray<nsCString>& aDisabledCommands) {
324 nsTHashSet<nsCString> commandsHandled;
326 nsCOMPtr<nsIControllers> controllers;
327 GetControllers(false, getter_AddRefs(controllers));
328 if (controllers) {
329 GetEnabledDisabledCommandsForControllers(
330 controllers, commandsHandled, aEnabledCommands, aDisabledCommands);
333 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
334 nsFocusManager::GetFocusedDescendant(mWindow,
335 nsFocusManager::eIncludeAllDescendants,
336 getter_AddRefs(focusedWindow));
337 while (focusedWindow) {
338 focusedWindow->GetControllers(getter_AddRefs(controllers));
339 if (controllers) {
340 GetEnabledDisabledCommandsForControllers(
341 controllers, commandsHandled, aEnabledCommands, aDisabledCommands);
344 nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(focusedWindow);
345 focusedWindow = win->GetPrivateParent();
349 already_AddRefed<nsINode> nsWindowRoot::GetPopupNode() {
350 nsCOMPtr<nsINode> popupNode = do_QueryReferent(mPopupNode);
351 return popupNode.forget();
354 void nsWindowRoot::SetPopupNode(nsINode* aNode) {
355 mPopupNode = do_GetWeakReference(aNode);
358 nsIGlobalObject* nsWindowRoot::GetParentObject() {
359 return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
362 JSObject* nsWindowRoot::WrapObject(JSContext* aCx,
363 JS::Handle<JSObject*> aGivenProto) {
364 return mozilla::dom::WindowRoot_Binding::Wrap(aCx, this, aGivenProto);
367 void nsWindowRoot::AddBrowser(nsIRemoteTab* aBrowser) {
368 nsWeakPtr weakBrowser = do_GetWeakReference(aBrowser);
369 mWeakBrowsers.Insert(weakBrowser);
372 void nsWindowRoot::RemoveBrowser(nsIRemoteTab* aBrowser) {
373 nsWeakPtr weakBrowser = do_GetWeakReference(aBrowser);
374 mWeakBrowsers.Remove(weakBrowser);
377 void nsWindowRoot::EnumerateBrowsers(BrowserEnumerator aEnumFunc, void* aArg) {
378 // Collect strong references to all browsers in a separate array in
379 // case aEnumFunc alters mWeakBrowsers.
380 nsTArray<nsCOMPtr<nsIRemoteTab>> remoteTabs;
381 for (const auto& key : mWeakBrowsers) {
382 nsCOMPtr<nsIRemoteTab> remoteTab(do_QueryReferent(key));
383 if (remoteTab) {
384 remoteTabs.AppendElement(remoteTab);
388 for (uint32_t i = 0; i < remoteTabs.Length(); ++i) {
389 aEnumFunc(remoteTabs[i], aArg);
393 ///////////////////////////////////////////////////////////////////////////////////
395 already_AddRefed<EventTarget> NS_NewWindowRoot(nsPIDOMWindowOuter* aWindow) {
396 nsCOMPtr<EventTarget> result = new nsWindowRoot(aWindow);
398 if (XRE_IsContentProcess()) {
399 RefPtr<JSActorService> wasvc = JSActorService::GetSingleton();
400 wasvc->RegisterChromeEventTarget(result);
403 return result.forget();