Line data Source code
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 : #include "mozilla/BasicEvents.h"
8 : #include "mozilla/EventDispatcher.h"
9 : #include "mozilla/EventListenerManager.h"
10 : #include "mozilla/dom/WindowRootBinding.h"
11 : #include "nsCOMPtr.h"
12 : #include "nsWindowRoot.h"
13 : #include "nsPIDOMWindow.h"
14 : #include "nsPresContext.h"
15 : #include "nsLayoutCID.h"
16 : #include "nsContentCID.h"
17 : #include "nsString.h"
18 : #include "nsGlobalWindow.h"
19 : #include "nsFocusManager.h"
20 : #include "nsIContent.h"
21 : #include "nsIDOMHTMLInputElement.h"
22 : #include "nsIDOMHTMLTextAreaElement.h"
23 : #include "nsIControllers.h"
24 : #include "nsIController.h"
25 : #include "xpcpublic.h"
26 : #include "nsCycleCollectionParticipant.h"
27 : #include "mozilla/dom/TabParent.h"
28 :
29 : #ifdef MOZ_XUL
30 : #include "nsXULElement.h"
31 : #endif
32 :
33 : using namespace mozilla;
34 : using namespace mozilla::dom;
35 :
36 3 : nsWindowRoot::nsWindowRoot(nsPIDOMWindowOuter* aWindow)
37 : {
38 3 : mWindow = aWindow;
39 3 : MOZ_ASSERT(mWindow->IsOuterWindow());
40 :
41 : // Keyboard indicators are not shown on Mac by default.
42 : #if defined(XP_MACOSX)
43 : mShowAccelerators = false;
44 : mShowFocusRings = false;
45 : #else
46 3 : mShowAccelerators = true;
47 3 : mShowFocusRings = true;
48 : #endif
49 3 : }
50 :
51 0 : nsWindowRoot::~nsWindowRoot()
52 : {
53 0 : if (mListenerManager) {
54 0 : mListenerManager->Disconnect();
55 : }
56 0 : }
57 :
58 0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsWindowRoot,
59 : mWindow,
60 : mListenerManager,
61 : mParent)
62 :
63 509 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot)
64 506 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
65 506 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget)
66 506 : NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
67 443 : NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
68 431 : NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
69 101 : NS_INTERFACE_MAP_END
70 :
71 734 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWindowRoot)
72 718 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWindowRoot)
73 :
74 320 : NS_IMPL_DOMTARGET_DEFAULTS(nsWindowRoot)
75 :
76 : NS_IMETHODIMP
77 2 : nsWindowRoot::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture)
78 : {
79 4 : if (RefPtr<EventListenerManager> elm = GetExistingListenerManager()) {
80 2 : elm->RemoveEventListener(aType, aListener, aUseCapture);
81 : }
82 2 : return NS_OK;
83 : }
84 :
85 1 : NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsWindowRoot)
86 :
87 : NS_IMETHODIMP
88 0 : nsWindowRoot::DispatchEvent(nsIDOMEvent* aEvt, bool *aRetVal)
89 : {
90 0 : nsEventStatus status = nsEventStatus_eIgnore;
91 0 : nsresult rv = EventDispatcher::DispatchDOMEvent(
92 0 : static_cast<EventTarget*>(this), nullptr, aEvt, nullptr, &status);
93 0 : *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
94 0 : return rv;
95 : }
96 :
97 : nsresult
98 19 : nsWindowRoot::DispatchDOMEvent(WidgetEvent* aEvent,
99 : nsIDOMEvent* aDOMEvent,
100 : nsPresContext* aPresContext,
101 : nsEventStatus* aEventStatus)
102 : {
103 19 : return EventDispatcher::DispatchDOMEvent(static_cast<EventTarget*>(this),
104 : aEvent, aDOMEvent,
105 19 : aPresContext, aEventStatus);
106 : }
107 :
108 : NS_IMETHODIMP
109 14 : nsWindowRoot::AddEventListener(const nsAString& aType,
110 : nsIDOMEventListener *aListener,
111 : bool aUseCapture, bool aWantsUntrusted,
112 : uint8_t aOptionalArgc)
113 : {
114 14 : NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
115 : "Won't check if this is chrome, you want to set "
116 : "aWantsUntrusted to false or make the aWantsUntrusted "
117 : "explicit by making optional_argc non-zero.");
118 :
119 14 : EventListenerManager* elm = GetOrCreateListenerManager();
120 14 : NS_ENSURE_STATE(elm);
121 14 : elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
122 14 : return NS_OK;
123 : }
124 :
125 : void
126 0 : nsWindowRoot::AddEventListener(const nsAString& aType,
127 : EventListener* aListener,
128 : const AddEventListenerOptionsOrBoolean& aOptions,
129 : const Nullable<bool>& aWantsUntrusted,
130 : ErrorResult& aRv)
131 : {
132 0 : bool wantsUntrusted = !aWantsUntrusted.IsNull() && aWantsUntrusted.Value();
133 0 : EventListenerManager* elm = GetOrCreateListenerManager();
134 0 : if (!elm) {
135 0 : aRv.Throw(NS_ERROR_UNEXPECTED);
136 0 : return;
137 : }
138 0 : elm->AddEventListener(aType, aListener, aOptions, wantsUntrusted);
139 : }
140 :
141 :
142 : NS_IMETHODIMP
143 7 : nsWindowRoot::AddSystemEventListener(const nsAString& aType,
144 : nsIDOMEventListener *aListener,
145 : bool aUseCapture,
146 : bool aWantsUntrusted,
147 : uint8_t aOptionalArgc)
148 : {
149 7 : NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
150 : "Won't check if this is chrome, you want to set "
151 : "aWantsUntrusted to false or make the aWantsUntrusted "
152 : "explicit by making optional_argc non-zero.");
153 :
154 7 : return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
155 7 : aWantsUntrusted);
156 : }
157 :
158 : EventListenerManager*
159 30 : nsWindowRoot::GetOrCreateListenerManager()
160 : {
161 30 : if (!mListenerManager) {
162 : mListenerManager =
163 3 : new EventListenerManager(static_cast<EventTarget*>(this));
164 : }
165 :
166 30 : return mListenerManager;
167 : }
168 :
169 : EventListenerManager*
170 233 : nsWindowRoot::GetExistingListenerManager() const
171 : {
172 233 : return mListenerManager;
173 : }
174 :
175 : nsIScriptContext*
176 0 : nsWindowRoot::GetContextForEventHandlers(nsresult* aRv)
177 : {
178 0 : *aRv = NS_OK;
179 0 : return nullptr;
180 : }
181 :
182 : nsresult
183 230 : nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
184 : {
185 230 : aVisitor.mCanHandle = true;
186 230 : aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
187 : // To keep mWindow alive
188 230 : aVisitor.mItemData = static_cast<nsISupports *>(mWindow);
189 230 : aVisitor.mParentTarget = mParent;
190 230 : return NS_OK;
191 : }
192 :
193 : nsresult
194 138 : nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor)
195 : {
196 138 : return NS_OK;
197 : }
198 :
199 : nsPIDOMWindowOuter*
200 0 : nsWindowRoot::GetOwnerGlobalForBindings()
201 : {
202 0 : return GetWindow();
203 : }
204 :
205 : nsIGlobalObject*
206 0 : nsWindowRoot::GetOwnerGlobal() const
207 : {
208 : nsCOMPtr<nsIGlobalObject> global =
209 0 : do_QueryInterface(mWindow->GetCurrentInnerWindow());
210 : // We're still holding a ref to it, so returning the raw pointer is ok...
211 0 : return global;
212 : }
213 :
214 : nsPIDOMWindowOuter*
215 9 : nsWindowRoot::GetWindow()
216 : {
217 9 : return mWindow;
218 : }
219 :
220 : nsresult
221 13 : nsWindowRoot::GetControllers(nsIControllers** aResult)
222 : {
223 13 : *aResult = nullptr;
224 :
225 : // XXX: we should fix this so there's a generic interface that
226 : // describes controllers, so this code would have no special
227 : // knowledge of what object might have controllers.
228 :
229 26 : nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
230 : nsIContent* focusedContent =
231 13 : nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow));
232 13 : if (focusedContent) {
233 : #ifdef MOZ_XUL
234 11 : RefPtr<nsXULElement> xulElement = nsXULElement::FromContent(focusedContent);
235 11 : if (xulElement) {
236 22 : ErrorResult rv;
237 11 : *aResult = xulElement->GetControllers(rv);
238 11 : NS_IF_ADDREF(*aResult);
239 11 : return rv.StealNSResult();
240 : }
241 : #endif
242 :
243 : nsCOMPtr<nsIDOMHTMLTextAreaElement> htmlTextArea =
244 0 : do_QueryInterface(focusedContent);
245 0 : if (htmlTextArea)
246 0 : return htmlTextArea->GetControllers(aResult);
247 :
248 : nsCOMPtr<nsIDOMHTMLInputElement> htmlInputElement =
249 0 : do_QueryInterface(focusedContent);
250 0 : if (htmlInputElement)
251 0 : return htmlInputElement->GetControllers(aResult);
252 :
253 0 : if (focusedContent->IsEditable() && focusedWindow)
254 0 : return focusedWindow->GetControllers(aResult);
255 : }
256 : else {
257 2 : return focusedWindow->GetControllers(aResult);
258 : }
259 :
260 0 : return NS_OK;
261 : }
262 :
263 : nsresult
264 11 : nsWindowRoot::GetControllerForCommand(const char * aCommand,
265 : nsIController** _retval)
266 : {
267 11 : NS_ENSURE_ARG_POINTER(_retval);
268 11 : *_retval = nullptr;
269 :
270 : {
271 22 : nsCOMPtr<nsIControllers> controllers;
272 11 : GetControllers(getter_AddRefs(controllers));
273 11 : if (controllers) {
274 22 : nsCOMPtr<nsIController> controller;
275 11 : controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
276 11 : if (controller) {
277 0 : controller.forget(_retval);
278 0 : return NS_OK;
279 : }
280 : }
281 : }
282 :
283 22 : nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
284 11 : nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow));
285 25 : while (focusedWindow) {
286 18 : nsCOMPtr<nsIControllers> controllers;
287 11 : focusedWindow->GetControllers(getter_AddRefs(controllers));
288 11 : if (controllers) {
289 18 : nsCOMPtr<nsIController> controller;
290 22 : controllers->GetControllerForCommand(aCommand,
291 22 : getter_AddRefs(controller));
292 11 : if (controller) {
293 4 : controller.forget(_retval);
294 4 : return NS_OK;
295 : }
296 : }
297 :
298 : // XXXndeakin P3 is this casting safe?
299 7 : nsGlobalWindow *win = nsGlobalWindow::Cast(focusedWindow);
300 7 : focusedWindow = win->GetPrivateParent();
301 : }
302 :
303 7 : return NS_OK;
304 : }
305 :
306 : void
307 4 : nsWindowRoot::GetEnabledDisabledCommandsForControllers(nsIControllers* aControllers,
308 : nsTHashtable<nsCharPtrHashKey>& aCommandsHandled,
309 : nsTArray<nsCString>& aEnabledCommands,
310 : nsTArray<nsCString>& aDisabledCommands)
311 : {
312 : uint32_t controllerCount;
313 4 : aControllers->GetControllerCount(&controllerCount);
314 8 : for (uint32_t c = 0; c < controllerCount; c++) {
315 8 : nsCOMPtr<nsIController> controller;
316 4 : aControllers->GetControllerAt(c, getter_AddRefs(controller));
317 :
318 8 : nsCOMPtr<nsICommandController> commandController(do_QueryInterface(controller));
319 4 : if (commandController) {
320 : uint32_t commandsCount;
321 : char** commands;
322 4 : if (NS_SUCCEEDED(commandController->GetSupportedCommands(&commandsCount, &commands))) {
323 248 : for (uint32_t e = 0; e < commandsCount; e++) {
324 : // Use a hash to determine which commands have already been handled by
325 : // earlier controllers, as the earlier controller's result should get
326 : // priority.
327 244 : if (aCommandsHandled.EnsureInserted(commands[e])) {
328 : // We inserted a new entry into aCommandsHandled.
329 122 : bool enabled = false;
330 122 : controller->IsCommandEnabled(commands[e], &enabled);
331 :
332 244 : const nsDependentCSubstring commandStr(commands[e], strlen(commands[e]));
333 122 : if (enabled) {
334 112 : aEnabledCommands.AppendElement(commandStr);
335 : } else {
336 10 : aDisabledCommands.AppendElement(commandStr);
337 : }
338 : }
339 : }
340 :
341 4 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(commandsCount, commands);
342 : }
343 : }
344 : }
345 4 : }
346 :
347 : void
348 2 : nsWindowRoot::GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands,
349 : nsTArray<nsCString>& aDisabledCommands)
350 : {
351 4 : nsTHashtable<nsCharPtrHashKey> commandsHandled;
352 :
353 4 : nsCOMPtr<nsIControllers> controllers;
354 2 : GetControllers(getter_AddRefs(controllers));
355 2 : if (controllers) {
356 2 : GetEnabledDisabledCommandsForControllers(controllers, commandsHandled,
357 2 : aEnabledCommands, aDisabledCommands);
358 : }
359 :
360 4 : nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
361 2 : nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow));
362 6 : while (focusedWindow) {
363 2 : focusedWindow->GetControllers(getter_AddRefs(controllers));
364 2 : if (controllers) {
365 2 : GetEnabledDisabledCommandsForControllers(controllers, commandsHandled,
366 2 : aEnabledCommands, aDisabledCommands);
367 : }
368 :
369 2 : nsGlobalWindow* win = nsGlobalWindow::Cast(focusedWindow);
370 2 : focusedWindow = win->GetPrivateParent();
371 : }
372 2 : }
373 :
374 : nsIDOMNode*
375 11 : nsWindowRoot::GetPopupNode()
376 : {
377 22 : nsCOMPtr<nsIDOMNode> popupNode = do_QueryReferent(mPopupNode);
378 22 : return popupNode;
379 : }
380 :
381 : void
382 0 : nsWindowRoot::SetPopupNode(nsIDOMNode* aNode)
383 : {
384 0 : mPopupNode = do_GetWeakReference(aNode);
385 0 : }
386 :
387 : nsIGlobalObject*
388 0 : nsWindowRoot::GetParentObject()
389 : {
390 0 : return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
391 : }
392 :
393 : JSObject*
394 0 : nsWindowRoot::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
395 : {
396 0 : return mozilla::dom::WindowRootBinding::Wrap(aCx, this, aGivenProto);
397 : }
398 :
399 : void
400 1 : nsWindowRoot::AddBrowser(mozilla::dom::TabParent* aBrowser)
401 : {
402 2 : nsWeakPtr weakBrowser = do_GetWeakReference(static_cast<nsITabParent*>(aBrowser));
403 1 : mWeakBrowsers.PutEntry(weakBrowser);
404 1 : }
405 :
406 : void
407 0 : nsWindowRoot::RemoveBrowser(mozilla::dom::TabParent* aBrowser)
408 : {
409 0 : nsWeakPtr weakBrowser = do_GetWeakReference(static_cast<nsITabParent*>(aBrowser));
410 0 : mWeakBrowsers.RemoveEntry(weakBrowser);
411 0 : }
412 :
413 : void
414 1 : nsWindowRoot::EnumerateBrowsers(BrowserEnumerator aEnumFunc, void* aArg)
415 : {
416 : // Collect strong references to all browsers in a separate array in
417 : // case aEnumFunc alters mWeakBrowsers.
418 2 : nsTArray<RefPtr<TabParent>> tabParents;
419 1 : for (auto iter = mWeakBrowsers.ConstIter(); !iter.Done(); iter.Next()) {
420 0 : nsCOMPtr<nsITabParent> tabParent(do_QueryReferent(iter.Get()->GetKey()));
421 0 : if (TabParent* tab = TabParent::GetFrom(tabParent)) {
422 0 : tabParents.AppendElement(tab);
423 : }
424 : }
425 :
426 1 : for (uint32_t i = 0; i < tabParents.Length(); ++i) {
427 0 : aEnumFunc(tabParents[i], aArg);
428 : }
429 1 : }
430 :
431 : ///////////////////////////////////////////////////////////////////////////////////
432 :
433 : already_AddRefed<EventTarget>
434 3 : NS_NewWindowRoot(nsPIDOMWindowOuter* aWindow)
435 : {
436 6 : nsCOMPtr<EventTarget> result = new nsWindowRoot(aWindow);
437 6 : return result.forget();
438 : }
|