no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / base / nsWindowRoot.cpp
blob1874898b6875fcf206bf4633c7397d7c2294ced7
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 "nsString.h"
17 #include "nsFrameLoaderOwner.h"
18 #include "nsFrameLoader.h"
19 #include "nsQueryActor.h"
20 #include "nsGlobalWindowOuter.h"
21 #include "nsFocusManager.h"
22 #include "nsIContent.h"
23 #include "nsIControllers.h"
24 #include "nsIController.h"
25 #include "nsQueryObject.h"
26 #include "xpcpublic.h"
27 #include "nsCycleCollectionParticipant.h"
28 #include "mozilla/dom/BrowserParent.h"
29 #include "mozilla/dom/CanonicalBrowsingContext.h"
30 #include "mozilla/dom/HTMLTextAreaElement.h"
31 #include "mozilla/dom/HTMLInputElement.h"
32 #include "mozilla/dom/JSActorService.h"
33 #include "mozilla/dom/WindowGlobalParent.h"
35 #include "nsXULElement.h"
37 using namespace mozilla;
38 using namespace mozilla::dom;
40 nsWindowRoot::nsWindowRoot(nsPIDOMWindowOuter* aWindow) {
41 SetIsOnMainThread();
42 mWindow = aWindow;
45 nsWindowRoot::~nsWindowRoot() {
46 if (mListenerManager) {
47 mListenerManager->Disconnect();
50 JSActorService::UnregisterChromeEventTarget(this);
53 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(nsWindowRoot)
55 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsWindowRoot)
56 JSActorService::UnregisterChromeEventTarget(tmp);
58 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
59 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
60 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
61 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
62 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
64 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsWindowRoot)
65 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
66 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
67 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
68 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
70 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot)
71 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
72 NS_INTERFACE_MAP_ENTRY(nsISupports)
73 NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
74 NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
75 NS_INTERFACE_MAP_END
77 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWindowRoot)
78 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWindowRoot)
80 bool nsWindowRoot::DispatchEvent(Event& aEvent, CallerType aCallerType,
81 ErrorResult& aRv) {
82 nsEventStatus status = nsEventStatus_eIgnore;
83 nsresult rv = EventDispatcher::DispatchDOMEvent(
84 static_cast<EventTarget*>(this), nullptr, &aEvent, nullptr, &status);
85 bool retval = !aEvent.DefaultPrevented(aCallerType);
86 if (NS_FAILED(rv)) {
87 aRv.Throw(rv);
89 return retval;
92 bool nsWindowRoot::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
93 return false;
96 EventListenerManager* nsWindowRoot::GetOrCreateListenerManager() {
97 if (!mListenerManager) {
98 mListenerManager =
99 new EventListenerManager(static_cast<EventTarget*>(this));
102 return mListenerManager;
105 EventListenerManager* nsWindowRoot::GetExistingListenerManager() const {
106 return mListenerManager;
109 void nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
110 aVisitor.mCanHandle = true;
111 aVisitor.mForceContentDispatch = true; // FIXME! Bug 329119
112 // To keep mWindow alive
113 aVisitor.mItemData = static_cast<nsISupports*>(mWindow);
114 aVisitor.SetParentTarget(mParent, false);
117 nsresult nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor) {
118 return NS_OK;
121 nsPIDOMWindowOuter* nsWindowRoot::GetOwnerGlobalForBindingsInternal() {
122 return mWindow;
125 nsIGlobalObject* nsWindowRoot::GetOwnerGlobal() const {
126 nsCOMPtr<nsIGlobalObject> global =
127 do_QueryInterface(mWindow->GetCurrentInnerWindow());
128 // We're still holding a ref to it, so returning the raw pointer is ok...
129 return global;
132 nsPIDOMWindowOuter* nsWindowRoot::GetWindow() { return mWindow; }
134 nsresult nsWindowRoot::GetControllers(bool aForVisibleWindow,
135 nsIControllers** aResult) {
136 *aResult = nullptr;
138 // XXX: we should fix this so there's a generic interface that
139 // describes controllers, so this code would have no special
140 // knowledge of what object might have controllers.
142 nsFocusManager::SearchRange searchRange =
143 aForVisibleWindow ? nsFocusManager::eIncludeVisibleDescendants
144 : nsFocusManager::eIncludeAllDescendants;
145 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
146 nsIContent* focusedContent = nsFocusManager::GetFocusedDescendant(
147 mWindow, searchRange, getter_AddRefs(focusedWindow));
148 if (focusedContent) {
149 RefPtr<nsXULElement> xulElement = nsXULElement::FromNode(focusedContent);
150 if (xulElement) {
151 ErrorResult rv;
152 *aResult = xulElement->GetControllers(rv);
153 NS_IF_ADDREF(*aResult);
154 return rv.StealNSResult();
157 HTMLTextAreaElement* htmlTextArea =
158 HTMLTextAreaElement::FromNode(focusedContent);
159 if (htmlTextArea) return htmlTextArea->GetControllers(aResult);
161 HTMLInputElement* htmlInputElement =
162 HTMLInputElement::FromNode(focusedContent);
163 if (htmlInputElement) return htmlInputElement->GetControllers(aResult);
165 if (focusedContent->IsEditable() && focusedWindow)
166 return focusedWindow->GetControllers(aResult);
167 } else {
168 return focusedWindow->GetControllers(aResult);
171 return NS_OK;
174 nsresult nsWindowRoot::GetControllerForCommand(const char* aCommand,
175 bool aForVisibleWindow,
176 nsIController** _retval) {
177 NS_ENSURE_ARG_POINTER(_retval);
178 *_retval = nullptr;
180 // If this is the parent process, check if a child browsing context from
181 // another process is focused, and ask if it has a controller actor that
182 // supports the command.
183 if (XRE_IsParentProcess()) {
184 nsFocusManager* fm = nsFocusManager::GetFocusManager();
185 if (!fm) {
186 return NS_ERROR_FAILURE;
189 // Unfortunately, messages updating the active/focus state in the focus
190 // manager don't happen fast enough in the case when switching focus between
191 // processes when clicking on a chrome UI element while a child tab is
192 // focused, so we need to check whether the focus manager thinks a child
193 // frame is focused as well.
194 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
195 nsIContent* focusedContent = nsFocusManager::GetFocusedDescendant(
196 mWindow, nsFocusManager::eIncludeAllDescendants,
197 getter_AddRefs(focusedWindow));
198 RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(focusedContent);
199 if (loaderOwner) {
200 // Only check browsing contexts if a remote frame is focused. If chrome is
201 // focused, just check the controllers directly below.
202 RefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
203 if (frameLoader && frameLoader->IsRemoteFrame()) {
204 // GetActiveBrowsingContextInChrome actually returns the top-level
205 // browsing context if the focus is in a child process tab, or null if
206 // the focus is in chrome.
207 BrowsingContext* focusedBC =
208 fm->GetActiveBrowsingContextInChrome()
209 ? fm->GetFocusedBrowsingContextInChrome()
210 : nullptr;
211 if (focusedBC) {
212 // At this point, it is known that a child process is focused, so ask
213 // its Controllers actor if the command is supported.
214 nsCOMPtr<nsIController> controller = do_QueryActor(
215 "Controllers", focusedBC->Canonical()->GetCurrentWindowGlobal());
216 if (controller) {
217 bool supported;
218 controller->SupportsCommand(aCommand, &supported);
219 if (supported) {
220 controller.forget(_retval);
221 return NS_OK;
230 nsCOMPtr<nsIControllers> controllers;
231 GetControllers(aForVisibleWindow, getter_AddRefs(controllers));
232 if (controllers) {
233 nsCOMPtr<nsIController> controller;
234 controllers->GetControllerForCommand(aCommand,
235 getter_AddRefs(controller));
236 if (controller) {
237 controller.forget(_retval);
238 return NS_OK;
243 nsFocusManager::SearchRange searchRange =
244 aForVisibleWindow ? nsFocusManager::eIncludeVisibleDescendants
245 : nsFocusManager::eIncludeAllDescendants;
246 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
247 nsFocusManager::GetFocusedDescendant(mWindow, searchRange,
248 getter_AddRefs(focusedWindow));
249 while (focusedWindow) {
250 nsCOMPtr<nsIControllers> controllers;
251 focusedWindow->GetControllers(getter_AddRefs(controllers));
252 if (controllers) {
253 nsCOMPtr<nsIController> controller;
254 controllers->GetControllerForCommand(aCommand,
255 getter_AddRefs(controller));
256 if (controller) {
257 controller.forget(_retval);
258 return NS_OK;
262 // XXXndeakin P3 is this casting safe?
263 nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(focusedWindow);
264 focusedWindow = win->GetPrivateParent();
267 return NS_OK;
270 void nsWindowRoot::GetEnabledDisabledCommandsForControllers(
271 nsIControllers* aControllers, nsTHashSet<nsCString>& aCommandsHandled,
272 nsTArray<nsCString>& aEnabledCommands,
273 nsTArray<nsCString>& aDisabledCommands) {
274 uint32_t controllerCount;
275 aControllers->GetControllerCount(&controllerCount);
276 for (uint32_t c = 0; c < controllerCount; c++) {
277 nsCOMPtr<nsIController> controller;
278 aControllers->GetControllerAt(c, getter_AddRefs(controller));
280 nsCOMPtr<nsICommandController> commandController(
281 do_QueryInterface(controller));
282 if (commandController) {
283 // All of our default command controllers have 20-60 commands. Let's just
284 // leave enough space here for all of them so we probably don't need to
285 // heap-allocate.
286 AutoTArray<nsCString, 64> commands;
287 if (NS_SUCCEEDED(commandController->GetSupportedCommands(commands))) {
288 for (auto& commandStr : commands) {
289 // Use a hash to determine which commands have already been handled by
290 // earlier controllers, as the earlier controller's result should get
291 // priority.
292 if (aCommandsHandled.EnsureInserted(commandStr)) {
293 // We inserted a new entry into aCommandsHandled.
294 bool enabled = false;
295 controller->IsCommandEnabled(commandStr.get(), &enabled);
297 if (enabled) {
298 aEnabledCommands.AppendElement(commandStr);
299 } else {
300 aDisabledCommands.AppendElement(commandStr);
309 void nsWindowRoot::GetEnabledDisabledCommands(
310 nsTArray<nsCString>& aEnabledCommands,
311 nsTArray<nsCString>& aDisabledCommands) {
312 nsTHashSet<nsCString> commandsHandled;
314 nsCOMPtr<nsIControllers> controllers;
315 GetControllers(false, getter_AddRefs(controllers));
316 if (controllers) {
317 GetEnabledDisabledCommandsForControllers(
318 controllers, commandsHandled, aEnabledCommands, aDisabledCommands);
321 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
322 nsFocusManager::GetFocusedDescendant(mWindow,
323 nsFocusManager::eIncludeAllDescendants,
324 getter_AddRefs(focusedWindow));
325 while (focusedWindow) {
326 focusedWindow->GetControllers(getter_AddRefs(controllers));
327 if (controllers) {
328 GetEnabledDisabledCommandsForControllers(
329 controllers, commandsHandled, aEnabledCommands, aDisabledCommands);
332 nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(focusedWindow);
333 focusedWindow = win->GetPrivateParent();
337 already_AddRefed<nsINode> nsWindowRoot::GetPopupNode() {
338 nsCOMPtr<nsINode> popupNode = do_QueryReferent(mPopupNode);
339 return popupNode.forget();
342 void nsWindowRoot::SetPopupNode(nsINode* aNode) {
343 mPopupNode = do_GetWeakReference(aNode);
346 nsIGlobalObject* nsWindowRoot::GetParentObject() {
347 return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
350 JSObject* nsWindowRoot::WrapObject(JSContext* aCx,
351 JS::Handle<JSObject*> aGivenProto) {
352 return mozilla::dom::WindowRoot_Binding::Wrap(aCx, this, aGivenProto);
355 void nsWindowRoot::AddBrowser(nsIRemoteTab* aBrowser) {
356 nsWeakPtr weakBrowser = do_GetWeakReference(aBrowser);
357 mWeakBrowsers.Insert(weakBrowser);
360 void nsWindowRoot::RemoveBrowser(nsIRemoteTab* aBrowser) {
361 nsWeakPtr weakBrowser = do_GetWeakReference(aBrowser);
362 mWeakBrowsers.Remove(weakBrowser);
365 void nsWindowRoot::EnumerateBrowsers(BrowserEnumerator aEnumFunc, void* aArg) {
366 // Collect strong references to all browsers in a separate array in
367 // case aEnumFunc alters mWeakBrowsers.
368 nsTArray<nsCOMPtr<nsIRemoteTab>> remoteTabs;
369 for (const auto& key : mWeakBrowsers) {
370 nsCOMPtr<nsIRemoteTab> remoteTab(do_QueryReferent(key));
371 if (remoteTab) {
372 remoteTabs.AppendElement(remoteTab);
376 for (uint32_t i = 0; i < remoteTabs.Length(); ++i) {
377 aEnumFunc(remoteTabs[i], aArg);
381 ///////////////////////////////////////////////////////////////////////////////////
383 already_AddRefed<EventTarget> NS_NewWindowRoot(nsPIDOMWindowOuter* aWindow) {
384 nsCOMPtr<EventTarget> result = new nsWindowRoot(aWindow);
386 RefPtr<JSActorService> wasvc = JSActorService::GetSingleton();
387 wasvc->RegisterChromeEventTarget(result);
389 return result.forget();