1 /* -*- Mode: C++; tab-width: 2; 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 "nsGlobalWindow.h"
11 #include "mozilla/MemoryReporting.h"
14 #include "Navigator.h"
16 #include "nsHistory.h"
17 #include "nsPerformance.h"
18 #include "nsDOMNavigationTiming.h"
19 #include "nsIDOMStorageManager.h"
20 #include "mozilla/dom/DOMStorage.h"
21 #include "mozilla/dom/StorageEvent.h"
22 #include "mozilla/dom/StorageEventBinding.h"
23 #include "nsDOMOfflineResourceList.h"
25 #include "nsIIdleService.h"
26 #include "nsISizeOfEventTarget.h"
27 #include "nsDOMJSUtils.h"
28 #include "nsArrayUtils.h"
29 #include "nsIDOMWindowCollection.h"
30 #include "nsDOMWindowList.h"
31 #include "mozilla/dom/WakeLock.h"
32 #include "mozilla/dom/power/PowerManagerService.h"
33 #include "nsIDocShellTreeOwner.h"
34 #include "nsIPermissionManager.h"
35 #include "nsIScriptContext.h"
36 #include "nsIScriptTimeoutHandler.h"
37 #include "nsIController.h"
38 #include "nsScriptNameSpaceManager.h"
39 #include "nsISlowScriptDebug.h"
40 #include "nsWindowMemoryReporter.h"
41 #include "WindowNamedPropertiesHandler.h"
42 #include "nsFrameSelection.h"
43 #include "nsISelectionListener.h"
46 #include "nsJSUtils.h"
47 #include "jsapi.h" // for JSAutoRequest
48 #include "js/OldDebugAPI.h" // for JS_ClearWatchPointsForObject
49 #include "jswrapper.h"
50 #include "nsReadableUtils.h"
51 #include "nsDOMClassInfo.h"
52 #include "nsJSEnvironment.h"
53 #include "ScriptSettings.h"
54 #include "mozilla/Preferences.h"
55 #include "mozilla/Likely.h"
56 #include "mozilla/unused.h"
59 #include "mozilla/dom/BarProps.h"
60 #include "nsContentCID.h"
61 #include "nsLayoutStatics.h"
62 #include "nsCCUncollectableMarker.h"
63 #include "mozilla/dom/workers/Workers.h"
64 #include "mozilla/dom/MessagePortList.h"
65 #include "mozilla/dom/ToJSValue.h"
66 #include "nsJSPrincipals.h"
67 #include "mozilla/Attributes.h"
68 #include "mozilla/Debug.h"
69 #include "mozilla/EventListenerManager.h"
70 #include "mozilla/EventStates.h"
71 #include "mozilla/MouseEvents.h"
72 #include "AudioChannelService.h"
73 #include "MessageEvent.h"
74 #include "nsAboutProtocolUtils.h"
78 #include "nsCanvasFrame.h"
79 #include "nsIWidget.h"
80 #include "nsIWidgetListener.h"
81 #include "nsIBaseWindow.h"
82 #include "nsIDeviceSensors.h"
83 #include "nsIContent.h"
84 #include "nsIDocShell.h"
85 #include "nsIDocCharset.h"
86 #include "nsIDocument.h"
88 #ifndef MOZ_DISABLE_CRYPTOLEGACY
89 #include "nsIDOMCryptoLegacy.h"
91 #include "nsIDOMDocument.h"
92 #include "nsIDOMElement.h"
93 #include "nsIDOMEvent.h"
94 #include "nsIDOMOfflineResourceList.h"
95 #include "nsDOMString.h"
96 #include "nsIEmbeddingSiteWindow.h"
97 #include "nsThreadUtils.h"
98 #include "nsILoadContext.h"
99 #include "nsIPresShell.h"
100 #include "nsIScriptSecurityManager.h"
101 #include "nsIScrollableFrame.h"
103 #include "nsViewManager.h"
104 #include "nsISelectionController.h"
105 #include "nsISelection.h"
106 #include "nsIPrompt.h"
107 #include "nsIPromptService.h"
108 #include "nsIPromptFactory.h"
109 #include "nsIWritablePropertyBag2.h"
110 #include "nsIWebNavigation.h"
111 #include "nsIWebBrowserChrome.h"
112 #include "nsIWebBrowserFind.h" // For window.find()
113 #include "nsIWindowMediator.h" // For window.find()
114 #include "nsComputedDOMStyle.h"
115 #include "nsIEntropyCollector.h"
116 #include "nsDOMCID.h"
117 #include "nsDOMWindowUtils.h"
118 #include "nsIWindowWatcher.h"
119 #include "nsPIWindowWatcher.h"
120 #include "nsIContentViewer.h"
121 #include "nsIScriptError.h"
122 #include "nsIControllers.h"
123 #include "nsIControllerContext.h"
124 #include "nsGlobalWindowCommands.h"
125 #include "nsAutoPtr.h"
126 #include "nsContentUtils.h"
127 #include "nsCSSProps.h"
128 #include "nsIDOMFile.h"
129 #include "nsIDOMFileList.h"
130 #include "nsIURIFixup.h"
132 #include "nsIAppStartup.h"
133 #include "nsToolkitCompsCID.h"
135 #include "nsCDefaultURIFixup.h"
136 #include "mozilla/EventDispatcher.h"
137 #include "mozilla/EventStateManager.h"
138 #include "nsIObserverService.h"
139 #include "nsFocusManager.h"
140 #include "nsIXULWindow.h"
141 #include "nsITimedChannel.h"
142 #include "nsServiceManagerUtils.h"
144 #include "nsIDOMXULControlElement.h"
145 #include "nsMenuPopupFrame.h"
147 #include "mozilla/dom/CustomEvent.h"
148 #include "nsIFrameRequestCallback.h"
149 #include "nsIJARChannel.h"
151 #include "xpcprivate.h"
154 #include "nsIPrintSettings.h"
155 #include "nsIPrintSettingsService.h"
156 #include "nsIWebBrowserPrint.h"
159 #include "nsWindowRoot.h"
160 #include "nsNetCID.h"
161 #include "nsIArray.h"
163 // XXX An unfortunate dependency exists here (two XUL files).
164 #include "nsIDOMXULDocument.h"
165 #include "nsIDOMXULCommandDispatcher.h"
167 #include "nsBindingManager.h"
168 #include "nsXBLService.h"
170 // used for popup blocking, needs to be converted to something
171 // belonging to the back-end like nsIContentPolicy
172 #include "nsIPopupWindowManager.h"
174 #include "nsIDragService.h"
175 #include "mozilla/dom/Element.h"
176 #include "mozilla/dom/Selection.h"
177 #include "nsFrameLoader.h"
178 #include "nsISupportsPrimitives.h"
179 #include "nsXPCOMCID.h"
180 #include "mozIThirdPartyUtil.h"
182 // so we can get logging even in release builds
183 #define FORCE_PR_LOG 1
189 #include "mozilla/dom/MessageChannel.h"
190 #include "mozilla/dom/MessagePort.h"
191 #include "mozilla/dom/MessagePortBinding.h"
192 #include "mozilla/dom/indexedDB/IDBFactory.h"
193 #include "mozilla/dom/quota/QuotaManager.h"
195 #include "mozilla/dom/StructuredCloneTags.h"
198 #include "mozilla/dom/GamepadService.h"
201 #include "nsRefreshDriver.h"
203 #include "mozilla/dom/SelectionChangeEvent.h"
205 #include "mozilla/Services.h"
206 #include "mozilla/Telemetry.h"
207 #include "nsLocation.h"
208 #include "nsHTMLDocument.h"
209 #include "nsWrapperCacheInlines.h"
210 #include "mozilla/DOMEventTargetHelper.h"
212 #include "nsSandboxFlags.h"
213 #include "TimeChangeObserver.h"
214 #include "mozilla/dom/AudioContext.h"
215 #include "mozilla/dom/BrowserElementDictionariesBinding.h"
216 #include "mozilla/dom/Console.h"
217 #include "mozilla/dom/FunctionBinding.h"
218 #include "mozilla/dom/HashChangeEvent.h"
219 #include "mozilla/dom/MozSelfSupportBinding.h"
220 #include "mozilla/dom/PopStateEvent.h"
221 #include "mozilla/dom/PopupBlockedEvent.h"
222 #include "mozilla/dom/WindowBinding.h"
223 #include "nsITabChild.h"
224 #include "mozilla/dom/MediaQueryList.h"
225 #include "mozilla/dom/ScriptSettings.h"
226 #include "mozilla/dom/NavigatorBinding.h"
228 #include "mozilla/dom/ExternalBinding.h"
232 #include "mozilla/dom/SpeechSynthesis.h"
236 #include "nsPISocketTransportService.h"
239 // Apple system headers seem to have a check() macro. <sigh>
241 class nsIScriptTimeoutHandler
;
244 #include "AccessCheck.h"
247 #include <android/log.h>
251 static PRLogModuleInfo
* gDOMLeakPRLog
;
256 #define getpid _getpid
258 #include <unistd.h> // for getpid()
261 static const char kStorageEnabled
[] = "dom.storage.enabled";
263 using namespace mozilla
;
264 using namespace mozilla::dom
;
265 using namespace mozilla::dom::ipc
;
266 using mozilla::TimeStamp
;
267 using mozilla::TimeDuration
;
269 nsGlobalWindow::WindowByIdTable
*nsGlobalWindow::sWindowsById
= nullptr;
270 bool nsGlobalWindow::sWarnedAboutWindowInternal
= false;
271 bool nsGlobalWindow::sIdleObserversAPIFuzzTimeDisabled
= false;
273 static nsIEntropyCollector
*gEntropyCollector
= nullptr;
274 static int32_t gRefCnt
= 0;
275 static int32_t gOpenPopupSpamCount
= 0;
276 static PopupControlState gPopupControlState
= openAbused
;
277 static int32_t gRunningTimeoutDepth
= 0;
278 static bool gMouseDown
= false;
279 static bool gDragServiceDisabled
= false;
280 static bool gSelectionCaretPrefEnabled
= false;
281 static FILE *gDumpFile
= nullptr;
282 static uint64_t gNextWindowID
= 0;
283 static uint32_t gSerialCounter
= 0;
284 static uint32_t gTimeoutsRecentlySet
= 0;
285 static TimeStamp gLastRecordedRecentTimeouts
;
286 #define STATISTICS_INTERVAL (30 * PR_MSEC_PER_SEC)
289 int32_t gTimeoutCnt
= 0;
292 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
293 #define DEBUG_PAGE_CACHE
296 #define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
298 // The default shortest interval/timeout we permit
299 #define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
300 #define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
301 static int32_t gMinTimeoutValue
;
302 static int32_t gMinBackgroundTimeoutValue
;
304 nsGlobalWindow::DOMMinTimeoutValue() const {
305 bool isBackground
= !mOuterWindow
|| mOuterWindow
->IsBackground();
307 std::max(isBackground
? gMinBackgroundTimeoutValue
: gMinTimeoutValue
, 0);
310 // The number of nested timeouts before we start clamping. HTML5 says 1, WebKit
312 #define DOM_CLAMP_TIMEOUT_NESTING_LEVEL 5
314 // The longest interval (as PRIntervalTime) we permit, or that our
315 // timer code can handle, really. See DELAY_INTERVAL_LIMIT in
316 // nsTimerImpl.h for details.
317 #define DOM_MAX_TIMEOUT_VALUE DELAY_INTERVAL_LIMIT
319 #define FORWARD_TO_OUTER(method, args, err_rval) \
321 if (IsInnerWindow()) { \
322 nsGlobalWindow *outer = GetOuterWindowInternal(); \
323 if (!HasActiveDocument()) { \
325 "Inner window does not have active document." : \
326 "No outer window available!"); \
329 return outer->method args; \
333 #define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval) \
335 if (IsInnerWindow()) { \
336 nsGlobalWindow *outer = GetOuterWindowInternal(); \
337 if (!HasActiveDocument()) { \
339 NS_WARNING("No outer window available!"); \
340 errorresult.Throw(NS_ERROR_NOT_INITIALIZED); \
342 errorresult.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \
345 return outer->method args; \
351 #define FORWARD_TO_OUTER_VOID(method, args) \
353 if (IsInnerWindow()) { \
354 nsGlobalWindow *outer = GetOuterWindowInternal(); \
355 if (!HasActiveDocument()) { \
357 "Inner window does not have active document." : \
358 "No outer window available!"); \
361 outer->method args; \
366 #define FORWARD_TO_OUTER_CHROME(method, args, err_rval) \
368 if (IsInnerWindow()) { \
369 nsGlobalWindow *outer = GetOuterWindowInternal(); \
370 if (!HasActiveDocument()) { \
372 "Inner window does not have active document." : \
373 "No outer window available!"); \
376 return ((nsGlobalChromeWindow *)outer)->method args; \
380 #define FORWARD_TO_INNER_CHROME(method, args, err_rval) \
382 if (IsOuterWindow()) { \
383 if (!mInnerWindow) { \
384 NS_WARNING("No inner window available!"); \
387 return ((nsGlobalChromeWindow *)mInnerWindow)->method args; \
391 #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
393 if (IsInnerWindow()) { \
394 nsGlobalWindow *outer = GetOuterWindowInternal(); \
395 if (!HasActiveDocument()) { \
397 "Inner window does not have active document." : \
398 "No outer window available!"); \
401 return ((nsGlobalModalWindow *)outer)->method args; \
405 #define FORWARD_TO_INNER(method, args, err_rval) \
407 if (IsOuterWindow()) { \
408 if (!mInnerWindow) { \
409 NS_WARNING("No inner window available!"); \
412 return GetCurrentInnerWindowInternal()->method args; \
416 #define FORWARD_TO_INNER_OR_THROW(method, args, errorresult, err_rval) \
418 if (IsOuterWindow()) { \
419 if (!mInnerWindow) { \
420 NS_WARNING("No inner window available!"); \
421 errorresult.Throw(NS_ERROR_NOT_INITIALIZED); \
424 return GetCurrentInnerWindowInternal()->method args; \
428 #define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
430 if (IsOuterWindow()) { \
431 if (!mInnerWindow) { \
432 NS_WARNING("No inner window available!"); \
435 return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \
439 #define FORWARD_TO_INNER_VOID(method, args) \
441 if (IsOuterWindow()) { \
442 if (!mInnerWindow) { \
443 NS_WARNING("No inner window available!"); \
446 GetCurrentInnerWindowInternal()->method args; \
451 // Same as FORWARD_TO_INNER, but this will create a fresh inner if an
452 // inner doesn't already exists.
453 #define FORWARD_TO_INNER_CREATE(method, args, err_rval) \
455 if (IsOuterWindow()) { \
456 if (!mInnerWindow) { \
460 nsCOMPtr<nsIDOMDocument> doc; \
461 nsresult fwdic_nr = GetDocument(getter_AddRefs(doc)); \
462 NS_ENSURE_SUCCESS(fwdic_nr, err_rval); \
463 if (!mInnerWindow) { \
467 return GetCurrentInnerWindowInternal()->method args; \
472 static NS_DEFINE_CID(kXULControllersCID
, NS_XULCONTROLLERS_CID
);
474 static const char sPopStatePrefStr
[] = "browser.history.allowPopState";
476 #define NETWORK_UPLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkupload")
477 #define NETWORK_DOWNLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkdownload")
480 * An indirect observer object that means we don't have to implement nsIObserver
481 * on nsGlobalWindow, where any script could see it.
483 class nsGlobalWindowObserver MOZ_FINAL
: public nsIObserver
,
484 public nsIInterfaceRequestor
487 explicit nsGlobalWindowObserver(nsGlobalWindow
* aWindow
) : mWindow(aWindow
) {}
489 NS_IMETHOD
Observe(nsISupports
* aSubject
, const char* aTopic
, const char16_t
* aData
)
493 return mWindow
->Observe(aSubject
, aTopic
, aData
);
495 void Forget() { mWindow
= nullptr; }
496 NS_IMETHODIMP
GetInterface(const nsIID
& aIID
, void** aResult
)
498 if (mWindow
&& aIID
.Equals(NS_GET_IID(nsIDOMWindow
)) && mWindow
) {
499 return mWindow
->QueryInterface(aIID
, aResult
);
501 return NS_NOINTERFACE
;
505 ~nsGlobalWindowObserver() {}
507 nsGlobalWindow
* mWindow
;
510 NS_IMPL_ISUPPORTS(nsGlobalWindowObserver
, nsIObserver
, nsIInterfaceRequestor
)
512 nsTimeout::nsTimeout()
520 mPopupState(openAllowed
)
524 extern int gTimeoutCnt
;
530 MOZ_COUNT_CTOR(nsTimeout
);
533 nsTimeout::~nsTimeout()
537 extern int gTimeoutCnt
;
548 MOZ_COUNT_DTOR(nsTimeout
);
551 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout
)
553 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsTimeout
)
554 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTimeout
)
555 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow
)
556 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal
)
557 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler
)
558 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
559 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout
, AddRef
)
560 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout
, Release
)
562 // Return true if this timeout has a refcount of 1. This is used to check
563 // that dummy_timeout doesn't leak from nsGlobalWindow::RunTimeout.
565 nsTimeout::HasRefCntOne()
567 return mRefCnt
.get() == 1;
570 nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow
*aOuterWindow
)
571 : mFrameElement(nullptr), mDocShell(nullptr), mModalStateDepth(0),
572 mRunningTimeout(nullptr), mMutationBits(0), mIsDocumentLoaded(false),
573 mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow
!= nullptr),
574 mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
575 mMayHaveTouchCaret(false), mMayHaveMouseEnterLeaveEventListener(false),
576 mMayHavePointerEnterLeaveEventListener(false),
577 mIsModalContentWindow(false),
578 mIsActive(false), mIsBackground(false),
579 mAudioMuted(false), mAudioVolume(1.0),
580 mInnerWindow(nullptr), mOuterWindow(aOuterWindow
),
581 // Make sure no actual window ends up with mWindowID == 0
582 mWindowID(++gNextWindowID
), mHasNotifiedGlobalCreated(false),
583 mMarkedCCGeneration(0), mSendAfterRemotePaint(false)
586 nsPIDOMWindow::~nsPIDOMWindow() {}
588 // DialogValueHolder CC goop.
589 NS_IMPL_CYCLE_COLLECTION(DialogValueHolder
, mValue
)
591 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DialogValueHolder
)
592 NS_INTERFACE_MAP_ENTRY(nsISupports
)
595 NS_IMPL_CYCLE_COLLECTING_ADDREF(DialogValueHolder
)
596 NS_IMPL_CYCLE_COLLECTING_RELEASE(DialogValueHolder
)
598 //*****************************************************************************
599 // nsOuterWindowProxy: Outer Window Proxy
600 //*****************************************************************************
602 class nsOuterWindowProxy
: public js::Wrapper
605 MOZ_CONSTEXPR
nsOuterWindowProxy() : js::Wrapper(0) { }
607 virtual bool finalizeInBackground(JS::Value priv
) const MOZ_OVERRIDE
{
611 virtual const char *className(JSContext
*cx
,
612 JS::Handle
<JSObject
*> wrapper
) const MOZ_OVERRIDE
;
613 virtual void finalize(JSFreeOp
*fop
, JSObject
*proxy
) const MOZ_OVERRIDE
;
616 virtual bool isExtensible(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
, bool *extensible
)
618 virtual bool preventExtensions(JSContext
*cx
,
619 JS::Handle
<JSObject
*> proxy
) const MOZ_OVERRIDE
;
620 virtual bool getPropertyDescriptor(JSContext
* cx
,
621 JS::Handle
<JSObject
*> proxy
,
623 JS::MutableHandle
<JSPropertyDescriptor
> desc
)
625 virtual bool getOwnPropertyDescriptor(JSContext
* cx
,
626 JS::Handle
<JSObject
*> proxy
,
628 JS::MutableHandle
<JSPropertyDescriptor
> desc
)
630 virtual bool defineProperty(JSContext
* cx
,
631 JS::Handle
<JSObject
*> proxy
,
633 JS::MutableHandle
<JSPropertyDescriptor
> desc
)
635 virtual bool getOwnPropertyNames(JSContext
*cx
,
636 JS::Handle
<JSObject
*> proxy
,
637 JS::AutoIdVector
&props
) const MOZ_OVERRIDE
;
638 virtual bool delete_(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
640 bool *bp
) const MOZ_OVERRIDE
;
641 virtual bool enumerate(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
642 JS::AutoIdVector
&props
) const MOZ_OVERRIDE
;
644 virtual bool watch(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
645 JS::Handle
<jsid
> id
, JS::Handle
<JSObject
*> callable
) const MOZ_OVERRIDE
;
646 virtual bool unwatch(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
647 JS::Handle
<jsid
> id
) const MOZ_OVERRIDE
;
650 virtual bool has(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
651 JS::Handle
<jsid
> id
, bool *bp
) const MOZ_OVERRIDE
;
652 virtual bool hasOwn(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
653 JS::Handle
<jsid
> id
, bool *bp
) const MOZ_OVERRIDE
;
654 virtual bool get(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
655 JS::Handle
<JSObject
*> receiver
,
657 JS::MutableHandle
<JS::Value
> vp
) const MOZ_OVERRIDE
;
658 virtual bool set(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
659 JS::Handle
<JSObject
*> receiver
,
662 JS::MutableHandle
<JS::Value
> vp
) const MOZ_OVERRIDE
;
663 virtual bool keys(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
664 JS::AutoIdVector
&props
) const MOZ_OVERRIDE
;
665 virtual bool iterate(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
667 JS::MutableHandle
<JS::Value
> vp
) const MOZ_OVERRIDE
;
669 static const nsOuterWindowProxy singleton
;
672 nsGlobalWindow
* GetWindow(JSObject
*proxy
) const
674 return nsGlobalWindow::FromSupports(
675 static_cast<nsISupports
*>(js::GetProxyExtra(proxy
, 0).toPrivate()));
678 // False return value means we threw an exception. True return value
679 // but false "found" means we didn't have a subframe at that index.
680 bool GetSubframeWindow(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
682 JS::MutableHandle
<JS::Value
> vp
,
685 // Returns a non-null window only if id is an index and we have a
686 // window at that index.
687 already_AddRefed
<nsIDOMWindow
> GetSubframeWindow(JSContext
*cx
,
688 JS::Handle
<JSObject
*> proxy
,
689 JS::Handle
<jsid
> id
) const;
691 bool AppendIndexedPropertyNames(JSContext
*cx
, JSObject
*proxy
,
692 JS::AutoIdVector
&props
) const;
695 const js::Class OuterWindowProxyClass
=
696 PROXY_CLASS_WITH_EXT(
698 0, /* additional slots */
699 0, /* additional class flags */
701 nullptr, /* construct */
703 nullptr, /* outerObject */
704 js::proxy_innerObject
,
705 nullptr, /* iteratorObject */
706 false /* isWrappedNative */
710 nsOuterWindowProxy::isExtensible(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
711 bool *extensible
) const
713 // If [[Extensible]] could be false, then navigating a window could navigate
714 // to a window that's [[Extensible]] after being at one that wasn't: an
715 // invariant violation. So always report true for this.
721 nsOuterWindowProxy::preventExtensions(JSContext
*cx
,
722 JS::Handle
<JSObject
*> proxy
) const
725 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr,
726 JSMSG_CANT_CHANGE_EXTENSIBILITY
);
731 nsOuterWindowProxy::className(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
) const
733 MOZ_ASSERT(js::IsProxy(proxy
));
739 nsOuterWindowProxy::finalize(JSFreeOp
*fop
, JSObject
*proxy
) const
741 nsGlobalWindow
* global
= GetWindow(proxy
);
743 global
->ClearWrapper();
745 // Ideally we would use OnFinalize here, but it's possible that
746 // EnsureScriptEnvironment will later be called on the window, and we don't
747 // want to create a new script object in that case. Therefore, we need to
748 // write a non-null value that will reliably crash when dereferenced.
749 global
->PoisonOuterWindowProxy(proxy
);
754 nsOuterWindowProxy::getPropertyDescriptor(JSContext
* cx
,
755 JS::Handle
<JSObject
*> proxy
,
757 JS::MutableHandle
<JSPropertyDescriptor
> desc
) const
759 // The only thing we can do differently from js::Wrapper is shadow stuff with
760 // our indexed properties, so we can just try getOwnPropertyDescriptor and if
761 // that gives us nothing call on through to js::Wrapper.
762 desc
.object().set(nullptr);
763 if (!getOwnPropertyDescriptor(cx
, proxy
, id
, desc
)) {
771 return js::Wrapper::getPropertyDescriptor(cx
, proxy
, id
, desc
);
775 nsOuterWindowProxy::getOwnPropertyDescriptor(JSContext
* cx
,
776 JS::Handle
<JSObject
*> proxy
,
778 JS::MutableHandle
<JSPropertyDescriptor
> desc
)
782 if (!GetSubframeWindow(cx
, proxy
, id
, desc
.value(), found
)) {
786 FillPropertyDescriptor(desc
, proxy
, true);
789 // else fall through to js::Wrapper
791 return js::Wrapper::getOwnPropertyDescriptor(cx
, proxy
, id
, desc
);
795 nsOuterWindowProxy::defineProperty(JSContext
* cx
,
796 JS::Handle
<JSObject
*> proxy
,
798 JS::MutableHandle
<JSPropertyDescriptor
> desc
)
801 int32_t index
= GetArrayIndexFromId(cx
, id
);
802 if (IsArrayIndex(index
)) {
803 // Spec says to Reject whether this is a supported index or not,
804 // since we have no indexed setter or indexed creator. That means
805 // throwing in strict mode (FIXME: Bug 828137), doing nothing in
810 return js::Wrapper::defineProperty(cx
, proxy
, id
, desc
);
814 nsOuterWindowProxy::getOwnPropertyNames(JSContext
*cx
,
815 JS::Handle
<JSObject
*> proxy
,
816 JS::AutoIdVector
&props
) const
818 // Just our indexed stuff followed by our "normal" own property names.
819 if (!AppendIndexedPropertyNames(cx
, proxy
, props
)) {
823 JS::AutoIdVector
innerProps(cx
);
824 if (!js::Wrapper::getOwnPropertyNames(cx
, proxy
, innerProps
)) {
827 return js::AppendUnique(cx
, props
, innerProps
);
831 nsOuterWindowProxy::delete_(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
832 JS::Handle
<jsid
> id
, bool *bp
) const
834 if (nsCOMPtr
<nsIDOMWindow
> frame
= GetSubframeWindow(cx
, proxy
, id
)) {
835 // Reject (which means throw if strict, else return false) the delete.
836 // Except we don't even know whether we're strict. See bug 803157.
841 int32_t index
= GetArrayIndexFromId(cx
, id
);
842 if (IsArrayIndex(index
)) {
843 // Indexed, but not supported. Spec says return true.
848 return js::Wrapper::delete_(cx
, proxy
, id
, bp
);
852 nsOuterWindowProxy::enumerate(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
853 JS::AutoIdVector
&props
) const
855 // Just our indexed stuff followed by our "normal" own property names.
856 if (!AppendIndexedPropertyNames(cx
, proxy
, props
)) {
860 JS::AutoIdVector
innerProps(cx
);
861 if (!js::Wrapper::enumerate(cx
, proxy
, innerProps
)) {
864 return js::AppendUnique(cx
, props
, innerProps
);
868 nsOuterWindowProxy::has(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
869 JS::Handle
<jsid
> id
, bool *bp
) const
871 if (nsCOMPtr
<nsIDOMWindow
> frame
= GetSubframeWindow(cx
, proxy
, id
)) {
876 return js::Wrapper::has(cx
, proxy
, id
, bp
);
880 nsOuterWindowProxy::hasOwn(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
881 JS::Handle
<jsid
> id
, bool *bp
) const
883 if (nsCOMPtr
<nsIDOMWindow
> frame
= GetSubframeWindow(cx
, proxy
, id
)) {
888 return js::Wrapper::hasOwn(cx
, proxy
, id
, bp
);
892 nsOuterWindowProxy::get(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
893 JS::Handle
<JSObject
*> receiver
,
895 JS::MutableHandle
<JS::Value
> vp
) const
897 if (id
== nsDOMClassInfo::sWrappedJSObject_id
&&
898 xpc::AccessCheck::isChrome(js::GetContextCompartment(cx
))) {
899 vp
.set(JS::ObjectValue(*proxy
));
904 if (!GetSubframeWindow(cx
, proxy
, id
, vp
, found
)) {
910 // Else fall through to js::Wrapper
912 return js::Wrapper::get(cx
, proxy
, receiver
, id
, vp
);
916 nsOuterWindowProxy::set(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
917 JS::Handle
<JSObject
*> receiver
,
920 JS::MutableHandle
<JS::Value
> vp
) const
922 int32_t index
= GetArrayIndexFromId(cx
, id
);
923 if (IsArrayIndex(index
)) {
924 // Reject (which means throw if and only if strict) the set.
926 // XXXbz This needs to throw, but see bug 828137.
931 return js::Wrapper::set(cx
, proxy
, receiver
, id
, strict
, vp
);
935 nsOuterWindowProxy::keys(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
936 JS::AutoIdVector
&props
) const
938 // BaseProxyHandler::keys seems to do what we want here: call
939 // getOwnPropertyNames and then filter out the non-enumerable properties.
940 return js::BaseProxyHandler::keys(cx
, proxy
, props
);
944 nsOuterWindowProxy::iterate(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
945 unsigned flags
, JS::MutableHandle
<JS::Value
> vp
) const
947 // BaseProxyHandler::iterate seems to do what we want here: fall
948 // back on the property names returned from keys() and enumerate().
949 return js::BaseProxyHandler::iterate(cx
, proxy
, flags
, vp
);
953 nsOuterWindowProxy::GetSubframeWindow(JSContext
*cx
,
954 JS::Handle
<JSObject
*> proxy
,
956 JS::MutableHandle
<JS::Value
> vp
,
959 nsCOMPtr
<nsIDOMWindow
> frame
= GetSubframeWindow(cx
, proxy
, id
);
966 // Just return the window's global
967 nsGlobalWindow
* global
= static_cast<nsGlobalWindow
*>(frame
.get());
968 global
->EnsureInnerWindow();
969 JSObject
* obj
= global
->FastGetGlobalJSObject();
970 // This null check fixes a hard-to-reproduce crash that occurs when we
971 // get here when we're mid-call to nsDocShell::Destroy. See bug 640904
973 if (MOZ_UNLIKELY(!obj
)) {
974 return xpc::Throw(cx
, NS_ERROR_FAILURE
);
978 return JS_WrapValue(cx
, vp
);
981 already_AddRefed
<nsIDOMWindow
>
982 nsOuterWindowProxy::GetSubframeWindow(JSContext
*cx
,
983 JS::Handle
<JSObject
*> proxy
,
984 JS::Handle
<jsid
> id
) const
986 int32_t index
= GetArrayIndexFromId(cx
, id
);
987 if (!IsArrayIndex(index
)) {
991 nsGlobalWindow
* win
= GetWindow(proxy
);
993 return win
->IndexedGetter(index
, unused
);
997 nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext
*cx
, JSObject
*proxy
,
998 JS::AutoIdVector
&props
) const
1000 uint32_t length
= GetWindow(proxy
)->Length();
1001 MOZ_ASSERT(int32_t(length
) >= 0);
1002 if (!props
.reserve(props
.length() + length
)) {
1005 for (int32_t i
= 0; i
< int32_t(length
); ++i
) {
1006 props
.append(INT_TO_JSID(i
));
1013 nsOuterWindowProxy::watch(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
1014 JS::Handle
<jsid
> id
, JS::Handle
<JSObject
*> callable
) const
1016 return js::WatchGuts(cx
, proxy
, id
, callable
);
1020 nsOuterWindowProxy::unwatch(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
1021 JS::Handle
<jsid
> id
) const
1023 return js::UnwatchGuts(cx
, proxy
, id
);
1026 const nsOuterWindowProxy
1027 nsOuterWindowProxy::singleton
;
1029 class nsChromeOuterWindowProxy
: public nsOuterWindowProxy
1032 MOZ_CONSTEXPR
nsChromeOuterWindowProxy() : nsOuterWindowProxy() { }
1034 virtual const char *className(JSContext
*cx
, JS::Handle
<JSObject
*> wrapper
) const MOZ_OVERRIDE
;
1036 static const nsChromeOuterWindowProxy singleton
;
1040 nsChromeOuterWindowProxy::className(JSContext
*cx
,
1041 JS::Handle
<JSObject
*> proxy
) const
1043 MOZ_ASSERT(js::IsProxy(proxy
));
1045 return "ChromeWindow";
1048 const nsChromeOuterWindowProxy
1049 nsChromeOuterWindowProxy::singleton
;
1052 NewOuterWindowProxy(JSContext
*cx
, JS::Handle
<JSObject
*> parent
, bool isChrome
)
1054 JSAutoCompartment
ac(cx
, parent
);
1055 js::WrapperOptions options
;
1056 options
.setClass(&OuterWindowProxyClass
);
1057 options
.setSingleton(true);
1058 JSObject
*obj
= js::Wrapper::New(cx
, parent
, parent
,
1059 isChrome
? &nsChromeOuterWindowProxy::singleton
1060 : &nsOuterWindowProxy::singleton
,
1063 NS_ASSERTION(js::GetObjectClass(obj
)->ext
.innerObject
, "bad class");
1067 //*****************************************************************************
1068 //*** nsGlobalWindow: Object Management
1069 //*****************************************************************************
1071 nsGlobalWindow::nsGlobalWindow(nsGlobalWindow
*aOuterWindow
)
1072 : nsPIDOMWindow(aOuterWindow
),
1074 mIdleCallbackIndex(-1),
1075 mCurrentlyIdle(false),
1076 mAddActiveEventFuzzTime(true),
1081 mHavePendingClose(false),
1082 mHadOriginalOpener(false),
1083 mIsPopupSpam(false),
1084 mBlockScriptedClosingFlag(false),
1085 mFireOfflineStatusChangeEventOnThaw(false),
1086 mNotifyIdleObserversIdleOnThaw(false),
1087 mNotifyIdleObserversActiveOnThaw(false),
1088 mCreatingInnerWindow(false),
1090 mCleanMessageManager(false),
1093 #if defined(XP_MACOSX)
1094 mShowAccelerators(false),
1095 mShowFocusRings(false),
1097 mShowAccelerators(true),
1098 mShowFocusRings(true),
1100 mShowFocusRingForContent(false),
1101 mFocusByKeyOccurred(false),
1102 mInnerObjectsFreed(false),
1105 mHasSeenGamepadInput(false),
1107 mNotifiedIDDestroyed(false),
1108 mAllowScriptsToClose(false),
1109 mTimeoutInsertionPoint(nullptr),
1110 mTimeoutPublicIdCounter(1),
1111 mTimeoutFiringDepth(0),
1112 mTimeoutsSuspendDepth(0),
1116 mSetOpenerWindowCalled(false),
1119 mNetworkUploadObserverEnabled(false),
1120 mNetworkDownloadObserverEnabled(false),
1123 mDialogAbuseCount(0),
1124 mAreDialogsEnabled(true)
1126 nsLayoutStatics::AddRef();
1128 // Initialize the PRCList (this).
1129 PR_INIT_CLIST(this);
1131 if (Preferences::GetBool("dom.window_experimental_bindings") ||
1137 // |this| is an inner window, add this inner window to the outer
1138 // window list of inners.
1139 PR_INSERT_AFTER(this, aOuterWindow
);
1141 mObserver
= new nsGlobalWindowObserver(this);
1143 NS_ADDREF(mObserver
);
1144 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
1146 // Watch for online/offline status changes so we can fire events. Use
1147 // a strong reference.
1148 os
->AddObserver(mObserver
, NS_IOSERVICE_OFFLINE_STATUS_TOPIC
,
1151 // Watch for dom-storage2-changed so we can fire storage
1152 // events. Use a strong reference.
1153 os
->AddObserver(mObserver
, "dom-storage2-changed", false);
1156 Preferences::AddStrongObserver(mObserver
, "intl.accept_languages");
1159 // |this| is an outer window. Outer windows start out frozen and
1160 // remain frozen until they get an inner window, so freeze this
1161 // outer window here.
1164 mObserver
= nullptr;
1167 // We could have failed the first time through trying
1168 // to create the entropy collector, so we should
1169 // try to get one until we succeed.
1174 Preferences::AddIntVarCache(&gMinTimeoutValue
,
1175 "dom.min_timeout_value",
1176 DEFAULT_MIN_TIMEOUT_VALUE
);
1177 Preferences::AddIntVarCache(&gMinBackgroundTimeoutValue
,
1178 "dom.min_background_timeout_value",
1179 DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE
);
1180 Preferences::AddBoolVarCache(&sIdleObserversAPIFuzzTimeDisabled
,
1181 "dom.idle-observers-api.fuzz_time.disabled",
1183 Preferences::AddBoolVarCache(&gSelectionCaretPrefEnabled
,
1184 "selectioncaret.enabled",
1188 if (gDumpFile
== nullptr) {
1189 const nsAdoptingCString
& fname
=
1190 Preferences::GetCString("browser.dom.window.dump.file");
1191 if (!fname
.IsEmpty()) {
1192 // if this fails to open, Dump() knows to just go to stdout
1194 gDumpFile
= fopen(fname
, "wb+");
1200 mSerial
= ++gSerialCounter
;
1203 if (!PR_GetEnv("MOZ_QUIET")) {
1204 printf_stderr("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
1206 static_cast<void*>(ToCanonicalSupports(this)),
1209 static_cast<void*>(ToCanonicalSupports(aOuterWindow
)));
1215 PR_LOG(gDOMLeakPRLog
, PR_LOG_DEBUG
,
1216 ("DOMWINDOW %p created outer=%p", this, aOuterWindow
));
1219 NS_ASSERTION(sWindowsById
, "Windows hash table must be created!");
1220 NS_ASSERTION(!sWindowsById
->Get(mWindowID
),
1221 "This window shouldn't be in the hash table yet!");
1222 // We seem to see crashes in release builds because of null |sWindowsById|.
1224 sWindowsById
->Put(mWindowID
, this);
1230 nsGlobalWindow::Init()
1232 CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID
, &gEntropyCollector
);
1233 NS_ASSERTION(gEntropyCollector
,
1234 "gEntropyCollector should have been initialized!");
1237 gDOMLeakPRLog
= PR_NewLogModule("DOMLeak");
1238 NS_ASSERTION(gDOMLeakPRLog
, "gDOMLeakPRLog should have been initialized!");
1241 sWindowsById
= new WindowByIdTable();
1244 static PLDHashOperator
1245 DisconnectEventTargetObjects(nsPtrHashKey
<DOMEventTargetHelper
>* aKey
,
1248 nsRefPtr
<DOMEventTargetHelper
> target
= aKey
->GetKey();
1249 target
->DisconnectFromOwner();
1250 return PL_DHASH_NEXT
;
1253 nsGlobalWindow::~nsGlobalWindow()
1255 mEventTargetObjects
.EnumerateEntries(DisconnectEventTargetObjects
, nullptr);
1256 mEventTargetObjects
.Clear();
1258 // We have to check if sWindowsById isn't null because ::Shutdown might have
1261 NS_ASSERTION(sWindowsById
->Get(mWindowID
),
1262 "This window should be in the hash table");
1263 sWindowsById
->Remove(mWindowID
);
1269 if (!PR_GetEnv("MOZ_QUIET")) {
1271 if (mLastOpenedURI
) {
1272 mLastOpenedURI
->GetSpec(url
);
1274 // Data URLs can be very long, so truncate to avoid flooding the log.
1275 const uint32_t maxURLLength
= 1000;
1276 if (url
.Length() > maxURLLength
) {
1277 url
.Truncate(maxURLLength
);
1281 nsGlobalWindow
* outer
= static_cast<nsGlobalWindow
*>(mOuterWindow
.get());
1282 printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n",
1284 static_cast<void*>(ToCanonicalSupports(this)),
1287 static_cast<void*>(ToCanonicalSupports(outer
)),
1294 PR_LOG(gDOMLeakPRLog
, PR_LOG_DEBUG
,
1295 ("DOMWINDOW %p destroyed", this));
1298 if (IsOuterWindow()) {
1299 JSObject
*proxy
= GetWrapperPreserveColor();
1301 js::SetProxyExtra(proxy
, 0, js::PrivateValue(nullptr));
1304 // An outer window is destroyed with inner windows still possibly
1305 // alive, iterate through the inner windows and null out their
1306 // back pointer to this outer, and pull them out of the list of
1310 while ((w
= (nsGlobalWindow
*)PR_LIST_HEAD(this)) != this) {
1311 PR_REMOVE_AND_INIT_LINK(w
);
1314 DropOuterWindowDocs();
1316 Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS
,
1317 mMutationBits
? 1 : 0);
1319 if (mListenerManager
) {
1320 mListenerManager
->Disconnect();
1321 mListenerManager
= nullptr;
1324 // An inner window is destroyed, pull it out of the outer window's
1325 // list if inner windows.
1327 PR_REMOVE_LINK(this);
1329 // If our outer window's inner window is this window, null out the
1330 // outer window's reference to this window that's being deleted.
1331 nsGlobalWindow
*outer
= GetOuterWindowInternal();
1333 outer
->MaybeClearInnerWindow(this);
1337 // Outer windows are always supposed to call CleanUp before letting themselves
1338 // be destroyed. And while CleanUp generally seems to be intended to clean up
1339 // outers, we've historically called it for both. Changing this would probably
1340 // involve auditing all of the references that inners and outers can have, and
1341 // separating the handling into CleanUp() and FreeInnerObjects.
1342 if (IsInnerWindow()) {
1345 MOZ_ASSERT(mCleanedUp
);
1348 nsCOMPtr
<nsIDeviceSensors
> ac
= do_GetService(NS_DEVICE_SENSORS_CONTRACTID
);
1350 ac
->RemoveWindowAsListener(this);
1352 nsLayoutStatics::Release();
1356 nsGlobalWindow::AddEventTargetObject(DOMEventTargetHelper
* aObject
)
1358 MOZ_ASSERT(IsInnerWindow());
1359 mEventTargetObjects
.PutEntry(aObject
);
1363 nsGlobalWindow::RemoveEventTargetObject(DOMEventTargetHelper
* aObject
)
1365 MOZ_ASSERT(IsInnerWindow());
1366 mEventTargetObjects
.RemoveEntry(aObject
);
1371 nsGlobalWindow::ShutDown()
1373 if (gDumpFile
&& gDumpFile
!= stdout
) {
1376 gDumpFile
= nullptr;
1378 NS_IF_RELEASE(gEntropyCollector
);
1380 delete sWindowsById
;
1381 sWindowsById
= nullptr;
1386 nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow
* aWindow
)
1388 if (aWindow
->mCachedXBLPrototypeHandlers
&&
1389 aWindow
->mCachedXBLPrototypeHandlers
->Count() > 0) {
1390 aWindow
->mCachedXBLPrototypeHandlers
->Clear();
1395 nsGlobalWindow::MaybeForgiveSpamCount()
1397 if (IsOuterWindow() &&
1398 IsPopupSpamWindow())
1400 SetPopupSpamWindow(false);
1401 --gOpenPopupSpamCount
;
1402 NS_ASSERTION(gOpenPopupSpamCount
>= 0,
1403 "Unbalanced decrement of gOpenPopupSpamCount");
1408 nsGlobalWindow::DropOuterWindowDocs()
1410 MOZ_ASSERT(IsOuterWindow());
1411 MOZ_ASSERT_IF(mDoc
, !mDoc
->EventHandlingSuppressed());
1413 mSuspendedDoc
= nullptr;
1417 nsGlobalWindow::CleanUp()
1419 // Guarantee idempotence.
1424 mEventTargetObjects
.EnumerateEntries(DisconnectEventTargetObjects
, nullptr);
1425 mEventTargetObjects
.Clear();
1428 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
1430 os
->RemoveObserver(mObserver
, NS_IOSERVICE_OFFLINE_STATUS_TOPIC
);
1431 os
->RemoveObserver(mObserver
, "dom-storage2-changed");
1435 DisableNetworkEvent(NS_NETWORK_UPLOAD_EVENT
);
1436 DisableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT
);
1440 mIdleService
->RemoveIdleObserver(mObserver
, MIN_IDLE_NOTIFICATION_TIME_S
);
1443 Preferences::RemoveObserver(mObserver
, "intl.accept_languages");
1445 // Drop its reference to this dying window, in case for some bogus reason
1446 // the object stays around.
1447 mObserver
->Forget();
1448 NS_RELEASE(mObserver
);
1452 mNavigator
->Invalidate();
1453 mNavigator
= nullptr;
1459 mLocationbar
= nullptr;
1460 mPersonalbar
= nullptr;
1461 mStatusbar
= nullptr;
1462 mScrollbars
= nullptr;
1463 mLocation
= nullptr;
1466 mWindowUtils
= nullptr;
1467 mApplicationCache
= nullptr;
1468 mIndexedDB
= nullptr;
1472 mExternal
= nullptr;
1474 mMozSelfSupport
= nullptr;
1476 mPerformance
= nullptr;
1478 #ifdef MOZ_WEBSPEECH
1479 mSpeechSynthesis
= nullptr;
1484 mOpener
= nullptr; // Forces Release
1486 mContext
= nullptr; // Forces Release
1488 mChromeEventHandler
= nullptr; // Forces Release
1489 mParentTarget
= nullptr;
1491 if (IsOuterWindow()) {
1492 nsGlobalWindow
* inner
= GetCurrentInnerWindowInternal();
1498 if (IsInnerWindow()) {
1499 DisableGamepadUpdates();
1500 mHasGamepad
= false;
1502 MOZ_ASSERT(!mHasGamepad
);
1505 if (mCleanMessageManager
) {
1506 NS_ABORT_IF_FALSE(mIsChrome
, "only chrome should have msg manager cleaned");
1507 nsGlobalChromeWindow
*asChrome
= static_cast<nsGlobalChromeWindow
*>(this);
1508 if (asChrome
->mMessageManager
) {
1509 static_cast<nsFrameMessageManager
*>(
1510 asChrome
->mMessageManager
.get())->Disconnect();
1514 mArguments
= nullptr;
1515 mDialogArguments
= nullptr;
1517 CleanupCachedXBLHandlers(this);
1519 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
1520 mAudioContexts
[i
]->Shutdown();
1522 mAudioContexts
.Clear();
1525 mIdleTimer
->Cancel();
1526 mIdleTimer
= nullptr;
1529 DisableTimeChangeNotifications();
1533 nsGlobalWindow::ClearControllers()
1537 mControllers
->GetControllerCount(&count
);
1540 nsCOMPtr
<nsIController
> controller
;
1541 mControllers
->GetControllerAt(count
, getter_AddRefs(controller
));
1543 nsCOMPtr
<nsIControllerContext
> context
= do_QueryInterface(controller
);
1545 context
->SetCommandContext(nullptr);
1548 mControllers
= nullptr;
1553 nsGlobalWindow::FreeInnerObjects()
1555 NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
1557 // Make sure that this is called before we null out the document and
1558 // other members that the window destroyed observers could
1560 NotifyDOMWindowDestroyed(this);
1562 mInnerObjectsFreed
= true;
1564 // Kill all of the workers for this window.
1565 mozilla::dom::workers::CancelWorkersForWindow(this);
1567 // Close all offline storages for this window.
1568 quota::QuotaManager
* quotaManager
= quota::QuotaManager::Get();
1570 quotaManager
->AbortCloseStoragesForWindow(this);
1576 mIdleTimer
->Cancel();
1577 mIdleTimer
= nullptr;
1580 mIdleObservers
.Clear();
1582 mChromeEventHandler
= nullptr;
1584 if (mListenerManager
) {
1585 mListenerManager
->Disconnect();
1586 mListenerManager
= nullptr;
1589 mLocation
= nullptr;
1593 mNavigator
->OnNavigation();
1594 mNavigator
->Invalidate();
1595 mNavigator
= nullptr;
1603 // Remember the document's principal and URI.
1604 mDocumentPrincipal
= mDoc
->NodePrincipal();
1605 mDocumentURI
= mDoc
->GetDocumentURI();
1606 mDocBaseURI
= mDoc
->GetDocBaseURI();
1608 while (mDoc
->EventHandlingSuppressed()) {
1609 mDoc
->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents
, false);
1612 // Note: we don't have to worry about eAnimationsOnly suppressions because
1616 // Remove our reference to the document and the document principal.
1617 mFocusedNode
= nullptr;
1619 if (mApplicationCache
) {
1620 static_cast<nsDOMOfflineResourceList
*>(mApplicationCache
.get())->Disconnect();
1621 mApplicationCache
= nullptr;
1624 mIndexedDB
= nullptr;
1626 NotifyWindowIDDestroyed("inner-window-destroyed");
1628 CleanupCachedXBLHandlers(this);
1630 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
1631 mAudioContexts
[i
]->Shutdown();
1633 mAudioContexts
.Clear();
1636 DisableGamepadUpdates();
1637 mHasGamepad
= false;
1642 //*****************************************************************************
1643 // nsGlobalWindow::nsISupports
1644 //*****************************************************************************
1646 DOMCI_DATA(Window
, nsGlobalWindow
)
1648 // QueryInterface implementation for nsGlobalWindow
1649 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow
)
1650 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1651 // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
1652 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDOMEventTarget
)
1653 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow
)
1655 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowB2G
)
1657 #ifdef MOZ_WEBSPEECH
1658 NS_INTERFACE_MAP_ENTRY(nsISpeechSynthesisGetter
)
1660 NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow
)
1661 if (aIID
.Equals(NS_GET_IID(nsIDOMWindowInternal
))) {
1662 foundInterface
= static_cast<nsIDOMWindowInternal
*>(this);
1663 if (!sWarnedAboutWindowInternal
) {
1664 sWarnedAboutWindowInternal
= true;
1665 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
1666 NS_LITERAL_CSTRING("Extensions"), mDoc
,
1667 nsContentUtils::eDOM_PROPERTIES
,
1668 "nsIDOMWindowInternalWarning");
1671 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject
)
1672 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject
)
1673 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal
)
1674 NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget
)
1675 NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget
)
1676 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow
)
1677 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
1678 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
1679 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowPerformance
)
1680 NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver
)
1681 NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers
)
1682 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window
)
1683 NS_INTERFACE_MAP_END
1686 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow
)
1687 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow
)
1689 static PLDHashOperator
1690 MarkXBLHandlers(nsXBLPrototypeHandler
* aKey
, JS::Heap
<JSObject
*>& aData
, void* aClosure
)
1692 JS::ExposeObjectToActiveJS(aData
);
1693 return PL_DHASH_NEXT
;
1696 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow
)
1697 if (tmp
->IsBlackForCC(false)) {
1698 if (tmp
->mCachedXBLPrototypeHandlers
) {
1699 tmp
->mCachedXBLPrototypeHandlers
->Enumerate(MarkXBLHandlers
, nullptr);
1701 if (EventListenerManager
* elm
= tmp
->GetExistingListenerManager()) {
1704 tmp
->UnmarkGrayTimers();
1707 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1709 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow
)
1710 return tmp
->IsBlackForCC(true);
1711 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1713 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow
)
1714 return tmp
->IsBlackForCC(false);
1715 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1718 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
& aCallback
,
1719 IdleObserverHolder
& aField
,
1723 CycleCollectionNoteChild(aCallback
, aField
.mIdleObserver
.get(), aName
, aFlags
);
1726 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow
)
1728 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow
)
1729 if (MOZ_UNLIKELY(cb
.WantDebugInfo())) {
1732 if (tmp
->mDoc
&& tmp
->mDoc
->GetDocumentURI()) {
1733 tmp
->mDoc
->GetDocumentURI()->GetSpec(uri
);
1735 PR_snprintf(name
, sizeof(name
), "nsGlobalWindow #%llu %s %s",
1736 tmp
->mWindowID
, tmp
->IsInnerWindow() ? "inner" : "outer",
1738 cb
.DescribeRefCountedNode(tmp
->mRefCnt
.get(), name
);
1740 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow
, tmp
->mRefCnt
.get())
1743 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext
)
1745 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers
)
1746 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments
)
1747 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments
)
1748 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue
)
1749 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator
)
1751 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance
)
1753 #ifdef MOZ_WEBSPEECH
1754 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis
)
1757 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow
)
1759 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager
)
1761 for (nsTimeout
* timeout
= tmp
->mTimeouts
.getFirst();
1763 timeout
= timeout
->getNext()) {
1764 cb
.NoteNativeChild(timeout
, NS_CYCLE_COLLECTION_PARTICIPANT(nsTimeout
));
1767 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage
)
1768 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage
)
1769 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache
)
1770 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal
)
1771 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc
)
1772 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService
)
1773 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents
)
1774 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers
)
1777 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads
)
1780 // Traverse stuff from nsPIDOMWindow
1781 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler
)
1782 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget
)
1783 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement
)
1784 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode
)
1786 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar
)
1787 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar
)
1788 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar
)
1789 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar
)
1790 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar
)
1791 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars
)
1792 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto
)
1793 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole
)
1794 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal
)
1795 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMozSelfSupport
)
1796 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
1797 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1799 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow
)
1800 nsGlobalWindow::CleanupCachedXBLHandlers(tmp
);
1802 NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext
)
1804 NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers
)
1805 NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments
)
1806 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments
)
1807 NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue
)
1808 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator
)
1810 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance
)
1812 #ifdef MOZ_WEBSPEECH
1813 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis
)
1816 if (tmp
->mOuterWindow
) {
1817 static_cast<nsGlobalWindow
*>(tmp
->mOuterWindow
.get())->MaybeClearInnerWindow(tmp
);
1818 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow
)
1821 if (tmp
->mListenerManager
) {
1822 tmp
->mListenerManager
->Disconnect();
1823 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager
)
1825 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage
)
1826 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage
)
1827 if (tmp
->mApplicationCache
) {
1828 static_cast<nsDOMOfflineResourceList
*>(tmp
->mApplicationCache
.get())->Disconnect();
1829 NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache
)
1831 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal
)
1832 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc
)
1833 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService
)
1834 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents
)
1835 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers
)
1838 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads
)
1841 // Unlink stuff from nsPIDOMWindow
1842 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler
)
1843 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget
)
1844 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement
)
1845 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode
)
1847 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar
)
1848 NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar
)
1849 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar
)
1850 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar
)
1851 NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar
)
1852 NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars
)
1853 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto
)
1854 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole
)
1855 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal
)
1856 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMozSelfSupport
)
1857 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1858 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1862 nsGlobalWindow::RiskyUnlink()
1864 NS_CYCLE_COLLECTION_INNERNAME
.Unlink(this);
1870 const TraceCallbacks
& callbacks
;
1874 static PLDHashOperator
1875 TraceXBLHandlers(nsXBLPrototypeHandler
* aKey
, JS::Heap
<JSObject
*>& aData
, void* aClosure
)
1877 TraceData
* data
= static_cast<TraceData
*>(aClosure
);
1878 data
->callbacks
.Trace(&aData
, "Cached XBL prototype handler", data
->closure
);
1879 return PL_DHASH_NEXT
;
1882 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow
)
1883 if (tmp
->mCachedXBLPrototypeHandlers
) {
1884 TraceData data
= { aCallbacks
, aClosure
};
1885 tmp
->mCachedXBLPrototypeHandlers
->Enumerate(TraceXBLHandlers
, &data
);
1887 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
1888 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1891 nsGlobalWindow::IsBlackForCC(bool aTracingNeeded
)
1893 if (!nsCCUncollectableMarker::sGeneration
) {
1897 return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
1900 HasNothingToTrace(static_cast<nsIDOMEventTarget
*>(this)));
1904 nsGlobalWindow::UnmarkGrayTimers()
1906 for (nsTimeout
* timeout
= mTimeouts
.getFirst();
1908 timeout
= timeout
->getNext()) {
1909 if (timeout
->mScriptHandler
) {
1910 Function
* f
= timeout
->mScriptHandler
->GetCallback();
1912 // Callable() already does xpc_UnmarkGrayObject.
1913 DebugOnly
<JS::Handle
<JSObject
*> > o
= f
->Callable();
1914 MOZ_ASSERT(!xpc_IsGrayGCThing(o
.value
), "Should have been unmarked");
1920 //*****************************************************************************
1921 // nsGlobalWindow::nsIScriptGlobalObject
1922 //*****************************************************************************
1925 nsGlobalWindow::EnsureScriptEnvironment()
1927 nsGlobalWindow
* outer
= GetOuterWindowInternal();
1929 NS_WARNING("No outer window available!");
1930 return NS_ERROR_FAILURE
;
1933 if (outer
->GetWrapperPreserveColor()) {
1937 NS_ASSERTION(!outer
->GetCurrentInnerWindowInternal(),
1938 "No cached wrapper, but we have an inner window?");
1940 // If this window is a [i]frame, don't bother GC'ing when the frame's context
1941 // is destroyed since a GC will happen when the frameset or host document is
1942 // destroyed anyway.
1943 nsCOMPtr
<nsIScriptContext
> context
= new nsJSContext(!IsFrame(), outer
);
1945 NS_ASSERTION(!outer
->mContext
, "Will overwrite mContext!");
1947 // should probably assert the context is clean???
1948 context
->WillInitializeContext();
1950 nsresult rv
= context
->InitContext();
1951 NS_ENSURE_SUCCESS(rv
, rv
);
1953 outer
->mContext
= context
;
1958 nsGlobalWindow::GetScriptContext()
1960 nsGlobalWindow
* outer
= GetOuterWindowInternal();
1961 return outer
? outer
->mContext
: nullptr;
1965 nsGlobalWindow::GetGlobalJSObject()
1967 return FastGetGlobalJSObject();
1971 nsGlobalWindow::TraceGlobalJSObject(JSTracer
* aTrc
)
1973 TraceWrapper(aTrc
, "active window global");
1978 nsGlobalWindow::OuterObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
)
1980 nsGlobalWindow
* origWin
= UnwrapDOMObject
<nsGlobalWindow
>(aObj
);
1981 nsGlobalWindow
* win
= origWin
->GetOuterWindowInternal();
1984 // If we no longer have an outer window. No code should ever be
1985 // running on a window w/o an outer, which means this hook should
1986 // never be called when we have no outer. But just in case, return
1987 // null to prevent leaking an inner window to code in a different
1989 NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
1990 Throw(aCx
, NS_ERROR_UNEXPECTED
);
1994 JS::Rooted
<JSObject
*> winObj(aCx
, win
->FastGetGlobalJSObject());
1997 // Note that while |wrapper| is same-compartment with cx, the outer window
1998 // might not be. If we're running script in an inactive scope and evalute
1999 // |this|, the outer window is actually a cross-compartment wrapper. So we
2000 // need to wrap here.
2001 if (!JS_WrapObject(aCx
, &winObj
)) {
2002 NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
2003 Throw(aCx
, NS_ERROR_UNEXPECTED
);
2011 nsGlobalWindow::WouldReuseInnerWindow(nsIDocument
* aNewDocument
)
2013 MOZ_ASSERT(IsOuterWindow());
2015 // We reuse the inner window when:
2016 // a. We are currently at our original document.
2017 // b. At least one of the following conditions are true:
2018 // -- The new document is the same as the old document. This means that we're
2019 // getting called from document.open().
2020 // -- The new document has the same origin as what we have loaded right now.
2022 if (!mDoc
|| !aNewDocument
) {
2026 if (!mDoc
->IsInitialDocument()) {
2030 NS_ASSERTION(NS_IsAboutBlank(mDoc
->GetDocumentURI()),
2031 "How'd this happen?");
2033 // Great, we're the original document, check for one of the other
2036 if (mDoc
== aNewDocument
) {
2041 if (NS_SUCCEEDED(mDoc
->NodePrincipal()->Equals(aNewDocument
->NodePrincipal(),
2044 // The origin is the same.
2052 nsGlobalWindow::SetInitialPrincipalToSubject()
2054 MOZ_ASSERT(IsOuterWindow());
2056 // First, grab the subject principal.
2057 nsCOMPtr
<nsIPrincipal
> newWindowPrincipal
= nsContentUtils::SubjectPrincipal();
2059 // Now, if we're about to use the system principal or an nsExpandedPrincipal,
2060 // make sure we're not using it for a content docshell.
2061 if (nsContentUtils::IsSystemOrExpandedPrincipal(newWindowPrincipal
) &&
2062 GetDocShell()->ItemType() != nsIDocShellTreeItem::typeChrome
) {
2063 newWindowPrincipal
= nullptr;
2066 // If there's an existing document, bail if it either:
2068 // (a) is not an initial about:blank document, or
2069 if (!mDoc
->IsInitialDocument())
2071 // (b) already has the correct principal.
2072 if (mDoc
->NodePrincipal() == newWindowPrincipal
)
2076 // If we have a document loaded at this point, it had better be about:blank.
2077 // Otherwise, something is really weird.
2078 nsCOMPtr
<nsIURI
> uri
;
2079 mDoc
->NodePrincipal()->GetURI(getter_AddRefs(uri
));
2080 NS_ASSERTION(uri
&& NS_IsAboutBlank(uri
) &&
2081 NS_IsAboutBlank(mDoc
->GetDocumentURI()),
2082 "Unexpected original document");
2086 GetDocShell()->CreateAboutBlankContentViewer(newWindowPrincipal
);
2087 mDoc
->SetIsInitialDocument(true);
2089 nsCOMPtr
<nsIPresShell
> shell
= GetDocShell()->GetPresShell();
2091 if (shell
&& !shell
->DidInitialize()) {
2092 // Ensure that if someone plays with this document they will get
2093 // layout happening.
2094 nsRect r
= shell
->GetPresContext()->GetVisibleArea();
2095 shell
->Initialize(r
.width
, r
.height
);
2100 PushPopupControlState(PopupControlState aState
, bool aForce
)
2102 MOZ_ASSERT(NS_IsMainThread());
2104 PopupControlState oldState
= gPopupControlState
;
2106 if (aState
< gPopupControlState
|| aForce
) {
2107 gPopupControlState
= aState
;
2114 PopPopupControlState(PopupControlState aState
)
2116 MOZ_ASSERT(NS_IsMainThread());
2118 gPopupControlState
= aState
;
2122 nsGlobalWindow::PushPopupControlState(PopupControlState aState
,
2125 return ::PushPopupControlState(aState
, aForce
);
2129 nsGlobalWindow::PopPopupControlState(PopupControlState aState
) const
2131 ::PopPopupControlState(aState
);
2135 nsGlobalWindow::GetPopupControlState() const
2137 MOZ_ASSERT(NS_IsMainThread());
2138 return gPopupControlState
;
2141 #define WINDOWSTATEHOLDER_IID \
2142 {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
2144 class WindowStateHolder MOZ_FINAL
: public nsISupports
2147 NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID
)
2150 WindowStateHolder(nsIScriptContext
* aContext
, nsGlobalWindow
*aWindow
);
2152 nsGlobalWindow
* GetInnerWindow() { return mInnerWindow
; }
2154 void DidRestoreWindow()
2156 mInnerWindow
= nullptr;
2157 mInnerWindowReflector
= nullptr;
2161 ~WindowStateHolder();
2163 nsGlobalWindow
*mInnerWindow
;
2164 // We hold onto this to make sure the inner window doesn't go away. The outer
2165 // window ends up recalculating it anyway.
2166 JS::PersistentRooted
<JSObject
*> mInnerWindowReflector
;
2169 NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder
, WINDOWSTATEHOLDER_IID
)
2171 WindowStateHolder::WindowStateHolder(nsIScriptContext
* aContext
,
2172 nsGlobalWindow
* aWindow
)
2173 : mInnerWindow(aWindow
),
2174 mInnerWindowReflector(aContext
->GetNativeContext(), aWindow
->GetWrapper())
2176 NS_PRECONDITION(aWindow
, "null window");
2177 NS_PRECONDITION(aWindow
->IsInnerWindow(), "Saving an outer window");
2179 aWindow
->SuspendTimeouts();
2181 // When a global goes into the bfcache, we disable script.
2182 xpc::Scriptability::Get(mInnerWindowReflector
).SetDocShellAllowsScript(false);
2185 WindowStateHolder::~WindowStateHolder()
2188 // This window was left in the bfcache and is now going away. We need to
2190 // Note that FreeInnerObjects may already have been called on the
2191 // inner window if its outer has already had SetDocShell(null)
2193 mInnerWindow
->FreeInnerObjects();
2197 NS_IMPL_ISUPPORTS(WindowStateHolder
, WindowStateHolder
)
2199 // We need certain special behavior for remote XUL whitelisted domains, but we
2200 // don't want that behavior to take effect in automation, because we whitelist
2201 // all the mochitest domains. So we need to check a pref here.
2203 TreatAsRemoteXUL(nsIPrincipal
* aPrincipal
)
2205 MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(aPrincipal
));
2206 return nsContentUtils::AllowXULXBLForPrincipal(aPrincipal
) &&
2207 !Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false);
2211 EnablePrivilege(JSContext
* cx
, unsigned argc
, JS::Value
* vp
)
2213 Telemetry::Accumulate(Telemetry::ENABLE_PRIVILEGE_EVER_CALLED
, true);
2214 return xpc::EnableUniversalXPConnect(cx
);
2217 static const JSFunctionSpec EnablePrivilegeSpec
[] = {
2218 JS_FS("enablePrivilege", EnablePrivilege
, 1, 0),
2223 InitializeLegacyNetscapeObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
)
2225 JSAutoCompartment
ac(aCx
, aGlobal
);
2227 // Note: MathJax depends on window.netscape being exposed. See bug 791526.
2228 JS::Rooted
<JSObject
*> obj(aCx
);
2229 obj
= JS_DefineObject(aCx
, aGlobal
, "netscape", nullptr);
2230 NS_ENSURE_TRUE(obj
, false);
2232 obj
= JS_DefineObject(aCx
, obj
, "security", nullptr);
2233 NS_ENSURE_TRUE(obj
, false);
2235 // We hide enablePrivilege behind a pref because it has been altered in a
2236 // way that makes it fundamentally insecure to use in production. Mozilla
2237 // uses this pref during automated testing to support legacy test code that
2238 // uses enablePrivilege. If you're not doing test automation, you _must_ not
2239 // flip this pref, or you will be exposing all your users to security
2241 if (!Preferences::GetBool("security.turn_off_all_security_so_that_viruses_can_take_over_this_computer")) {
2245 /* Define PrivilegeManager object with the necessary "static" methods. */
2246 obj
= JS_DefineObject(aCx
, obj
, "PrivilegeManager", nullptr);
2247 NS_ENSURE_TRUE(obj
, false);
2249 return JS_DefineFunctions(aCx
, obj
, EnablePrivilegeSpec
);
2253 * Create a new global object that will be used for an inner window.
2254 * Return the native global and an nsISupports 'holder' that can be used
2255 * to manage the lifetime of it.
2258 CreateNativeGlobalForInner(JSContext
* aCx
,
2259 nsGlobalWindow
* aNewInner
,
2261 nsIPrincipal
* aPrincipal
,
2262 JS::MutableHandle
<JSObject
*> aGlobal
)
2265 MOZ_ASSERT(aNewInner
);
2266 MOZ_ASSERT(aNewInner
->IsInnerWindow());
2267 MOZ_ASSERT(aPrincipal
);
2269 // DOMWindow with nsEP is not supported, we have to make sure
2270 // no one creates one accidentally.
2271 nsCOMPtr
<nsIExpandedPrincipal
> nsEP
= do_QueryInterface(aPrincipal
);
2272 MOZ_RELEASE_ASSERT(!nsEP
, "DOMWindow with nsEP is not supported");
2274 nsGlobalWindow
*top
= nullptr;
2275 if (aNewInner
->GetOuterWindow()) {
2276 top
= aNewInner
->GetTop();
2278 JS::CompartmentOptions options
;
2280 if (top
->GetGlobalJSObject()) {
2281 options
.setSameZoneAs(top
->GetGlobalJSObject());
2285 // Determine if we need the Components object.
2286 bool needComponents
= nsContentUtils::IsSystemPrincipal(aPrincipal
) ||
2287 TreatAsRemoteXUL(aPrincipal
);
2288 uint32_t flags
= needComponents
? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT
;
2289 flags
|= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK
;
2291 if (aNewInner
->IsDOMBinding()) {
2292 aGlobal
.set(WindowBinding::Wrap(aCx
, aNewInner
, aNewInner
, options
,
2293 nsJSPrincipals::get(aPrincipal
), false));
2294 if (!aGlobal
|| !xpc::InitGlobalObject(aCx
, aGlobal
, flags
)) {
2295 return NS_ERROR_FAILURE
;
2298 nsIXPConnect
* xpc
= nsContentUtils::XPConnect();
2299 nsCOMPtr
<nsIXPConnectJSObjectHolder
> holder
;
2300 nsresult rv
= xpc
->InitClassesWithNewWrappedGlobal(
2301 aCx
, ToSupports(aNewInner
),
2302 aPrincipal
, flags
, options
, getter_AddRefs(holder
));
2303 NS_ENSURE_SUCCESS(rv
, rv
);
2305 aGlobal
.set(holder
->GetJSObject());
2306 MOZ_ASSERT(aGlobal
);
2309 MOZ_ASSERT(aNewInner
->GetWrapperPreserveColor() == aGlobal
);
2311 // Set the location information for the new global, so that tools like
2312 // about:memory may use that information
2313 xpc::SetLocationForGlobal(aGlobal
, aURI
);
2315 if (!InitializeLegacyNetscapeObject(aCx
, aGlobal
)) {
2316 return NS_ERROR_FAILURE
;
2323 nsGlobalWindow::SetNewDocument(nsIDocument
* aDocument
,
2324 nsISupports
* aState
,
2325 bool aForceReuseInnerWindow
)
2327 NS_PRECONDITION(mDocumentPrincipal
== nullptr,
2328 "mDocumentPrincipal prematurely set!");
2329 MOZ_ASSERT(aDocument
);
2331 if (IsInnerWindow()) {
2332 if (!mOuterWindow
) {
2333 return NS_ERROR_NOT_INITIALIZED
;
2336 // Refuse to set a new document if the call came from an inner
2337 // window that's not the current inner window.
2338 if (mOuterWindow
->GetCurrentInnerWindow() != this) {
2339 return NS_ERROR_NOT_AVAILABLE
;
2342 return GetOuterWindowInternal()->SetNewDocument(aDocument
, aState
,
2343 aForceReuseInnerWindow
);
2346 NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
2348 // Bail out early if we're in process of closing down the window.
2349 NS_ENSURE_STATE(!mCleanedUp
);
2352 // This outer is now getting its first inner, thaw the outer now
2353 // that it's ready and is getting an inner window.
2358 NS_ASSERTION(!GetCurrentInnerWindow() ||
2359 GetCurrentInnerWindow()->GetExtantDoc() == mDoc
,
2360 "Uh, mDoc doesn't match the current inner window "
2363 bool wouldReuseInnerWindow
= WouldReuseInnerWindow(aDocument
);
2364 if (aForceReuseInnerWindow
&&
2365 !wouldReuseInnerWindow
&&
2367 mDoc
->NodePrincipal() != aDocument
->NodePrincipal()) {
2368 NS_ERROR("Attempted forced inner window reuse while changing principal");
2369 return NS_ERROR_UNEXPECTED
;
2372 nsCOMPtr
<nsIDocument
> oldDoc
= mDoc
;
2374 #ifndef MOZ_DISABLE_CRYPTOLEGACY
2375 // clear smartcard events, our document has gone away.
2376 if (mCrypto
&& XRE_GetProcessType() != GeckoProcessType_Content
) {
2377 nsresult rv
= mCrypto
->SetEnableSmartCardEvents(false);
2378 NS_ENSURE_SUCCESS(rv
, rv
);
2384 JSContext
*cx
= jsapi
.cx();
2387 // First document load.
2389 // Get our private root. If it is equal to us, then we need to
2390 // attach our global key bindings that handles browser scrolling
2391 // and other browser commands.
2392 nsIDOMWindow
* privateRoot
= nsGlobalWindow::GetPrivateRoot();
2394 if (privateRoot
== static_cast<nsIDOMWindow
*>(this)) {
2395 nsXBLService::AttachGlobalKeyHandler(mChromeEventHandler
);
2399 /* No mDocShell means we're already been partially closed down. When that
2400 happens, setting status isn't a big requirement, so don't. (Doesn't happen
2401 under normal circumstances, but bug 49615 describes a case.) */
2403 nsContentUtils::AddScriptRunner(
2404 NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus
));
2406 // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner
2407 // window (see bug 776497). Be safe.
2408 bool reUseInnerWindow
= (aForceReuseInnerWindow
|| wouldReuseInnerWindow
) &&
2409 GetCurrentInnerWindowInternal();
2411 nsresult rv
= NS_OK
;
2413 // Set mDoc even if this is an outer window to avoid
2414 // having to *always* reach into the inner window to find the
2417 if (IsInnerWindow() && IsDOMBinding()) {
2418 WindowBinding::ClearCachedDocumentValue(cx
, this);
2421 // Take this opportunity to clear mSuspendedDoc. Our old inner window is now
2422 // responsible for unsuspending it.
2423 mSuspendedDoc
= nullptr;
2426 mLastOpenedURI
= aDocument
->GetDocumentURI();
2429 mContext
->WillInitializeContext();
2431 nsGlobalWindow
*currentInner
= GetCurrentInnerWindowInternal();
2433 if (currentInner
&& currentInner
->mNavigator
) {
2434 currentInner
->mNavigator
->OnNavigation();
2437 nsRefPtr
<nsGlobalWindow
> newInnerWindow
;
2438 bool createdInnerWindow
= false;
2440 bool thisChrome
= IsChromeWindow();
2442 // Check if we're anywhere near the stack limit before we reach the
2443 // transplanting code, since it has no good way to handle errors. This uses
2444 // the untrusted script limit, which is not strictly necessary since no
2445 // actual script should run.
2446 JS_CHECK_RECURSION_CONSERVATIVE(cx
, return NS_ERROR_FAILURE
);
2448 nsCOMPtr
<WindowStateHolder
> wsh
= do_QueryInterface(aState
);
2449 NS_ASSERTION(!aState
|| wsh
, "What kind of weird state are you giving me here?");
2451 JS::Rooted
<JSObject
*> newInnerGlobal(cx
);
2452 if (reUseInnerWindow
) {
2453 // We're reusing the current inner window.
2454 NS_ASSERTION(!currentInner
->IsFrozen(),
2455 "We should never be reusing a shared inner window");
2456 newInnerWindow
= currentInner
;
2457 newInnerGlobal
= currentInner
->GetWrapperPreserveColor();
2459 if (aDocument
!= oldDoc
) {
2460 JS::ExposeObjectToActiveJS(newInnerGlobal
);
2463 // We're reusing the inner window, but this still counts as a navigation,
2464 // so all expandos and such defined on the outer window should go away. Force
2465 // all Xray wrappers to be recomputed.
2466 JS::Rooted
<JSObject
*> rootedObject(cx
, GetWrapperPreserveColor());
2467 JS::ExposeObjectToActiveJS(rootedObject
);
2468 if (!JS_RefreshCrossCompartmentWrappers(cx
, rootedObject
)) {
2469 return NS_ERROR_FAILURE
;
2472 // Inner windows are only reused for same-origin principals, but the principals
2473 // don't necessarily match exactly. Update the principal on the compartment to
2474 // match the new document.
2475 // NB: We don't just call currentInner->RefreshCompartmentPrincipals() here
2476 // because we haven't yet set its mDoc to aDocument.
2477 JSCompartment
*compartment
= js::GetObjectCompartment(newInnerGlobal
);
2479 bool sameOrigin
= false;
2480 nsIPrincipal
*existing
=
2481 nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment
));
2482 aDocument
->NodePrincipal()->Equals(existing
, &sameOrigin
);
2483 MOZ_ASSERT(sameOrigin
);
2485 JS_SetCompartmentPrincipals(compartment
,
2486 nsJSPrincipals::get(aDocument
->NodePrincipal()));
2489 newInnerWindow
= wsh
->GetInnerWindow();
2490 newInnerGlobal
= newInnerWindow
->GetWrapperPreserveColor();
2493 newInnerWindow
= new nsGlobalChromeWindow(this);
2494 } else if (mIsModalContentWindow
) {
2495 newInnerWindow
= new nsGlobalModalWindow(this);
2497 newInnerWindow
= new nsGlobalWindow(this);
2500 // Freeze the outer window and null out the inner window so
2501 // that initializing classes on the new inner doesn't end up
2502 // reaching into the old inner window for classes etc.
2504 // [This happens with Object.prototype when XPConnect creates
2505 // a temporary global while initializing classes; the reason
2506 // being that xpconnect creates the temp global w/o a parent
2507 // and proto, which makes the JS engine look up classes in
2508 // cx->globalObject, i.e. this outer window].
2510 mInnerWindow
= nullptr;
2513 mCreatingInnerWindow
= true;
2514 // Every script context we are initialized with must create a
2516 rv
= CreateNativeGlobalForInner(cx
, newInnerWindow
,
2517 aDocument
->GetDocumentURI(),
2518 aDocument
->NodePrincipal(),
2520 NS_ASSERTION(NS_SUCCEEDED(rv
) && newInnerGlobal
&&
2521 newInnerWindow
->GetWrapperPreserveColor() == newInnerGlobal
,
2522 "Failed to get script global");
2524 mCreatingInnerWindow
= false;
2525 createdInnerWindow
= true;
2528 NS_ENSURE_SUCCESS(rv
, rv
);
2531 if (currentInner
&& currentInner
->GetWrapperPreserveColor()) {
2532 if (oldDoc
== aDocument
) {
2533 // Move the navigator from the old inner window to the new one since
2534 // this is a document.write. This is safe from a same-origin point of
2535 // view because document.write can only be used by the same origin.
2536 newInnerWindow
->mNavigator
= currentInner
->mNavigator
;
2537 currentInner
->mNavigator
= nullptr;
2538 if (newInnerWindow
->mNavigator
) {
2539 newInnerWindow
->mNavigator
->SetWindow(newInnerWindow
);
2542 // Make a copy of the old window's performance object on document.open.
2543 // Note that we have to force eager creation of it here, because we need
2544 // to grab the current document channel and whatnot before that changes.
2545 currentInner
->CreatePerformanceObjectIfNeeded();
2546 if (currentInner
->mPerformance
) {
2547 newInnerWindow
->mPerformance
=
2548 new nsPerformance(newInnerWindow
,
2549 currentInner
->mPerformance
->GetDOMTiming(),
2550 currentInner
->mPerformance
->GetChannel(),
2551 currentInner
->mPerformance
->GetParentPerformance());
2555 // Don't free objects on our current inner window if it's going to be
2556 // held in the bfcache.
2557 if (!currentInner
->IsFrozen()) {
2558 currentInner
->FreeInnerObjects();
2562 mInnerWindow
= newInnerWindow
;
2564 if (!GetWrapperPreserveColor()) {
2565 JS::Rooted
<JSObject
*> outer(cx
,
2566 NewOuterWindowProxy(cx
, newInnerGlobal
, thisChrome
));
2567 NS_ENSURE_TRUE(outer
, NS_ERROR_FAILURE
);
2569 js::SetProxyExtra(outer
, 0, js::PrivateValue(ToSupports(this)));
2571 // Inform the nsJSContext, which is the canonical holder of the outer.
2572 mContext
->SetWindowProxy(outer
);
2573 mContext
->DidInitializeContext();
2575 SetWrapper(mContext
->GetWindowProxy());
2577 JS::ExposeObjectToActiveJS(newInnerGlobal
);
2578 JS::Rooted
<JSObject
*> outerObject(cx
,
2579 NewOuterWindowProxy(cx
, newInnerGlobal
, thisChrome
));
2581 NS_ERROR("out of memory");
2582 return NS_ERROR_FAILURE
;
2585 JS::Rooted
<JSObject
*> obj(cx
, GetWrapperPreserveColor());
2587 js::SetProxyExtra(obj
, 0, js::PrivateValue(nullptr));
2589 outerObject
= xpc::TransplantObject(cx
, obj
, outerObject
);
2591 NS_ERROR("unable to transplant wrappers, probably OOM");
2592 return NS_ERROR_FAILURE
;
2595 js::SetProxyExtra(outerObject
, 0, js::PrivateValue(ToSupports(this)));
2597 SetWrapper(outerObject
);
2600 JSAutoCompartment
ac(cx
, outerObject
);
2602 JS_SetParent(cx
, outerObject
, newInnerGlobal
);
2604 // Inform the nsJSContext, which is the canonical holder of the outer.
2605 mContext
->SetWindowProxy(outerObject
);
2607 NS_ASSERTION(!JS_IsExceptionPending(cx
),
2608 "We might overwrite a pending exception!");
2609 XPCWrappedNativeScope
* scope
= xpc::ObjectScope(outerObject
);
2610 if (scope
->mWaiverWrapperMap
) {
2611 scope
->mWaiverWrapperMap
->Reparent(cx
, newInnerGlobal
);
2616 // Enter the new global's compartment.
2617 JSAutoCompartment
ac(cx
, GetWrapperPreserveColor());
2619 // Set scriptability based on the state of the docshell.
2620 bool allow
= GetDocShell()->GetCanExecuteScripts();
2621 xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow
);
2623 // If we created a new inner window above, we need to do the last little bit
2624 // of initialization now that the dust has settled.
2625 if (createdInnerWindow
) {
2626 if (newInnerWindow
->IsDOMBinding()) {
2627 JS::Rooted
<JSObject
*> global(cx
, newInnerGlobal
);
2628 JS::Rooted
<JSObject
*> proto(cx
);
2629 JS_GetPrototype(cx
, global
, &proto
);
2630 WindowNamedPropertiesHandler::Install(cx
, proto
);
2632 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
2633 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
;
2634 nsresult rv
= xpc
->GetWrappedNativeOfJSObject(cx
, newInnerGlobal
,
2635 getter_AddRefs(wrapper
));
2636 NS_ENSURE_SUCCESS(rv
, rv
);
2637 NS_ABORT_IF_FALSE(wrapper
, "bad wrapper");
2638 rv
= wrapper
->FinishInitForWrappedGlobal();
2639 NS_ENSURE_SUCCESS(rv
, rv
);
2644 JS::Rooted
<JSObject
*> rootedWrapper(cx
, GetWrapperPreserveColor());
2645 if (!JS_DefineProperty(cx
, newInnerGlobal
, "window", rootedWrapper
,
2646 JSPROP_ENUMERATE
| JSPROP_READONLY
| JSPROP_PERMANENT
,
2647 JS_PropertyStub
, JS_StrictPropertyStub
)) {
2648 NS_ERROR("can't create the 'window' property");
2649 return NS_ERROR_FAILURE
;
2654 JSAutoCompartment
ac(cx
, GetWrapperPreserveColor());
2656 if (!aState
&& !reUseInnerWindow
) {
2657 // Loading a new page and creating a new inner window, *not*
2658 // restoring from session history.
2660 // Now that both the the inner and outer windows are initialized
2661 // let the script context do its magic to hook them together.
2662 MOZ_ASSERT(mContext
->GetWindowProxy() == GetWrapperPreserveColor());
2664 JS::Rooted
<JSObject
*> rootedJSObject(cx
, GetWrapperPreserveColor());
2665 JS::Rooted
<JSObject
*> proto1(cx
), proto2(cx
);
2666 JS_GetPrototype(cx
, rootedJSObject
, &proto1
);
2667 JS_GetPrototype(cx
, newInnerGlobal
, &proto2
);
2668 NS_ASSERTION(proto1
== proto2
,
2669 "outer and inner globals should have the same prototype");
2672 nsCOMPtr
<Element
> frame
= GetFrameElementInternal();
2674 nsPIDOMWindow
* parentWindow
= frame
->OwnerDoc()->GetWindow();
2675 if (parentWindow
&& parentWindow
->TimeoutSuspendCount()) {
2676 SuspendTimeouts(parentWindow
->TimeoutSuspendCount());
2681 // Add an extra ref in case we release mContext during GC.
2682 nsCOMPtr
<nsIScriptContext
> kungFuDeathGrip(mContext
);
2684 aDocument
->SetScriptGlobalObject(newInnerWindow
);
2687 if (reUseInnerWindow
) {
2689 if (newInnerWindow
->mDoc
!= aDocument
) {
2690 newInnerWindow
->mDoc
= aDocument
;
2692 // The storage objects contain the URL of the window. We have to
2693 // recreate them when the innerWindow is reused.
2694 newInnerWindow
->mLocalStorage
= nullptr;
2695 newInnerWindow
->mSessionStorage
= nullptr;
2697 if (newInnerWindow
->IsDOMBinding()) {
2698 WindowBinding::ClearCachedDocumentValue(cx
, newInnerWindow
);
2700 // We're reusing the inner window for a new document. In this
2701 // case we don't clear the inner window's scope, but we must
2702 // make sure the cached document property gets updated.
2704 JS::Rooted
<JSObject
*> obj(cx
,
2705 currentInner
->GetWrapperPreserveColor());
2706 ::JS_DeleteProperty(cx
, obj
, "document");
2710 newInnerWindow
->InnerSetNewDocument(cx
, aDocument
);
2712 // Initialize DOM classes etc on the inner window.
2713 JS::Rooted
<JSObject
*> obj(cx
, newInnerGlobal
);
2714 rv
= mContext
->InitClasses(obj
);
2715 NS_ENSURE_SUCCESS(rv
, rv
);
2718 // If the document comes from a JAR, check if the channel was determined
2719 // to be unsafe. If so, permanently disable script on the compartment by
2720 // calling Block() and throwing away the key.
2721 nsCOMPtr
<nsIJARChannel
> jarChannel
= do_QueryInterface(aDocument
->GetChannel());
2722 if (jarChannel
&& jarChannel
->GetIsUnsafe()) {
2723 xpc::Scriptability::Get(newInnerGlobal
).Block();
2727 newInnerWindow
->DefineArgumentsProperty(mArguments
);
2728 mArguments
= nullptr;
2731 // Give the new inner window our chrome event handler (since it
2732 // doesn't have one).
2733 newInnerWindow
->mChromeEventHandler
= mChromeEventHandler
;
2736 mContext
->GC(JS::gcreason::SET_NEW_DOCUMENT
);
2737 mContext
->DidInitializeContext();
2739 // We wait to fire the debugger hook until the window is all set up and hooked
2740 // up with the outer. See bug 969156.
2741 if (createdInnerWindow
) {
2742 // AutoEntryScript required to invoke debugger hook, which is a
2743 // Gecko-specific concept at present.
2744 AutoEntryScript
aes(newInnerWindow
);
2745 JS::Rooted
<JSObject
*> global(aes
.cx(), newInnerWindow
->GetWrapper());
2746 JS_FireOnNewGlobalObject(aes
.cx(), global
);
2749 if (newInnerWindow
&& !newInnerWindow
->mHasNotifiedGlobalCreated
&& mDoc
) {
2750 // We should probably notify. However if this is the, arguably bad,
2751 // situation when we're creating a temporary non-chrome-about-blank
2752 // document in a chrome docshell, don't notify just yet. Instead wait
2753 // until we have a real chrome doc.
2755 mDocShell
->ItemType() != nsIDocShellTreeItem::typeChrome
||
2756 nsContentUtils::IsSystemPrincipal(mDoc
->NodePrincipal())) {
2757 newInnerWindow
->mHasNotifiedGlobalCreated
= true;
2758 nsContentUtils::AddScriptRunner(
2759 NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated
));
2763 PreloadLocalStorage();
2769 nsGlobalWindow::PreloadLocalStorage()
2771 MOZ_ASSERT(IsOuterWindow());
2773 if (!Preferences::GetBool(kStorageEnabled
)) {
2777 if (IsChromeWindow()) {
2781 nsIPrincipal
* principal
= GetPrincipal();
2788 nsCOMPtr
<nsIDOMStorageManager
> storageManager
=
2789 do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv
);
2790 if (NS_FAILED(rv
)) {
2794 storageManager
->PrecacheStorage(principal
);
2798 nsGlobalWindow::DispatchDOMWindowCreated()
2800 MOZ_ASSERT(IsOuterWindow());
2806 // Fire DOMWindowCreated at chrome event listeners
2807 nsContentUtils::DispatchChromeEvent(mDoc
, mDoc
, NS_LITERAL_STRING("DOMWindowCreated"),
2809 false /* not cancellable */);
2811 nsCOMPtr
<nsIObserverService
> observerService
=
2812 mozilla::services::GetObserverService();
2813 if (observerService
) {
2814 nsAutoString origin
;
2815 nsIPrincipal
* principal
= mDoc
->NodePrincipal();
2816 nsContentUtils::GetUTFOrigin(principal
, origin
);
2818 NotifyObservers(static_cast<nsIDOMWindow
*>(this),
2819 nsContentUtils::IsSystemPrincipal(principal
) ?
2820 "chrome-document-global-created" :
2821 "content-document-global-created",
2827 nsGlobalWindow::ClearStatus()
2829 SetStatus(EmptyString());
2833 nsGlobalWindow::InnerSetNewDocument(JSContext
* aCx
, nsIDocument
* aDocument
)
2835 NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
2836 MOZ_ASSERT(aDocument
);
2839 if (gDOMLeakPRLog
&& PR_LOG_TEST(gDOMLeakPRLog
, PR_LOG_DEBUG
)) {
2840 nsIURI
*uri
= aDocument
->GetDocumentURI();
2844 PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec
.get());
2849 if (IsDOMBinding()) {
2850 WindowBinding::ClearCachedDocumentValue(aCx
, this);
2852 mFocusedNode
= nullptr;
2853 mLocalStorage
= nullptr;
2854 mSessionStorage
= nullptr;
2857 mLastOpenedURI
= aDocument
->GetDocumentURI();
2860 Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS
,
2861 mMutationBits
? 1 : 0);
2863 // Clear our mutation bitfield.
2868 nsGlobalWindow::SetDocShell(nsIDocShell
* aDocShell
)
2870 NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
2871 MOZ_ASSERT(aDocShell
);
2873 if (aDocShell
== mDocShell
) {
2877 mDocShell
= aDocShell
; // Weak Reference
2879 NS_ASSERTION(!mNavigator
, "Non-null mNavigator in outer window!");
2882 mFrames
->SetDocShell(aDocShell
);
2885 // Get our enclosing chrome shell and retrieve its global window impl, so
2886 // that we can do some forwarding to the chrome document.
2887 nsCOMPtr
<nsIDOMEventTarget
> chromeEventHandler
;
2888 mDocShell
->GetChromeEventHandler(getter_AddRefs(chromeEventHandler
));
2889 mChromeEventHandler
= do_QueryInterface(chromeEventHandler
);
2890 if (!mChromeEventHandler
) {
2891 // We have no chrome event handler. If we have a parent,
2892 // get our chrome event handler from the parent. If
2893 // we don't have a parent, then we need to make a new
2894 // window root object that will function as a chrome event
2895 // handler and receive all events that occur anywhere inside
2897 nsCOMPtr
<nsIDOMWindow
> parentWindow
;
2898 GetParent(getter_AddRefs(parentWindow
));
2899 if (parentWindow
.get() != static_cast<nsIDOMWindow
*>(this)) {
2900 nsCOMPtr
<nsPIDOMWindow
> piWindow(do_QueryInterface(parentWindow
));
2901 mChromeEventHandler
= piWindow
->GetChromeEventHandler();
2904 mChromeEventHandler
= NS_NewWindowRoot(this);
2908 bool docShellActive
;
2909 mDocShell
->GetIsActive(&docShellActive
);
2910 mIsBackground
= !docShellActive
;
2914 nsGlobalWindow::DetachFromDocShell()
2916 NS_ASSERTION(IsOuterWindow(), "Uh, DetachFromDocShell() called on inner window!");
2918 // DetachFromDocShell means the window is being torn down. Drop our
2919 // reference to the script context, allowing it to be deleted
2920 // later. Meanwhile, keep our weak reference to the script object
2921 // so that it can be retrieved later (until it is finalized by the JS GC).
2923 NS_ASSERTION(mTimeouts
.isEmpty(), "Uh, outer window holds timeouts!");
2925 // Call FreeInnerObjects on all inner windows, not just the current
2926 // one, since some could be held by WindowStateHolder objects that
2928 for (nsRefPtr
<nsGlobalWindow
> inner
= (nsGlobalWindow
*)PR_LIST_HEAD(this);
2930 inner
= (nsGlobalWindow
*)PR_NEXT_LINK(inner
)) {
2931 NS_ASSERTION(!inner
->mOuterWindow
|| inner
->mOuterWindow
== this,
2932 "bad outer window pointer");
2933 inner
->FreeInnerObjects();
2936 // Make sure that this is called before we null out the document.
2937 NotifyDOMWindowDestroyed(this);
2939 NotifyWindowIDDestroyed("outer-window-destroyed");
2941 nsGlobalWindow
*currentInner
= GetCurrentInnerWindowInternal();
2944 NS_ASSERTION(mDoc
, "Must have doc!");
2946 // Remember the document's principal and URI.
2947 mDocumentPrincipal
= mDoc
->NodePrincipal();
2948 mDocumentURI
= mDoc
->GetDocumentURI();
2949 mDocBaseURI
= mDoc
->GetDocBaseURI();
2951 // Release our document reference
2952 DropOuterWindowDocs();
2953 mFocusedNode
= nullptr;
2958 mChromeEventHandler
= nullptr; // force release now
2961 mContext
->GC(JS::gcreason::SET_DOC_SHELL
);
2965 mDocShell
= nullptr; // Weak Reference
2967 NS_ASSERTION(!mNavigator
, "Non-null mNavigator in outer window!");
2970 mFrames
->SetDocShell(nullptr);
2973 MaybeForgiveSpamCount();
2978 nsGlobalWindow::SetOpenerWindow(nsIDOMWindow
* aOpener
,
2979 bool aOriginalOpener
)
2981 FORWARD_TO_OUTER_VOID(SetOpenerWindow
, (aOpener
, aOriginalOpener
));
2983 NS_ASSERTION(!aOriginalOpener
|| !mSetOpenerWindowCalled
,
2984 "aOriginalOpener is true, but not first call to "
2985 "SetOpenerWindow!");
2986 NS_ASSERTION(aOpener
|| !aOriginalOpener
,
2987 "Shouldn't set mHadOriginalOpener if aOpener is null");
2990 nsCOMPtr
<nsPIDOMWindow
> opener
= do_QueryInterface(aOpener
);
2991 MOZ_ASSERT(!opener
|| opener
->IsOuterWindow());
2993 mOpener
= do_GetWeakReference(aOpener
);
2994 NS_ASSERTION(mOpener
|| !aOpener
, "Opener must support weak references!");
2996 if (aOriginalOpener
) {
2997 mHadOriginalOpener
= true;
3001 mSetOpenerWindowCalled
= true;
3006 already_AddRefed
<EventTarget
>
3007 TryGetTabChildGlobalAsEventTarget(nsISupports
*aFrom
)
3009 nsCOMPtr
<nsIFrameLoaderOwner
> frameLoaderOwner
= do_QueryInterface(aFrom
);
3010 if (!frameLoaderOwner
) {
3014 nsRefPtr
<nsFrameLoader
> frameLoader
= frameLoaderOwner
->GetFrameLoader();
3019 nsCOMPtr
<EventTarget
> target
= frameLoader
->GetTabChildGlobalAsEventTarget();
3020 return target
.forget();
3024 nsGlobalWindow::UpdateParentTarget()
3026 // Try to get our frame element's tab child global (its in-process message
3027 // manager). If that fails, fall back to the chrome event handler's tab
3028 // child global, and if it doesn't have one, just use the chrome event
3031 nsCOMPtr
<Element
> frameElement
= GetFrameElementInternal();
3032 nsCOMPtr
<EventTarget
> eventTarget
=
3033 TryGetTabChildGlobalAsEventTarget(frameElement
);
3036 nsGlobalWindow
* topWin
= GetScriptableTop();
3038 frameElement
= topWin
->GetFrameElementInternal();
3039 eventTarget
= TryGetTabChildGlobalAsEventTarget(frameElement
);
3044 eventTarget
= TryGetTabChildGlobalAsEventTarget(mChromeEventHandler
);
3048 eventTarget
= mChromeEventHandler
;
3051 mParentTarget
= eventTarget
;
3055 nsGlobalWindow::GetTargetForDOMEvent()
3057 return GetOuterWindowInternal();
3061 nsGlobalWindow::GetTargetForEventTargetChain()
3063 return IsInnerWindow() ? this : GetCurrentInnerWindowInternal();
3067 nsGlobalWindow::WillHandleEvent(EventChainPostVisitor
& aVisitor
)
3073 nsGlobalWindow::GetJSContextForEventHandlers()
3079 nsGlobalWindow::PreHandleEvent(EventChainPreVisitor
& aVisitor
)
3081 NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
3082 static uint32_t count
= 0;
3083 uint32_t msg
= aVisitor
.mEvent
->message
;
3085 aVisitor
.mCanHandle
= true;
3086 aVisitor
.mForceContentDispatch
= true; //FIXME! Bug 329119
3087 if ((msg
== NS_MOUSE_MOVE
) && gEntropyCollector
) {
3088 //Chances are this counter will overflow during the life of the
3089 //process, but that's OK for our case. Means we get a little
3091 if (count
++ % 100 == 0) {
3092 //Since the high bits seem to be zero's most of the time,
3093 //let's only take the lowest half of the point structure.
3096 myCoord
[0] = aVisitor
.mEvent
->refPoint
.x
;
3097 myCoord
[1] = aVisitor
.mEvent
->refPoint
.y
;
3098 gEntropyCollector
->RandomUpdate((void*)myCoord
, sizeof(myCoord
));
3099 gEntropyCollector
->RandomUpdate((void*)&(aVisitor
.mEvent
->time
),
3102 } else if (msg
== NS_RESIZE_EVENT
) {
3103 mIsHandlingResizeEvent
= true;
3104 } else if (msg
== NS_MOUSE_BUTTON_DOWN
&&
3105 aVisitor
.mEvent
->mFlags
.mIsTrusted
) {
3107 } else if ((msg
== NS_MOUSE_BUTTON_UP
||
3108 msg
== NS_DRAGDROP_END
) &&
3109 aVisitor
.mEvent
->mFlags
.mIsTrusted
) {
3111 if (gDragServiceDisabled
) {
3112 nsCOMPtr
<nsIDragService
> ds
=
3113 do_GetService("@mozilla.org/widget/dragservice;1");
3115 gDragServiceDisabled
= false;
3121 aVisitor
.mParentTarget
= GetParentTarget();
3123 // Handle 'active' event.
3124 if (!mIdleObservers
.IsEmpty() &&
3125 aVisitor
.mEvent
->mFlags
.mIsTrusted
&&
3126 (aVisitor
.mEvent
->HasMouseEventMessage() ||
3127 aVisitor
.mEvent
->HasDragEventMessage())) {
3128 mAddActiveEventFuzzTime
= false;
3135 nsGlobalWindow::ShouldPromptToBlockDialogs()
3137 MOZ_ASSERT(IsOuterWindow());
3139 nsGlobalWindow
*topWindow
= GetScriptableTop();
3141 NS_ASSERTION(!mDocShell
, "ShouldPromptToBlockDialogs() called without a top window?");
3145 topWindow
= topWindow
->GetCurrentInnerWindowInternal();
3150 return topWindow
->DialogsAreBeingAbused();
3154 nsGlobalWindow::AreDialogsEnabled()
3156 MOZ_ASSERT(IsOuterWindow());
3158 nsGlobalWindow
*topWindow
= GetScriptableTop();
3160 NS_ERROR("AreDialogsEnabled() called without a top window?");
3164 // TODO: Warn if no top window?
3165 topWindow
= topWindow
->GetCurrentInnerWindowInternal();
3170 // Dialogs are blocked if the content viewer is hidden
3172 nsCOMPtr
<nsIContentViewer
> cv
;
3173 mDocShell
->GetContentViewer(getter_AddRefs(cv
));
3176 cv
->GetIsHidden(&isHidden
);
3182 return topWindow
->mAreDialogsEnabled
;
3186 nsGlobalWindow::DialogsAreBeingAbused()
3188 MOZ_ASSERT(IsInnerWindow());
3189 NS_ASSERTION(GetScriptableTop() &&
3190 GetScriptableTop()->GetCurrentInnerWindowInternal() == this,
3191 "DialogsAreBeingAbused called with invalid window");
3193 if (mLastDialogQuitTime
.IsNull() ||
3194 nsContentUtils::IsCallerChrome()) {
3198 TimeDuration
dialogInterval(TimeStamp::Now() - mLastDialogQuitTime
);
3199 if (dialogInterval
.ToSeconds() <
3200 Preferences::GetInt("dom.successive_dialog_time_limit",
3201 DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT
)) {
3202 mDialogAbuseCount
++;
3204 return GetPopupControlState() > openAllowed
||
3205 mDialogAbuseCount
> MAX_SUCCESSIVE_DIALOG_COUNT
;
3208 // Reset the abuse counter
3209 mDialogAbuseCount
= 0;
3215 nsGlobalWindow::ConfirmDialogIfNeeded()
3217 MOZ_ASSERT(IsOuterWindow());
3219 NS_ENSURE_TRUE(mDocShell
, false);
3220 nsCOMPtr
<nsIPromptService
> promptSvc
=
3221 do_GetService("@mozilla.org/embedcomp/prompt-service;1");
3227 // Reset popup state while opening a modal dialog, and firing events
3228 // about the dialog, to prevent the current state from being active
3229 // the whole time a modal dialog is open.
3230 nsAutoPopupStatePusher
popupStatePusher(openAbused
, true);
3232 bool disableDialog
= false;
3233 nsXPIDLString label
, title
;
3234 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES
,
3235 "ScriptDialogLabel", label
);
3236 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES
,
3237 "ScriptDialogPreventTitle", title
);
3238 promptSvc
->Confirm(this, title
.get(), label
.get(), &disableDialog
);
3239 if (disableDialog
) {
3248 nsGlobalWindow::DisableDialogs()
3250 nsGlobalWindow
*topWindow
= GetScriptableTop();
3252 NS_ERROR("DisableDialogs() called without a top window?");
3256 topWindow
= topWindow
->GetCurrentInnerWindowInternal();
3257 // TODO: Warn if no top window?
3259 topWindow
->mAreDialogsEnabled
= false;
3264 nsGlobalWindow::EnableDialogs()
3266 nsGlobalWindow
*topWindow
= GetScriptableTop();
3268 NS_ERROR("EnableDialogs() called without a top window?");
3272 // TODO: Warn if no top window?
3273 topWindow
= topWindow
->GetCurrentInnerWindowInternal();
3275 topWindow
->mAreDialogsEnabled
= true;
3280 nsGlobalWindow::PostHandleEvent(EventChainPostVisitor
& aVisitor
)
3282 NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
3284 // Return early if there is nothing to do.
3285 switch (aVisitor
.mEvent
->message
) {
3286 case NS_RESIZE_EVENT
:
3287 case NS_PAGE_UNLOAD
:
3294 /* mChromeEventHandler and mContext go dangling in the middle of this
3295 function under some circumstances (events that destroy the window)
3296 without this addref. */
3297 nsCOMPtr
<nsIDOMEventTarget
> kungFuDeathGrip1(mChromeEventHandler
);
3298 nsCOMPtr
<nsIScriptContext
> kungFuDeathGrip2(GetContextInternal());
3300 if (aVisitor
.mEvent
->message
== NS_RESIZE_EVENT
) {
3301 mIsHandlingResizeEvent
= false;
3302 } else if (aVisitor
.mEvent
->message
== NS_PAGE_UNLOAD
&&
3303 aVisitor
.mEvent
->mFlags
.mIsTrusted
) {
3304 // Execute bindingdetached handlers before we tear ourselves
3307 mDoc
->BindingManager()->ExecuteDetachedHandlers();
3309 mIsDocumentLoaded
= false;
3310 } else if (aVisitor
.mEvent
->message
== NS_LOAD
&&
3311 aVisitor
.mEvent
->mFlags
.mIsTrusted
) {
3312 // This is page load event since load events don't propagate to |window|.
3313 // @see nsDocument::PreHandleEvent.
3314 mIsDocumentLoaded
= true;
3316 nsCOMPtr
<Element
> element
= GetFrameElementInternal();
3317 nsIDocShell
* docShell
= GetDocShell();
3318 if (element
&& GetParentInternal() &&
3319 docShell
&& docShell
->ItemType() != nsIDocShellTreeItem::typeChrome
) {
3320 // If we're not in chrome, or at a chrome boundary, fire the
3321 // onload event for the frame element.
3323 nsEventStatus status
= nsEventStatus_eIgnore
;
3324 WidgetEvent
event(aVisitor
.mEvent
->mFlags
.mIsTrusted
, NS_LOAD
);
3325 event
.mFlags
.mBubbles
= false;
3327 // Most of the time we could get a pres context to pass in here,
3328 // but not always (i.e. if this window is not shown there won't
3329 // be a pres context available). Since we're not firing a GUI
3330 // event we don't need a pres context anyway so we just pass
3331 // null as the pres context all the time here.
3332 EventDispatcher::Dispatch(element
, nullptr, &event
, nullptr, &status
);
3340 nsGlobalWindow::DispatchDOMEvent(WidgetEvent
* aEvent
,
3341 nsIDOMEvent
* aDOMEvent
,
3342 nsPresContext
* aPresContext
,
3343 nsEventStatus
* aEventStatus
)
3345 return EventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow
*>(this),
3346 aEvent
, aDOMEvent
, aPresContext
,
3351 nsGlobalWindow::PoisonOuterWindowProxy(JSObject
*aObject
)
3353 MOZ_ASSERT(IsOuterWindow());
3354 if (aObject
== GetWrapperPreserveColor()) {
3360 nsGlobalWindow::SetArguments(nsIArray
*aArguments
)
3362 MOZ_ASSERT(IsOuterWindow());
3365 // Historically, we've used the same machinery to handle openDialog arguments
3366 // (exposed via window.arguments) and showModalDialog arguments (exposed via
3367 // window.dialogArguments), even though the former is XUL-only and uses an XPCOM
3368 // array while the latter is web-exposed and uses an arbitrary JS value.
3369 // Moreover, per-spec |dialogArguments| is a property of the browsing context
3370 // (outer), whereas |arguments| lives on the inner.
3372 // We've now mostly separated them, but the difference is still opaque to
3373 // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
3374 // embedding waltz we do here).
3376 // So we need to demultiplex the two cases here.
3377 nsGlobalWindow
*currentInner
= GetCurrentInnerWindowInternal();
3378 if (mIsModalContentWindow
) {
3379 // nsWindowWatcher blindly converts the original nsISupports into an array
3380 // of length 1. We need to recover it, and then cast it back to the concrete
3381 // object we know it to be.
3382 nsCOMPtr
<nsISupports
> supports
= do_QueryElementAt(aArguments
, 0, &rv
);
3383 NS_ENSURE_SUCCESS(rv
, rv
);
3384 mDialogArguments
= static_cast<DialogValueHolder
*>(supports
.get());
3386 mArguments
= aArguments
;
3387 rv
= currentInner
->DefineArgumentsProperty(aArguments
);
3388 NS_ENSURE_SUCCESS(rv
, rv
);
3395 nsGlobalWindow::DefineArgumentsProperty(nsIArray
*aArguments
)
3397 MOZ_ASSERT(IsInnerWindow());
3398 MOZ_ASSERT(!mIsModalContentWindow
); // Handled separately.
3400 nsIScriptContext
*ctx
= GetOuterWindowInternal()->mContext
;
3401 NS_ENSURE_TRUE(aArguments
&& ctx
, NS_ERROR_NOT_INITIALIZED
);
3404 JS::Rooted
<JSObject
*> obj(cx
, GetWrapperPreserveColor());
3405 return ctx
->SetProperty(obj
, "arguments", aArguments
);
3408 //*****************************************************************************
3409 // nsGlobalWindow::nsIScriptObjectPrincipal
3410 //*****************************************************************************
3413 nsGlobalWindow::GetPrincipal()
3416 // If we have a document, get the principal from the document
3417 return mDoc
->NodePrincipal();
3420 if (mDocumentPrincipal
) {
3421 return mDocumentPrincipal
;
3424 // If we don't have a principal and we don't have a document we
3425 // ask the parent window for the principal. This can happen when
3426 // loading a frameset that has a <frame src="javascript:xxx">, in
3427 // that case the global window is used in JS before we've loaded
3428 // a document into the window.
3430 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
3431 do_QueryInterface(GetParentInternal());
3434 return objPrincipal
->GetPrincipal();
3440 //*****************************************************************************
3441 // nsGlobalWindow::nsIDOMWindow
3442 //*****************************************************************************
3445 nsPIDOMWindow::GetDocumentURI() const
3447 return mDoc
? mDoc
->GetDocumentURI() : mDocumentURI
.get();
3451 nsPIDOMWindow::GetDocBaseURI() const
3453 return mDoc
? mDoc
->GetDocBaseURI() : mDocBaseURI
.get();
3457 nsPIDOMWindow::MaybeCreateDoc()
3460 if (nsIDocShell
* docShell
= GetDocShell()) {
3461 // Note that |document| here is the same thing as our mDoc, but we
3462 // don't have to explicitly set the member variable because the docshell
3463 // has already called SetNewDocument().
3464 nsCOMPtr
<nsIDocument
> document
= docShell
->GetDocument();
3469 nsPIDOMWindow::GetFrameElementInternal() const
3472 return mOuterWindow
->GetFrameElementInternal();
3475 NS_ASSERTION(!IsInnerWindow(),
3476 "GetFrameElementInternal() called on orphan inner window");
3478 return mFrameElement
;
3482 nsPIDOMWindow::SetFrameElementInternal(Element
* aFrameElement
)
3484 if (IsOuterWindow()) {
3485 mFrameElement
= aFrameElement
;
3490 if (!mOuterWindow
) {
3491 NS_ERROR("frameElement set on inner window with no outer!");
3496 mOuterWindow
->SetFrameElementInternal(aFrameElement
);
3500 nsPIDOMWindow::AddAudioContext(AudioContext
* aAudioContext
)
3502 MOZ_ASSERT(IsInnerWindow());
3504 mAudioContexts
.AppendElement(aAudioContext
);
3506 nsIDocShell
* docShell
= GetDocShell();
3507 if (docShell
&& !docShell
->GetAllowMedia() && !aAudioContext
->IsOffline()) {
3508 aAudioContext
->Mute();
3513 nsPIDOMWindow::RemoveAudioContext(AudioContext
* aAudioContext
)
3515 MOZ_ASSERT(IsInnerWindow());
3517 mAudioContexts
.RemoveElement(aAudioContext
);
3521 nsPIDOMWindow::MuteAudioContexts()
3523 MOZ_ASSERT(IsInnerWindow());
3525 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
3526 if (!mAudioContexts
[i
]->IsOffline()) {
3527 mAudioContexts
[i
]->Mute();
3533 nsPIDOMWindow::UnmuteAudioContexts()
3535 MOZ_ASSERT(IsInnerWindow());
3537 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
3538 if (!mAudioContexts
[i
]->IsOffline()) {
3539 mAudioContexts
[i
]->Unmute();
3545 nsGlobalWindow::GetDocument(nsIDOMDocument
** aDocument
)
3547 nsCOMPtr
<nsIDOMDocument
> document
= do_QueryInterface(GetDocument());
3548 document
.forget(aDocument
);
3553 nsGlobalWindow::GetWindow(ErrorResult
& aError
)
3555 FORWARD_TO_OUTER_OR_THROW(GetWindow
, (aError
), aError
, nullptr);
3561 nsGlobalWindow::GetWindow(nsIDOMWindow
** aWindow
)
3564 nsCOMPtr
<nsIDOMWindow
> window
= GetWindow(rv
);
3565 window
.forget(aWindow
);
3567 return rv
.ErrorCode();
3571 nsGlobalWindow::GetSelf(ErrorResult
& aError
)
3573 FORWARD_TO_OUTER_OR_THROW(GetSelf
, (aError
), aError
, nullptr);
3579 nsGlobalWindow::GetSelf(nsIDOMWindow
** aWindow
)
3582 nsCOMPtr
<nsIDOMWindow
> window
= GetSelf(rv
);
3583 window
.forget(aWindow
);
3585 return rv
.ErrorCode();
3589 nsGlobalWindow::GetNavigator(ErrorResult
& aError
)
3591 FORWARD_TO_INNER_OR_THROW(GetNavigator
, (aError
), aError
, nullptr);
3594 mNavigator
= new Navigator(this);
3601 nsGlobalWindow::GetNavigator(nsIDOMNavigator
** aNavigator
)
3604 nsCOMPtr
<nsIDOMNavigator
> navigator
= GetNavigator(rv
);
3605 navigator
.forget(aNavigator
);
3607 return rv
.ErrorCode();
3611 nsGlobalWindow::GetScreen(ErrorResult
& aError
)
3613 FORWARD_TO_INNER_OR_THROW(GetScreen
, (aError
), aError
, nullptr);
3616 mScreen
= nsScreen::Create(this);
3618 aError
.Throw(NS_ERROR_UNEXPECTED
);
3627 nsGlobalWindow::GetScreen(nsIDOMScreen
** aScreen
)
3630 nsRefPtr
<nsScreen
> screen
= GetScreen(rv
);
3631 screen
.forget(aScreen
);
3633 return rv
.ErrorCode();
3637 nsGlobalWindow::GetHistory(ErrorResult
& aError
)
3639 FORWARD_TO_INNER_OR_THROW(GetHistory
, (aError
), aError
, nullptr);
3642 mHistory
= new nsHistory(this);
3649 nsGlobalWindow::GetHistory(nsISupports
** aHistory
)
3652 nsCOMPtr
<nsISupports
> history
= GetHistory(rv
);
3653 history
.forget(aHistory
);
3655 return rv
.ErrorCode();
3659 nsGlobalWindow::GetPerformance(ErrorResult
& aError
)
3661 FORWARD_TO_INNER_OR_THROW(GetPerformance
, (aError
), aError
, nullptr);
3663 nsPerformance
* p
= nsPIDOMWindow::GetPerformance();
3665 aError
.Throw(NS_ERROR_FAILURE
);
3671 nsGlobalWindow::GetPerformance(nsISupports
** aPerformance
)
3674 nsCOMPtr
<nsISupports
> performance
= GetPerformance(rv
);
3675 performance
.forget(aPerformance
);
3677 return rv
.ErrorCode();
3681 nsPIDOMWindow::GetPerformance()
3683 MOZ_ASSERT(IsInnerWindow());
3684 CreatePerformanceObjectIfNeeded();
3685 return mPerformance
;
3689 nsPIDOMWindow::CreatePerformanceObjectIfNeeded()
3691 MOZ_ASSERT(IsInnerWindow());
3693 if (mPerformance
|| !mDoc
) {
3696 nsRefPtr
<nsDOMNavigationTiming
> timing
= mDoc
->GetNavigationTiming();
3697 nsCOMPtr
<nsITimedChannel
> timedChannel(do_QueryInterface(mDoc
->GetChannel()));
3698 bool timingEnabled
= false;
3699 if (!timedChannel
||
3700 !NS_SUCCEEDED(timedChannel
->GetTimingEnabled(&timingEnabled
)) ||
3702 timedChannel
= nullptr;
3705 // If we are dealing with an iframe, we will need the parent's performance
3706 // object (so we can add the iframe as a resource of that page).
3707 nsPerformance
* parentPerformance
= nullptr;
3708 nsCOMPtr
<nsIDOMWindow
> parentWindow
;
3709 GetScriptableParent(getter_AddRefs(parentWindow
));
3710 nsCOMPtr
<nsPIDOMWindow
> parentPWindow
= do_GetInterface(parentWindow
);
3711 if (GetOuterWindow() != parentPWindow
) {
3712 if (parentPWindow
&& !parentPWindow
->IsInnerWindow()) {
3713 parentPWindow
= parentPWindow
->GetCurrentInnerWindow();
3715 if (parentPWindow
) {
3716 parentPerformance
= parentPWindow
->GetPerformance();
3720 new nsPerformance(this, timing
, timedChannel
, parentPerformance
);
3725 nsPIDOMWindow::GetAudioMuted() const
3727 if (!IsInnerWindow()) {
3728 return mInnerWindow
->GetAudioMuted();
3735 nsPIDOMWindow::SetAudioMuted(bool aMuted
)
3737 if (!IsInnerWindow()) {
3738 mInnerWindow
->SetAudioMuted(aMuted
);
3742 if (mAudioMuted
== aMuted
) {
3746 mAudioMuted
= aMuted
;
3747 RefreshMediaElements();
3751 nsPIDOMWindow::GetAudioVolume() const
3753 if (!IsInnerWindow()) {
3754 return mInnerWindow
->GetAudioVolume();
3757 return mAudioVolume
;
3761 nsPIDOMWindow::SetAudioVolume(float aVolume
)
3763 if (!IsInnerWindow()) {
3764 return mInnerWindow
->SetAudioVolume(aVolume
);
3767 if (aVolume
< 0.0) {
3768 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
3771 if (mAudioVolume
== aVolume
) {
3775 mAudioVolume
= aVolume
;
3776 RefreshMediaElements();
3781 nsPIDOMWindow::GetAudioGlobalVolume()
3783 float globalVolume
= 1.0;
3784 nsCOMPtr
<nsPIDOMWindow
> window
= this;
3787 if (window
->GetAudioMuted()) {
3791 globalVolume
*= window
->GetAudioVolume();
3793 nsCOMPtr
<nsIDOMWindow
> win
;
3794 window
->GetParent(getter_AddRefs(win
));
3795 if (window
== win
) {
3799 window
= do_QueryInterface(win
);
3801 // If there is not parent, or we are the toplevel or the volume is
3802 // already 0.0, we don't continue.
3803 } while (window
&& window
!= this && globalVolume
);
3805 return globalVolume
;
3809 nsPIDOMWindow::RefreshMediaElements()
3811 nsRefPtr
<AudioChannelService
> service
=
3812 AudioChannelService::GetOrCreateAudioChannelService();
3813 service
->RefreshAgentsVolume(this);
3817 nsPIDOMWindow::SendAfterRemotePaintIfRequested()
3819 if (!mSendAfterRemotePaint
) {
3823 mSendAfterRemotePaint
= false;
3825 nsContentUtils::DispatchChromeEvent(GetExtantDoc(),
3827 NS_LITERAL_STRING("MozAfterRemotePaint"),
3831 // nsISpeechSynthesisGetter
3833 #ifdef MOZ_WEBSPEECH
3835 nsGlobalWindow::GetSpeechSynthesis(ErrorResult
& aError
)
3837 FORWARD_TO_INNER_OR_THROW(GetSpeechSynthesis
, (aError
), aError
, nullptr);
3839 if (!mSpeechSynthesis
) {
3840 mSpeechSynthesis
= new SpeechSynthesis(this);
3843 return mSpeechSynthesis
;
3847 nsGlobalWindow::GetSpeechSynthesis(nsISupports
** aSpeechSynthesis
)
3850 nsCOMPtr
<nsISupports
> speechSynthesis
;
3851 if (Preferences::GetBool("media.webspeech.synth.enabled")) {
3852 speechSynthesis
= GetSpeechSynthesis(rv
);
3854 speechSynthesis
.forget(aSpeechSynthesis
);
3856 return rv
.ErrorCode();
3860 already_AddRefed
<nsIDOMWindow
>
3861 nsGlobalWindow::GetParent(ErrorResult
& aError
)
3863 FORWARD_TO_OUTER_OR_THROW(GetParent
, (aError
), aError
, nullptr);
3869 nsCOMPtr
<nsIDOMWindow
> parent
;
3870 if (mDocShell
->GetIsBrowserOrApp()) {
3873 aError
= GetRealParent(getter_AddRefs(parent
));
3876 return parent
.forget();
3880 * GetScriptableParent is called when script reads window.parent.
3882 * In contrast to GetRealParent, GetScriptableParent respects <iframe
3883 * mozbrowser> boundaries, so if |this| is contained by an <iframe
3884 * mozbrowser>, we will return |this| as its own parent.
3887 nsGlobalWindow::GetScriptableParent(nsIDOMWindow
** aParent
)
3890 nsCOMPtr
<nsIDOMWindow
> parent
= GetParent(rv
);
3891 parent
.forget(aParent
);
3893 return rv
.ErrorCode();
3897 * nsIDOMWindow::GetParent (when called from C++) is just a wrapper around
3901 nsGlobalWindow::GetRealParent(nsIDOMWindow
** aParent
)
3903 FORWARD_TO_OUTER(GetRealParent
, (aParent
), NS_ERROR_NOT_INITIALIZED
);
3910 nsCOMPtr
<nsIDocShell
> parent
;
3911 mDocShell
->GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent
));
3914 nsCOMPtr
<nsPIDOMWindow
> win
= parent
->GetWindow();
3915 win
.forget(aParent
);
3918 *aParent
= static_cast<nsIDOMWindow
*>(this);
3919 NS_ADDREF(*aParent
);
3925 GetTopImpl(nsGlobalWindow
* aWin
, nsIDOMWindow
** aTop
, bool aScriptable
)
3929 // Walk up the parent chain.
3931 nsCOMPtr
<nsIDOMWindow
> prevParent
= aWin
;
3932 nsCOMPtr
<nsIDOMWindow
> parent
= aWin
;
3938 prevParent
= parent
;
3940 nsCOMPtr
<nsIDOMWindow
> newParent
;
3943 rv
= parent
->GetScriptableParent(getter_AddRefs(newParent
));
3946 rv
= parent
->GetParent(getter_AddRefs(newParent
));
3948 NS_ENSURE_SUCCESS(rv
, rv
);
3952 } while (parent
!= prevParent
);
3962 * GetScriptableTop is called when script reads window.top.
3964 * In contrast to GetRealTop, GetScriptableTop respects <iframe mozbrowser>
3965 * boundaries. If we encounter a window owned by an <iframe mozbrowser> while
3966 * walking up the window hierarchy, we'll stop and return that window.
3969 nsGlobalWindow::GetScriptableTop(nsIDOMWindow
**aTop
)
3971 FORWARD_TO_OUTER(GetScriptableTop
, (aTop
), NS_ERROR_NOT_INITIALIZED
);
3972 return GetTopImpl(this, aTop
, /* aScriptable = */ true);
3976 * nsIDOMWindow::GetTop (when called from C++) is just a wrapper around
3980 nsGlobalWindow::GetRealTop(nsIDOMWindow
** aTop
)
3982 nsGlobalWindow
* outer
;
3983 if (IsInnerWindow()) {
3984 outer
= GetOuterWindowInternal();
3986 NS_WARNING("No outer window available!");
3987 return NS_ERROR_NOT_INITIALIZED
;
3992 return GetTopImpl(outer
, aTop
, /* aScriptable = */ false);
3996 nsGlobalWindow::GetContent(JSContext
* aCx
,
3997 JS::MutableHandle
<JSObject
*> aRetval
,
3998 ErrorResult
& aError
)
4000 FORWARD_TO_OUTER_OR_THROW(GetContent
, (aCx
, aRetval
, aError
), aError
, );
4002 nsCOMPtr
<nsIDOMWindow
> content
= GetContentInternal(aError
);
4003 if (aError
.Failed()) {
4008 JS::Rooted
<JS::Value
> val(aCx
);
4009 aError
= nsContentUtils::WrapNative(aCx
, content
, &val
);
4010 if (aError
.Failed()) {
4014 aRetval
.set(&val
.toObject());
4018 aRetval
.set(nullptr);
4022 already_AddRefed
<nsIDOMWindow
>
4023 nsGlobalWindow::GetContentInternal(ErrorResult
& aError
)
4025 // First check for a named frame named "content"
4026 nsCOMPtr
<nsIDOMWindow
> domWindow
=
4027 GetChildWindow(NS_LITERAL_STRING("content"));
4029 return domWindow
.forget();
4032 // If we're contained in <iframe mozbrowser> or <iframe mozapp>, then
4033 // GetContent is the same as window.top.
4034 if (mDocShell
&& mDocShell
->GetIsInBrowserOrApp()) {
4035 return GetTop(aError
);
4038 nsCOMPtr
<nsIDocShellTreeItem
> primaryContent
;
4039 if (!nsContentUtils::IsCallerChrome()) {
4040 // If we're called by non-chrome code, make sure we don't return
4041 // the primary content window if the calling tab is hidden. In
4042 // such a case we return the same-type root in the hidden tab,
4043 // which is "good enough", for now.
4044 nsCOMPtr
<nsIBaseWindow
> baseWin(do_QueryInterface(mDocShell
));
4047 bool visible
= false;
4048 baseWin
->GetVisibility(&visible
);
4051 mDocShell
->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent
));
4056 if (!primaryContent
) {
4057 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
= GetTreeOwner();
4059 aError
.Throw(NS_ERROR_FAILURE
);
4063 treeOwner
->GetPrimaryContentShell(getter_AddRefs(primaryContent
));
4066 if (!primaryContent
) {
4070 domWindow
= primaryContent
->GetWindow();
4071 return domWindow
.forget();
4075 nsGlobalWindow::GetContent(nsIDOMWindow
** aContent
)
4078 *aContent
= GetContentInternal(rv
).take();
4080 return rv
.ErrorCode();
4084 nsGlobalWindow::GetMozSelfSupport(ErrorResult
& aError
)
4086 if (mMozSelfSupport
) {
4087 return mMozSelfSupport
;
4090 AutoSafeJSContext cx
;
4091 GlobalObject
global(cx
, FastGetGlobalJSObject());
4092 mMozSelfSupport
= MozSelfSupport::Constructor(global
, cx
, aError
);
4093 return mMozSelfSupport
;
4097 nsGlobalWindow::GetScriptableContent(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aVal
)
4100 JS::Rooted
<JSObject
*> content(aCx
);
4101 GetContent(aCx
, &content
, rv
);
4103 aVal
.setObjectOrNull(content
);
4106 return rv
.ErrorCode();
4110 nsGlobalWindow::GetPrompter(nsIPrompt
** aPrompt
)
4112 if (IsInnerWindow()) {
4113 nsGlobalWindow
* outer
= GetOuterWindowInternal();
4115 NS_WARNING("No outer window available!");
4116 return NS_ERROR_NOT_INITIALIZED
;
4118 return outer
->GetPrompter(aPrompt
);
4122 return NS_ERROR_FAILURE
;
4124 nsCOMPtr
<nsIPrompt
> prompter(do_GetInterface(mDocShell
));
4125 NS_ENSURE_TRUE(prompter
, NS_ERROR_NO_INTERFACE
);
4127 NS_ADDREF(*aPrompt
= prompter
);
4132 nsGlobalWindow::GetMenubar(ErrorResult
& aError
)
4134 FORWARD_TO_INNER_OR_THROW(GetMenubar
, (aError
), aError
, nullptr);
4137 mMenubar
= new MenubarProp(this);
4144 nsGlobalWindow::GetMenubar(nsISupports
** aMenubar
)
4147 nsCOMPtr
<nsISupports
> menubar
= GetMenubar(rv
);
4148 menubar
.forget(aMenubar
);
4150 return rv
.ErrorCode();
4154 nsGlobalWindow::GetToolbar(ErrorResult
& aError
)
4156 FORWARD_TO_INNER_OR_THROW(GetToolbar
, (aError
), aError
, nullptr);
4159 mToolbar
= new ToolbarProp(this);
4166 nsGlobalWindow::GetToolbar(nsISupports
** aToolbar
)
4169 nsCOMPtr
<nsISupports
> toolbar
= GetToolbar(rv
);
4170 toolbar
.forget(aToolbar
);
4172 return rv
.ErrorCode();
4176 nsGlobalWindow::GetLocationbar(ErrorResult
& aError
)
4178 FORWARD_TO_INNER_OR_THROW(GetLocationbar
, (aError
), aError
, nullptr);
4180 if (!mLocationbar
) {
4181 mLocationbar
= new LocationbarProp(this);
4183 return mLocationbar
;
4187 nsGlobalWindow::GetLocationbar(nsISupports
** aLocationbar
)
4190 nsCOMPtr
<nsISupports
> locationbar
= GetLocationbar(rv
);
4191 locationbar
.forget(aLocationbar
);
4193 return rv
.ErrorCode();
4197 nsGlobalWindow::GetPersonalbar(ErrorResult
& aError
)
4199 FORWARD_TO_INNER_OR_THROW(GetPersonalbar
, (aError
), aError
, nullptr);
4201 if (!mPersonalbar
) {
4202 mPersonalbar
= new PersonalbarProp(this);
4204 return mPersonalbar
;
4208 nsGlobalWindow::GetPersonalbar(nsISupports
** aPersonalbar
)
4211 nsCOMPtr
<nsISupports
> personalbar
= GetPersonalbar(rv
);
4212 personalbar
.forget(aPersonalbar
);
4214 return rv
.ErrorCode();
4218 nsGlobalWindow::GetStatusbar(ErrorResult
& aError
)
4220 FORWARD_TO_INNER_OR_THROW(GetStatusbar
, (aError
), aError
, nullptr);
4223 mStatusbar
= new StatusbarProp(this);
4229 nsGlobalWindow::GetStatusbar(nsISupports
** aStatusbar
)
4232 nsCOMPtr
<nsISupports
> statusbar
= GetStatusbar(rv
);
4233 statusbar
.forget(aStatusbar
);
4235 return rv
.ErrorCode();
4239 nsGlobalWindow::GetScrollbars(ErrorResult
& aError
)
4241 FORWARD_TO_INNER_OR_THROW(GetScrollbars
, (aError
), aError
, nullptr);
4244 mScrollbars
= new ScrollbarsProp(this);
4251 nsGlobalWindow::GetScrollbars(nsISupports
** aScrollbars
)
4254 nsCOMPtr
<nsISupports
> scrollbars
= GetScrollbars(rv
);
4255 scrollbars
.forget(aScrollbars
);
4257 return rv
.ErrorCode();
4261 nsGlobalWindow::GetClosed(ErrorResult
& aError
)
4263 FORWARD_TO_OUTER_OR_THROW(GetClosed
, (aError
), aError
, false);
4265 // If someone called close(), or if we don't have a docshell, we're closed.
4266 return mIsClosed
|| !mDocShell
;
4270 nsGlobalWindow::GetClosed(bool* aClosed
)
4273 *aClosed
= GetClosed(rv
);
4275 return rv
.ErrorCode();
4279 nsGlobalWindow::GetWindowList()
4281 MOZ_ASSERT(IsOuterWindow());
4283 if (!mFrames
&& mDocShell
) {
4284 mFrames
= new nsDOMWindowList(mDocShell
);
4291 nsGlobalWindow::GetFrames(nsIDOMWindowCollection
** aFrames
)
4293 FORWARD_TO_OUTER(GetFrames
, (aFrames
), NS_ERROR_NOT_INITIALIZED
);
4295 *aFrames
= GetWindowList();
4296 NS_IF_ADDREF(*aFrames
);
4300 already_AddRefed
<nsIDOMWindow
>
4301 nsGlobalWindow::IndexedGetter(uint32_t aIndex
, bool& aFound
)
4305 FORWARD_TO_OUTER(IndexedGetter
, (aIndex
, aFound
), nullptr);
4307 nsDOMWindowList
* windows
= GetWindowList();
4308 NS_ENSURE_TRUE(windows
, nullptr);
4310 return windows
->IndexedGetter(aIndex
, aFound
);
4314 nsGlobalWindow::GetSupportedNames(nsTArray
<nsString
>& aNames
)
4316 FORWARD_TO_OUTER_VOID(GetSupportedNames
, (aNames
));
4318 nsDOMWindowList
* windows
= GetWindowList();
4320 uint32_t length
= windows
->GetLength();
4321 nsString
* name
= aNames
.AppendElements(length
);
4322 for (uint32_t i
= 0; i
< length
; ++i
, ++name
) {
4323 nsCOMPtr
<nsIDocShellTreeItem
> item
=
4324 windows
->GetDocShellTreeItemAt(i
);
4325 item
->GetName(*name
);
4331 nsGlobalWindow::DoNewResolve(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
4332 JS::Handle
<jsid
> aId
,
4333 JS::MutableHandle
<JSPropertyDescriptor
> aDesc
)
4335 MOZ_ASSERT(IsInnerWindow());
4337 // Note: The infallibleInit call in GlobalResolve depends on this check.
4338 if (!JSID_IS_STRING(aId
)) {
4342 nsresult rv
= nsWindowSH::GlobalResolve(this, aCx
, aObj
, aId
, aDesc
);
4343 if (NS_FAILED(rv
)) {
4344 return Throw(aCx
, rv
);
4350 struct GlobalNameEnumeratorClosure
4352 GlobalNameEnumeratorClosure(JSContext
* aCx
, nsGlobalWindow
* aWindow
,
4353 nsTArray
<nsString
>& aNames
)
4356 mWrapper(aCx
, aWindow
->GetWrapper()),
4362 nsGlobalWindow
* mWindow
;
4363 JS::Rooted
<JSObject
*> mWrapper
;
4364 nsTArray
<nsString
>& mNames
;
4367 static PLDHashOperator
4368 EnumerateGlobalName(const nsAString
& aName
,
4369 const nsGlobalNameStruct
& aNameStruct
,
4372 GlobalNameEnumeratorClosure
* closure
=
4373 static_cast<GlobalNameEnumeratorClosure
*>(aClosure
);
4375 if (nsWindowSH::NameStructEnabled(closure
->mCx
, closure
->mWindow
, aName
,
4377 (!aNameStruct
.mConstructorEnabled
||
4378 aNameStruct
.mConstructorEnabled(closure
->mCx
, closure
->mWrapper
))) {
4379 closure
->mNames
.AppendElement(aName
);
4381 return PL_DHASH_NEXT
;
4385 nsGlobalWindow::GetOwnPropertyNames(JSContext
* aCx
, nsTArray
<nsString
>& aNames
,
4388 // "Components" is marked as enumerable but only resolved on demand :-/.
4389 //aNames.AppendElement(NS_LITERAL_STRING("Components"));
4391 nsScriptNameSpaceManager
* nameSpaceManager
= GetNameSpaceManager();
4392 if (nameSpaceManager
) {
4393 GlobalNameEnumeratorClosure
closure(aCx
, this, aNames
);
4394 nameSpaceManager
->EnumerateGlobalNames(EnumerateGlobalName
, &closure
);
4399 nsGlobalWindow::IsChromeWindow(JSContext
* aCx
, JSObject
* aObj
)
4401 // For now, have to deal with XPConnect objects here.
4402 return xpc::WindowOrNull(aObj
)->IsChromeWindow();
4406 nsGlobalWindow::IsShowModalDialogEnabled(JSContext
*, JSObject
*)
4408 static bool sAddedPrefCache
= false;
4409 static bool sIsDisabled
;
4410 static const char sShowModalDialogPref
[] = "dom.disable_window_showModalDialog";
4412 if (!sAddedPrefCache
) {
4413 Preferences::AddBoolVarCache(&sIsDisabled
, sShowModalDialogPref
, false);
4414 sAddedPrefCache
= true;
4417 return !sIsDisabled
;
4420 nsIDOMOfflineResourceList
*
4421 nsGlobalWindow::GetApplicationCache(ErrorResult
& aError
)
4423 FORWARD_TO_INNER_OR_THROW(GetApplicationCache
, (aError
), aError
, nullptr);
4425 if (!mApplicationCache
) {
4426 nsCOMPtr
<nsIWebNavigation
> webNav(do_QueryInterface(GetDocShell()));
4428 aError
.Throw(NS_ERROR_FAILURE
);
4432 nsCOMPtr
<nsIURI
> uri
;
4433 aError
= webNav
->GetCurrentURI(getter_AddRefs(uri
));
4434 if (aError
.Failed()) {
4438 nsCOMPtr
<nsIURI
> manifestURI
;
4439 nsContentUtils::GetOfflineAppManifest(mDoc
, getter_AddRefs(manifestURI
));
4441 nsRefPtr
<nsDOMOfflineResourceList
> applicationCache
=
4442 new nsDOMOfflineResourceList(manifestURI
, uri
, this);
4444 applicationCache
->Init();
4446 mApplicationCache
= applicationCache
;
4449 return mApplicationCache
;
4453 nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList
**aApplicationCache
)
4456 nsCOMPtr
<nsIDOMOfflineResourceList
> applicationCache
=
4457 GetApplicationCache(rv
);
4458 applicationCache
.forget(aApplicationCache
);
4460 return rv
.ErrorCode();
4464 nsGlobalWindow::GetCrypto(ErrorResult
& aError
)
4466 FORWARD_TO_INNER_OR_THROW(GetCrypto
, (aError
), aError
, nullptr);
4469 #ifndef MOZ_DISABLE_CRYPTOLEGACY
4470 if (XRE_GetProcessType() != GeckoProcessType_Content
) {
4472 mCrypto
= do_CreateInstance(NS_CRYPTO_CONTRACTID
, &rv
);
4473 if (NS_FAILED(rv
)) {
4480 mCrypto
= new Crypto();
4483 mCrypto
->Init(this);
4489 nsGlobalWindow::GetCrypto(nsIDOMCrypto
** aCrypto
)
4492 nsCOMPtr
<nsIDOMCrypto
> crypto
= GetCrypto(rv
);
4493 crypto
.forget(aCrypto
);
4495 return rv
.ErrorCode();
4499 nsGlobalWindow::GetControllers(ErrorResult
& aError
)
4501 FORWARD_TO_OUTER_OR_THROW(GetControllers
, (aError
), aError
, nullptr);
4503 if (!mControllers
) {
4505 mControllers
= do_CreateInstance(kXULControllersCID
, &rv
);
4506 if (NS_FAILED(rv
)) {
4511 // Add in the default controller
4512 nsCOMPtr
<nsIController
> controller
= do_CreateInstance(
4513 NS_WINDOWCONTROLLER_CONTRACTID
, &rv
);
4514 if (NS_FAILED(rv
)) {
4519 mControllers
->InsertControllerAt(0, controller
);
4520 nsCOMPtr
<nsIControllerContext
> controllerContext
= do_QueryInterface(controller
);
4521 if (!controllerContext
) {
4522 aError
.Throw(NS_ERROR_FAILURE
);
4526 controllerContext
->SetCommandContext(static_cast<nsIDOMWindow
*>(this));
4529 return mControllers
;
4533 nsGlobalWindow::GetControllers(nsIControllers
** aResult
)
4536 nsCOMPtr
<nsIControllers
> controllers
= GetControllers(rv
);
4537 controllers
.forget(aResult
);
4539 return rv
.ErrorCode();
4543 nsGlobalWindow::GetOpenerWindow(ErrorResult
& aError
)
4545 FORWARD_TO_OUTER_OR_THROW(GetOpenerWindow
, (aError
), aError
, nullptr);
4547 nsCOMPtr
<nsPIDOMWindow
> opener
= do_QueryReferent(mOpener
);
4552 // First, check if we were called from a privileged chrome script
4553 if (nsContentUtils::IsCallerChrome()) {
4557 // First, ensure that we're not handing back a chrome window.
4558 nsGlobalWindow
*win
= static_cast<nsGlobalWindow
*>(opener
.get());
4559 if (win
->IsChromeWindow()) {
4563 // We don't want to reveal the opener if the opener is a mail window,
4564 // because opener can be used to spoof the contents of a message (bug 105050).
4565 // So, we look in the opener's root docshell to see if it's a mail window.
4566 nsCOMPtr
<nsIDocShell
> openerDocShell
= opener
->GetDocShell();
4568 if (openerDocShell
) {
4569 nsCOMPtr
<nsIDocShellTreeItem
> openerRootItem
;
4570 openerDocShell
->GetRootTreeItem(getter_AddRefs(openerRootItem
));
4571 nsCOMPtr
<nsIDocShell
> openerRootDocShell(do_QueryInterface(openerRootItem
));
4572 if (openerRootDocShell
) {
4574 nsresult rv
= openerRootDocShell
->GetAppType(&appType
);
4575 if (NS_SUCCEEDED(rv
) && appType
!= nsIDocShell::APP_TYPE_MAIL
) {
4585 nsGlobalWindow::GetOpener(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aRetval
,
4586 ErrorResult
& aError
)
4588 nsCOMPtr
<nsIDOMWindow
> opener
= GetOpenerWindow(aError
);
4589 if (aError
.Failed() || !opener
) {
4594 aError
= nsContentUtils::WrapNative(aCx
, opener
, aRetval
);
4598 nsGlobalWindow::GetScriptableOpener(JSContext
* aCx
,
4599 JS::MutableHandle
<JS::Value
> aOpener
)
4602 GetOpener(aCx
, aOpener
, rv
);
4604 return rv
.ErrorCode();
4608 nsGlobalWindow::GetOpener(nsIDOMWindow
** aOpener
)
4611 nsCOMPtr
<nsIDOMWindow
> opener
= GetOpenerWindow(rv
);
4612 opener
.forget(aOpener
);
4613 return rv
.ErrorCode();
4617 nsGlobalWindow::SetOpener(JSContext
* aCx
, JS::Handle
<JS::Value
> aOpener
,
4618 ErrorResult
& aError
)
4620 // Check if we were called from a privileged chrome script. If not, and if
4621 // aOpener is not null, just define aOpener on our inner window's JS object,
4622 // wrapped into the current compartment so that for Xrays we define on the
4623 // Xray expando object, but don't set it on the outer window, so that it'll
4624 // get reset on navigation. This is just like replaceable properties, but
4625 // we're not quite readonly.
4626 if (!aOpener
.isNull() && !nsContentUtils::IsCallerChrome()) {
4627 JS::Rooted
<JSObject
*> thisObj(aCx
, GetWrapperPreserveColor());
4629 aError
.Throw(NS_ERROR_UNEXPECTED
);
4633 if (!JS_WrapObject(aCx
, &thisObj
) ||
4634 !JS_DefineProperty(aCx
, thisObj
, "opener", aOpener
, JSPROP_ENUMERATE
,
4635 JS_PropertyStub
, JS_StrictPropertyStub
)) {
4636 aError
.Throw(NS_ERROR_FAILURE
);
4642 if (!aOpener
.isObjectOrNull()) {
4643 // Chrome code trying to set some random value as opener
4644 aError
.Throw(NS_ERROR_INVALID_ARG
);
4648 nsPIDOMWindow
* win
= nullptr;
4649 if (aOpener
.isObject()) {
4650 JSObject
* unwrapped
= js::CheckedUnwrap(&aOpener
.toObject(),
4651 /* stopAtOuter = */ false);
4653 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
4657 win
= xpc::WindowOrNull(unwrapped
);
4660 aError
.Throw(NS_ERROR_INVALID_ARG
);
4665 if (win
&& win
->IsInnerWindow()) {
4666 if (!win
->IsCurrentInnerWindow()) {
4667 aError
.Throw(NS_ERROR_FAILURE
);
4670 win
= win
->GetOuterWindow();
4673 SetOpenerWindow(win
, false);
4677 nsGlobalWindow::SetScriptableOpener(JSContext
* aCx
,
4678 JS::Handle
<JS::Value
> aOpener
)
4681 SetOpener(aCx
, aOpener
, rv
);
4683 return rv
.ErrorCode();
4687 nsGlobalWindow::SetOpener(nsIDOMWindow
* aOpener
)
4689 SetOpenerWindow(aOpener
, false);
4694 nsGlobalWindow::GetStatus(nsAString
& aStatus
, ErrorResult
& aError
)
4696 FORWARD_TO_OUTER_OR_THROW(GetStatus
, (aStatus
, aError
), aError
, );
4702 nsGlobalWindow::GetStatus(nsAString
& aStatus
)
4705 GetStatus(aStatus
, rv
);
4707 return rv
.ErrorCode();
4711 nsGlobalWindow::SetStatus(const nsAString
& aStatus
, ErrorResult
& aError
)
4713 FORWARD_TO_OUTER_OR_THROW(SetStatus
, (aStatus
, aError
), aError
, );
4718 * If caller is not chrome and dom.disable_window_status_change is true,
4719 * prevent propagating window.status to the UI by exiting early
4722 if (!CanSetProperty("dom.disable_window_status_change")) {
4726 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome
= GetWebBrowserChrome();
4727 if (browserChrome
) {
4728 browserChrome
->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT
,
4729 PromiseFlatString(aStatus
).get());
4734 nsGlobalWindow::SetStatus(const nsAString
& aStatus
)
4737 SetStatus(aStatus
, rv
);
4739 return rv
.ErrorCode();
4743 nsGlobalWindow::GetName(nsAString
& aName
, ErrorResult
& aError
)
4745 FORWARD_TO_OUTER_OR_THROW(GetName
, (aName
, aError
), aError
, );
4748 mDocShell
->GetName(aName
);
4753 nsGlobalWindow::GetName(nsAString
& aName
)
4758 return rv
.ErrorCode();
4762 nsGlobalWindow::SetName(const nsAString
& aName
, mozilla::ErrorResult
& aError
)
4764 FORWARD_TO_OUTER_OR_THROW(SetName
, (aName
, aError
), aError
, );
4767 aError
= mDocShell
->SetName(aName
);
4772 nsGlobalWindow::SetName(const nsAString
& aName
)
4777 return rv
.ErrorCode();
4780 // Helper functions used by many methods below.
4782 nsGlobalWindow::DevToCSSIntPixels(int32_t px
)
4785 return px
; // assume 1:1
4787 nsRefPtr
<nsPresContext
> presContext
;
4788 mDocShell
->GetPresContext(getter_AddRefs(presContext
));
4792 return presContext
->DevPixelsToIntCSSPixels(px
);
4796 nsGlobalWindow::CSSToDevIntPixels(int32_t px
)
4799 return px
; // assume 1:1
4801 nsRefPtr
<nsPresContext
> presContext
;
4802 mDocShell
->GetPresContext(getter_AddRefs(presContext
));
4806 return presContext
->CSSPixelsToDevPixels(px
);
4810 nsGlobalWindow::DevToCSSIntPixels(nsIntSize px
)
4813 return px
; // assume 1:1
4815 nsRefPtr
<nsPresContext
> presContext
;
4816 mDocShell
->GetPresContext(getter_AddRefs(presContext
));
4821 presContext
->DevPixelsToIntCSSPixels(px
.width
),
4822 presContext
->DevPixelsToIntCSSPixels(px
.height
));
4826 nsGlobalWindow::CSSToDevIntPixels(nsIntSize px
)
4829 return px
; // assume 1:1
4831 nsRefPtr
<nsPresContext
> presContext
;
4832 mDocShell
->GetPresContext(getter_AddRefs(presContext
));
4837 presContext
->CSSPixelsToDevPixels(px
.width
),
4838 presContext
->CSSPixelsToDevPixels(px
.height
));
4842 nsGlobalWindow::GetInnerSize(CSSIntSize
& aSize
)
4844 MOZ_ASSERT(IsOuterWindow());
4846 EnsureSizeUpToDate();
4848 NS_ENSURE_STATE(mDocShell
);
4850 nsRefPtr
<nsPresContext
> presContext
;
4851 mDocShell
->GetPresContext(getter_AddRefs(presContext
));
4852 nsRefPtr
<nsIPresShell
> presShell
= mDocShell
->GetPresShell();
4854 if (!presContext
|| !presShell
) {
4855 aSize
= CSSIntSize(0, 0);
4860 * On platforms with resolution-based zooming, the CSS viewport
4861 * and visual viewport may not be the same. The inner size should
4862 * be the visual viewport, but we fall back to the CSS viewport
4865 if (presShell
->IsScrollPositionClampingScrollPortSizeSet()) {
4866 aSize
= CSSIntRect::FromAppUnitsRounded(
4867 presShell
->GetScrollPositionClampingScrollPortSize());
4869 nsRefPtr
<nsViewManager
> viewManager
= presShell
->GetViewManager();
4871 viewManager
->FlushDelayedResize(false);
4874 aSize
= CSSIntRect::FromAppUnitsRounded(
4875 presContext
->GetVisibleArea().Size());
4881 nsGlobalWindow::GetInnerWidth(ErrorResult
& aError
)
4883 FORWARD_TO_OUTER_OR_THROW(GetInnerWidth
, (aError
), aError
, 0);
4886 aError
= GetInnerSize(size
);
4891 nsGlobalWindow::GetInnerWidth(int32_t* aInnerWidth
)
4894 *aInnerWidth
= GetInnerWidth(rv
);
4896 return rv
.ErrorCode();
4900 nsGlobalWindow::SetInnerWidth(int32_t aInnerWidth
, ErrorResult
& aError
)
4902 FORWARD_TO_OUTER_OR_THROW(SetInnerWidth
, (aInnerWidth
, aError
), aError
, );
4905 aError
.Throw(NS_ERROR_UNEXPECTED
);
4910 * If caller is not chrome and the user has not explicitly exempted the site,
4911 * prevent setting window.innerWidth by exiting early
4913 if (!CanMoveResizeWindows() || IsFrame()) {
4917 CheckSecurityWidthAndHeight(&aInnerWidth
, nullptr);
4919 nsRefPtr
<nsIPresShell
> presShell
= mDocShell
->GetPresShell();
4921 if (presShell
&& presShell
->GetIsViewportOverridden())
4925 nsRefPtr
<nsPresContext
> presContext
;
4926 presContext
= presShell
->GetPresContext();
4928 nsRect shellArea
= presContext
->GetVisibleArea();
4929 height
= shellArea
.height
;
4930 SetCSSViewportWidthAndHeight(nsPresContext::CSSPixelsToAppUnits(aInnerWidth
),
4938 nsCOMPtr
<nsIBaseWindow
> docShellAsWin(do_QueryInterface(mDocShell
));
4939 docShellAsWin
->GetSize(&unused
, &height
);
4940 aError
= SetDocShellWidthAndHeight(CSSToDevIntPixels(aInnerWidth
), height
);
4944 nsGlobalWindow::SetInnerWidth(int32_t aInnerWidth
)
4947 SetInnerWidth(aInnerWidth
, rv
);
4949 return rv
.ErrorCode();
4953 nsGlobalWindow::GetInnerHeight(ErrorResult
& aError
)
4955 FORWARD_TO_OUTER_OR_THROW(GetInnerHeight
, (aError
), aError
, 0);
4958 aError
= GetInnerSize(size
);
4963 nsGlobalWindow::GetInnerHeight(int32_t* aInnerHeight
)
4966 *aInnerHeight
= GetInnerHeight(rv
);
4968 return rv
.ErrorCode();
4972 nsGlobalWindow::SetInnerHeight(int32_t aInnerHeight
, ErrorResult
& aError
)
4974 FORWARD_TO_OUTER_OR_THROW(SetInnerHeight
, (aInnerHeight
, aError
), aError
, );
4977 aError
.Throw(NS_ERROR_UNEXPECTED
);
4982 * If caller is not chrome and the user has not explicitly exempted the site,
4983 * prevent setting window.innerHeight by exiting early
4985 if (!CanMoveResizeWindows() || IsFrame()) {
4989 nsRefPtr
<nsIPresShell
> presShell
= mDocShell
->GetPresShell();
4991 if (presShell
&& presShell
->GetIsViewportOverridden())
4993 nsRefPtr
<nsPresContext
> presContext
;
4994 presContext
= presShell
->GetPresContext();
4996 nsRect shellArea
= presContext
->GetVisibleArea();
4997 nscoord height
= aInnerHeight
;
4998 nscoord width
= shellArea
.width
;
4999 CheckSecurityWidthAndHeight(nullptr, &height
);
5000 SetCSSViewportWidthAndHeight(width
,
5001 nsPresContext::CSSPixelsToAppUnits(height
));
5008 nsCOMPtr
<nsIBaseWindow
> docShellAsWin(do_QueryInterface(mDocShell
));
5009 docShellAsWin
->GetSize(&width
, &height
);
5010 CheckSecurityWidthAndHeight(nullptr, &aInnerHeight
);
5011 aError
= SetDocShellWidthAndHeight(width
, CSSToDevIntPixels(aInnerHeight
));
5015 nsGlobalWindow::SetInnerHeight(int32_t aInnerHeight
)
5018 SetInnerHeight(aInnerHeight
, rv
);
5020 return rv
.ErrorCode();
5024 nsGlobalWindow::GetOuterSize(ErrorResult
& aError
)
5026 MOZ_ASSERT(IsOuterWindow());
5028 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
5029 if (!treeOwnerAsWin
) {
5030 aError
.Throw(NS_ERROR_FAILURE
);
5031 return nsIntSize(0, 0);
5034 nsGlobalWindow
* rootWindow
=
5035 static_cast<nsGlobalWindow
*>(GetPrivateRoot());
5037 rootWindow
->FlushPendingNotifications(Flush_Layout
);
5040 nsIntSize sizeDevPixels
;
5041 aError
= treeOwnerAsWin
->GetSize(&sizeDevPixels
.width
, &sizeDevPixels
.height
);
5042 if (aError
.Failed()) {
5046 return DevToCSSIntPixels(sizeDevPixels
);
5050 nsGlobalWindow::GetOuterWidth(ErrorResult
& aError
)
5052 FORWARD_TO_OUTER_OR_THROW(GetOuterWidth
, (aError
), aError
, 0);
5053 return GetOuterSize(aError
).width
;
5057 nsGlobalWindow::GetOuterWidth(int32_t* aOuterWidth
)
5060 *aOuterWidth
= GetOuterWidth(rv
);
5062 return rv
.ErrorCode();
5066 nsGlobalWindow::GetOuterHeight(ErrorResult
& aError
)
5068 FORWARD_TO_OUTER_OR_THROW(GetOuterHeight
, (aError
), aError
, 0);
5069 return GetOuterSize(aError
).height
;
5073 nsGlobalWindow::GetOuterHeight(int32_t* aOuterHeight
)
5076 *aOuterHeight
= GetOuterHeight(rv
);
5078 return rv
.ErrorCode();
5082 nsGlobalWindow::SetOuterSize(int32_t aLengthCSSPixels
, bool aIsWidth
,
5083 ErrorResult
& aError
)
5085 MOZ_ASSERT(IsOuterWindow());
5088 * If caller is not chrome and the user has not explicitly exempted the site,
5089 * prevent setting window.outerWidth by exiting early
5092 if (!CanMoveResizeWindows() || IsFrame()) {
5096 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
5097 if (!treeOwnerAsWin
) {
5098 aError
.Throw(NS_ERROR_FAILURE
);
5102 CheckSecurityWidthAndHeight(aIsWidth
? &aLengthCSSPixels
: nullptr,
5103 aIsWidth
? nullptr : &aLengthCSSPixels
);
5105 int32_t width
, height
;
5106 aError
= treeOwnerAsWin
->GetSize(&width
, &height
);
5107 if (aError
.Failed()) {
5111 int32_t lengthDevPixels
= CSSToDevIntPixels(aLengthCSSPixels
);
5113 width
= lengthDevPixels
;
5115 height
= lengthDevPixels
;
5117 aError
= treeOwnerAsWin
->SetSize(width
, height
, true);
5121 nsGlobalWindow::SetOuterWidth(int32_t aOuterWidth
, ErrorResult
& aError
)
5123 FORWARD_TO_OUTER_OR_THROW(SetOuterWidth
, (aOuterWidth
, aError
), aError
, );
5125 SetOuterSize(aOuterWidth
, true, aError
);
5129 nsGlobalWindow::SetOuterWidth(int32_t aOuterWidth
)
5132 SetOuterWidth(aOuterWidth
, rv
);
5134 return rv
.ErrorCode();
5138 nsGlobalWindow::SetOuterHeight(int32_t aOuterHeight
, ErrorResult
& aError
)
5140 FORWARD_TO_OUTER_OR_THROW(SetOuterHeight
, (aOuterHeight
, aError
), aError
, );
5142 SetOuterSize(aOuterHeight
, false, aError
);
5146 nsGlobalWindow::SetOuterHeight(int32_t aOuterHeight
)
5149 SetOuterHeight(aOuterHeight
, rv
);
5151 return rv
.ErrorCode();
5155 nsGlobalWindow::GetScreenXY(ErrorResult
& aError
)
5157 MOZ_ASSERT(IsOuterWindow());
5159 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
5160 if (!treeOwnerAsWin
) {
5161 aError
.Throw(NS_ERROR_FAILURE
);
5162 return nsIntPoint(0, 0);
5165 int32_t x
= 0, y
= 0;
5166 aError
= treeOwnerAsWin
->GetPosition(&x
, &y
);
5167 return nsIntPoint(x
, y
);
5171 nsGlobalWindow::GetScreenX(ErrorResult
& aError
)
5173 FORWARD_TO_OUTER_OR_THROW(GetScreenX
, (aError
), aError
, 0);
5175 return DevToCSSIntPixels(GetScreenXY(aError
).x
);
5179 nsGlobalWindow::GetScreenX(int32_t* aScreenX
)
5182 *aScreenX
= GetScreenX(rv
);
5184 return rv
.ErrorCode();
5188 nsGlobalWindow::GetInnerScreenRect()
5190 MOZ_ASSERT(IsOuterWindow());
5196 nsGlobalWindow
* rootWindow
=
5197 static_cast<nsGlobalWindow
*>(GetPrivateRoot());
5199 rootWindow
->FlushPendingNotifications(Flush_Layout
);
5206 nsCOMPtr
<nsIPresShell
> presShell
= mDocShell
->GetPresShell();
5210 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
5215 return rootFrame
->GetScreenRectInAppUnits();
5219 nsGlobalWindow::GetMozInnerScreenX(ErrorResult
& aError
)
5221 FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenX
, (aError
), aError
, 0);
5223 nsRect r
= GetInnerScreenRect();
5224 return nsPresContext::AppUnitsToFloatCSSPixels(r
.x
);
5228 nsGlobalWindow::GetMozInnerScreenX(float* aScreenX
)
5231 *aScreenX
= GetMozInnerScreenX(rv
);
5233 return rv
.ErrorCode();
5237 nsGlobalWindow::GetMozInnerScreenY(ErrorResult
& aError
)
5239 FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenY
, (aError
), aError
, 0);
5241 nsRect r
= GetInnerScreenRect();
5242 return nsPresContext::AppUnitsToFloatCSSPixels(r
.y
);
5246 nsGlobalWindow::GetMozInnerScreenY(float* aScreenY
)
5249 *aScreenY
= GetMozInnerScreenY(rv
);
5251 return rv
.ErrorCode();
5255 nsGlobalWindow::GetDevicePixelRatio(ErrorResult
& aError
)
5257 FORWARD_TO_OUTER_OR_THROW(GetDevicePixelRatio
, (aError
), aError
, 0.0);
5263 nsRefPtr
<nsPresContext
> presContext
;
5264 mDocShell
->GetPresContext(getter_AddRefs(presContext
));
5269 return float(nsPresContext::AppUnitsPerCSSPixel())/
5270 presContext
->AppUnitsPerDevPixel();
5274 nsGlobalWindow::GetDevicePixelRatio(float* aRatio
)
5277 *aRatio
= GetDevicePixelRatio(rv
);
5279 return rv
.ErrorCode();
5283 nsGlobalWindow::GetMozPaintCount(ErrorResult
& aError
)
5285 FORWARD_TO_OUTER_OR_THROW(GetMozPaintCount
, (aError
), aError
, 0);
5291 nsCOMPtr
<nsIPresShell
> presShell
= mDocShell
->GetPresShell();
5292 return presShell
? presShell
->GetPaintCount() : 0;
5296 nsGlobalWindow::GetMozPaintCount(uint64_t* aResult
)
5299 *aResult
= GetMozPaintCount(rv
);
5301 return rv
.ErrorCode();
5305 nsGlobalWindow::MozRequestAnimationFrame(nsIFrameRequestCallback
* aCallback
,
5310 mDoc
->WarnOnceAbout(nsIDocument::eMozBeforePaint
);
5312 return NS_ERROR_XPC_BAD_CONVERT_JS
;
5316 nsIDocument::FrameRequestCallbackHolder
holder(aCallback
);
5317 *aHandle
= RequestAnimationFrame(holder
, rv
);
5319 return rv
.ErrorCode();
5323 nsGlobalWindow::RequestAnimationFrame(FrameRequestCallback
& aCallback
,
5324 ErrorResult
& aError
)
5326 nsIDocument::FrameRequestCallbackHolder
holder(&aCallback
);
5327 return RequestAnimationFrame(holder
, aError
);
5331 nsGlobalWindow::MozRequestAnimationFrame(nsIFrameRequestCallback
* aCallback
,
5332 ErrorResult
& aError
)
5334 nsIDocument::FrameRequestCallbackHolder
holder(aCallback
);
5335 return RequestAnimationFrame(holder
, aError
);
5339 nsGlobalWindow::RequestAnimationFrame(const nsIDocument::FrameRequestCallbackHolder
& aCallback
,
5340 ErrorResult
& aError
)
5342 FORWARD_TO_INNER_OR_THROW(RequestAnimationFrame
, (aCallback
, aError
), aError
,
5349 if (GetWrapperPreserveColor()) {
5350 js::NotifyAnimationActivity(GetWrapperPreserveColor());
5354 aError
= mDoc
->ScheduleFrameRequestCallback(aCallback
, &handle
);
5359 nsGlobalWindow::RequestAnimationFrame(JS::Handle
<JS::Value
> aCallback
,
5363 if (!aCallback
.isObject() || !JS_ObjectIsCallable(cx
, &aCallback
.toObject())) {
5364 return NS_ERROR_INVALID_ARG
;
5367 JS::Rooted
<JSObject
*> callbackObj(cx
, &aCallback
.toObject());
5368 nsRefPtr
<FrameRequestCallback
> callback
=
5369 new FrameRequestCallback(callbackObj
, GetIncumbentGlobal());
5372 *aHandle
= RequestAnimationFrame(*callback
, rv
);
5374 return rv
.ErrorCode();
5378 nsGlobalWindow::MozCancelRequestAnimationFrame(int32_t aHandle
)
5380 return CancelAnimationFrame(aHandle
);
5384 nsGlobalWindow::MozCancelAnimationFrame(int32_t aHandle
)
5386 return CancelAnimationFrame(aHandle
);
5390 nsGlobalWindow::CancelAnimationFrame(int32_t aHandle
, ErrorResult
& aError
)
5392 FORWARD_TO_INNER_OR_THROW(CancelAnimationFrame
, (aHandle
, aError
), aError
, );
5398 mDoc
->CancelFrameRequestCallback(aHandle
);
5402 nsGlobalWindow::CancelAnimationFrame(int32_t aHandle
)
5405 CancelAnimationFrame(aHandle
, rv
);
5407 return rv
.ErrorCode();
5411 nsGlobalWindow::GetMozAnimationStartTime(ErrorResult
& aError
)
5413 FORWARD_TO_INNER_OR_THROW(GetMozAnimationStartTime
, (aError
), aError
, 0);
5416 nsIPresShell
* presShell
= mDoc
->GetShell();
5418 return presShell
->GetPresContext()->RefreshDriver()->
5419 MostRecentRefreshEpochTime() / PR_USEC_PER_MSEC
;
5423 // If all else fails, just be compatible with Date.now()
5424 return JS_Now() / PR_USEC_PER_MSEC
;
5428 nsGlobalWindow::GetMozAnimationStartTime(int64_t *aTime
)
5431 *aTime
= GetMozAnimationStartTime(rv
);
5433 return rv
.ErrorCode();
5436 already_AddRefed
<MediaQueryList
>
5437 nsGlobalWindow::MatchMedia(const nsAString
& aMediaQueryList
,
5438 ErrorResult
& aError
)
5440 // FIXME: This whole forward-to-outer and then get a pres
5441 // shell/context off the docshell dance is sort of silly; it'd make
5442 // more sense to forward to the inner, but it's what everyone else
5443 // (GetSelection, GetScrollXY, etc.) does around here.
5444 FORWARD_TO_OUTER_OR_THROW(MatchMedia
, (aMediaQueryList
, aError
), aError
,
5447 // We need this now to ensure that we have a non-null |presContext|
5448 // when we ought to.
5449 // This is similar to EnsureSizeUpToDate, but only flushes frames.
5450 nsGlobalWindow
*parent
= static_cast<nsGlobalWindow
*>(GetPrivateParent());
5452 parent
->FlushPendingNotifications(Flush_Frames
);
5459 nsRefPtr
<nsPresContext
> presContext
;
5460 mDocShell
->GetPresContext(getter_AddRefs(presContext
));
5466 return presContext
->MatchMedia(aMediaQueryList
);
5470 nsGlobalWindow::MatchMedia(const nsAString
& aMediaQueryList
,
5471 nsISupports
** aResult
)
5474 nsRefPtr
<MediaQueryList
> mediaQueryList
= MatchMedia(aMediaQueryList
, rv
);
5475 mediaQueryList
.forget(aResult
);
5477 return rv
.ErrorCode();
5481 nsGlobalWindow::SetScreenX(int32_t aScreenX
, ErrorResult
& aError
)
5483 FORWARD_TO_OUTER_OR_THROW(SetScreenX
, (aScreenX
, aError
), aError
, );
5486 * If caller is not chrome and the user has not explicitly exempted the site,
5487 * prevent setting window.screenX by exiting early
5490 if (!CanMoveResizeWindows() || IsFrame()) {
5494 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
5495 if (!treeOwnerAsWin
) {
5496 aError
.Throw(NS_ERROR_FAILURE
);
5501 aError
= treeOwnerAsWin
->GetPosition(&x
, &y
);
5502 if (aError
.Failed()) {
5506 CheckSecurityLeftAndTop(&aScreenX
, nullptr);
5507 x
= CSSToDevIntPixels(aScreenX
);
5509 aError
= treeOwnerAsWin
->SetPosition(x
, y
);
5513 nsGlobalWindow::SetScreenX(int32_t aScreenX
)
5516 SetScreenX(aScreenX
, rv
);
5518 return rv
.ErrorCode();
5522 nsGlobalWindow::GetScreenY(ErrorResult
& aError
)
5524 FORWARD_TO_OUTER_OR_THROW(GetScreenY
, (aError
), aError
, 0);
5526 return DevToCSSIntPixels(GetScreenXY(aError
).y
);
5530 nsGlobalWindow::GetScreenY(int32_t* aScreenY
)
5533 *aScreenY
= GetScreenY(rv
);
5535 return rv
.ErrorCode();
5539 nsGlobalWindow::SetScreenY(int32_t aScreenY
, ErrorResult
& aError
)
5541 FORWARD_TO_OUTER_OR_THROW(SetScreenY
, (aScreenY
, aError
), aError
, );
5544 * If caller is not chrome and the user has not explicitly exempted the site,
5545 * prevent setting window.screenY by exiting early
5548 if (!CanMoveResizeWindows() || IsFrame()) {
5552 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
5553 if (!treeOwnerAsWin
) {
5554 aError
.Throw(NS_ERROR_FAILURE
);
5559 aError
= treeOwnerAsWin
->GetPosition(&x
, &y
);
5560 if (aError
.Failed()) {
5564 CheckSecurityLeftAndTop(nullptr, &aScreenY
);
5565 y
= CSSToDevIntPixels(aScreenY
);
5567 aError
= treeOwnerAsWin
->SetPosition(x
, y
);
5571 nsGlobalWindow::SetScreenY(int32_t aScreenY
)
5574 SetScreenY(aScreenY
, rv
);
5576 return rv
.ErrorCode();
5579 // NOTE: Arguments to this function should have values scaled to
5580 // CSS pixels, not device pixels.
5582 nsGlobalWindow::CheckSecurityWidthAndHeight(int32_t* aWidth
, int32_t* aHeight
)
5584 MOZ_ASSERT(IsOuterWindow());
5587 if (!nsContentUtils::IsCallerChrome()) {
5588 // if attempting to resize the window, hide any open popups
5589 nsContentUtils::HidePopupsInDocument(mDoc
);
5593 // This one is easy. Just ensure the variable is greater than 100;
5594 if ((aWidth
&& *aWidth
< 100) || (aHeight
&& *aHeight
< 100)) {
5595 // Check security state for use in determing window dimensions
5597 if (!nsContentUtils::IsCallerChrome()) {
5599 if (aWidth
&& *aWidth
< 100) {
5602 if (aHeight
&& *aHeight
< 100) {
5609 // NOTE: Arguments to this function should have values in device pixels
5611 nsGlobalWindow::SetDocShellWidthAndHeight(int32_t aInnerWidth
, int32_t aInnerHeight
)
5613 MOZ_ASSERT(IsOuterWindow());
5615 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_FAILURE
);
5617 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
5618 mDocShell
->GetTreeOwner(getter_AddRefs(treeOwner
));
5619 NS_ENSURE_TRUE(treeOwner
, NS_ERROR_FAILURE
);
5621 NS_ENSURE_SUCCESS(treeOwner
->SizeShellTo(mDocShell
, aInnerWidth
, aInnerHeight
),
5627 // NOTE: Arguments to this function should have values in app units
5629 nsGlobalWindow::SetCSSViewportWidthAndHeight(nscoord aInnerWidth
, nscoord aInnerHeight
)
5631 MOZ_ASSERT(IsOuterWindow());
5633 nsRefPtr
<nsPresContext
> presContext
;
5634 mDocShell
->GetPresContext(getter_AddRefs(presContext
));
5636 nsRect shellArea
= presContext
->GetVisibleArea();
5637 shellArea
.height
= aInnerHeight
;
5638 shellArea
.width
= aInnerWidth
;
5640 presContext
->SetVisibleArea(shellArea
);
5643 // NOTE: Arguments to this function should have values scaled to
5644 // CSS pixels, not device pixels.
5646 nsGlobalWindow::CheckSecurityLeftAndTop(int32_t* aLeft
, int32_t* aTop
)
5648 MOZ_ASSERT(IsOuterWindow());
5650 // This one is harder. We have to get the screen size and window dimensions.
5652 // Check security state for use in determing window dimensions
5654 if (!nsContentUtils::IsCallerChrome()) {
5656 // if attempting to move the window, hide any open popups
5657 nsContentUtils::HidePopupsInDocument(mDoc
);
5660 nsGlobalWindow
* rootWindow
=
5661 static_cast<nsGlobalWindow
*>(GetPrivateRoot());
5663 rootWindow
->FlushPendingNotifications(Flush_Layout
);
5666 nsCOMPtr
<nsIBaseWindow
> treeOwner
= GetTreeOwnerWindow();
5668 nsCOMPtr
<nsIDOMScreen
> screen
;
5669 GetScreen(getter_AddRefs(screen
));
5671 if (treeOwner
&& screen
) {
5672 int32_t screenLeft
, screenTop
, screenWidth
, screenHeight
;
5673 int32_t winLeft
, winTop
, winWidth
, winHeight
;
5675 // Get the window size
5676 treeOwner
->GetPositionAndSize(&winLeft
, &winTop
, &winWidth
, &winHeight
);
5678 // convert those values to CSS pixels
5679 // XXX four separate retrievals of the prescontext
5680 winLeft
= DevToCSSIntPixels(winLeft
);
5681 winTop
= DevToCSSIntPixels(winTop
);
5682 winWidth
= DevToCSSIntPixels(winWidth
);
5683 winHeight
= DevToCSSIntPixels(winHeight
);
5685 // Get the screen dimensions
5686 // XXX This should use nsIScreenManager once it's fully fleshed out.
5687 screen
->GetAvailLeft(&screenLeft
);
5688 screen
->GetAvailWidth(&screenWidth
);
5689 screen
->GetAvailHeight(&screenHeight
);
5690 #if defined(XP_MACOSX)
5691 /* The mac's coordinate system is different from the assumed Windows'
5692 system. It offsets by the height of the menubar so that a window
5693 placed at (0,0) will be entirely visible. Unfortunately that
5694 correction is made elsewhere (in Widget) and the meaning of
5695 the Avail... coordinates is overloaded. Here we allow a window
5696 to be placed at (0,0) because it does make sense to do so.
5698 screen
->GetTop(&screenTop
);
5700 screen
->GetAvailTop(&screenTop
);
5704 if (screenLeft
+screenWidth
< *aLeft
+winWidth
)
5705 *aLeft
= screenLeft
+screenWidth
- winWidth
;
5706 if (screenLeft
> *aLeft
)
5707 *aLeft
= screenLeft
;
5710 if (screenTop
+screenHeight
< *aTop
+winHeight
)
5711 *aTop
= screenTop
+screenHeight
- winHeight
;
5712 if (screenTop
> *aTop
)
5725 nsGlobalWindow::GetPageXOffset(int32_t* aPageXOffset
)
5727 return GetScrollX(aPageXOffset
);
5731 nsGlobalWindow::GetPageYOffset(int32_t* aPageYOffset
)
5733 return GetScrollY(aPageYOffset
);
5737 nsGlobalWindow::GetScrollMaxXY(int32_t* aScrollMaxX
, int32_t* aScrollMaxY
,
5738 ErrorResult
& aError
)
5740 FORWARD_TO_OUTER_OR_THROW(GetScrollMaxXY
, (aScrollMaxX
, aScrollMaxY
, aError
),
5743 FlushPendingNotifications(Flush_Layout
);
5744 nsIScrollableFrame
*sf
= GetScrollFrame();
5749 nsRect scrollRange
= sf
->GetScrollRange();
5752 *aScrollMaxX
= std::max(0,
5753 (int32_t)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange
.XMost())));
5756 *aScrollMaxY
= std::max(0,
5757 (int32_t)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange
.YMost())));
5762 nsGlobalWindow::GetScrollMaxX(ErrorResult
& aError
)
5764 int32_t scrollMaxX
= 0;
5765 GetScrollMaxXY(&scrollMaxX
, nullptr, aError
);
5770 nsGlobalWindow::GetScrollMaxX(int32_t* aScrollMaxX
)
5772 NS_ENSURE_ARG_POINTER(aScrollMaxX
);
5774 *aScrollMaxX
= GetScrollMaxX(rv
);
5776 return rv
.ErrorCode();
5780 nsGlobalWindow::GetScrollMaxY(ErrorResult
& aError
)
5782 int32_t scrollMaxY
= 0;
5783 GetScrollMaxXY(nullptr, &scrollMaxY
, aError
);
5788 nsGlobalWindow::GetScrollMaxY(int32_t* aScrollMaxY
)
5790 NS_ENSURE_ARG_POINTER(aScrollMaxY
);
5792 *aScrollMaxY
= GetScrollMaxY(rv
);
5794 return rv
.ErrorCode();
5798 nsGlobalWindow::GetScrollXY(bool aDoFlush
)
5800 MOZ_ASSERT(IsOuterWindow());
5803 FlushPendingNotifications(Flush_Layout
);
5805 EnsureSizeUpToDate();
5808 nsIScrollableFrame
*sf
= GetScrollFrame();
5810 return CSSIntPoint(0, 0);
5813 nsPoint scrollPos
= sf
->GetScrollPosition();
5814 if (scrollPos
!= nsPoint(0,0) && !aDoFlush
) {
5815 // Oh, well. This is the expensive case -- the window is scrolled and we
5816 // didn't actually flush yet. Repeat, but with a flush, since the content
5817 // may get shorter and hence our scroll position may decrease.
5818 return GetScrollXY(true);
5821 return sf
->GetScrollPositionCSSPixels();
5825 nsGlobalWindow::GetScrollX(ErrorResult
& aError
)
5827 FORWARD_TO_OUTER_OR_THROW(GetScrollX
, (aError
), aError
, 0);
5828 return GetScrollXY(false).x
;
5832 nsGlobalWindow::GetScrollX(int32_t* aScrollX
)
5834 NS_ENSURE_ARG_POINTER(aScrollX
);
5836 *aScrollX
= GetScrollX(rv
);
5837 return rv
.ErrorCode();
5841 nsGlobalWindow::GetScrollY(ErrorResult
& aError
)
5843 FORWARD_TO_OUTER_OR_THROW(GetScrollY
, (aError
), aError
, 0);
5844 return GetScrollXY(false).y
;
5848 nsGlobalWindow::GetScrollY(int32_t* aScrollY
)
5850 NS_ENSURE_ARG_POINTER(aScrollY
);
5852 *aScrollY
= GetScrollY(rv
);
5853 return rv
.ErrorCode();
5857 nsGlobalWindow::Length()
5859 FORWARD_TO_OUTER(Length
, (), 0);
5861 nsDOMWindowList
* windows
= GetWindowList();
5863 return windows
? windows
->GetLength() : 0;
5867 nsGlobalWindow::GetLength(uint32_t* aLength
)
5869 *aLength
= Length();
5874 nsGlobalWindow::GetChildWindow(const nsAString
& aName
)
5876 nsCOMPtr
<nsIDocShell
> docShell(GetDocShell());
5877 NS_ENSURE_TRUE(docShell
, nullptr);
5879 nsCOMPtr
<nsIDocShellTreeItem
> child
;
5880 docShell
->FindChildWithName(PromiseFlatString(aName
).get(),
5881 false, true, nullptr, nullptr,
5882 getter_AddRefs(child
));
5884 return child
? child
->GetWindow() : nullptr;
5888 nsGlobalWindow::DispatchCustomEvent(const nsAString
& aEventName
)
5890 MOZ_ASSERT(IsOuterWindow());
5892 bool defaultActionEnabled
= true;
5893 nsContentUtils::DispatchTrustedEvent(mDoc
, ToSupports(this), aEventName
,
5894 true, true, &defaultActionEnabled
);
5896 return defaultActionEnabled
;
5900 nsGlobalWindow::DispatchResizeEvent(const CSSIntSize
& aSize
)
5902 MOZ_ASSERT(IsOuterWindow());
5905 nsRefPtr
<Event
> domEvent
=
5906 mDoc
->CreateEvent(NS_LITERAL_STRING("CustomEvent"), res
);
5911 AutoSafeJSContext cx
;
5912 JSAutoCompartment
ac(cx
, GetWrapperPreserveColor());
5913 DOMWindowResizeEventDetail detail
;
5914 detail
.mWidth
= aSize
.width
;
5915 detail
.mHeight
= aSize
.height
;
5916 JS::Rooted
<JS::Value
> detailValue(cx
);
5917 if (!ToJSValue(cx
, detail
, &detailValue
)) {
5921 CustomEvent
* customEvent
= static_cast<CustomEvent
*>(domEvent
.get());
5922 customEvent
->InitCustomEvent(cx
,
5923 NS_LITERAL_STRING("DOMWindowResize"),
5924 /* bubbles = */ true,
5925 /* cancelable = */ true,
5932 domEvent
->SetTrusted(true);
5933 domEvent
->GetInternalNSEvent()->mFlags
.mOnlyChromeDispatch
= true;
5935 nsCOMPtr
<EventTarget
> target
= do_QueryInterface(GetOuterWindow());
5936 domEvent
->SetTarget(target
);
5938 bool defaultActionEnabled
= true;
5939 target
->DispatchEvent(domEvent
, &defaultActionEnabled
);
5941 return defaultActionEnabled
;
5945 nsGlobalWindow::RefreshCompartmentPrincipal()
5947 MOZ_ASSERT(IsInnerWindow());
5949 JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()),
5950 nsJSPrincipals::get(mDoc
->NodePrincipal()));
5953 static already_AddRefed
<nsIDocShellTreeItem
>
5954 GetCallerDocShellTreeItem()
5956 nsCOMPtr
<nsIWebNavigation
> callerWebNav
= do_GetInterface(GetEntryGlobal());
5957 nsCOMPtr
<nsIDocShellTreeItem
> callerItem
= do_QueryInterface(callerWebNav
);
5959 return callerItem
.forget();
5963 nsGlobalWindow::WindowExists(const nsAString
& aName
,
5964 bool aLookForCallerOnJSStack
)
5966 NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
5967 NS_PRECONDITION(mDocShell
, "Must have docshell");
5969 nsCOMPtr
<nsIDocShellTreeItem
> caller
;
5970 if (aLookForCallerOnJSStack
) {
5971 caller
= GetCallerDocShellTreeItem();
5978 nsCOMPtr
<nsIDocShellTreeItem
> namedItem
;
5979 mDocShell
->FindItemWithName(PromiseFlatString(aName
).get(), nullptr, caller
,
5980 getter_AddRefs(namedItem
));
5981 return namedItem
!= nullptr;
5984 already_AddRefed
<nsIWidget
>
5985 nsGlobalWindow::GetMainWidget()
5987 FORWARD_TO_OUTER(GetMainWidget
, (), nullptr);
5989 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
5991 nsCOMPtr
<nsIWidget
> widget
;
5993 if (treeOwnerAsWin
) {
5994 treeOwnerAsWin
->GetMainWidget(getter_AddRefs(widget
));
5997 return widget
.forget();
6001 nsGlobalWindow::GetNearestWidget()
6003 nsIDocShell
* docShell
= GetDocShell();
6004 NS_ENSURE_TRUE(docShell
, nullptr);
6005 nsCOMPtr
<nsIPresShell
> presShell
= docShell
->GetPresShell();
6006 NS_ENSURE_TRUE(presShell
, nullptr);
6007 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
6008 NS_ENSURE_TRUE(rootFrame
, nullptr);
6009 return rootFrame
->GetView()->GetNearestWidget(nullptr);
6013 nsGlobalWindow::SetFullScreen(bool aFullScreen
, mozilla::ErrorResult
& aError
)
6015 FORWARD_TO_OUTER_OR_THROW(SetFullScreen
, (aFullScreen
, aError
), aError
, /* void */);
6017 aError
= SetFullScreenInternal(aFullScreen
, true);
6021 nsGlobalWindow::SetFullScreen(bool aFullScreen
)
6023 FORWARD_TO_OUTER(SetFullScreen
, (aFullScreen
), NS_ERROR_NOT_INITIALIZED
);
6025 return SetFullScreenInternal(aFullScreen
, true);
6029 nsGlobalWindow::SetFullScreenInternal(bool aFullScreen
, bool aRequireTrust
)
6031 MOZ_ASSERT(IsOuterWindow());
6033 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_FAILURE
);
6035 // Only chrome can change our fullScreen mode, unless we're running in
6037 if (aFullScreen
== FullScreen() ||
6038 (aRequireTrust
&& !nsContentUtils::IsCallerChrome())) {
6042 // SetFullScreen needs to be called on the root window, so get that
6043 // via the DocShell tree, and if we are not already the root,
6044 // call SetFullScreen on that window instead.
6045 nsCOMPtr
<nsIDocShellTreeItem
> rootItem
;
6046 mDocShell
->GetRootTreeItem(getter_AddRefs(rootItem
));
6047 nsCOMPtr
<nsPIDOMWindow
> window
= rootItem
? rootItem
->GetWindow() : nullptr;
6049 return NS_ERROR_FAILURE
;
6050 if (rootItem
!= mDocShell
)
6051 return window
->SetFullScreenInternal(aFullScreen
, aRequireTrust
);
6053 // make sure we don't try to set full screen on a non-chrome window,
6054 // which might happen in embedding world
6055 if (mDocShell
->ItemType() != nsIDocShellTreeItem::typeChrome
)
6056 return NS_ERROR_FAILURE
;
6058 // If we are already in full screen mode, just return.
6059 if (mFullScreen
== aFullScreen
)
6062 // dispatch a "fullscreen" DOM event so that XUL apps can
6063 // respond visually if we are kicked into full screen mode
6064 if (!DispatchCustomEvent(NS_LITERAL_STRING("fullscreen"))) {
6068 // Prevent chrome documents which are still loading from resizing
6069 // the window after we set fullscreen mode.
6070 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
6071 nsCOMPtr
<nsIXULWindow
> xulWin(do_GetInterface(treeOwnerAsWin
));
6072 if (aFullScreen
&& xulWin
) {
6073 xulWin
->SetIntrinsicallySized(false);
6076 // Set this before so if widget sends an event indicating its
6077 // gone full screen, the state trap above works.
6078 mFullScreen
= aFullScreen
;
6080 // Sometimes we don't want the top-level widget to actually go fullscreen,
6081 // for example in the B2G desktop client, we don't want the emulated screen
6082 // dimensions to appear to increase when entering fullscreen mode; we just
6083 // want the content to fill the entire client area of the emulator window.
6084 if (!Preferences::GetBool("full-screen-api.ignore-widgets", false)) {
6085 nsCOMPtr
<nsIWidget
> widget
= GetMainWidget();
6087 widget
->MakeFullScreen(aFullScreen
);
6091 // Force exit from DOM full-screen mode. This is so that if we're in
6092 // DOM full-screen mode and the user exits full-screen mode with
6093 // the browser full-screen mode toggle keyboard-shortcut, we'll detect
6094 // that and leave DOM API full-screen mode too.
6095 nsIDocument::ExitFullscreen(mDoc
, /* async */ false);
6098 if (!mWakeLock
&& mFullScreen
) {
6099 nsRefPtr
<power::PowerManagerService
> pmService
=
6100 power::PowerManagerService::GetInstance();
6101 NS_ENSURE_TRUE(pmService
, NS_OK
);
6104 mWakeLock
= pmService
->NewWakeLock(NS_LITERAL_STRING("DOM_Fullscreen"),
6107 return rv
.ErrorCode();
6110 } else if (mWakeLock
&& !mFullScreen
) {
6112 mWakeLock
->Unlock(rv
);
6113 NS_WARN_IF_FALSE(!rv
.Failed(), "Failed to unlock the wakelock.");
6114 mWakeLock
= nullptr;
6121 nsGlobalWindow::FullScreen() const
6123 MOZ_ASSERT(IsOuterWindow());
6125 NS_ENSURE_TRUE(mDocShell
, mFullScreen
);
6127 // Get the fullscreen value of the root window, to always have the value
6128 // accurate, even when called from content.
6129 nsCOMPtr
<nsIDocShellTreeItem
> rootItem
;
6130 mDocShell
->GetRootTreeItem(getter_AddRefs(rootItem
));
6131 if (rootItem
== mDocShell
) {
6132 // We are the root window. Return our internal value.
6136 nsCOMPtr
<nsIDOMWindow
> window
= rootItem
->GetWindow();
6137 NS_ENSURE_TRUE(window
, mFullScreen
);
6139 return static_cast<nsGlobalWindow
*>(window
.get())->FullScreen();
6143 nsGlobalWindow::GetFullScreen(ErrorResult
& aError
)
6145 FORWARD_TO_OUTER_OR_THROW(GetFullScreen
, (aError
), aError
, false);
6146 return FullScreen();
6150 nsGlobalWindow::GetFullScreen(bool* aFullScreen
)
6153 *aFullScreen
= GetFullScreen(rv
);
6155 return rv
.ErrorCode();
6159 nsGlobalWindow::Dump(const nsAString
& aStr
)
6161 if (!nsContentUtils::DOMWindowDumpEnabled()) {
6165 char *cstr
= ToNewUTF8String(aStr
);
6167 #if defined(XP_MACOSX)
6168 // have to convert \r to \n so that printing to the console works
6169 char *c
= cstr
, *cEnd
= cstr
+ strlen(cstr
);
6179 PrintToDebugger(cstr
);
6182 __android_log_write(ANDROID_LOG_INFO
, "GeckoDump", cstr
);
6184 FILE *fp
= gDumpFile
? gDumpFile
: stdout
;
6187 nsMemory::Free(cstr
);
6194 nsGlobalWindow::EnsureReflowFlushAndPaint()
6196 MOZ_ASSERT(IsOuterWindow());
6197 NS_ASSERTION(mDocShell
, "EnsureReflowFlushAndPaint() called with no "
6203 nsCOMPtr
<nsIPresShell
> presShell
= mDocShell
->GetPresShell();
6208 // Flush pending reflows.
6210 mDoc
->FlushPendingNotifications(Flush_Layout
);
6213 // Unsuppress painting.
6214 presShell
->UnsuppressPainting();
6218 nsGlobalWindow::GetTextZoom(float *aZoom
)
6220 FORWARD_TO_OUTER(GetTextZoom
, (aZoom
), NS_ERROR_NOT_INITIALIZED
);
6223 nsCOMPtr
<nsIContentViewer
> contentViewer
;
6224 mDocShell
->GetContentViewer(getter_AddRefs(contentViewer
));
6226 if (contentViewer
) {
6227 return contentViewer
->GetTextZoom(aZoom
);
6230 return NS_ERROR_FAILURE
;
6234 nsGlobalWindow::SetTextZoom(float aZoom
)
6236 FORWARD_TO_OUTER(SetTextZoom
, (aZoom
), NS_ERROR_NOT_INITIALIZED
);
6239 nsCOMPtr
<nsIContentViewer
> contentViewer
;
6240 mDocShell
->GetContentViewer(getter_AddRefs(contentViewer
));
6243 return contentViewer
->SetTextZoom(aZoom
);
6245 return NS_ERROR_FAILURE
;
6250 nsGlobalWindow::MakeScriptDialogTitle(nsAString
&aOutTitle
)
6252 aOutTitle
.Truncate();
6254 // Try to get a host from the running principal -- this will do the
6255 // right thing for javascript: and data: documents.
6257 nsCOMPtr
<nsIPrincipal
> principal
= nsContentUtils::SubjectPrincipal();
6258 nsCOMPtr
<nsIURI
> uri
;
6259 nsresult rv
= principal
->GetURI(getter_AddRefs(uri
));
6260 // Note - The check for the current JSContext here isn't necessarily sensical.
6261 // It's just designed to preserve existing behavior during a mass-conversion
6263 if (NS_SUCCEEDED(rv
) && uri
&& nsContentUtils::GetCurrentJSContext()) {
6264 // remove user:pass for privacy and spoof prevention
6266 nsCOMPtr
<nsIURIFixup
> fixup(do_GetService(NS_URIFIXUP_CONTRACTID
));
6268 nsCOMPtr
<nsIURI
> fixedURI
;
6269 rv
= fixup
->CreateExposableURI(uri
, getter_AddRefs(fixedURI
));
6270 if (NS_SUCCEEDED(rv
) && fixedURI
) {
6272 fixedURI
->GetHost(host
);
6274 if (!host
.IsEmpty()) {
6275 // if this URI has a host we'll show it. For other
6276 // schemes (e.g. file:) we fall back to the localized
6279 nsAutoCString prepath
;
6280 fixedURI
->GetPrePath(prepath
);
6282 NS_ConvertUTF8toUTF16
ucsPrePath(prepath
);
6283 const char16_t
*formatStrings
[] = { ucsPrePath
.get() };
6284 nsXPIDLString tempString
;
6285 nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES
,
6289 aOutTitle
= tempString
;
6295 if (aOutTitle
.IsEmpty()) {
6296 // We didn't find a host so use the generic heading
6297 nsXPIDLString tempString
;
6298 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES
,
6299 "ScriptDlgGenericHeading",
6301 aOutTitle
= tempString
;
6305 if (aOutTitle
.IsEmpty()) {
6306 NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
6307 aOutTitle
.AssignLiteral("[Script]");
6312 nsGlobalWindow::CanMoveResizeWindows()
6314 MOZ_ASSERT(IsOuterWindow());
6316 // When called from chrome, we can avoid the following checks.
6317 if (!nsContentUtils::IsCallerChrome()) {
6318 // Don't allow scripts to move or resize windows that were not opened by a
6320 if (!mHadOriginalOpener
) {
6324 if (!CanSetProperty("dom.disable_window_move_resize")) {
6328 // Ignore the request if we have more than one tab in the window.
6329 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
= GetTreeOwner();
6332 if (NS_SUCCEEDED(treeOwner
->GetTargetableShellCount(&itemCount
)) &&
6339 // The preference is useful for the webapp runtime. Webapps should be able
6340 // to resize or move their window.
6341 if (mDocShell
&& !Preferences::GetBool("dom.always_allow_move_resize_window",
6344 nsresult rv
= mDocShell
->GetAllowWindowControl(&allow
);
6345 if (NS_SUCCEEDED(rv
) && !allow
)
6349 if (gMouseDown
&& !gDragServiceDisabled
) {
6350 nsCOMPtr
<nsIDragService
> ds
=
6351 do_GetService("@mozilla.org/widget/dragservice;1");
6353 gDragServiceDisabled
= true;
6361 nsGlobalWindow::AlertOrConfirm(bool aAlert
,
6362 const nsAString
& aMessage
,
6363 mozilla::ErrorResult
& aError
)
6365 // XXX This method is very similar to nsGlobalWindow::Prompt, make
6366 // sure any modifications here don't need to happen over there!
6367 MOZ_ASSERT(IsOuterWindow());
6369 if (!AreDialogsEnabled()) {
6370 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
6374 // Reset popup state while opening a modal dialog, and firing events
6375 // about the dialog, to prevent the current state from being active
6376 // the whole time a modal dialog is open.
6377 nsAutoPopupStatePusher
popupStatePusher(openAbused
, true);
6379 // Before bringing up the window, unsuppress painting and flush
6381 EnsureReflowFlushAndPaint();
6384 MakeScriptDialogTitle(title
);
6386 // Remove non-terminating null characters from the
6387 // string. See bug #310037.
6389 nsContentUtils::StripNullChars(aMessage
, final
);
6392 nsCOMPtr
<nsIPromptFactory
> promptFac
=
6393 do_GetService("@mozilla.org/prompter;1", &rv
);
6394 if (NS_FAILED(rv
)) {
6399 nsCOMPtr
<nsIPrompt
> prompt
;
6400 aError
= promptFac
->GetPrompt(this, NS_GET_IID(nsIPrompt
),
6401 getter_AddRefs(prompt
));
6402 if (aError
.Failed()) {
6406 // Always allow tab modal prompts for alert and confirm.
6407 if (nsCOMPtr
<nsIWritablePropertyBag2
> promptBag
= do_QueryInterface(prompt
)) {
6408 promptBag
->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
6411 bool result
= false;
6412 nsAutoSyncOperation
sync(mDoc
);
6413 if (ShouldPromptToBlockDialogs()) {
6414 bool disallowDialog
= false;
6415 nsXPIDLString label
;
6416 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES
,
6417 "ScriptDialogLabel", label
);
6420 prompt
->AlertCheck(title
.get(), final
.get(), label
.get(),
6422 prompt
->ConfirmCheck(title
.get(), final
.get(), label
.get(),
6423 &disallowDialog
, &result
);
6429 prompt
->Alert(title
.get(), final
.get()) :
6430 prompt
->Confirm(title
.get(), final
.get(), &result
);
6437 nsGlobalWindow::Alert(mozilla::ErrorResult
& aError
)
6439 Alert(EmptyString(), aError
);
6443 nsGlobalWindow::Alert(const nsAString
& aMessage
, mozilla::ErrorResult
& aError
)
6445 FORWARD_TO_OUTER_OR_THROW(Alert
, (aMessage
, aError
), aError
, );
6446 AlertOrConfirm(/* aAlert = */ true, aMessage
, aError
);
6450 nsGlobalWindow::Alert(const nsAString
& aString
)
6455 return rv
.ErrorCode();
6459 nsGlobalWindow::Confirm(const nsAString
& aMessage
, ErrorResult
& aError
)
6461 FORWARD_TO_OUTER_OR_THROW(Confirm
, (aMessage
, aError
), aError
, false);
6463 return AlertOrConfirm(/* aAlert = */ false, aMessage
, aError
);
6467 nsGlobalWindow::Confirm(const nsAString
& aString
, bool* aReturn
)
6470 *aReturn
= Confirm(aString
, rv
);
6472 return rv
.ErrorCode();
6476 nsGlobalWindow::Prompt(const nsAString
& aMessage
, const nsAString
& aInitial
,
6477 nsAString
& aReturn
, ErrorResult
& aError
)
6479 // XXX This method is very similar to nsGlobalWindow::AlertOrConfirm, make
6480 // sure any modifications here don't need to happen over there!
6481 FORWARD_TO_OUTER_OR_THROW(Prompt
, (aMessage
, aInitial
, aReturn
, aError
),
6484 SetDOMStringToNull(aReturn
);
6486 if (!AreDialogsEnabled()) {
6487 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
6491 // Reset popup state while opening a modal dialog, and firing events
6492 // about the dialog, to prevent the current state from being active
6493 // the whole time a modal dialog is open.
6494 nsAutoPopupStatePusher
popupStatePusher(openAbused
, true);
6496 // Before bringing up the window, unsuppress painting and flush
6498 EnsureReflowFlushAndPaint();
6501 MakeScriptDialogTitle(title
);
6503 // Remove non-terminating null characters from the
6504 // string. See bug #310037.
6505 nsAutoString fixedMessage
, fixedInitial
;
6506 nsContentUtils::StripNullChars(aMessage
, fixedMessage
);
6507 nsContentUtils::StripNullChars(aInitial
, fixedInitial
);
6510 nsCOMPtr
<nsIPromptFactory
> promptFac
=
6511 do_GetService("@mozilla.org/prompter;1", &rv
);
6512 if (NS_FAILED(rv
)) {
6517 nsCOMPtr
<nsIPrompt
> prompt
;
6518 aError
= promptFac
->GetPrompt(this, NS_GET_IID(nsIPrompt
),
6519 getter_AddRefs(prompt
));
6520 if (aError
.Failed()) {
6524 // Always allow tab modal prompts for prompt.
6525 if (nsCOMPtr
<nsIWritablePropertyBag2
> promptBag
= do_QueryInterface(prompt
)) {
6526 promptBag
->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
6529 // Pass in the default value, if any.
6530 char16_t
*inoutValue
= ToNewUnicode(fixedInitial
);
6531 bool disallowDialog
= false;
6533 nsXPIDLString label
;
6534 if (ShouldPromptToBlockDialogs()) {
6535 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES
,
6536 "ScriptDialogLabel", label
);
6539 nsAutoSyncOperation
sync(mDoc
);
6541 aError
= prompt
->Prompt(title
.get(), fixedMessage
.get(),
6542 &inoutValue
, label
.get(), &disallowDialog
, &ok
);
6544 if (disallowDialog
) {
6548 if (aError
.Failed()) {
6552 nsAdoptingString
outValue(inoutValue
);
6554 if (ok
&& outValue
) {
6555 aReturn
.Assign(outValue
);
6560 nsGlobalWindow::Prompt(const nsAString
& aMessage
, const nsAString
& aInitial
,
6564 Prompt(aMessage
, aInitial
, aReturn
, rv
);
6566 return rv
.ErrorCode();
6570 nsGlobalWindow::Focus(ErrorResult
& aError
)
6572 FORWARD_TO_OUTER_OR_THROW(Focus
, (aError
), aError
, );
6574 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
6579 nsCOMPtr
<nsIBaseWindow
> baseWin
= do_QueryInterface(mDocShell
);
6581 bool isVisible
= false;
6583 baseWin
->GetVisibility(&isVisible
);
6587 // A hidden tab is being focused, ignore this call.
6591 nsCOMPtr
<nsPIDOMWindow
> caller
= do_QueryInterface(GetEntryGlobal());
6592 caller
= caller
? caller
->GetOuterWindow() : nullptr;
6593 nsCOMPtr
<nsIDOMWindow
> opener
;
6594 GetOpener(getter_AddRefs(opener
));
6596 // Enforce dom.disable_window_flip (for non-chrome), but still allow the
6597 // window which opened us to raise us at times when popups are allowed
6598 // (bugs 355482 and 369306).
6599 bool canFocus
= CanSetProperty("dom.disable_window_flip") ||
6600 (opener
== caller
&&
6601 RevisePopupAbuseLevel(gPopupControlState
) < openAbused
);
6603 nsCOMPtr
<nsIDOMWindow
> activeWindow
;
6604 fm
->GetActiveWindow(getter_AddRefs(activeWindow
));
6606 nsCOMPtr
<nsIDocShellTreeItem
> rootItem
;
6607 mDocShell
->GetRootTreeItem(getter_AddRefs(rootItem
));
6608 nsCOMPtr
<nsIDOMWindow
> rootWin
= rootItem
? rootItem
->GetWindow() : nullptr;
6609 bool isActive
= (rootWin
== activeWindow
);
6611 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
6612 if (treeOwnerAsWin
&& (canFocus
|| isActive
)) {
6613 bool isEnabled
= true;
6614 if (NS_SUCCEEDED(treeOwnerAsWin
->GetEnabled(&isEnabled
)) && !isEnabled
) {
6615 NS_WARNING( "Should not try to set the focus on a disabled window" );
6619 // XXXndeakin not sure what this is for or if it should go somewhere else
6620 nsCOMPtr
<nsIEmbeddingSiteWindow
> embeddingWin(do_GetInterface(treeOwnerAsWin
));
6622 embeddingWin
->SetFocus();
6629 nsCOMPtr
<nsIPresShell
> presShell
;
6630 // Don't look for a presshell if we're a root chrome window that's got
6631 // about:blank loaded. We don't want to focus our widget in that case.
6632 // XXXbz should we really be checking for IsInitialDocument() instead?
6633 bool lookForPresShell
= true;
6634 if (mDocShell
->ItemType() == nsIDocShellTreeItem::typeChrome
&&
6635 GetPrivateRoot() == static_cast<nsIDOMWindow
*>(this) &&
6637 nsIURI
* ourURI
= mDoc
->GetDocumentURI();
6639 lookForPresShell
= !NS_IsAboutBlank(ourURI
);
6643 if (lookForPresShell
) {
6644 mDocShell
->GetEldestPresShell(getter_AddRefs(presShell
));
6647 nsCOMPtr
<nsIDocShellTreeItem
> parentDsti
;
6648 mDocShell
->GetParent(getter_AddRefs(parentDsti
));
6650 // set the parent's current focus to the frame containing this window.
6651 nsCOMPtr
<nsPIDOMWindow
> parent
=
6652 parentDsti
? parentDsti
->GetWindow() : nullptr;
6654 nsCOMPtr
<nsIDocument
> parentdoc
= parent
->GetDoc();
6659 nsIContent
* frame
= parentdoc
->FindContentForSubDocument(mDoc
);
6660 nsCOMPtr
<nsIDOMElement
> frameElement
= do_QueryInterface(frame
);
6662 uint32_t flags
= nsIFocusManager::FLAG_NOSCROLL
;
6664 flags
|= nsIFocusManager::FLAG_RAISE
;
6665 aError
= fm
->SetFocus(frameElement
, flags
);
6669 if (nsCOMPtr
<nsITabChild
> child
= do_GetInterface(mDocShell
)) {
6670 child
->SendRequestFocus(canFocus
);
6674 // if there is no parent, this must be a toplevel window, so raise the
6675 // window if canFocus is true
6676 aError
= fm
->SetActiveWindow(this);
6681 nsGlobalWindow::Focus()
6686 return rv
.ErrorCode();
6690 nsGlobalWindow::Blur(ErrorResult
& aError
)
6692 FORWARD_TO_OUTER_OR_THROW(Blur
, (aError
), aError
, );
6694 // If dom.disable_window_flip == true, then content should not be allowed
6695 // to call this function (this would allow popunders, bug 369306)
6696 if (!CanSetProperty("dom.disable_window_flip")) {
6700 // If embedding apps don't implement nsIEmbeddingSiteWindow, we
6701 // shouldn't throw exceptions to web content.
6703 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
= GetTreeOwner();
6704 nsCOMPtr
<nsIEmbeddingSiteWindow
> siteWindow(do_GetInterface(treeOwner
));
6706 // This method call may cause mDocShell to become nullptr.
6709 // if the root is focused, clear the focus
6710 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
6712 nsCOMPtr
<nsIDOMElement
> element
;
6713 fm
->GetFocusedElementForWindow(this, false, nullptr, getter_AddRefs(element
));
6714 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(element
);
6715 if (content
== mDoc
->GetRootElement())
6716 fm
->ClearFocus(this);
6722 nsGlobalWindow::Blur()
6727 return rv
.ErrorCode();
6731 nsGlobalWindow::Back(ErrorResult
& aError
)
6733 FORWARD_TO_OUTER_OR_THROW(Back
, (aError
), aError
, );
6735 nsCOMPtr
<nsIWebNavigation
> webNav(do_QueryInterface(mDocShell
));
6737 aError
.Throw(NS_ERROR_FAILURE
);
6741 aError
= webNav
->GoBack();
6745 nsGlobalWindow::Back()
6750 return rv
.ErrorCode();
6754 nsGlobalWindow::Forward(ErrorResult
& aError
)
6756 FORWARD_TO_OUTER_OR_THROW(Forward
, (aError
), aError
, );
6758 nsCOMPtr
<nsIWebNavigation
> webNav(do_QueryInterface(mDocShell
));
6760 aError
.Throw(NS_ERROR_FAILURE
);
6764 aError
= webNav
->GoForward();
6768 nsGlobalWindow::Forward()
6773 return rv
.ErrorCode();
6777 nsGlobalWindow::Home(ErrorResult
& aError
)
6779 FORWARD_TO_OUTER_OR_THROW(Home
, (aError
), aError
, );
6785 nsAdoptingString homeURL
=
6786 Preferences::GetLocalizedString(PREF_BROWSER_STARTUP_HOMEPAGE
);
6788 if (homeURL
.IsEmpty()) {
6789 // if all else fails, use this
6791 printf("all else failed. using %s as the home page\n", DEFAULT_HOME_PAGE
);
6793 CopyASCIItoUTF16(DEFAULT_HOME_PAGE
, homeURL
);
6798 // Firefox lets the user specify multiple home pages to open in
6799 // individual tabs by separating them with '|'. Since we don't
6800 // have the machinery in place to easily open new tabs from here,
6801 // simply truncate the homeURL at the first '|' character to
6802 // prevent any possibilities of leaking the users list of home
6803 // pages to the first home page.
6805 // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
6806 // fixed we can revisit this.
6807 int32_t firstPipe
= homeURL
.FindChar('|');
6809 if (firstPipe
> 0) {
6810 homeURL
.Truncate(firstPipe
);
6815 nsCOMPtr
<nsIWebNavigation
> webNav(do_QueryInterface(mDocShell
));
6817 aError
.Throw(NS_ERROR_FAILURE
);
6821 aError
= webNav
->LoadURI(homeURL
.get(),
6822 nsIWebNavigation::LOAD_FLAGS_NONE
,
6829 nsGlobalWindow::Home()
6834 return rv
.ErrorCode();
6838 nsGlobalWindow::Stop(ErrorResult
& aError
)
6840 FORWARD_TO_OUTER_OR_THROW(Stop
, (aError
), aError
, );
6842 nsCOMPtr
<nsIWebNavigation
> webNav(do_QueryInterface(mDocShell
));
6844 aError
= webNav
->Stop(nsIWebNavigation::STOP_ALL
);
6849 nsGlobalWindow::Stop()
6854 return rv
.ErrorCode();
6858 nsGlobalWindow::Print(ErrorResult
& aError
)
6861 FORWARD_TO_OUTER_OR_THROW(Print
, (aError
), aError
, );
6863 if (Preferences::GetBool("dom.disable_window_print", false)) {
6864 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
6868 if (!AreDialogsEnabled()) {
6869 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
6873 if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
6874 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
6878 nsCOMPtr
<nsIWebBrowserPrint
> webBrowserPrint
;
6879 if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint
),
6880 getter_AddRefs(webBrowserPrint
)))) {
6881 nsAutoSyncOperation
sync(GetCurrentInnerWindowInternal() ?
6882 GetCurrentInnerWindowInternal()->mDoc
:
6885 nsCOMPtr
<nsIPrintSettingsService
> printSettingsService
=
6886 do_GetService("@mozilla.org/gfx/printsettings-service;1");
6888 nsCOMPtr
<nsIPrintSettings
> printSettings
;
6889 if (printSettingsService
) {
6890 bool printSettingsAreGlobal
=
6891 Preferences::GetBool("print.use_global_printsettings", false);
6893 if (printSettingsAreGlobal
) {
6894 printSettingsService
->GetGlobalPrintSettings(getter_AddRefs(printSettings
));
6896 nsXPIDLString printerName
;
6897 printSettings
->GetPrinterName(getter_Copies(printerName
));
6898 if (printerName
.IsEmpty()) {
6899 printSettingsService
->GetDefaultPrinterName(getter_Copies(printerName
));
6900 printSettings
->SetPrinterName(printerName
);
6902 printSettingsService
->InitPrintSettingsFromPrinter(printerName
, printSettings
);
6903 printSettingsService
->InitPrintSettingsFromPrefs(printSettings
,
6905 nsIPrintSettings::kInitSaveAll
);
6907 printSettingsService
->GetNewPrintSettings(getter_AddRefs(printSettings
));
6911 webBrowserPrint
->Print(printSettings
, nullptr);
6914 bool savePrintSettings
=
6915 Preferences::GetBool("print.save_print_settings", false);
6916 if (printSettingsAreGlobal
&& savePrintSettings
) {
6917 printSettingsService
->
6918 SavePrintSettingsToPrefs(printSettings
,
6920 nsIPrintSettings::kInitSaveAll
);
6921 printSettingsService
->
6922 SavePrintSettingsToPrefs(printSettings
,
6924 nsIPrintSettings::kInitSavePrinterName
);
6927 webBrowserPrint
->GetGlobalPrintSettings(getter_AddRefs(printSettings
));
6928 webBrowserPrint
->Print(printSettings
, nullptr);
6931 #endif //NS_PRINTING
6935 nsGlobalWindow::Print()
6940 return rv
.ErrorCode();
6944 nsGlobalWindow::MoveTo(int32_t aXPos
, int32_t aYPos
, ErrorResult
& aError
)
6946 FORWARD_TO_OUTER_OR_THROW(MoveTo
, (aXPos
, aYPos
, aError
), aError
, );
6949 * If caller is not chrome and the user has not explicitly exempted the site,
6950 * prevent window.moveTo() by exiting early
6953 if (!CanMoveResizeWindows() || IsFrame()) {
6957 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
6958 if (!treeOwnerAsWin
) {
6959 aError
.Throw(NS_ERROR_FAILURE
);
6963 // Mild abuse of a "size" object so we don't need more helper functions.
6964 nsIntSize
cssPos(aXPos
, aYPos
);
6965 CheckSecurityLeftAndTop(&cssPos
.width
, &cssPos
.height
);
6967 nsIntSize devPos
= CSSToDevIntPixels(cssPos
);
6969 aError
= treeOwnerAsWin
->SetPosition(devPos
.width
, devPos
.height
);
6973 nsGlobalWindow::MoveTo(int32_t aXPos
, int32_t aYPos
)
6976 MoveTo(aXPos
, aYPos
, rv
);
6978 return rv
.ErrorCode();
6982 nsGlobalWindow::MoveBy(int32_t aXDif
, int32_t aYDif
, ErrorResult
& aError
)
6984 FORWARD_TO_OUTER_OR_THROW(MoveBy
, (aXDif
, aYDif
, aError
), aError
, );
6987 * If caller is not chrome and the user has not explicitly exempted the site,
6988 * prevent window.moveBy() by exiting early
6991 if (!CanMoveResizeWindows() || IsFrame()) {
6995 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
6996 if (!treeOwnerAsWin
) {
6997 aError
.Throw(NS_ERROR_FAILURE
);
7001 // To do this correctly we have to convert what we get from GetPosition
7002 // into CSS pixels, add the arguments, do the security check, and
7003 // then convert back to device pixels for the call to SetPosition.
7006 aError
= treeOwnerAsWin
->GetPosition(&x
, &y
);
7007 if (aError
.Failed()) {
7011 // mild abuse of a "size" object so we don't need more helper functions
7012 nsIntSize
cssPos(DevToCSSIntPixels(nsIntSize(x
, y
)));
7014 cssPos
.width
+= aXDif
;
7015 cssPos
.height
+= aYDif
;
7017 CheckSecurityLeftAndTop(&cssPos
.width
, &cssPos
.height
);
7019 nsIntSize
newDevPos(CSSToDevIntPixels(cssPos
));
7021 aError
= treeOwnerAsWin
->SetPosition(newDevPos
.width
, newDevPos
.height
);
7025 nsGlobalWindow::MoveBy(int32_t aXDif
, int32_t aYDif
)
7028 MoveBy(aXDif
, aYDif
, rv
);
7030 return rv
.ErrorCode();
7034 nsGlobalWindow::ResizeTo(int32_t aWidth
, int32_t aHeight
, ErrorResult
& aError
)
7036 FORWARD_TO_OUTER_OR_THROW(ResizeTo
, (aWidth
, aHeight
, aError
), aError
, );
7039 * If caller is a browser-element then dispatch a resize event to
7042 if (mDocShell
&& mDocShell
->GetIsBrowserOrApp()) {
7043 CSSIntSize
size(aWidth
, aHeight
);
7044 if (!DispatchResizeEvent(size
)) {
7045 // The embedder chose to prevent the default action for this
7046 // event, so let's not resize this window after all...
7052 * If caller is not chrome and the user has not explicitly exempted the site,
7053 * prevent window.resizeTo() by exiting early
7056 if (!CanMoveResizeWindows() || IsFrame()) {
7060 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
7061 if (!treeOwnerAsWin
) {
7062 aError
.Throw(NS_ERROR_FAILURE
);
7066 nsIntSize
cssSize(aWidth
, aHeight
);
7067 CheckSecurityWidthAndHeight(&cssSize
.width
, &cssSize
.height
);
7069 nsIntSize
devSz(CSSToDevIntPixels(cssSize
));
7071 aError
= treeOwnerAsWin
->SetSize(devSz
.width
, devSz
.height
, true);
7075 nsGlobalWindow::ResizeTo(int32_t aWidth
, int32_t aHeight
)
7078 ResizeTo(aWidth
, aHeight
, rv
);
7080 return rv
.ErrorCode();
7084 nsGlobalWindow::ResizeBy(int32_t aWidthDif
, int32_t aHeightDif
,
7085 ErrorResult
& aError
)
7087 FORWARD_TO_OUTER_OR_THROW(ResizeBy
, (aWidthDif
, aHeightDif
, aError
), aError
, );
7090 * If caller is a browser-element then dispatch a resize event to
7093 if (mDocShell
&& mDocShell
->GetIsBrowserOrApp()) {
7095 if (NS_FAILED(GetInnerSize(size
))) {
7099 size
.width
+= aWidthDif
;
7100 size
.height
+= aHeightDif
;
7102 if (!DispatchResizeEvent(size
)) {
7103 // The embedder chose to prevent the default action for this
7104 // event, so let's not resize this window after all...
7110 * If caller is not chrome and the user has not explicitly exempted the site,
7111 * prevent window.resizeBy() by exiting early
7114 if (!CanMoveResizeWindows() || IsFrame()) {
7118 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
7119 if (!treeOwnerAsWin
) {
7120 aError
.Throw(NS_ERROR_FAILURE
);
7124 int32_t width
, height
;
7125 aError
= treeOwnerAsWin
->GetSize(&width
, &height
);
7126 if (aError
.Failed()) {
7130 // To do this correctly we have to convert what we got from GetSize
7131 // into CSS pixels, add the arguments, do the security check, and
7132 // then convert back to device pixels for the call to SetSize.
7134 nsIntSize
cssSize(DevToCSSIntPixels(nsIntSize(width
, height
)));
7136 cssSize
.width
+= aWidthDif
;
7137 cssSize
.height
+= aHeightDif
;
7139 CheckSecurityWidthAndHeight(&cssSize
.width
, &cssSize
.height
);
7141 nsIntSize
newDevSize(CSSToDevIntPixels(cssSize
));
7143 aError
= treeOwnerAsWin
->SetSize(newDevSize
.width
, newDevSize
.height
, true);
7147 nsGlobalWindow::ResizeBy(int32_t aWidthDif
, int32_t aHeightDif
)
7150 ResizeBy(aWidthDif
, aHeightDif
, rv
);
7152 return rv
.ErrorCode();
7156 nsGlobalWindow::SizeToContent(ErrorResult
& aError
)
7158 FORWARD_TO_OUTER_OR_THROW(SizeToContent
, (aError
), aError
, );
7165 * If caller is not chrome and the user has not explicitly exempted the site,
7166 * prevent window.sizeToContent() by exiting early
7169 if (!CanMoveResizeWindows() || IsFrame()) {
7173 // The content viewer does a check to make sure that it's a content
7174 // viewer for a toplevel docshell.
7175 nsCOMPtr
<nsIContentViewer
> cv
;
7176 mDocShell
->GetContentViewer(getter_AddRefs(cv
));
7178 aError
.Throw(NS_ERROR_FAILURE
);
7182 int32_t width
, height
;
7183 aError
= cv
->GetContentSize(&width
, &height
);
7184 if (aError
.Failed()) {
7188 // Make sure the new size is following the CheckSecurityWidthAndHeight
7190 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
= GetTreeOwner();
7192 aError
.Throw(NS_ERROR_FAILURE
);
7196 nsIntSize
cssSize(DevToCSSIntPixels(nsIntSize(width
, height
)));
7197 CheckSecurityWidthAndHeight(&cssSize
.width
, &cssSize
.height
);
7199 nsIntSize
newDevSize(CSSToDevIntPixels(cssSize
));
7201 aError
= treeOwner
->SizeShellTo(mDocShell
, newDevSize
.width
,
7206 nsGlobalWindow::SizeToContent()
7211 return rv
.ErrorCode();
7215 nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget
**aWindowRoot
)
7217 nsCOMPtr
<nsPIWindowRoot
> root
= GetTopWindowRoot();
7218 return CallQueryInterface(root
, aWindowRoot
);
7221 already_AddRefed
<nsPIWindowRoot
>
7222 nsGlobalWindow::GetTopWindowRoot()
7224 nsPIDOMWindow
* piWin
= GetPrivateRoot();
7229 nsCOMPtr
<nsPIWindowRoot
> window
= do_QueryInterface(piWin
->GetChromeEventHandler());
7230 return window
.forget();
7234 nsGlobalWindow::Scroll(double aXScroll
, double aYScroll
,
7235 const ScrollOptions
& aOptions
)
7237 // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
7238 CSSIntPoint
scrollPos(mozilla::ToZeroIfNonfinite(aXScroll
),
7239 mozilla::ToZeroIfNonfinite(aYScroll
));
7240 ScrollTo(scrollPos
, aOptions
);
7244 nsGlobalWindow::ScrollTo(double aXScroll
, double aYScroll
,
7245 const ScrollOptions
& aOptions
)
7247 // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
7248 CSSIntPoint
scrollPos(mozilla::ToZeroIfNonfinite(aXScroll
),
7249 mozilla::ToZeroIfNonfinite(aYScroll
));
7250 ScrollTo(scrollPos
, aOptions
);
7254 nsGlobalWindow::Scroll(int32_t aXScroll
, int32_t aYScroll
)
7256 ScrollTo(CSSIntPoint(aXScroll
, aYScroll
), ScrollOptions());
7261 nsGlobalWindow::ScrollTo(int32_t aXScroll
, int32_t aYScroll
)
7263 ScrollTo(CSSIntPoint(aXScroll
, aYScroll
), ScrollOptions());
7268 nsGlobalWindow::ScrollTo(const CSSIntPoint
& aScroll
,
7269 const ScrollOptions
& aOptions
)
7271 FlushPendingNotifications(Flush_Layout
);
7272 nsIScrollableFrame
*sf
= GetScrollFrame();
7275 // Here we calculate what the max pixel value is that we can
7276 // scroll to, we do this by dividing maxint with the pixel to
7277 // twips conversion factor, and subtracting 4, the 4 comes from
7278 // experimenting with this value, anything less makes the view
7279 // code not scroll correctly, I have no idea why. -- jst
7280 const int32_t maxpx
= nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
7282 CSSIntPoint
scroll(aScroll
);
7283 if (scroll
.x
> maxpx
) {
7287 if (scroll
.y
> maxpx
) {
7291 sf
->ScrollToCSSPixels(scroll
,
7292 aOptions
.mBehavior
== ScrollBehavior::Smooth
7293 ? nsIScrollableFrame::SMOOTH_MSD
7294 : nsIScrollableFrame::INSTANT
);
7299 nsGlobalWindow::ScrollBy(int32_t aXScrollDif
, int32_t aYScrollDif
)
7301 ScrollBy(aXScrollDif
, aYScrollDif
, ScrollOptions());
7307 nsGlobalWindow::ScrollBy(double aXScrollDif
, double aYScrollDif
,
7308 const ScrollOptions
& aOptions
)
7310 FlushPendingNotifications(Flush_Layout
);
7311 nsIScrollableFrame
*sf
= GetScrollFrame();
7314 // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
7315 CSSIntPoint
scrollDif(mozilla::ToZeroIfNonfinite(aXScrollDif
),
7316 mozilla::ToZeroIfNonfinite(aYScrollDif
));
7317 // It seems like it would make more sense for ScrollBy to use
7318 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
7319 // Perhaps Web content does too.
7320 ScrollTo(sf
->GetScrollPositionCSSPixels() + scrollDif
, aOptions
);
7325 nsGlobalWindow::ScrollByLines(int32_t numLines
)
7327 ScrollByLines(numLines
, ScrollOptions());
7333 nsGlobalWindow::ScrollByLines(int32_t numLines
,
7334 const ScrollOptions
& aOptions
)
7336 FlushPendingNotifications(Flush_Layout
);
7337 nsIScrollableFrame
*sf
= GetScrollFrame();
7339 // It seems like it would make more sense for ScrollByLines to use
7340 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
7341 // Perhaps Web content does too.
7342 sf
->ScrollBy(nsIntPoint(0, numLines
), nsIScrollableFrame::LINES
,
7343 aOptions
.mBehavior
== ScrollBehavior::Smooth
7344 ? nsIScrollableFrame::SMOOTH_MSD
7345 : nsIScrollableFrame::INSTANT
);
7350 nsGlobalWindow::ScrollByPages(int32_t numPages
)
7352 ScrollByPages(numPages
, ScrollOptions());
7358 nsGlobalWindow::ScrollByPages(int32_t numPages
,
7359 const ScrollOptions
& aOptions
)
7361 FlushPendingNotifications(Flush_Layout
);
7362 nsIScrollableFrame
*sf
= GetScrollFrame();
7364 // It seems like it would make more sense for ScrollByPages to use
7365 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
7366 // Perhaps Web content does too.
7367 sf
->ScrollBy(nsIntPoint(0, numPages
), nsIScrollableFrame::PAGES
,
7368 aOptions
.mBehavior
== ScrollBehavior::Smooth
7369 ? nsIScrollableFrame::SMOOTH_MSD
7370 : nsIScrollableFrame::INSTANT
);
7375 nsGlobalWindow::MozRequestOverfill(OverfillCallback
& aCallback
,
7376 mozilla::ErrorResult
& aError
)
7378 nsIWidget
* widget
= nsContentUtils::WidgetForDocument(mDoc
);
7380 mozilla::layers::LayerManager
* manager
= widget
->GetLayerManager();
7382 manager
->RequestOverfill(&aCallback
);
7387 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
7391 nsGlobalWindow::ClearTimeout(int32_t aHandle
, ErrorResult
& aError
)
7394 ClearTimeoutOrInterval(aHandle
, aError
);
7399 nsGlobalWindow::ClearTimeout(int32_t aHandle
)
7402 ClearTimeout(aHandle
, rv
);
7404 return rv
.ErrorCode();
7408 nsGlobalWindow::ClearInterval(int32_t aHandle
, ErrorResult
& aError
)
7411 ClearTimeoutOrInterval(aHandle
, aError
);
7416 nsGlobalWindow::ClearInterval(int32_t aHandle
)
7419 ClearInterval(aHandle
, rv
);
7421 return rv
.ErrorCode();
7425 nsGlobalWindow::SetTimeout(int32_t *_retval
)
7427 return SetTimeoutOrInterval(false, _retval
);
7431 nsGlobalWindow::SetInterval(int32_t *_retval
)
7433 return SetTimeoutOrInterval(true, _retval
);
7437 nsGlobalWindow::SetResizable(bool aResizable
)
7445 nsGlobalWindow::CaptureEvents()
7448 mDoc
->WarnOnceAbout(nsIDocument::eUseOfCaptureEvents
);
7455 nsGlobalWindow::ReleaseEvents()
7458 mDoc
->WarnOnceAbout(nsIDocument::eUseOfReleaseEvents
);
7465 bool IsPopupBlocked(nsIDocument
* aDoc
)
7467 nsCOMPtr
<nsIPopupWindowManager
> pm
=
7468 do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID
);
7478 uint32_t permission
= nsIPopupWindowManager::ALLOW_POPUP
;
7479 pm
->TestPermission(aDoc
->NodePrincipal(), &permission
);
7480 return permission
== nsIPopupWindowManager::DENY_POPUP
;
7484 nsGlobalWindow::FirePopupBlockedEvent(nsIDocument
* aDoc
,
7486 const nsAString
& aPopupWindowName
,
7487 const nsAString
& aPopupWindowFeatures
)
7491 // Fire a "DOMPopupBlocked" event so that the UI can hear about
7493 PopupBlockedEventInit init
;
7494 init
.mBubbles
= true;
7495 init
.mCancelable
= true;
7496 init
.mRequestingWindow
= this;
7497 init
.mPopupWindowURI
= aPopupURI
;
7498 init
.mPopupWindowName
= aPopupWindowName
;
7499 init
.mPopupWindowFeatures
= aPopupWindowFeatures
;
7501 nsRefPtr
<PopupBlockedEvent
> event
=
7502 PopupBlockedEvent::Constructor(aDoc
,
7503 NS_LITERAL_STRING("DOMPopupBlocked"),
7506 event
->SetTrusted(true);
7508 bool defaultActionEnabled
;
7509 aDoc
->DispatchEvent(event
, &defaultActionEnabled
);
7512 static void FirePopupWindowEvent(nsIDocument
* aDoc
)
7514 // Fire a "PopupWindow" event
7515 nsContentUtils::DispatchTrustedEvent(aDoc
, aDoc
,
7516 NS_LITERAL_STRING("PopupWindow"),
7522 nsGlobalWindow::CanSetProperty(const char *aPrefName
)
7524 // Chrome can set any property.
7525 if (nsContentUtils::IsCallerChrome()) {
7529 // If the pref is set to true, we can not set the property
7531 return !Preferences::GetBool(aPrefName
, true);
7535 nsGlobalWindow::PopupWhitelisted()
7537 if (!IsPopupBlocked(mDoc
))
7540 nsCOMPtr
<nsIDOMWindow
> parent
;
7542 if (NS_FAILED(GetParent(getter_AddRefs(parent
))) ||
7543 parent
== static_cast<nsIDOMWindow
*>(this))
7548 return static_cast<nsGlobalWindow
*>
7549 (static_cast<nsIDOMWindow
*>
7550 (parent
.get()))->PopupWhitelisted();
7554 * Examine the current document state to see if we're in a way that is
7555 * typically abused by web designers. The window.open code uses this
7556 * routine to determine whether to allow the new window.
7557 * Returns a value from the PopupControlState enum.
7560 nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl
)
7562 MOZ_ASSERT(IsOuterWindow());
7564 NS_ASSERTION(mDocShell
, "Must have docshell");
7566 if (mDocShell
->ItemType() != nsIDocShellTreeItem::typeContent
) {
7570 PopupControlState abuse
= aControl
;
7572 case openControlled
:
7574 case openOverridden
:
7575 if (PopupWhitelisted())
7576 abuse
= PopupControlState(abuse
- 1);
7577 case openAllowed
: break;
7579 NS_WARNING("Strange PopupControlState!");
7582 // limit the number of simultaneously open popups
7583 if (abuse
== openAbused
|| abuse
== openControlled
) {
7584 int32_t popupMax
= Preferences::GetInt("dom.popup_maximum", -1);
7585 if (popupMax
>= 0 && gOpenPopupSpamCount
>= popupMax
)
7586 abuse
= openOverridden
;
7592 /* If a window open is blocked, fire the appropriate DOM events.
7593 aBlocked signifies we just blocked a popup.
7594 aWindow signifies we just opened what is probably a popup.
7597 nsGlobalWindow::FireAbuseEvents(bool aBlocked
, bool aWindow
,
7598 const nsAString
&aPopupURL
,
7599 const nsAString
&aPopupWindowName
,
7600 const nsAString
&aPopupWindowFeatures
)
7602 // fetch the URI of the window requesting the opened window
7604 nsCOMPtr
<nsIDOMWindow
> topWindow
;
7605 GetTop(getter_AddRefs(topWindow
));
7606 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(topWindow
);
7611 nsCOMPtr
<nsIDocument
> topDoc
= window
->GetDoc();
7612 nsCOMPtr
<nsIURI
> popupURI
;
7614 // build the URI of the would-have-been popup window
7615 // (see nsWindowWatcher::URIfromURL)
7617 // first, fetch the opener's base URI
7619 nsIURI
*baseURL
= nullptr;
7621 nsCOMPtr
<nsIDocument
> doc
= GetEntryDocument();
7623 baseURL
= doc
->GetDocBaseURI();
7625 // use the base URI to build what would have been the popup's URI
7626 nsCOMPtr
<nsIIOService
> ios(do_GetService(NS_IOSERVICE_CONTRACTID
));
7628 ios
->NewURI(NS_ConvertUTF16toUTF8(aPopupURL
), 0, baseURL
,
7629 getter_AddRefs(popupURI
));
7631 // fire an event chock full of informative URIs
7633 FirePopupBlockedEvent(topDoc
, popupURI
, aPopupWindowName
,
7634 aPopupWindowFeatures
);
7637 FirePopupWindowEvent(topDoc
);
7640 already_AddRefed
<nsIDOMWindow
>
7641 nsGlobalWindow::Open(const nsAString
& aUrl
, const nsAString
& aName
,
7642 const nsAString
& aOptions
, ErrorResult
& aError
)
7644 FORWARD_TO_OUTER_OR_THROW(Open
, (aUrl
, aName
, aOptions
, aError
), aError
,
7646 nsCOMPtr
<nsIDOMWindow
> window
;
7647 aError
= OpenJS(aUrl
, aName
, aOptions
, getter_AddRefs(window
));
7648 return window
.forget();
7652 nsGlobalWindow::Open(const nsAString
& aUrl
, const nsAString
& aName
,
7653 const nsAString
& aOptions
, nsIDOMWindow
**_retval
)
7655 FORWARD_TO_OUTER(Open
, (aUrl
, aName
, aOptions
, _retval
),
7656 NS_ERROR_NOT_INITIALIZED
);
7657 return OpenInternal(aUrl
, aName
, aOptions
,
7659 false, // aContentModal
7660 true, // aCalledNoScript
7661 false, // aDoJSFixups
7663 nullptr, nullptr, // No args
7664 GetPrincipal(), // aCalleePrincipal
7665 nullptr, // aJSCallerContext
7670 nsGlobalWindow::OpenJS(const nsAString
& aUrl
, const nsAString
& aName
,
7671 const nsAString
& aOptions
, nsIDOMWindow
**_retval
)
7673 FORWARD_TO_OUTER(OpenJS
, (aUrl
, aName
, aOptions
, _retval
),
7674 NS_ERROR_NOT_INITIALIZED
);
7675 return OpenInternal(aUrl
, aName
, aOptions
,
7677 false, // aContentModal
7678 false, // aCalledNoScript
7679 true, // aDoJSFixups
7681 nullptr, nullptr, // No args
7682 GetPrincipal(), // aCalleePrincipal
7683 nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
7687 // like Open, but attaches to the new window any extra parameters past
7688 // [features] as a JS property named "arguments"
7690 nsGlobalWindow::OpenDialog(const nsAString
& aUrl
, const nsAString
& aName
,
7691 const nsAString
& aOptions
,
7692 nsISupports
* aExtraArgument
, nsIDOMWindow
** _retval
)
7694 FORWARD_TO_OUTER(OpenDialog
, (aUrl
, aName
, aOptions
, aExtraArgument
, _retval
),
7695 NS_ERROR_NOT_INITIALIZED
);
7696 return OpenInternal(aUrl
, aName
, aOptions
,
7698 false, // aContentModal
7699 true, // aCalledNoScript
7700 false, // aDoJSFixups
7702 nullptr, aExtraArgument
, // Arguments
7703 GetPrincipal(), // aCalleePrincipal
7704 nullptr, // aJSCallerContext
7708 // Like Open, but passes aNavigate=false.
7709 /* virtual */ nsresult
7710 nsGlobalWindow::OpenNoNavigate(const nsAString
& aUrl
,
7711 const nsAString
& aName
,
7712 const nsAString
& aOptions
,
7713 nsIDOMWindow
**_retval
)
7715 MOZ_ASSERT(IsOuterWindow());
7716 return OpenInternal(aUrl
, aName
, aOptions
,
7718 false, // aContentModal
7719 true, // aCalledNoScript
7720 false, // aDoJSFixups
7722 nullptr, nullptr, // No args
7723 GetPrincipal(), // aCalleePrincipal
7724 nullptr, // aJSCallerContext
7729 already_AddRefed
<nsIDOMWindow
>
7730 nsGlobalWindow::OpenDialog(JSContext
* aCx
, const nsAString
& aUrl
,
7731 const nsAString
& aName
, const nsAString
& aOptions
,
7732 const Sequence
<JS::Value
>& aExtraArgument
,
7733 ErrorResult
& aError
)
7735 FORWARD_TO_OUTER_OR_THROW(OpenDialog
,
7736 (aCx
, aUrl
, aName
, aOptions
, aExtraArgument
, aError
),
7739 nsCOMPtr
<nsIJSArgArray
> argvArray
;
7740 aError
= NS_CreateJSArgv(aCx
, aExtraArgument
.Length(),
7741 const_cast<JS::Value
*>(aExtraArgument
.Elements()),
7742 getter_AddRefs(argvArray
));
7743 if (aError
.Failed()) {
7747 nsCOMPtr
<nsIDOMWindow
> dialog
;
7748 aError
= OpenInternal(aUrl
, aName
, aOptions
,
7750 false, // aContentModal
7751 false, // aCalledNoScript
7752 false, // aDoJSFixups
7754 argvArray
, nullptr, // Arguments
7755 GetPrincipal(), // aCalleePrincipal
7756 aCx
, // aJSCallerContext
7757 getter_AddRefs(dialog
));
7758 return dialog
.forget();
7762 nsGlobalWindow::OpenDialog(const nsAString
& aUrl
, const nsAString
& aName
,
7763 const nsAString
& aOptions
, nsIDOMWindow
** _retval
)
7765 FORWARD_TO_OUTER(OpenDialog
, (aUrl
, aName
, aOptions
, _retval
),
7766 NS_ERROR_NOT_INITIALIZED
);
7768 if (!nsContentUtils::IsCallerChrome()) {
7769 return NS_ERROR_DOM_SECURITY_ERR
;
7772 nsAXPCNativeCallContext
*ncc
= nullptr;
7773 nsresult rv
= nsContentUtils::XPConnect()->
7774 GetCurrentNativeCallContext(&ncc
);
7775 NS_ENSURE_SUCCESS(rv
, rv
);
7778 return NS_ERROR_NOT_AVAILABLE
;
7780 JSContext
*cx
= nullptr;
7782 rv
= ncc
->GetJSContext(&cx
);
7783 NS_ENSURE_SUCCESS(rv
, rv
);
7786 JS::Value
*argv
= nullptr;
7788 // XXX - need to get this as nsISupports?
7789 ncc
->GetArgc(&argc
);
7790 ncc
->GetArgvPtr(&argv
);
7792 // Strip the url, name and options from the args seen by scripts.
7793 uint32_t argOffset
= argc
< 3 ? argc
: 3;
7794 nsCOMPtr
<nsIJSArgArray
> argvArray
;
7795 rv
= NS_CreateJSArgv(cx
, argc
- argOffset
, argv
+ argOffset
,
7796 getter_AddRefs(argvArray
));
7797 NS_ENSURE_SUCCESS(rv
, rv
);
7799 return OpenInternal(aUrl
, aName
, aOptions
,
7801 false, // aContentModal
7802 false, // aCalledNoScript
7803 false, // aDoJSFixups
7805 argvArray
, nullptr, // Arguments
7806 GetPrincipal(), // aCalleePrincipal
7807 cx
, // aJSCallerContext
7811 already_AddRefed
<nsIDOMWindow
>
7812 nsGlobalWindow::GetFrames(ErrorResult
& aError
)
7814 FORWARD_TO_OUTER_OR_THROW(GetFrames
, (aError
), aError
, nullptr);
7816 nsRefPtr
<nsGlobalWindow
> frames(this);
7817 FlushPendingNotifications(Flush_ContentAndNotify
);
7818 return frames
.forget();
7822 nsGlobalWindow::GetFrames(nsIDOMWindow
** aFrames
)
7825 nsCOMPtr
<nsIDOMWindow
> frames
= GetFrames(rv
);
7826 frames
.forget(aFrames
);
7828 return rv
.ErrorCode();
7832 nsGlobalWindow::CallerInnerWindow()
7834 JSContext
*cx
= nsContentUtils::GetCurrentJSContext();
7835 NS_ENSURE_TRUE(cx
, nullptr);
7836 nsIGlobalObject
* global
= GetIncumbentGlobal();
7837 NS_ENSURE_TRUE(global
, nullptr);
7838 JS::Rooted
<JSObject
*> scope(cx
, global
->GetGlobalJSObject());
7839 NS_ENSURE_TRUE(scope
, nullptr);
7841 // When Jetpack runs content scripts inside a sandbox, it uses
7842 // sandboxPrototype to make them appear as though they're running in the
7843 // scope of the page. So when a content script invokes postMessage, it expects
7844 // the |source| of the received message to be the window set as the
7845 // sandboxPrototype. This used to work incidentally for unrelated reasons, but
7846 // now we need to do some special handling to support it.
7847 if (xpc::IsSandbox(scope
)) {
7848 JSAutoCompartment
ac(cx
, scope
);
7849 JS::Rooted
<JSObject
*> scopeProto(cx
);
7850 bool ok
= JS_GetPrototype(cx
, scope
, &scopeProto
);
7851 NS_ENSURE_TRUE(ok
, nullptr);
7852 if (scopeProto
&& xpc::IsSandboxPrototypeProxy(scopeProto
) &&
7853 (scopeProto
= js::CheckedUnwrap(scopeProto
, /* stopAtOuter = */ false)))
7855 global
= xpc::GetNativeForGlobal(scopeProto
);
7856 NS_ENSURE_TRUE(global
, nullptr);
7860 // The calling window must be holding a reference, so we can return a weak
7862 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(global
);
7863 return static_cast<nsGlobalWindow
*>(win
.get());
7867 * Class used to represent events generated by calls to Window.postMessage,
7868 * which asynchronously creates and dispatches events.
7870 class PostMessageEvent
: public nsRunnable
7875 PostMessageEvent(nsGlobalWindow
* aSource
,
7876 const nsAString
& aCallerOrigin
,
7877 nsGlobalWindow
* aTargetWindow
,
7878 nsIPrincipal
* aProvidedPrincipal
,
7879 bool aTrustedCaller
)
7881 mCallerOrigin(aCallerOrigin
),
7882 mTargetWindow(aTargetWindow
),
7883 mProvidedPrincipal(aProvidedPrincipal
),
7884 mTrustedCaller(aTrustedCaller
)
7886 MOZ_COUNT_CTOR(PostMessageEvent
);
7892 MOZ_COUNT_DTOR(PostMessageEvent
);
7896 JSAutoStructuredCloneBuffer
& Buffer()
7901 bool StoreISupports(nsISupports
* aSupports
)
7903 mSupportsArray
.AppendElement(aSupports
);
7908 JSAutoStructuredCloneBuffer mBuffer
;
7909 nsRefPtr
<nsGlobalWindow
> mSource
;
7910 nsString mCallerOrigin
;
7911 nsRefPtr
<nsGlobalWindow
> mTargetWindow
;
7912 nsCOMPtr
<nsIPrincipal
> mProvidedPrincipal
;
7913 bool mTrustedCaller
;
7914 nsTArray
<nsCOMPtr
<nsISupports
> > mSupportsArray
;
7919 struct StructuredCloneInfo
{
7920 PostMessageEvent
* event
;
7922 nsPIDOMWindow
* window
;
7923 nsRefPtrHashtable
<nsRefPtrHashKey
<MessagePortBase
>, MessagePortBase
> ports
;
7927 PostMessageReadStructuredClone(JSContext
* cx
,
7928 JSStructuredCloneReader
* reader
,
7933 if (tag
== SCTAG_DOM_BLOB
) {
7934 NS_ASSERTION(!data
, "Data should be empty");
7936 // What we get back from the reader is a DOMFileImpl.
7937 // From that we create a new DOMFile.
7938 nsISupports
* supports
;
7939 if (JS_ReadBytes(reader
, &supports
, sizeof(supports
))) {
7940 nsCOMPtr
<nsIDOMBlob
> file
= new DOMFile(static_cast<DOMFileImpl
*>(supports
));
7941 JS::Rooted
<JS::Value
> val(cx
);
7942 if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx
, file
, &val
))) {
7943 return val
.toObjectOrNull();
7948 if (tag
== SCTAG_DOM_FILELIST
) {
7949 NS_ASSERTION(!data
, "Data should be empty");
7951 nsISupports
* supports
;
7952 if (JS_ReadBytes(reader
, &supports
, sizeof(supports
))) {
7953 JS::Rooted
<JS::Value
> val(cx
);
7954 if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx
, supports
, &val
))) {
7955 return val
.toObjectOrNull();
7960 const JSStructuredCloneCallbacks
* runtimeCallbacks
=
7961 js::GetContextStructuredCloneCallbacks(cx
);
7963 if (runtimeCallbacks
) {
7964 return runtimeCallbacks
->read(cx
, reader
, tag
, data
, nullptr);
7971 PostMessageWriteStructuredClone(JSContext
* cx
,
7972 JSStructuredCloneWriter
* writer
,
7973 JS::Handle
<JSObject
*> obj
,
7976 StructuredCloneInfo
* scInfo
= static_cast<StructuredCloneInfo
*>(closure
);
7977 NS_ASSERTION(scInfo
, "Must have scInfo!");
7979 nsCOMPtr
<nsIXPConnectWrappedNative
> wrappedNative
;
7980 nsContentUtils::XPConnect()->
7981 GetWrappedNativeOfJSObject(cx
, obj
, getter_AddRefs(wrappedNative
));
7982 if (wrappedNative
) {
7984 nsISupports
* supports
= wrappedNative
->Native();
7986 nsCOMPtr
<nsIDOMBlob
> blob
= do_QueryInterface(supports
);
7987 if (blob
&& scInfo
->subsumes
) {
7988 scTag
= SCTAG_DOM_BLOB
;
7989 DOMFile
* file
= static_cast<DOMFile
*>(blob
.get());
7990 supports
= file
->Impl();
7993 nsCOMPtr
<nsIDOMFileList
> list
= do_QueryInterface(supports
);
7994 if (list
&& scInfo
->subsumes
)
7995 scTag
= SCTAG_DOM_FILELIST
;
7998 return JS_WriteUint32Pair(writer
, scTag
, 0) &&
7999 JS_WriteBytes(writer
, &supports
, sizeof(supports
)) &&
8000 scInfo
->event
->StoreISupports(supports
);
8003 const JSStructuredCloneCallbacks
* runtimeCallbacks
=
8004 js::GetContextStructuredCloneCallbacks(cx
);
8006 if (runtimeCallbacks
) {
8007 return runtimeCallbacks
->write(cx
, writer
, obj
, nullptr);
8014 PostMessageReadTransferStructuredClone(JSContext
* aCx
,
8015 JSStructuredCloneReader
* reader
,
8016 uint32_t tag
, void* aData
,
8017 uint64_t aExtraData
,
8019 JS::MutableHandle
<JSObject
*> returnObject
)
8021 StructuredCloneInfo
* scInfo
= static_cast<StructuredCloneInfo
*>(aClosure
);
8022 NS_ASSERTION(scInfo
, "Must have scInfo!");
8024 if (tag
== SCTAG_DOM_MAP_MESSAGEPORT
) {
8025 MessagePort
* port
= static_cast<MessagePort
*>(aData
);
8026 port
->BindToOwner(scInfo
->window
);
8027 scInfo
->ports
.Put(port
, nullptr);
8029 JS::Rooted
<JSObject
*> obj(aCx
, port
->WrapObject(aCx
));
8030 if (JS_WrapObject(aCx
, &obj
)) {
8031 MOZ_ASSERT(port
->GetOwner() == scInfo
->window
);
8032 returnObject
.set(obj
);
8042 PostMessageTransferStructuredClone(JSContext
* aCx
,
8043 JS::Handle
<JSObject
*> aObj
,
8046 JS::TransferableOwnership
* aOwnership
,
8048 uint64_t* aExtraData
)
8050 StructuredCloneInfo
* scInfo
= static_cast<StructuredCloneInfo
*>(aClosure
);
8051 NS_ASSERTION(scInfo
, "Must have scInfo!");
8053 MessagePortBase
* port
= nullptr;
8054 nsresult rv
= UNWRAP_OBJECT(MessagePort
, aObj
, port
);
8055 if (NS_SUCCEEDED(rv
)) {
8056 nsRefPtr
<MessagePortBase
> newPort
;
8057 if (scInfo
->ports
.Get(port
, getter_AddRefs(newPort
))) {
8062 newPort
= port
->Clone();
8063 scInfo
->ports
.Put(port
, newPort
);
8065 *aTag
= SCTAG_DOM_MAP_MESSAGEPORT
;
8066 *aOwnership
= JS::SCTAG_TMO_CUSTOM
;
8067 *aContent
= newPort
;
8077 PostMessageFreeTransferStructuredClone(uint32_t aTag
, JS::TransferableOwnership aOwnership
,
8078 void *aContent
, uint64_t aExtraData
, void* aClosure
)
8080 StructuredCloneInfo
* scInfo
= static_cast<StructuredCloneInfo
*>(aClosure
);
8081 NS_ASSERTION(scInfo
, "Must have scInfo!");
8083 if (aTag
== SCTAG_DOM_MAP_MESSAGEPORT
) {
8084 nsRefPtr
<MessagePortBase
> port(static_cast<MessagePort
*>(aContent
));
8085 scInfo
->ports
.Remove(port
);
8089 JSStructuredCloneCallbacks kPostMessageCallbacks
= {
8090 PostMessageReadStructuredClone
,
8091 PostMessageWriteStructuredClone
,
8093 PostMessageReadTransferStructuredClone
,
8094 PostMessageTransferStructuredClone
,
8095 PostMessageFreeTransferStructuredClone
8098 } // anonymous namespace
8100 static PLDHashOperator
8101 PopulateMessagePortList(MessagePortBase
* aKey
, MessagePortBase
* aValue
, void* aClosure
)
8103 nsTArray
<nsRefPtr
<MessagePortBase
> > *array
=
8104 static_cast<nsTArray
<nsRefPtr
<MessagePortBase
> > *>(aClosure
);
8106 array
->AppendElement(aKey
);
8107 return PL_DHASH_NEXT
;
8111 PostMessageEvent::Run()
8113 NS_ABORT_IF_FALSE(mTargetWindow
->IsOuterWindow(),
8114 "should have been passed an outer window!");
8115 NS_ABORT_IF_FALSE(!mSource
|| mSource
->IsOuterWindow(),
8116 "should have been passed an outer window!");
8120 JSContext
* cx
= jsapi
.cx();
8122 // If we bailed before this point we're going to leak mMessage, but
8123 // that's probably better than crashing.
8125 nsRefPtr
<nsGlobalWindow
> targetWindow
;
8126 if (mTargetWindow
->IsClosedOrClosing() ||
8127 !(targetWindow
= mTargetWindow
->GetCurrentInnerWindowInternal()) ||
8128 targetWindow
->IsClosedOrClosing())
8131 NS_ABORT_IF_FALSE(targetWindow
->IsInnerWindow(),
8132 "we ordered an inner window!");
8133 JSAutoCompartment
ac(cx
, targetWindow
->GetWrapperPreserveColor());
8135 // Ensure that any origin which might have been provided is the origin of this
8136 // window's document. Note that we do this *now* instead of when postMessage
8137 // is called because the target window might have been navigated to a
8138 // different location between then and now. If this check happened when
8139 // postMessage was called, it would be fairly easy for a malicious webpage to
8140 // intercept messages intended for another site by carefully timing navigation
8141 // of the target window so it changed location after postMessage but before
8143 if (mProvidedPrincipal
) {
8144 // Get the target's origin either from its principal or, in the case the
8145 // principal doesn't carry a URI (e.g. the system principal), the target's
8147 nsIPrincipal
* targetPrin
= targetWindow
->GetPrincipal();
8148 if (NS_WARN_IF(!targetPrin
))
8151 // Note: This is contrary to the spec with respect to file: URLs, which
8152 // the spec groups into a single origin, but given we intentionally
8153 // don't do that in other places it seems better to hold the line for
8154 // now. Long-term, we want HTML5 to address this so that we can
8155 // be compliant while being safer.
8156 if (!targetPrin
->Equals(mProvidedPrincipal
)) {
8161 // Deserialize the structured clone data
8162 JS::Rooted
<JS::Value
> messageData(cx
);
8163 StructuredCloneInfo scInfo
;
8164 scInfo
.event
= this;
8165 scInfo
.window
= targetWindow
;
8167 if (!mBuffer
.read(cx
, &messageData
, &kPostMessageCallbacks
, &scInfo
)) {
8168 return NS_ERROR_DOM_DATA_CLONE_ERR
;
8172 nsCOMPtr
<mozilla::dom::EventTarget
> eventTarget
=
8173 do_QueryInterface(static_cast<nsPIDOMWindow
*>(targetWindow
.get()));
8174 nsRefPtr
<MessageEvent
> event
=
8175 new MessageEvent(eventTarget
, nullptr, nullptr);
8177 event
->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */,
8178 false /*cancelable */, messageData
, mCallerOrigin
,
8179 EmptyString(), mSource
);
8181 nsTArray
<nsRefPtr
<MessagePortBase
> > ports
;
8182 scInfo
.ports
.EnumerateRead(PopulateMessagePortList
, &ports
);
8183 event
->SetPorts(new MessagePortList(static_cast<dom::Event
*>(event
.get()), ports
));
8185 // We can't simply call dispatchEvent on the window because doing so ends
8186 // up flipping the trusted bit on the event, and we don't want that to
8187 // happen because then untrusted content can call postMessage on a chrome
8188 // window if it can get a reference to it.
8190 nsIPresShell
*shell
= targetWindow
->mDoc
->GetShell();
8191 nsRefPtr
<nsPresContext
> presContext
;
8193 presContext
= shell
->GetPresContext();
8195 event
->SetTrusted(mTrustedCaller
);
8196 WidgetEvent
* internalEvent
= event
->GetInternalNSEvent();
8198 nsEventStatus status
= nsEventStatus_eIgnore
;
8199 EventDispatcher::Dispatch(static_cast<nsPIDOMWindow
*>(mTargetWindow
),
8202 static_cast<dom::Event
*>(event
.get()),
8208 nsGlobalWindow::PostMessageMoz(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
8209 const nsAString
& aTargetOrigin
,
8210 JS::Handle
<JS::Value
> aTransfer
,
8211 ErrorResult
& aError
)
8213 FORWARD_TO_OUTER_OR_THROW(PostMessageMoz
,
8214 (aCx
, aMessage
, aTargetOrigin
, aTransfer
, aError
),
8218 // Window.postMessage is an intentional subversion of the same-origin policy.
8219 // As such, this code must be particularly careful in the information it
8220 // exposes to calling code.
8222 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
8225 // First, get the caller's window
8226 nsRefPtr
<nsGlobalWindow
> callerInnerWin
= CallerInnerWindow();
8227 nsIPrincipal
* callerPrin
;
8228 if (callerInnerWin
) {
8229 NS_ABORT_IF_FALSE(callerInnerWin
->IsInnerWindow(),
8230 "should have gotten an inner window here");
8232 // Compute the caller's origin either from its principal or, in the case the
8233 // principal doesn't carry a URI (e.g. the system principal), the caller's
8234 // document. We must get this now instead of when the event is created and
8235 // dispatched, because ultimately it is the identity of the calling window
8236 // *now* that determines who sent the message (and not an identity which might
8237 // have changed due to intervening navigations).
8238 callerPrin
= callerInnerWin
->GetPrincipal();
8241 // In case the global is not a window, it can be a sandbox, and the sandbox's
8242 // principal can be used for the security check.
8243 nsIGlobalObject
* global
= GetIncumbentGlobal();
8244 NS_ASSERTION(global
, "Why is there no global object?");
8245 callerPrin
= global
->PrincipalOrNull();
8251 nsCOMPtr
<nsIURI
> callerOuterURI
;
8252 if (NS_FAILED(callerPrin
->GetURI(getter_AddRefs(callerOuterURI
)))) {
8256 nsAutoString origin
;
8257 if (callerOuterURI
) {
8258 // if the principal has a URI, use that to generate the origin
8259 nsContentUtils::GetUTFOrigin(callerPrin
, origin
);
8261 else if (callerInnerWin
) {
8262 // otherwise use the URI of the document to generate origin
8263 nsCOMPtr
<nsIDocument
> doc
= callerInnerWin
->GetExtantDoc();
8267 callerOuterURI
= doc
->GetDocumentURI();
8268 // if the principal has a URI, use that to generate the origin
8269 nsContentUtils::GetUTFOrigin(callerOuterURI
, origin
);
8272 // in case of a sandbox with a system principal origin can be empty
8273 if (!nsContentUtils::IsSystemPrincipal(callerPrin
)) {
8278 // Convert the provided origin string into a URI for comparison purposes.
8279 nsCOMPtr
<nsIPrincipal
> providedPrincipal
;
8281 if (aTargetOrigin
.EqualsASCII("/")) {
8282 providedPrincipal
= GetEntryGlobal()->PrincipalOrNull();
8283 if (NS_WARN_IF(!providedPrincipal
))
8287 // "*" indicates no specific origin is required.
8288 else if (!aTargetOrigin
.EqualsASCII("*")) {
8289 nsCOMPtr
<nsIURI
> originURI
;
8290 if (NS_FAILED(NS_NewURI(getter_AddRefs(originURI
), aTargetOrigin
))) {
8291 aError
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
8295 if (NS_FAILED(originURI
->SetUserPass(EmptyCString())) ||
8296 NS_FAILED(originURI
->SetPath(EmptyCString()))) {
8300 nsCOMPtr
<nsIScriptSecurityManager
> ssm
=
8301 nsContentUtils::GetSecurityManager();
8304 nsCOMPtr
<nsIPrincipal
> principal
= nsContentUtils::SubjectPrincipal();
8305 MOZ_ASSERT(principal
);
8308 if (NS_WARN_IF(NS_FAILED(principal
->GetAppId(&appId
))))
8312 if (NS_WARN_IF(NS_FAILED(principal
->GetIsInBrowserElement(&isInBrowser
))))
8315 // Create a nsIPrincipal inheriting the app/browser attributes from the
8317 nsresult rv
= ssm
->GetAppCodebasePrincipal(originURI
, appId
, isInBrowser
,
8318 getter_AddRefs(providedPrincipal
));
8319 if (NS_WARN_IF(NS_FAILED(rv
))) {
8324 // Create and asynchronously dispatch a runnable which will handle actual DOM
8325 // event creation and dispatch.
8326 nsRefPtr
<PostMessageEvent
> event
=
8327 new PostMessageEvent(nsContentUtils::IsCallerChrome() || !callerInnerWin
8329 : callerInnerWin
->GetOuterWindowInternal(),
8333 nsContentUtils::IsCallerChrome());
8335 // We *must* clone the data here, or the JS::Value could be modified
8337 StructuredCloneInfo scInfo
;
8338 scInfo
.event
= event
;
8339 scInfo
.window
= this;
8341 nsIPrincipal
* principal
= GetPrincipal();
8342 JS::Rooted
<JS::Value
> message(aCx
, aMessage
);
8343 JS::Rooted
<JS::Value
> transfer(aCx
, aTransfer
);
8344 if (NS_FAILED(callerPrin
->Subsumes(principal
, &scInfo
.subsumes
)) ||
8345 !event
->Buffer().write(aCx
, message
, transfer
, &kPostMessageCallbacks
,
8347 aError
.Throw(NS_ERROR_DOM_DATA_CLONE_ERR
);
8351 aError
= NS_DispatchToCurrentThread(event
);
8355 nsGlobalWindow::PostMessageMoz(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
8356 const nsAString
& aTargetOrigin
,
8357 const Optional
<Sequence
<JS::Value
> >& aTransfer
,
8358 ErrorResult
& aError
)
8360 JS::Rooted
<JS::Value
> transferArray(aCx
, JS::UndefinedValue());
8361 if (aTransfer
.WasPassed()) {
8362 const Sequence
<JS::Value
>& values
= aTransfer
.Value();
8364 // The input sequence only comes from the generated bindings code, which
8365 // ensures it is rooted.
8366 JS::HandleValueArray elements
=
8367 JS::HandleValueArray::fromMarkedLocation(values
.Length(), values
.Elements());
8369 transferArray
= JS::ObjectOrNullValue(JS_NewArrayObject(aCx
, elements
));
8370 if (transferArray
.isNull()) {
8371 aError
.Throw(NS_ERROR_OUT_OF_MEMORY
);
8376 PostMessageMoz(aCx
, aMessage
, aTargetOrigin
, transferArray
, aError
);
8380 nsGlobalWindow::PostMessageMoz(JS::Handle
<JS::Value
> aMessage
,
8381 const nsAString
& aOrigin
,
8382 JS::Handle
<JS::Value
> aTransfer
,
8386 PostMessageMoz(aCx
, aMessage
, aOrigin
, aTransfer
, rv
);
8388 return rv
.ErrorCode();
8391 class nsCloseEvent
: public nsRunnable
{
8393 nsRefPtr
<nsGlobalWindow
> mWindow
;
8396 nsCloseEvent(nsGlobalWindow
*aWindow
, bool aIndirect
)
8398 , mIndirect(aIndirect
)
8404 PostCloseEvent(nsGlobalWindow
* aWindow
, bool aIndirect
) {
8405 nsCOMPtr
<nsIRunnable
> ev
= new nsCloseEvent(aWindow
, aIndirect
);
8406 nsresult rv
= NS_DispatchToCurrentThread(ev
);
8407 if (NS_SUCCEEDED(rv
))
8408 aWindow
->MaybeForgiveSpamCount();
8415 return PostCloseEvent(mWindow
, false);
8417 mWindow
->ReallyCloseWindow();
8425 nsGlobalWindow::CanClose()
8427 MOZ_ASSERT(IsOuterWindow());
8433 // Ask the content viewer whether the toplevel window can close.
8434 // If the content viewer returns false, it is responsible for calling
8435 // Close() as soon as it is possible for the window to close.
8436 // This allows us to not close the window while printing is happening.
8438 nsCOMPtr
<nsIContentViewer
> cv
;
8439 mDocShell
->GetContentViewer(getter_AddRefs(cv
));
8442 nsresult rv
= cv
->PermitUnload(false, &canClose
);
8443 if (NS_SUCCEEDED(rv
) && !canClose
)
8446 rv
= cv
->RequestWindowClose(&canClose
);
8447 if (NS_SUCCEEDED(rv
) && !canClose
)
8455 nsGlobalWindow::Close(ErrorResult
& aError
)
8457 FORWARD_TO_OUTER_OR_THROW(Close
, (aError
), aError
, );
8459 if (!mDocShell
|| IsInModalState() ||
8460 (IsFrame() && !mDocShell
->GetIsBrowserOrApp())) {
8461 // window.close() is called on a frame in a frameset, on a window
8462 // that's already closed, or on a window for which there's
8463 // currently a modal dialog open. Ignore such calls.
8467 if (mHavePendingClose
) {
8468 // We're going to be closed anyway; do nothing since we don't want
8473 if (mBlockScriptedClosingFlag
)
8475 // A script's popup has been blocked and we don't want
8476 // the window to be closed directly after this event,
8477 // so the user can see that there was a blocked popup.
8481 // Don't allow scripts from content to close non-app or non-neterror
8482 // windows that were not opened by script.
8485 if (!mDocShell
->GetIsApp() &&
8486 !StringBeginsWith(url
, NS_LITERAL_STRING("about:neterror")) &&
8487 !mHadOriginalOpener
&& !nsContentUtils::IsCallerChrome()) {
8488 bool allowClose
= mAllowScriptsToClose
||
8489 Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
8491 // We're blocking the close operation
8492 // report localized error msg in JS console
8493 nsContentUtils::ReportToConsole(
8494 nsIScriptError::warningFlag
,
8495 NS_LITERAL_CSTRING("DOM Window"), mDoc
, // Better name for the category?
8496 nsContentUtils::eDOM_PROPERTIES
,
8497 "WindowCloseBlockedWarning");
8503 if (!mInClose
&& !mIsClosed
&& !CanClose()) {
8507 // Fire a DOM event notifying listeners that this window is about to
8508 // be closed. The tab UI code may choose to cancel the default
8509 // action for this event, if so, we won't actually close the window
8510 // (since the tab UI code will close the tab in stead). Sure, this
8511 // could be abused by content code, but do we care? I don't think
8514 bool wasInClose
= mInClose
;
8517 if (!DispatchCustomEvent(NS_LITERAL_STRING("DOMWindowClose"))) {
8518 // Someone chose to prevent the default action for this event, if
8519 // so, let's not close this window after all...
8521 mInClose
= wasInClose
;
8529 nsGlobalWindow::Close()
8534 return rv
.ErrorCode();
8538 nsGlobalWindow::ForceClose()
8540 MOZ_ASSERT(IsOuterWindow());
8542 if (IsFrame() || !mDocShell
) {
8543 // This may be a frame in a frameset, or a window that's already closed.
8544 // Ignore such calls.
8548 if (mHavePendingClose
) {
8549 // We're going to be closed anyway; do nothing since we don't want
8556 DispatchCustomEvent(NS_LITERAL_STRING("DOMWindowClose"));
8562 nsGlobalWindow::FinalClose()
8564 MOZ_ASSERT(IsOuterWindow());
8566 // Flag that we were closed.
8569 // This stuff is non-sensical but incredibly fragile. The reasons for the
8570 // behavior here don't make sense today and may not have ever made sense,
8571 // but various bits of frontend code break when you change them. If you need
8572 // to fix up this behavior, feel free to. It's a righteous task, but involves
8573 // wrestling with various download manager tests, frontend code, and possible
8574 // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
8577 // In particular, if |win|'s JSContext is at the top of the stack, we must
8578 // complete _two_ round-trips to the event loop before the call to
8579 // ReallyCloseWindow. This allows setTimeout handlers that are set after
8580 // FinalClose() is called to run before the window is torn down.
8581 bool indirect
= GetContextInternal() && // Occasionally null. See bug 877390.
8582 (nsContentUtils::GetCurrentJSContext() ==
8583 GetContextInternal()->GetNativeContext());
8584 if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect
))) {
8585 ReallyCloseWindow();
8587 mHavePendingClose
= true;
8593 nsGlobalWindow::ReallyCloseWindow()
8595 FORWARD_TO_OUTER_VOID(ReallyCloseWindow
, ());
8597 // Make sure we never reenter this method.
8598 mHavePendingClose
= true;
8600 nsCOMPtr
<nsIBaseWindow
> treeOwnerAsWin
= GetTreeOwnerWindow();
8602 // If there's no treeOwnerAsWin, this window must already be closed.
8604 if (treeOwnerAsWin
) {
8606 // but if we're a browser window we could be in some nasty
8607 // self-destroying cascade that we should mostly ignore
8610 nsCOMPtr
<nsIBrowserDOMWindow
> bwin
;
8611 nsCOMPtr
<nsIDocShellTreeItem
> rootItem
;
8612 mDocShell
->GetRootTreeItem(getter_AddRefs(rootItem
));
8613 nsCOMPtr
<nsIDOMWindow
> rootWin
=
8614 rootItem
? rootItem
->GetWindow() : nullptr;
8615 nsCOMPtr
<nsIDOMChromeWindow
> chromeWin(do_QueryInterface(rootWin
));
8617 chromeWin
->GetBrowserDOMWindow(getter_AddRefs(bwin
));
8620 /* Normally we destroy the entire window, but not if
8621 this DOM window belongs to a tabbed browser and doesn't
8622 correspond to a tab. This allows a well-behaved tab
8623 to destroy the container as it should but is a final measure
8624 to prevent an errant tab from doing so when it shouldn't.
8625 This works because we reach this code when we shouldn't only
8626 in the particular circumstance that we belong to a tab
8627 that has just been closed (and is therefore already missing
8628 from the list of browsers) (and has an unload handler
8629 that closes the window). */
8630 // XXXbz now that we have mHavePendingClose, is this needed?
8632 if (rootWin
== this ||
8633 !bwin
|| (bwin
->IsTabContentWindow(GetOuterWindowInternal(),
8635 treeOwnerAsWin
->Destroy();
8644 nsGlobalWindow::EnterModalState()
8646 MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
8648 // GetScriptableTop, not GetTop, so that EnterModalState works properly with
8649 // <iframe mozbrowser>.
8650 nsGlobalWindow
* topWin
= GetScriptableTop();
8653 NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
8657 // If there is an active ESM in this window, clear it. Otherwise, this can
8658 // cause a problem if a modal state is entered during a mouseup event.
8659 EventStateManager
* activeESM
=
8660 static_cast<EventStateManager
*>(
8661 EventStateManager::GetActiveEventStateManager());
8662 if (activeESM
&& activeESM
->GetPresContext()) {
8663 nsIPresShell
* activeShell
= activeESM
->GetPresContext()->GetPresShell();
8664 if (activeShell
&& (
8665 nsContentUtils::ContentIsCrossDocDescendantOf(activeShell
->GetDocument(), mDoc
) ||
8666 nsContentUtils::ContentIsCrossDocDescendantOf(mDoc
, activeShell
->GetDocument()))) {
8667 EventStateManager::ClearGlobalActiveContent(activeESM
);
8669 activeShell
->SetCapturingContent(nullptr, 0);
8672 nsRefPtr
<nsFrameSelection
> frameSelection
= activeShell
->FrameSelection();
8673 frameSelection
->SetDragState(false);
8678 // If there are any drag and drop operations in flight, try to end them.
8679 nsCOMPtr
<nsIDragService
> ds
=
8680 do_GetService("@mozilla.org/widget/dragservice;1");
8682 ds
->EndDragSession(true);
8685 // Clear the capturing content if it is under topDoc.
8686 // Usually the activeESM check above does that, but there are cases when
8687 // we don't have activeESM, or it is for different document.
8688 nsIDocument
* topDoc
= topWin
->GetExtantDoc();
8689 nsIContent
* capturingContent
= nsIPresShell::GetCapturingContent();
8690 if (capturingContent
&& topDoc
&&
8691 nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent
, topDoc
)) {
8692 nsIPresShell::SetCapturingContent(nullptr, 0);
8695 if (topWin
->mModalStateDepth
== 0) {
8696 NS_ASSERTION(!mSuspendedDoc
, "Shouldn't have mSuspendedDoc here!");
8698 mSuspendedDoc
= topDoc
;
8699 if (mSuspendedDoc
) {
8700 mSuspendedDoc
->SuppressEventHandling(nsIDocument::eAnimationsOnly
);
8703 topWin
->mModalStateDepth
++;
8708 nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow
*aTopWindow
,
8709 nsGlobalWindow
*aWindow
)
8711 nsGlobalWindow
*inner
;
8713 // Return early if we're frozen or have no inner window.
8714 if (!(inner
= aWindow
->GetCurrentInnerWindowInternal()) ||
8715 inner
->IsFrozen()) {
8719 inner
->RunTimeout(nullptr);
8721 // Check again if we're frozen since running pending timeouts
8722 // could've frozen us.
8723 if (inner
->IsFrozen()) {
8727 nsCOMPtr
<nsIDOMWindowCollection
> frames
;
8728 aWindow
->GetFrames(getter_AddRefs(frames
));
8735 if (NS_FAILED(frames
->GetLength(&length
)) || !length
) {
8739 for (i
= 0; i
< length
&& aTopWindow
->mModalStateDepth
== 0; i
++) {
8740 nsCOMPtr
<nsIDOMWindow
> child
;
8741 frames
->Item(i
, getter_AddRefs(child
));
8747 nsGlobalWindow
*childWin
=
8748 static_cast<nsGlobalWindow
*>
8749 (static_cast<nsIDOMWindow
*>
8752 RunPendingTimeoutsRecursive(aTopWindow
, childWin
);
8756 class nsPendingTimeoutRunner
: public nsRunnable
8759 explicit nsPendingTimeoutRunner(nsGlobalWindow
* aWindow
)
8762 NS_ASSERTION(mWindow
, "mWindow is null.");
8767 nsGlobalWindow::RunPendingTimeoutsRecursive(mWindow
, mWindow
);
8773 nsRefPtr
<nsGlobalWindow
> mWindow
;
8777 nsGlobalWindow::LeaveModalState()
8779 MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
8781 nsGlobalWindow
* topWin
= GetScriptableTop();
8784 NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
8788 topWin
->mModalStateDepth
--;
8790 if (topWin
->mModalStateDepth
== 0) {
8791 nsCOMPtr
<nsIRunnable
> runner
= new nsPendingTimeoutRunner(topWin
);
8792 if (NS_FAILED(NS_DispatchToCurrentThread(runner
)))
8793 NS_WARNING("failed to dispatch pending timeout runnable");
8795 if (mSuspendedDoc
) {
8796 nsCOMPtr
<nsIDocument
> currentDoc
= topWin
->GetExtantDoc();
8797 mSuspendedDoc
->UnsuppressEventHandlingAndFireEvents(nsIDocument::eAnimationsOnly
,
8798 currentDoc
== mSuspendedDoc
);
8799 mSuspendedDoc
= nullptr;
8803 // Remember the time of the last dialog quit.
8804 nsGlobalWindow
*inner
= topWin
->GetCurrentInnerWindowInternal();
8806 inner
->mLastDialogQuitTime
= TimeStamp::Now();
8810 nsGlobalWindow::IsInModalState()
8812 nsGlobalWindow
*topWin
= GetScriptableTop();
8815 NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
8820 return topWin
->mModalStateDepth
!= 0;
8825 nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow
* aWindow
) {
8826 nsCOMPtr
<nsIObserverService
> observerService
=
8827 services::GetObserverService();
8828 if (observerService
) {
8830 NotifyObservers(ToSupports(aWindow
),
8831 DOM_WINDOW_DESTROYED_TOPIC
, nullptr);
8835 class WindowDestroyedEvent
: public nsRunnable
8838 WindowDestroyedEvent(nsPIDOMWindow
* aWindow
, uint64_t aID
,
8839 const char* aTopic
) :
8840 mID(aID
), mTopic(aTopic
)
8842 mWindow
= do_GetWeakReference(aWindow
);
8847 nsCOMPtr
<nsIObserverService
> observerService
=
8848 do_GetService("@mozilla.org/observer-service;1");
8849 if (observerService
) {
8850 nsCOMPtr
<nsISupportsPRUint64
> wrapper
=
8851 do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID
);
8853 wrapper
->SetData(mID
);
8854 observerService
->NotifyObservers(wrapper
, mTopic
.get(), nullptr);
8858 bool skipNukeCrossCompartment
= false;
8860 nsCOMPtr
<nsIAppStartup
> appStartup
=
8861 do_GetService(NS_APPSTARTUP_CONTRACTID
);
8864 appStartup
->GetShuttingDown(&skipNukeCrossCompartment
);
8868 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryReferent(mWindow
);
8869 if (!skipNukeCrossCompartment
&& window
) {
8870 nsGlobalWindow
* currentInner
=
8871 window
->IsInnerWindow() ? static_cast<nsGlobalWindow
*>(window
.get()) :
8872 static_cast<nsGlobalWindow
*>(window
->GetCurrentInnerWindow());
8873 NS_ENSURE_TRUE(currentInner
, NS_OK
);
8875 AutoSafeJSContext cx
;
8876 JS::Rooted
<JSObject
*> obj(cx
, currentInner
->FastGetGlobalJSObject());
8877 // We only want to nuke wrappers for the chrome->content case
8878 if (obj
&& !js::IsSystemCompartment(js::GetObjectCompartment(obj
))) {
8879 js::NukeCrossCompartmentWrappers(cx
,
8880 js::ChromeCompartmentsOnly(),
8881 js::SingleCompartment(js::GetObjectCompartment(obj
)),
8882 window
->IsInnerWindow() ? js::DontNukeWindowReferences
:
8883 js::NukeWindowReferences
);
8897 nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic
)
8899 nsRefPtr
<nsIRunnable
> runnable
= new WindowDestroyedEvent(this, mWindowID
, aTopic
);
8900 nsresult rv
= NS_DispatchToCurrentThread(runnable
);
8901 if (NS_SUCCEEDED(rv
)) {
8902 mNotifiedIDDestroyed
= true;
8908 nsGlobalWindow::NotifyDOMWindowFrozen(nsGlobalWindow
* aWindow
) {
8909 if (aWindow
&& aWindow
->IsInnerWindow()) {
8910 nsCOMPtr
<nsIObserverService
> observerService
=
8911 services::GetObserverService();
8912 if (observerService
) {
8914 NotifyObservers(ToSupports(aWindow
),
8915 DOM_WINDOW_FROZEN_TOPIC
, nullptr);
8922 nsGlobalWindow::NotifyDOMWindowThawed(nsGlobalWindow
* aWindow
) {
8923 if (aWindow
&& aWindow
->IsInnerWindow()) {
8924 nsCOMPtr
<nsIObserverService
> observerService
=
8925 services::GetObserverService();
8926 if (observerService
) {
8928 NotifyObservers(ToSupports(aWindow
),
8929 DOM_WINDOW_THAWED_TOPIC
, nullptr);
8935 nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler
* aKey
)
8937 AutoSafeJSContext cx
;
8938 JS::Rooted
<JSObject
*> handler(cx
);
8939 if (mCachedXBLPrototypeHandlers
) {
8940 mCachedXBLPrototypeHandlers
->Get(aKey
, handler
.address());
8946 nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler
* aKey
,
8947 JS::Handle
<JSObject
*> aHandler
)
8949 if (!mCachedXBLPrototypeHandlers
) {
8950 mCachedXBLPrototypeHandlers
= new nsJSThingHashtable
<nsPtrHashKey
<nsXBLPrototypeHandler
>, JSObject
*>();
8951 PreserveWrapper(ToSupports(this));
8954 mCachedXBLPrototypeHandlers
->Put(aKey
, aHandler
);
8958 * GetScriptableFrameElement is called when script reads
8959 * nsIGlobalWindow::frameElement.
8961 * In contrast to GetRealFrameElement, GetScriptableFrameElement says that the
8962 * window contained by an <iframe mozbrowser> or <iframe mozapp> has no frame
8963 * element (effectively treating a mozbrowser the same as a content/chrome
8967 nsGlobalWindow::GetScriptableFrameElement(nsIDOMElement
** aFrameElement
)
8970 nsCOMPtr
<nsIDOMElement
> frameElement
= do_QueryInterface(GetFrameElement(rv
));
8972 return rv
.ErrorCode();
8975 frameElement
.forget(aFrameElement
);
8981 nsGlobalWindow::GetFrameElement(ErrorResult
& aError
)
8983 FORWARD_TO_OUTER_OR_THROW(GetFrameElement
, (aError
), aError
, nullptr);
8985 if (!mDocShell
|| mDocShell
->GetIsBrowserOrApp()) {
8989 // Per HTML5, the frameElement getter returns null in cross-origin situations.
8990 Element
* element
= GetRealFrameElement(aError
);
8991 if (aError
.Failed() || !element
) {
8994 if (!nsContentUtils::SubjectPrincipal()->
8995 SubsumesConsideringDomain(element
->NodePrincipal())) {
9002 nsGlobalWindow::GetRealFrameElement(ErrorResult
& aError
)
9004 FORWARD_TO_OUTER_OR_THROW(GetRealFrameElement
, (aError
), aError
, nullptr);
9010 nsCOMPtr
<nsIDocShell
> parent
;
9011 mDocShell
->GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent
));
9013 if (!parent
|| parent
== mDocShell
) {
9014 // We're at a chrome boundary, don't expose the chrome iframe
9015 // element to content code.
9019 return mFrameElement
;
9023 * nsIGlobalWindow::GetFrameElement (when called from C++) is just a wrapper
9024 * around GetRealFrameElement.
9027 nsGlobalWindow::GetRealFrameElement(nsIDOMElement
** aFrameElement
)
9030 nsCOMPtr
<nsIDOMElement
> frameElement
=
9031 do_QueryInterface(GetRealFrameElement(rv
));
9032 frameElement
.forget(aFrameElement
);
9034 return rv
.ErrorCode();
9037 // Helper for converting window.showModalDialog() options (list of ';'
9038 // separated name (:|=) value pairs) to a format that's parsable by
9039 // our normal window opening code.
9042 ConvertDialogOptions(const nsAString
& aOptions
, nsAString
& aResult
)
9044 nsAString::const_iterator end
;
9045 aOptions
.EndReading(end
);
9047 nsAString::const_iterator iter
;
9048 aOptions
.BeginReading(iter
);
9050 while (iter
!= end
) {
9052 while (nsCRT::IsAsciiSpace(*iter
) && iter
!= end
) {
9056 nsAString::const_iterator name_start
= iter
;
9058 // Skip characters until we find whitespace, ';', ':', or '='
9059 while (iter
!= end
&& !nsCRT::IsAsciiSpace(*iter
) &&
9066 nsAString::const_iterator name_end
= iter
;
9069 while (nsCRT::IsAsciiSpace(*iter
) && iter
!= end
) {
9074 // No value found, skip the ';' and keep going.
9080 nsAString::const_iterator value_start
= iter
;
9081 nsAString::const_iterator value_end
= iter
;
9083 if (*iter
== ':' || *iter
== '=') {
9084 // We found name followed by ':' or '='. Look for a value.
9086 iter
++; // Skip the ':' or '='
9089 while (nsCRT::IsAsciiSpace(*iter
) && iter
!= end
) {
9095 // Skip until we find whitespace, or ';'.
9096 while (iter
!= end
&& !nsCRT::IsAsciiSpace(*iter
) &&
9104 while (nsCRT::IsAsciiSpace(*iter
) && iter
!= end
) {
9109 const nsDependentSubstring
& name
= Substring(name_start
, name_end
);
9110 const nsDependentSubstring
& value
= Substring(value_start
, value_end
);
9112 if (name
.LowerCaseEqualsLiteral("center")) {
9113 if (value
.LowerCaseEqualsLiteral("on") ||
9114 value
.LowerCaseEqualsLiteral("yes") ||
9115 value
.LowerCaseEqualsLiteral("1")) {
9116 aResult
.AppendLiteral(",centerscreen=1");
9118 } else if (name
.LowerCaseEqualsLiteral("dialogwidth")) {
9119 if (!value
.IsEmpty()) {
9120 aResult
.AppendLiteral(",width=");
9121 aResult
.Append(value
);
9123 } else if (name
.LowerCaseEqualsLiteral("dialogheight")) {
9124 if (!value
.IsEmpty()) {
9125 aResult
.AppendLiteral(",height=");
9126 aResult
.Append(value
);
9128 } else if (name
.LowerCaseEqualsLiteral("dialogtop")) {
9129 if (!value
.IsEmpty()) {
9130 aResult
.AppendLiteral(",top=");
9131 aResult
.Append(value
);
9133 } else if (name
.LowerCaseEqualsLiteral("dialogleft")) {
9134 if (!value
.IsEmpty()) {
9135 aResult
.AppendLiteral(",left=");
9136 aResult
.Append(value
);
9138 } else if (name
.LowerCaseEqualsLiteral("resizable")) {
9139 if (value
.LowerCaseEqualsLiteral("on") ||
9140 value
.LowerCaseEqualsLiteral("yes") ||
9141 value
.LowerCaseEqualsLiteral("1")) {
9142 aResult
.AppendLiteral(",resizable=1");
9144 } else if (name
.LowerCaseEqualsLiteral("scroll")) {
9145 if (value
.LowerCaseEqualsLiteral("off") ||
9146 value
.LowerCaseEqualsLiteral("no") ||
9147 value
.LowerCaseEqualsLiteral("0")) {
9148 aResult
.AppendLiteral(",scrollbars=0");
9160 already_AddRefed
<nsIVariant
>
9161 nsGlobalWindow::ShowModalDialog(const nsAString
& aUrl
, nsIVariant
* aArgument
,
9162 const nsAString
& aOptions
, ErrorResult
& aError
)
9165 mDoc
->WarnOnceAbout(nsIDocument::eShowModalDialog
);
9168 FORWARD_TO_OUTER_OR_THROW(ShowModalDialog
,
9169 (aUrl
, aArgument
, aOptions
, aError
), aError
,
9172 if (!IsShowModalDialogEnabled()) {
9173 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
9177 nsRefPtr
<DialogValueHolder
> argHolder
=
9178 new DialogValueHolder(nsContentUtils::SubjectPrincipal(), aArgument
);
9180 // Before bringing up the window/dialog, unsuppress painting and flush
9182 EnsureReflowFlushAndPaint();
9184 if (!AreDialogsEnabled()) {
9185 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
9189 if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
9190 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
9194 nsCOMPtr
<nsIDOMWindow
> dlgWin
;
9195 nsAutoString
options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
9197 ConvertDialogOptions(aOptions
, options
);
9199 options
.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
9202 uint32_t oldMicroTaskLevel
= nsContentUtils::MicroTaskLevel();
9203 nsContentUtils::SetMicroTaskLevel(0);
9204 aError
= OpenInternal(aUrl
, EmptyString(), options
,
9206 true, // aContentModal
9207 true, // aCalledNoScript
9208 true, // aDoJSFixups
9210 nullptr, argHolder
, // args
9211 GetPrincipal(), // aCalleePrincipal
9212 nullptr, // aJSCallerContext
9213 getter_AddRefs(dlgWin
));
9214 nsContentUtils::SetMicroTaskLevel(oldMicroTaskLevel
);
9216 if (aError
.Failed()) {
9220 nsCOMPtr
<nsIDOMModalContentWindow
> dialog
= do_QueryInterface(dlgWin
);
9225 nsCOMPtr
<nsIVariant
> retVal
;
9226 aError
= dialog
->GetReturnValue(getter_AddRefs(retVal
));
9227 MOZ_ASSERT(!aError
.Failed());
9229 return retVal
.forget();
9233 nsGlobalWindow::ShowModalDialog(JSContext
* aCx
, const nsAString
& aUrl
,
9234 JS::Handle
<JS::Value
> aArgument
,
9235 const nsAString
& aOptions
,
9236 JS::MutableHandle
<JS::Value
> aRetval
,
9237 ErrorResult
& aError
)
9239 nsCOMPtr
<nsIVariant
> args
;
9240 aError
= nsContentUtils::XPConnect()->JSToVariant(aCx
,
9242 getter_AddRefs(args
));
9243 if (aError
.Failed()) {
9247 nsCOMPtr
<nsIVariant
> retVal
= ShowModalDialog(aUrl
, args
, aOptions
, aError
);
9248 if (aError
.Failed()) {
9252 JS::Rooted
<JS::Value
> result(aCx
);
9254 aError
= nsContentUtils::XPConnect()->VariantToJS(aCx
,
9255 FastGetGlobalJSObject(),
9263 nsGlobalWindow::ShowModalDialog(const nsAString
& aURI
, nsIVariant
*aArgs_
,
9264 const nsAString
& aOptions
, uint8_t aArgc
,
9265 nsIVariant
**aRetVal
)
9267 // Per-spec the |arguments| parameter is supposed to pass through unmodified.
9268 // However, XPConnect default-initializes variants to null, rather than
9269 // undefined. Fix this up here.
9270 nsCOMPtr
<nsIVariant
> aArgs
= aArgs_
;
9272 aArgs
= CreateVoidVariant();
9276 nsCOMPtr
<nsIVariant
> retVal
= ShowModalDialog(aURI
, aArgs
, aOptions
, rv
);
9277 retVal
.forget(aRetVal
);
9279 return rv
.ErrorCode();
9282 class CommandDispatcher
: public nsRunnable
9285 CommandDispatcher(nsIDOMXULCommandDispatcher
* aDispatcher
,
9286 const nsAString
& aAction
)
9287 : mDispatcher(aDispatcher
), mAction(aAction
) {}
9291 return mDispatcher
->UpdateCommands(mAction
);
9294 nsCOMPtr
<nsIDOMXULCommandDispatcher
> mDispatcher
;
9299 CheckReason(int16_t aReason
, SelectionChangeReason aReasonType
)
9301 switch (aReasonType
) {
9302 case SelectionChangeReason::Drag
:
9303 return aReason
& nsISelectionListener::DRAG_REASON
;
9304 case SelectionChangeReason::Mousedown
:
9305 return aReason
& nsISelectionListener::MOUSEDOWN_REASON
;
9306 case SelectionChangeReason::Mouseup
:
9307 return aReason
& nsISelectionListener::MOUSEUP_REASON
;
9308 case SelectionChangeReason::Keypress
:
9309 return aReason
& nsISelectionListener::KEYPRESS_REASON
;
9310 case SelectionChangeReason::Selectall
:
9311 return aReason
& nsISelectionListener::SELECTALL_REASON
;
9312 case SelectionChangeReason::Collapsetostart
:
9313 return aReason
& nsISelectionListener::COLLAPSETOSTART_REASON
;
9314 case SelectionChangeReason::Collapsetoend
:
9315 return aReason
& nsISelectionListener::COLLAPSETOEND_REASON
;
9322 nsGlobalWindow::UpdateCommands(const nsAString
& anAction
, nsISelection
* aSel
, int16_t aReason
)
9324 nsPIDOMWindow
*rootWindow
= nsGlobalWindow::GetPrivateRoot();
9328 nsCOMPtr
<nsIDOMXULDocument
> xulDoc
=
9329 do_QueryInterface(rootWindow
->GetExtantDoc());
9330 // See if we contain a XUL document.
9331 // selectionchange action is only used for mozbrowser, not for XUL. So we bypass
9332 // XUL command dispatch if anAction is "selectionchange".
9333 if (xulDoc
&& !anAction
.EqualsLiteral("selectionchange")) {
9334 // Retrieve the command dispatcher and call updateCommands on it.
9335 nsCOMPtr
<nsIDOMXULCommandDispatcher
> xulCommandDispatcher
;
9336 xulDoc
->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher
));
9337 if (xulCommandDispatcher
) {
9338 nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher
,
9343 if (gSelectionCaretPrefEnabled
&& mDoc
&& anAction
.EqualsLiteral("selectionchange")) {
9344 SelectionChangeEventInit init
;
9345 init
.mBubbles
= true;
9347 nsCOMPtr
<nsIDOMRange
> range
;
9348 nsresult rv
= aSel
->GetRangeAt(0, getter_AddRefs(range
));
9349 if (NS_SUCCEEDED(rv
) && range
) {
9350 nsRefPtr
<nsRange
> nsrange
= static_cast<nsRange
*>(range
.get());
9351 init
.mBoundingClientRect
= nsrange
->GetBoundingClientRect(true, false);
9352 range
->ToString(init
.mSelectedText
);
9354 for (uint32_t reasonType
= 0;
9355 reasonType
< static_cast<uint32_t>(SelectionChangeReason::EndGuard_
);
9357 SelectionChangeReason strongReasonType
=
9358 static_cast<SelectionChangeReason
>(reasonType
);
9359 if (CheckReason(aReason
, strongReasonType
)) {
9360 init
.mReasons
.AppendElement(strongReasonType
);
9365 nsRefPtr
<SelectionChangeEvent
> event
=
9366 SelectionChangeEvent::Constructor(mDoc
, NS_LITERAL_STRING("mozselectionchange"), init
);
9368 event
->SetTrusted(true);
9369 event
->GetInternalNSEvent()->mFlags
.mOnlyChromeDispatch
= true;
9371 mDoc
->DispatchEvent(event
, &ret
);
9379 nsGlobalWindow::GetSelection(ErrorResult
& aError
)
9381 FORWARD_TO_OUTER_OR_THROW(GetSelection
, (aError
), aError
, nullptr);
9387 nsCOMPtr
<nsIPresShell
> presShell
= mDocShell
->GetPresShell();
9392 return static_cast<Selection
*>(presShell
->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL
));
9396 nsGlobalWindow::GetSelection(nsISelection
** aSelection
)
9399 nsCOMPtr
<nsISelection
> selection
= GetSelection(rv
);
9400 selection
.forget(aSelection
);
9402 return rv
.ErrorCode();
9406 nsGlobalWindow::Find(const nsAString
& aString
, bool aCaseSensitive
,
9407 bool aBackwards
, bool aWrapAround
, bool aWholeWord
,
9408 bool aSearchInFrames
, bool aShowDialog
,
9409 ErrorResult
& aError
)
9411 if (Preferences::GetBool("dom.disable_window_find", false)) {
9412 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
9416 FORWARD_TO_OUTER_OR_THROW(Find
,
9417 (aString
, aCaseSensitive
, aBackwards
, aWrapAround
,
9418 aWholeWord
, aSearchInFrames
, aShowDialog
, aError
),
9421 nsCOMPtr
<nsIWebBrowserFind
> finder(do_GetInterface(mDocShell
));
9423 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
9427 // Set the options of the search
9428 aError
= finder
->SetSearchString(PromiseFlatString(aString
).get());
9429 if (aError
.Failed()) {
9432 finder
->SetMatchCase(aCaseSensitive
);
9433 finder
->SetFindBackwards(aBackwards
);
9434 finder
->SetWrapFind(aWrapAround
);
9435 finder
->SetEntireWord(aWholeWord
);
9436 finder
->SetSearchFrames(aSearchInFrames
);
9438 // the nsIWebBrowserFind is initialized to use this window
9439 // as the search root, but uses focus to set the current search
9440 // frame. If we're being called from JS (as here), this window
9441 // should be the current search frame.
9442 nsCOMPtr
<nsIWebBrowserFindInFrames
> framesFinder(do_QueryInterface(finder
));
9444 framesFinder
->SetRootSearchFrame(this); // paranoia
9445 framesFinder
->SetCurrentSearchFrame(this);
9448 // The Find API does not accept empty strings. Launch the Find Dialog.
9449 if (aString
.IsEmpty() || aShowDialog
) {
9450 // See if the find dialog is already up using nsIWindowMediator
9451 nsCOMPtr
<nsIWindowMediator
> windowMediator
=
9452 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
);
9454 nsCOMPtr
<nsIDOMWindow
> findDialog
;
9456 if (windowMediator
) {
9457 windowMediator
->GetMostRecentWindow(MOZ_UTF16("findInPage"),
9458 getter_AddRefs(findDialog
));
9462 // The Find dialog is already open, bring it to the top.
9463 aError
= findDialog
->Focus();
9464 } else if (finder
) {
9465 // Open a Find dialog
9466 nsCOMPtr
<nsIDOMWindow
> dialog
;
9467 aError
= OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"),
9468 NS_LITERAL_STRING("_blank"),
9469 NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"),
9470 finder
, getter_AddRefs(dialog
));
9476 // Launch the search with the passed in search string
9477 bool didFind
= false;
9478 aError
= finder
->FindNext(&didFind
);
9483 nsGlobalWindow::Find(const nsAString
& aStr
, bool aCaseSensitive
,
9484 bool aBackwards
, bool aWrapAround
, bool aWholeWord
,
9485 bool aSearchInFrames
, bool aShowDialog
,
9489 *aDidFind
= Find(aStr
, aCaseSensitive
, aBackwards
, aWrapAround
, aWholeWord
,
9490 aSearchInFrames
, aShowDialog
, rv
);
9492 return rv
.ErrorCode();
9496 nsGlobalWindow::Atob(const nsAString
& aAsciiBase64String
,
9497 nsAString
& aBinaryData
, ErrorResult
& aError
)
9499 aError
= nsContentUtils::Atob(aAsciiBase64String
, aBinaryData
);
9503 nsGlobalWindow::Atob(const nsAString
& aAsciiBase64String
,
9504 nsAString
& aBinaryData
)
9507 Atob(aAsciiBase64String
, aBinaryData
, rv
);
9509 return rv
.ErrorCode();
9513 nsGlobalWindow::Btoa(const nsAString
& aBinaryData
,
9514 nsAString
& aAsciiBase64String
, ErrorResult
& aError
)
9516 aError
= nsContentUtils::Btoa(aBinaryData
, aAsciiBase64String
);
9520 nsGlobalWindow::Btoa(const nsAString
& aBinaryData
,
9521 nsAString
& aAsciiBase64String
)
9524 Btoa(aBinaryData
, aAsciiBase64String
, rv
);
9526 return rv
.ErrorCode();
9529 //*****************************************************************************
9530 // nsGlobalWindow::nsIDOMEventTarget
9531 //*****************************************************************************
9534 nsGlobalWindow::RemoveEventListener(const nsAString
& aType
,
9535 nsIDOMEventListener
* aListener
,
9538 if (nsRefPtr
<EventListenerManager
> elm
= GetExistingListenerManager()) {
9539 elm
->RemoveEventListener(aType
, aListener
, aUseCapture
);
9544 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow
)
9547 nsGlobalWindow::DispatchEvent(nsIDOMEvent
* aEvent
, bool* aRetVal
)
9549 FORWARD_TO_INNER(DispatchEvent
, (aEvent
, aRetVal
), NS_OK
);
9551 if (!IsCurrentInnerWindow()) {
9552 NS_WARNING("DispatchEvent called on non-current inner window, dropping. "
9553 "Please check the window in the caller instead.");
9554 return NS_ERROR_FAILURE
;
9558 return NS_ERROR_FAILURE
;
9561 // Obtain a presentation shell
9562 nsIPresShell
*shell
= mDoc
->GetShell();
9563 nsRefPtr
<nsPresContext
> presContext
;
9565 // Retrieve the context
9566 presContext
= shell
->GetPresContext();
9569 nsEventStatus status
= nsEventStatus_eIgnore
;
9571 EventDispatcher::DispatchDOMEvent(GetOuterWindow(), nullptr, aEvent
,
9572 presContext
, &status
);
9574 *aRetVal
= (status
!= nsEventStatus_eConsumeNoDefault
);
9579 nsGlobalWindow::AddEventListener(const nsAString
& aType
,
9580 nsIDOMEventListener
*aListener
,
9581 bool aUseCapture
, bool aWantsUntrusted
,
9582 uint8_t aOptionalArgc
)
9584 NS_ASSERTION(!aWantsUntrusted
|| aOptionalArgc
> 1,
9585 "Won't check if this is chrome, you want to set "
9586 "aWantsUntrusted to false or make the aWantsUntrusted "
9587 "explicit by making optional_argc non-zero.");
9589 if (IsOuterWindow() && mInnerWindow
&&
9590 !nsContentUtils::CanCallerAccess(mInnerWindow
)) {
9591 return NS_ERROR_DOM_SECURITY_ERR
;
9594 if (!aWantsUntrusted
&&
9595 (aOptionalArgc
< 2 && !nsContentUtils::IsChromeDoc(mDoc
))) {
9596 aWantsUntrusted
= true;
9599 EventListenerManager
* manager
= GetOrCreateListenerManager();
9600 NS_ENSURE_STATE(manager
);
9601 manager
->AddEventListener(aType
, aListener
, aUseCapture
, aWantsUntrusted
);
9606 nsGlobalWindow::AddEventListener(const nsAString
& aType
,
9607 EventListener
* aListener
,
9609 const Nullable
<bool>& aWantsUntrusted
,
9612 if (IsOuterWindow() && mInnerWindow
&&
9613 !nsContentUtils::CanCallerAccess(mInnerWindow
)) {
9614 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
9618 bool wantsUntrusted
;
9619 if (aWantsUntrusted
.IsNull()) {
9620 wantsUntrusted
= !nsContentUtils::IsChromeDoc(mDoc
);
9622 wantsUntrusted
= aWantsUntrusted
.Value();
9625 EventListenerManager
* manager
= GetOrCreateListenerManager();
9627 aRv
.Throw(NS_ERROR_UNEXPECTED
);
9630 manager
->AddEventListener(aType
, aListener
, aUseCapture
, wantsUntrusted
);
9634 nsGlobalWindow::AddSystemEventListener(const nsAString
& aType
,
9635 nsIDOMEventListener
*aListener
,
9637 bool aWantsUntrusted
,
9638 uint8_t aOptionalArgc
)
9640 NS_ASSERTION(!aWantsUntrusted
|| aOptionalArgc
> 1,
9641 "Won't check if this is chrome, you want to set "
9642 "aWantsUntrusted to false or make the aWantsUntrusted "
9643 "explicit by making optional_argc non-zero.");
9645 if (IsOuterWindow() && mInnerWindow
&&
9646 !nsContentUtils::CanCallerAccess(mInnerWindow
)) {
9647 return NS_ERROR_DOM_SECURITY_ERR
;
9650 if (!aWantsUntrusted
&&
9651 (aOptionalArgc
< 2 && !nsContentUtils::IsChromeDoc(mDoc
))) {
9652 aWantsUntrusted
= true;
9655 return NS_AddSystemEventListener(this, aType
, aListener
, aUseCapture
,
9659 EventListenerManager
*
9660 nsGlobalWindow::GetOrCreateListenerManager()
9662 FORWARD_TO_INNER_CREATE(GetOrCreateListenerManager
, (), nullptr);
9664 if (!mListenerManager
) {
9666 new EventListenerManager(static_cast<EventTarget
*>(this));
9669 return mListenerManager
;
9672 EventListenerManager
*
9673 nsGlobalWindow::GetExistingListenerManager() const
9675 FORWARD_TO_INNER(GetExistingListenerManager
, (), nullptr);
9677 return mListenerManager
;
9681 nsGlobalWindow::GetContextForEventHandlers(nsresult
* aRv
)
9683 *aRv
= NS_ERROR_UNEXPECTED
;
9684 NS_ENSURE_TRUE(!IsInnerWindow() || IsCurrentInnerWindow(), nullptr);
9686 nsIScriptContext
* scx
;
9687 if ((scx
= GetContext())) {
9694 //*****************************************************************************
9695 // nsGlobalWindow::nsPIDOMWindow
9696 //*****************************************************************************
9699 nsGlobalWindow::GetPrivateParent()
9701 MOZ_ASSERT(IsOuterWindow());
9703 nsCOMPtr
<nsIDOMWindow
> parent
;
9704 GetParent(getter_AddRefs(parent
));
9706 if (static_cast<nsIDOMWindow
*>(this) == parent
.get()) {
9707 nsCOMPtr
<nsIContent
> chromeElement(do_QueryInterface(mChromeEventHandler
));
9709 return nullptr; // This is ok, just means a null parent.
9711 nsIDocument
* doc
= chromeElement
->GetComposedDoc();
9713 return nullptr; // This is ok, just means a null parent.
9715 return doc
->GetWindow();
9719 return static_cast<nsGlobalWindow
*>
9720 (static_cast<nsIDOMWindow
*>(parent
.get()));
9727 nsGlobalWindow::GetPrivateRoot()
9729 if (IsInnerWindow()) {
9730 nsGlobalWindow
* outer
= GetOuterWindowInternal();
9732 NS_WARNING("No outer window available!");
9735 return outer
->GetPrivateRoot();
9738 nsCOMPtr
<nsIDOMWindow
> top
;
9739 GetTop(getter_AddRefs(top
));
9741 nsCOMPtr
<nsIContent
> chromeElement(do_QueryInterface(mChromeEventHandler
));
9742 if (chromeElement
) {
9743 nsIDocument
* doc
= chromeElement
->GetComposedDoc();
9745 nsIDOMWindow
*parent
= doc
->GetWindow();
9747 parent
->GetTop(getter_AddRefs(top
));
9752 return static_cast<nsGlobalWindow
*>(top
.get());
9757 nsGlobalWindow::GetLocation(ErrorResult
& aError
)
9759 FORWARD_TO_INNER_OR_THROW(GetLocation
, (aError
), aError
, nullptr);
9761 nsIDocShell
*docShell
= GetDocShell();
9762 if (!mLocation
&& docShell
) {
9763 mLocation
= new nsLocation(this, docShell
);
9769 nsGlobalWindow::GetLocation(nsIDOMLocation
** aLocation
)
9772 nsCOMPtr
<nsIDOMLocation
> location
= GetLocation(rv
);
9773 location
.forget(aLocation
);
9775 return rv
.ErrorCode();
9779 nsGlobalWindow::ActivateOrDeactivate(bool aActivate
)
9781 MOZ_ASSERT(IsOuterWindow());
9783 // Set / unset mIsActive on the top level window, which is used for the
9784 // :-moz-window-inactive pseudoclass, and its sheet (if any).
9785 nsCOMPtr
<nsIWidget
> mainWidget
= GetMainWidget();
9789 // Get the top level widget (if the main widget is a sheet, this will
9790 // be the sheet's top (non-sheet) parent).
9791 nsCOMPtr
<nsIWidget
> topLevelWidget
= mainWidget
->GetSheetWindowParent();
9792 if (!topLevelWidget
) {
9793 topLevelWidget
= mainWidget
;
9796 nsCOMPtr
<nsPIDOMWindow
> piMainWindow(
9797 do_QueryInterface(static_cast<nsIDOMWindow
*>(this)));
9798 piMainWindow
->SetActive(aActivate
);
9800 if (mainWidget
!= topLevelWidget
) {
9801 // This is a workaround for the following problem:
9802 // When a window with an open sheet gains or loses focus, only the sheet
9803 // window receives the NS_ACTIVATE/NS_DEACTIVATE event. However the
9804 // styling of the containing top level window also needs to change. We
9805 // get around this by calling nsPIDOMWindow::SetActive() on both windows.
9807 // Get the top level widget's nsGlobalWindow
9808 nsCOMPtr
<nsIDOMWindow
> topLevelWindow
;
9810 // widgetListener should be a nsXULWindow
9811 nsIWidgetListener
* listener
= topLevelWidget
->GetWidgetListener();
9813 nsCOMPtr
<nsIXULWindow
> window
= listener
->GetXULWindow();
9814 nsCOMPtr
<nsIInterfaceRequestor
> req(do_QueryInterface(window
));
9815 topLevelWindow
= do_GetInterface(req
);
9818 if (topLevelWindow
) {
9819 nsCOMPtr
<nsPIDOMWindow
> piWin(do_QueryInterface(topLevelWindow
));
9820 piWin
->SetActive(aActivate
);
9826 NotifyDocumentTree(nsIDocument
* aDocument
, void* aData
)
9828 aDocument
->EnumerateSubDocuments(NotifyDocumentTree
, nullptr);
9829 aDocument
->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE
);
9834 nsGlobalWindow::SetActive(bool aActive
)
9836 nsPIDOMWindow::SetActive(aActive
);
9837 NotifyDocumentTree(mDoc
, nullptr);
9840 void nsGlobalWindow::SetIsBackground(bool aIsBackground
)
9842 MOZ_ASSERT(IsOuterWindow());
9844 bool resetTimers
= (!aIsBackground
&& IsBackground());
9845 nsPIDOMWindow::SetIsBackground(aIsBackground
);
9847 ResetTimersForNonBackgroundWindow();
9850 if (!aIsBackground
) {
9851 nsGlobalWindow
* inner
= GetCurrentInnerWindowInternal();
9853 inner
->SyncGamepadState();
9859 void nsGlobalWindow::MaybeUpdateTouchState()
9861 FORWARD_TO_INNER_VOID(MaybeUpdateTouchState
, ());
9863 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
9865 nsCOMPtr
<nsIDOMWindow
> focusedWindow
;
9866 fm
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
9868 if(this == focusedWindow
) {
9872 if (mMayHaveTouchEventListener
) {
9873 nsCOMPtr
<nsIObserverService
> observerService
=
9874 services::GetObserverService();
9876 if (observerService
) {
9877 observerService
->NotifyObservers(static_cast<nsIDOMWindow
*>(this),
9878 DOM_TOUCH_LISTENER_ADDED
,
9884 void nsGlobalWindow::UpdateTouchState()
9886 FORWARD_TO_INNER_VOID(UpdateTouchState
, ());
9888 nsCOMPtr
<nsIWidget
> mainWidget
= GetMainWidget();
9893 if (mMayHaveTouchEventListener
) {
9894 mainWidget
->RegisterTouchWindow();
9896 mainWidget
->UnregisterTouchWindow();
9901 nsGlobalWindow::EnableGamepadUpdates()
9903 MOZ_ASSERT(IsInnerWindow());
9907 nsRefPtr
<GamepadService
> gamepadsvc(GamepadService::GetService());
9909 gamepadsvc
->AddListener(this);
9916 nsGlobalWindow::DisableGamepadUpdates()
9918 MOZ_ASSERT(IsInnerWindow());
9922 nsRefPtr
<GamepadService
> gamepadsvc(GamepadService::GetService());
9924 gamepadsvc
->RemoveListener(this);
9931 nsGlobalWindow::SetChromeEventHandler(EventTarget
* aChromeEventHandler
)
9933 MOZ_ASSERT(IsOuterWindow());
9935 SetChromeEventHandlerInternal(aChromeEventHandler
);
9936 // update the chrome event handler on all our inner windows
9937 for (nsGlobalWindow
*inner
= (nsGlobalWindow
*)PR_LIST_HEAD(this);
9939 inner
= (nsGlobalWindow
*)PR_NEXT_LINK(inner
)) {
9940 NS_ASSERTION(!inner
->mOuterWindow
|| inner
->mOuterWindow
== this,
9941 "bad outer window pointer");
9942 inner
->SetChromeEventHandlerInternal(aChromeEventHandler
);
9946 static bool IsLink(nsIContent
* aContent
)
9948 return aContent
&& (aContent
->IsHTML(nsGkAtoms::a
) ||
9949 aContent
->AttrValueIs(kNameSpaceID_XLink
, nsGkAtoms::type
,
9950 nsGkAtoms::simple
, eCaseMatters
));
9954 nsGlobalWindow::SetFocusedNode(nsIContent
* aNode
,
9955 uint32_t aFocusMethod
,
9958 FORWARD_TO_INNER_VOID(SetFocusedNode
, (aNode
, aFocusMethod
, aNeedsFocus
));
9960 if (aNode
&& aNode
->GetComposedDoc() != mDoc
) {
9961 NS_WARNING("Trying to set focus to a node from a wrong document");
9966 NS_ASSERTION(!aNode
, "Trying to focus cleaned up window!");
9968 aNeedsFocus
= false;
9970 if (mFocusedNode
!= aNode
) {
9971 UpdateCanvasFocus(false, aNode
);
9972 mFocusedNode
= aNode
;
9973 mFocusMethod
= aFocusMethod
& FOCUSMETHOD_MASK
;
9974 mShowFocusRingForContent
= false;
9978 // if a node was focused by a keypress, turn on focus rings for the
9980 if (mFocusMethod
& nsIFocusManager::FLAG_BYKEY
) {
9981 mFocusByKeyOccurred
= true;
9983 // otherwise, we set mShowFocusRingForContent, as we don't want this to
9984 // be permanent for the window. On Windows, focus rings are only shown
9985 // when the FLAG_SHOWRING flag is used. On other platforms, focus rings
9986 // are only hidden for clicks on links.
9988 !(mFocusMethod
& nsIFocusManager::FLAG_BYMOUSE
) || !IsLink(aNode
) ||
9990 aFocusMethod
& nsIFocusManager::FLAG_SHOWRING
) {
9991 mShowFocusRingForContent
= true;
9996 mNeedsFocus
= aNeedsFocus
;
10000 nsGlobalWindow::GetFocusMethod()
10002 FORWARD_TO_INNER(GetFocusMethod
, (), 0);
10004 return mFocusMethod
;
10008 nsGlobalWindow::ShouldShowFocusRing()
10010 FORWARD_TO_INNER(ShouldShowFocusRing
, (), false);
10012 return mShowFocusRings
|| mShowFocusRingForContent
|| mFocusByKeyOccurred
;
10016 nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators
,
10017 UIStateChangeType aShowFocusRings
)
10019 FORWARD_TO_INNER_VOID(SetKeyboardIndicators
, (aShowAccelerators
, aShowFocusRings
));
10021 bool oldShouldShowFocusRing
= ShouldShowFocusRing();
10023 // only change the flags that have been modified
10024 if (aShowAccelerators
!= UIStateChangeType_NoChange
)
10025 mShowAccelerators
= aShowAccelerators
== UIStateChangeType_Set
;
10026 if (aShowFocusRings
!= UIStateChangeType_NoChange
)
10027 mShowFocusRings
= aShowFocusRings
== UIStateChangeType_Set
;
10029 // propagate the indicators to child windows
10030 nsCOMPtr
<nsIDocShell
> docShell
= GetDocShell();
10032 int32_t childCount
= 0;
10033 docShell
->GetChildCount(&childCount
);
10035 for (int32_t i
= 0; i
< childCount
; ++i
) {
10036 nsCOMPtr
<nsIDocShellTreeItem
> childShell
;
10037 docShell
->GetChildAt(i
, getter_AddRefs(childShell
));
10042 nsCOMPtr
<nsPIDOMWindow
> childWindow
= childShell
->GetWindow();
10044 childWindow
->SetKeyboardIndicators(aShowAccelerators
, aShowFocusRings
);
10049 bool newShouldShowFocusRing
= ShouldShowFocusRing();
10050 if (mHasFocus
&& mFocusedNode
&&
10051 oldShouldShowFocusRing
!= newShouldShowFocusRing
&&
10052 mFocusedNode
->IsElement()) {
10053 // Update mFocusedNode's state.
10054 if (newShouldShowFocusRing
) {
10055 mFocusedNode
->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING
);
10057 mFocusedNode
->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING
);
10063 nsGlobalWindow::GetKeyboardIndicators(bool* aShowAccelerators
,
10064 bool* aShowFocusRings
)
10066 FORWARD_TO_INNER_VOID(GetKeyboardIndicators
, (aShowAccelerators
, aShowFocusRings
));
10068 *aShowAccelerators
= mShowAccelerators
;
10069 *aShowFocusRings
= mShowFocusRings
;
10073 nsGlobalWindow::TakeFocus(bool aFocus
, uint32_t aFocusMethod
)
10075 FORWARD_TO_INNER(TakeFocus
, (aFocus
, aFocusMethod
), false);
10082 mFocusMethod
= aFocusMethod
& FOCUSMETHOD_MASK
;
10084 if (mHasFocus
!= aFocus
) {
10085 mHasFocus
= aFocus
;
10086 UpdateCanvasFocus(true, mFocusedNode
);
10089 // if mNeedsFocus is true, then the document has not yet received a
10090 // document-level focus event. If there is a root content node, then return
10091 // true to tell the calling focus manager that a focus event is expected. If
10092 // there is no root content node, the document hasn't loaded enough yet, or
10093 // there isn't one and there is no point in firing a focus event.
10094 if (aFocus
&& mNeedsFocus
&& mDoc
&& mDoc
->GetRootElement() != nullptr) {
10095 mNeedsFocus
= false;
10099 mNeedsFocus
= false;
10104 nsGlobalWindow::SetReadyForFocus()
10106 FORWARD_TO_INNER_VOID(SetReadyForFocus
, ());
10108 bool oldNeedsFocus
= mNeedsFocus
;
10109 mNeedsFocus
= false;
10111 // update whether focus rings need to be shown using the state from the
10113 nsPIDOMWindow
* root
= GetPrivateRoot();
10115 bool showAccelerators
, showFocusRings
;
10116 root
->GetKeyboardIndicators(&showAccelerators
, &showFocusRings
);
10117 mShowFocusRings
= showFocusRings
;
10120 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
10122 fm
->WindowShown(this, oldNeedsFocus
);
10126 nsGlobalWindow::PageHidden()
10128 FORWARD_TO_INNER_VOID(PageHidden
, ());
10130 // the window is being hidden, so tell the focus manager that the frame is
10131 // no longer valid. Use the persisted field to determine if the document
10132 // is being destroyed.
10134 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
10136 fm
->WindowHidden(this);
10138 mNeedsFocus
= true;
10141 class HashchangeCallback
: public nsRunnable
10144 HashchangeCallback(const nsAString
&aOldURL
,
10145 const nsAString
&aNewURL
,
10146 nsGlobalWindow
* aWindow
)
10149 MOZ_ASSERT(mWindow
);
10150 MOZ_ASSERT(mWindow
->IsInnerWindow());
10151 mOldURL
.Assign(aOldURL
);
10152 mNewURL
.Assign(aNewURL
);
10157 NS_PRECONDITION(NS_IsMainThread(), "Should be called on the main thread.");
10158 return mWindow
->FireHashchange(mOldURL
, mNewURL
);
10164 nsRefPtr
<nsGlobalWindow
> mWindow
;
10168 nsGlobalWindow::DispatchAsyncHashchange(nsIURI
*aOldURI
, nsIURI
*aNewURI
)
10170 FORWARD_TO_INNER(DispatchAsyncHashchange
, (aOldURI
, aNewURI
), NS_OK
);
10172 // Make sure that aOldURI and aNewURI are identical up to the '#', and that
10173 // their hashes are different.
10174 nsAutoCString oldBeforeHash
, oldHash
, newBeforeHash
, newHash
;
10175 nsContentUtils::SplitURIAtHash(aOldURI
, oldBeforeHash
, oldHash
);
10176 nsContentUtils::SplitURIAtHash(aNewURI
, newBeforeHash
, newHash
);
10178 NS_ENSURE_STATE(oldBeforeHash
.Equals(newBeforeHash
));
10179 NS_ENSURE_STATE(!oldHash
.Equals(newHash
));
10181 nsAutoCString oldSpec
, newSpec
;
10182 aOldURI
->GetSpec(oldSpec
);
10183 aNewURI
->GetSpec(newSpec
);
10185 NS_ConvertUTF8toUTF16
oldWideSpec(oldSpec
);
10186 NS_ConvertUTF8toUTF16
newWideSpec(newSpec
);
10188 nsCOMPtr
<nsIRunnable
> callback
=
10189 new HashchangeCallback(oldWideSpec
, newWideSpec
, this);
10190 return NS_DispatchToMainThread(callback
);
10194 nsGlobalWindow::FireHashchange(const nsAString
&aOldURL
,
10195 const nsAString
&aNewURL
)
10197 MOZ_ASSERT(IsInnerWindow());
10199 // Don't do anything if the window is frozen.
10203 // Get a presentation shell for use in creating the hashchange event.
10204 NS_ENSURE_STATE(IsCurrentInnerWindow());
10206 nsIPresShell
*shell
= mDoc
->GetShell();
10207 nsRefPtr
<nsPresContext
> presContext
;
10209 presContext
= shell
->GetPresContext();
10212 HashChangeEventInit init
;
10213 init
.mBubbles
= true;
10214 init
.mCancelable
= false;
10215 init
.mNewURL
= aNewURL
;
10216 init
.mOldURL
= aOldURL
;
10218 nsRefPtr
<HashChangeEvent
> event
=
10219 HashChangeEvent::Constructor(this, NS_LITERAL_STRING("hashchange"),
10222 event
->SetTrusted(true);
10225 return DispatchEvent(event
, &dummy
);
10229 nsGlobalWindow::DispatchSyncPopState()
10231 FORWARD_TO_INNER(DispatchSyncPopState
, (), NS_OK
);
10233 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
10234 "Must be safe to run script here.");
10236 // Check that PopState hasn't been pref'ed off.
10237 if (!Preferences::GetBool(sPopStatePrefStr
, false)) {
10241 nsresult rv
= NS_OK
;
10243 // Bail if the window is frozen.
10248 // Get the document's pending state object -- it contains the data we're
10249 // going to send along with the popstate event. The object is serialized
10250 // using structured clone.
10251 nsCOMPtr
<nsIVariant
> stateObj
;
10252 rv
= mDoc
->GetStateObject(getter_AddRefs(stateObj
));
10253 NS_ENSURE_SUCCESS(rv
, rv
);
10255 // Obtain a presentation shell for use in creating a popstate event.
10256 nsIPresShell
*shell
= mDoc
->GetShell();
10257 nsRefPtr
<nsPresContext
> presContext
;
10259 presContext
= shell
->GetPresContext();
10262 bool result
= true;
10263 nsPIDOMWindow
* outerWindow
= GetOuterWindow();
10264 nsCOMPtr
<EventTarget
> outerWindowET
= do_QueryInterface(outerWindow
);
10265 NS_ENSURE_TRUE(outerWindowET
, NS_ERROR_FAILURE
);
10268 result
= jsapi
.Init(outerWindow
);
10269 NS_ENSURE_TRUE(result
, NS_ERROR_FAILURE
);
10271 JSContext
* cx
= jsapi
.cx();
10272 JS::Rooted
<JS::Value
> stateJSValue(cx
, JS::NullValue());
10273 result
= stateObj
? VariantToJsval(cx
, stateObj
, &stateJSValue
) : true;
10274 NS_ENSURE_TRUE(result
, NS_ERROR_FAILURE
);
10276 RootedDictionary
<PopStateEventInit
> init(cx
);
10277 init
.mBubbles
= true;
10278 init
.mCancelable
= false;
10279 init
.mState
= stateJSValue
;
10281 nsRefPtr
<PopStateEvent
> event
=
10282 PopStateEvent::Constructor(outerWindowET
, NS_LITERAL_STRING("popstate"),
10284 event
->SetTrusted(true);
10285 event
->SetTarget(outerWindowET
);
10287 bool dummy
; // default action
10288 return DispatchEvent(event
, &dummy
);
10291 // Find an nsICanvasFrame under aFrame. Only search the principal
10292 // child lists. aFrame must be non-null.
10293 static nsCanvasFrame
* FindCanvasFrame(nsIFrame
* aFrame
)
10295 nsCanvasFrame
* canvasFrame
= do_QueryFrame(aFrame
);
10297 return canvasFrame
;
10300 nsIFrame
* kid
= aFrame
->GetFirstPrincipalChild();
10302 canvasFrame
= FindCanvasFrame(kid
);
10304 return canvasFrame
;
10306 kid
= kid
->GetNextSibling();
10312 //-------------------------------------------------------
10313 // Tells the HTMLFrame/CanvasFrame that is now has focus
10315 nsGlobalWindow::UpdateCanvasFocus(bool aFocusChanged
, nsIContent
* aNewContent
)
10317 MOZ_ASSERT(IsInnerWindow());
10319 // this is called from the inner window so use GetDocShell
10320 nsIDocShell
* docShell
= GetDocShell();
10325 docShell
->GetEditable(&editable
);
10329 nsCOMPtr
<nsIPresShell
> presShell
= docShell
->GetPresShell();
10330 if (!presShell
|| !mDoc
)
10333 Element
*rootElement
= mDoc
->GetRootElement();
10335 if ((mHasFocus
|| aFocusChanged
) &&
10336 (mFocusedNode
== rootElement
|| aNewContent
== rootElement
)) {
10337 nsIFrame
* frame
= rootElement
->GetPrimaryFrame();
10339 frame
= frame
->GetParent();
10340 nsCanvasFrame
* canvasFrame
= do_QueryFrame(frame
);
10342 canvasFrame
->SetHasFocus(mHasFocus
&& rootElement
== aNewContent
);
10347 // Look for the frame the hard way
10348 nsIFrame
* frame
= presShell
->GetRootFrame();
10350 nsCanvasFrame
* canvasFrame
= FindCanvasFrame(frame
);
10352 canvasFrame
->SetHasFocus(false);
10358 already_AddRefed
<nsICSSDeclaration
>
10359 nsGlobalWindow::GetComputedStyle(Element
& aElt
, const nsAString
& aPseudoElt
,
10360 ErrorResult
& aError
)
10362 return GetComputedStyleHelper(aElt
, aPseudoElt
, false, aError
);
10366 nsGlobalWindow::GetComputedStyle(nsIDOMElement
* aElt
,
10367 const nsAString
& aPseudoElt
,
10368 nsIDOMCSSStyleDeclaration
** aReturn
)
10370 return GetComputedStyleHelper(aElt
, aPseudoElt
, false, aReturn
);
10373 already_AddRefed
<nsICSSDeclaration
>
10374 nsGlobalWindow::GetDefaultComputedStyle(Element
& aElt
,
10375 const nsAString
& aPseudoElt
,
10376 ErrorResult
& aError
)
10378 return GetComputedStyleHelper(aElt
, aPseudoElt
, true, aError
);
10382 nsGlobalWindow::GetDefaultComputedStyle(nsIDOMElement
* aElt
,
10383 const nsAString
& aPseudoElt
,
10384 nsIDOMCSSStyleDeclaration
** aReturn
)
10386 return GetComputedStyleHelper(aElt
, aPseudoElt
, true, aReturn
);
10390 nsGlobalWindow::GetComputedStyleHelper(nsIDOMElement
* aElt
,
10391 const nsAString
& aPseudoElt
,
10392 bool aDefaultStylesOnly
,
10393 nsIDOMCSSStyleDeclaration
** aReturn
)
10395 NS_ENSURE_ARG_POINTER(aReturn
);
10396 *aReturn
= nullptr;
10398 nsCOMPtr
<dom::Element
> element
= do_QueryInterface(aElt
);
10400 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
10404 nsCOMPtr
<nsIDOMCSSStyleDeclaration
> declaration
=
10405 GetComputedStyleHelper(*element
, aPseudoElt
, aDefaultStylesOnly
, rv
);
10406 declaration
.forget(aReturn
);
10408 return rv
.ErrorCode();
10411 already_AddRefed
<nsICSSDeclaration
>
10412 nsGlobalWindow::GetComputedStyleHelper(Element
& aElt
,
10413 const nsAString
& aPseudoElt
,
10414 bool aDefaultStylesOnly
,
10415 ErrorResult
& aError
)
10417 FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelper
,
10418 (aElt
, aPseudoElt
, aDefaultStylesOnly
, aError
),
10425 nsCOMPtr
<nsIPresShell
> presShell
= mDocShell
->GetPresShell();
10428 // Try flushing frames on our parent in case there's a pending
10429 // style change that will create the presshell.
10430 nsGlobalWindow
*parent
=
10431 static_cast<nsGlobalWindow
*>(GetPrivateParent());
10436 parent
->FlushPendingNotifications(Flush_Frames
);
10438 // Might have killed mDocShell
10443 presShell
= mDocShell
->GetPresShell();
10449 nsRefPtr
<nsComputedDOMStyle
> compStyle
=
10450 NS_NewComputedDOMStyle(&aElt
, aPseudoElt
, presShell
,
10451 aDefaultStylesOnly
? nsComputedDOMStyle::eDefaultOnly
:
10452 nsComputedDOMStyle::eAll
);
10454 return compStyle
.forget();
10458 nsGlobalWindow::GetSessionStorage(ErrorResult
& aError
)
10460 FORWARD_TO_INNER_OR_THROW(GetSessionStorage
, (aError
), aError
, nullptr);
10462 nsIPrincipal
*principal
= GetPrincipal();
10463 nsIDocShell
* docShell
= GetDocShell();
10465 if (!principal
|| !docShell
|| !Preferences::GetBool(kStorageEnabled
)) {
10469 if (mSessionStorage
) {
10471 if (PR_LOG_TEST(gDOMLeakPRLog
, PR_LOG_DEBUG
)) {
10472 PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage
.get());
10475 bool canAccess
= mSessionStorage
->CanAccess(principal
);
10476 NS_ASSERTION(canAccess
,
10477 "This window owned sessionStorage "
10478 "that could not be accessed!");
10480 mSessionStorage
= nullptr;
10484 if (!mSessionStorage
) {
10485 nsString documentURI
;
10487 mDoc
->GetDocumentURI(documentURI
);
10490 // If the document has the sandboxed origin flag set
10491 // don't allow access to sessionStorage.
10493 aError
.Throw(NS_ERROR_FAILURE
);
10497 if (mDoc
->GetSandboxFlags() & SANDBOXED_ORIGIN
) {
10498 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
10504 nsCOMPtr
<nsIDOMStorageManager
> storageManager
= do_QueryInterface(docShell
, &rv
);
10505 if (NS_FAILED(rv
)) {
10510 nsCOMPtr
<nsILoadContext
> loadContext
= do_QueryInterface(docShell
);
10512 nsCOMPtr
<nsIDOMStorage
> storage
;
10513 aError
= storageManager
->CreateStorage(this, principal
, documentURI
,
10514 loadContext
&& loadContext
->UsePrivateBrowsing(),
10515 getter_AddRefs(storage
));
10516 if (aError
.Failed()) {
10520 mSessionStorage
= static_cast<DOMStorage
*>(storage
.get());
10521 MOZ_ASSERT(mSessionStorage
);
10524 if (PR_LOG_TEST(gDOMLeakPRLog
, PR_LOG_DEBUG
)) {
10525 PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage
.get());
10529 if (!mSessionStorage
) {
10530 aError
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
10536 if (PR_LOG_TEST(gDOMLeakPRLog
, PR_LOG_DEBUG
)) {
10537 PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage
.get());
10541 return mSessionStorage
;
10545 nsGlobalWindow::GetSessionStorage(nsISupports
** aSessionStorage
)
10548 nsCOMPtr
<nsIDOMStorage
> storage
= GetSessionStorage(rv
);
10549 storage
.forget(aSessionStorage
);
10551 return rv
.ErrorCode();
10555 nsGlobalWindow::GetLocalStorage(ErrorResult
& aError
)
10557 FORWARD_TO_INNER_OR_THROW(GetLocalStorage
, (aError
), aError
, nullptr);
10559 if (!Preferences::GetBool(kStorageEnabled
)) {
10563 if (!mLocalStorage
) {
10564 if (!DOMStorage::CanUseStorage()) {
10565 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
10569 nsIPrincipal
*principal
= GetPrincipal();
10575 nsCOMPtr
<nsIDOMStorageManager
> storageManager
=
10576 do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv
);
10577 if (NS_FAILED(rv
)) {
10582 // If the document has the sandboxed origin flag set
10583 // don't allow access to localStorage.
10584 if (mDoc
&& (mDoc
->GetSandboxFlags() & SANDBOXED_ORIGIN
)) {
10585 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
10589 nsString documentURI
;
10591 mDoc
->GetDocumentURI(documentURI
);
10594 nsIDocShell
* docShell
= GetDocShell();
10595 nsCOMPtr
<nsILoadContext
> loadContext
= do_QueryInterface(docShell
);
10597 nsCOMPtr
<nsIDOMStorage
> storage
;
10598 aError
= storageManager
->CreateStorage(this, principal
, documentURI
,
10599 loadContext
&& loadContext
->UsePrivateBrowsing(),
10600 getter_AddRefs(storage
));
10601 if (aError
.Failed()) {
10605 mLocalStorage
= static_cast<DOMStorage
*>(storage
.get());
10606 MOZ_ASSERT(mLocalStorage
);
10609 return mLocalStorage
;
10613 nsGlobalWindow::GetLocalStorage(nsISupports
** aLocalStorage
)
10615 NS_ENSURE_ARG(aLocalStorage
);
10618 nsCOMPtr
<nsIDOMStorage
> storage
= GetLocalStorage(rv
);
10619 storage
.forget(aLocalStorage
);
10621 return rv
.ErrorCode();
10625 GetIndexedDBEnabledForAboutURI(nsIURI
*aURI
)
10627 nsCOMPtr
<nsIAboutModule
> module
;
10628 nsresult rv
= NS_GetAboutModule(aURI
, getter_AddRefs(module
));
10629 NS_ENSURE_SUCCESS(rv
, false);
10632 rv
= module
->GetURIFlags(aURI
, &flags
);
10633 NS_ENSURE_SUCCESS(rv
, false);
10635 return flags
& nsIAboutModule::ENABLE_INDEXED_DB
;
10638 indexedDB::IDBFactory
*
10639 nsGlobalWindow::GetIndexedDB(ErrorResult
& aError
)
10642 // If the document has the sandboxed origin flag set
10643 // don't allow access to indexedDB.
10644 if (mDoc
&& (mDoc
->GetSandboxFlags() & SANDBOXED_ORIGIN
)) {
10645 aError
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
10649 if (!IsChromeWindow()) {
10650 // Whitelist about:home, since it doesn't have a base domain it would not
10651 // pass the thirdPartyUtil check, though it should be able to use
10653 bool skipThirdPartyCheck
= false;
10654 nsIPrincipal
*principal
= GetPrincipal();
10656 nsCOMPtr
<nsIURI
> uri
;
10657 principal
->GetURI(getter_AddRefs(uri
));
10660 bool isAbout
= false;
10661 if (NS_SUCCEEDED(uri
->SchemeIs("about", &isAbout
)) && isAbout
) {
10662 skipThirdPartyCheck
= GetIndexedDBEnabledForAboutURI(uri
);
10667 if (!skipThirdPartyCheck
) {
10668 nsCOMPtr
<mozIThirdPartyUtil
> thirdPartyUtil
=
10669 do_GetService(THIRDPARTYUTIL_CONTRACTID
);
10670 if (!thirdPartyUtil
) {
10671 aError
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
10676 aError
= thirdPartyUtil
->IsThirdPartyWindow(this, nullptr,
10678 if (aError
.Failed() || isThirdParty
) {
10679 NS_WARN_IF_FALSE(aError
.Failed(),
10680 "IndexedDB is not permitted in a third-party window.");
10686 // This may be null if being created from a file.
10687 aError
= indexedDB::IDBFactory::Create(this, nullptr,
10688 getter_AddRefs(mIndexedDB
));
10695 nsGlobalWindow::GetIndexedDB(nsISupports
** _retval
)
10698 nsCOMPtr
<nsISupports
> request(GetIndexedDB(rv
));
10699 request
.forget(_retval
);
10701 return rv
.ErrorCode();
10705 nsGlobalWindow::GetMozIndexedDB(nsISupports
** _retval
)
10707 return GetIndexedDB(_retval
);
10710 //*****************************************************************************
10711 // nsGlobalWindow::nsIInterfaceRequestor
10712 //*****************************************************************************
10715 nsGlobalWindow::GetInterface(const nsIID
& aIID
, void **aSink
)
10717 NS_ENSURE_ARG_POINTER(aSink
);
10720 if (aIID
.Equals(NS_GET_IID(nsIDocCharset
))) {
10721 nsGlobalWindow
* outer
= GetOuterWindowInternal();
10722 NS_ENSURE_TRUE(outer
, NS_ERROR_NOT_INITIALIZED
);
10724 NS_WARNING("Using deprecated nsIDocCharset: use nsIDocShell.GetCharset() instead ");
10725 nsCOMPtr
<nsIDocCharset
> docCharset(do_QueryInterface(outer
->mDocShell
));
10726 docCharset
.forget(aSink
);
10728 else if (aIID
.Equals(NS_GET_IID(nsIWebNavigation
))) {
10729 nsGlobalWindow
* outer
= GetOuterWindowInternal();
10730 NS_ENSURE_TRUE(outer
, NS_ERROR_NOT_INITIALIZED
);
10732 nsCOMPtr
<nsIWebNavigation
> webNav(do_QueryInterface(outer
->mDocShell
));
10733 webNav
.forget(aSink
);
10735 else if (aIID
.Equals(NS_GET_IID(nsIDocShell
))) {
10736 nsGlobalWindow
* outer
= GetOuterWindowInternal();
10737 NS_ENSURE_TRUE(outer
, NS_ERROR_NOT_INITIALIZED
);
10739 nsCOMPtr
<nsIDocShell
> docShell
= outer
->mDocShell
;
10740 docShell
.forget(aSink
);
10743 else if (aIID
.Equals(NS_GET_IID(nsIWebBrowserPrint
))) {
10744 nsGlobalWindow
* outer
= GetOuterWindowInternal();
10745 NS_ENSURE_TRUE(outer
, NS_ERROR_NOT_INITIALIZED
);
10747 if (outer
->mDocShell
) {
10748 nsCOMPtr
<nsIContentViewer
> viewer
;
10749 outer
->mDocShell
->GetContentViewer(getter_AddRefs(viewer
));
10751 nsCOMPtr
<nsIWebBrowserPrint
> webBrowserPrint(do_QueryInterface(viewer
));
10752 webBrowserPrint
.forget(aSink
);
10757 else if (aIID
.Equals(NS_GET_IID(nsIDOMWindowUtils
))) {
10758 nsGlobalWindow
* outer
= GetOuterWindowInternal();
10759 NS_ENSURE_TRUE(outer
, NS_ERROR_NOT_INITIALIZED
);
10761 if (!mWindowUtils
) {
10762 mWindowUtils
= new nsDOMWindowUtils(outer
);
10765 *aSink
= mWindowUtils
;
10766 NS_ADDREF(((nsISupports
*) *aSink
));
10768 else if (aIID
.Equals(NS_GET_IID(nsILoadContext
))) {
10769 nsGlobalWindow
* outer
= GetOuterWindowInternal();
10770 NS_ENSURE_TRUE(outer
, NS_ERROR_NOT_INITIALIZED
);
10772 nsCOMPtr
<nsILoadContext
> loadContext(do_QueryInterface(outer
->mDocShell
));
10773 loadContext
.forget(aSink
);
10776 return QueryInterface(aIID
, aSink
);
10779 return *aSink
? NS_OK
: NS_ERROR_NO_INTERFACE
;
10783 nsGlobalWindow::GetInterface(JSContext
* aCx
, nsIJSID
* aIID
,
10784 JS::MutableHandle
<JS::Value
> aRetval
,
10785 ErrorResult
& aError
)
10787 dom::GetInterface(aCx
, this, aIID
, aRetval
, aError
);
10791 nsGlobalWindow::FireOfflineStatusEvent()
10793 if (!IsCurrentInnerWindow())
10796 if (NS_IsOffline()) {
10797 name
.AssignLiteral("offline");
10799 name
.AssignLiteral("online");
10801 // The event is fired at the body element, or if there is no body element,
10802 // at the document.
10803 nsCOMPtr
<EventTarget
> eventTarget
= mDoc
.get();
10804 nsHTMLDocument
* htmlDoc
= mDoc
->AsHTMLDocument();
10806 Element
* body
= htmlDoc
->GetBody();
10808 eventTarget
= body
;
10811 Element
* documentElement
= mDoc
->GetDocumentElement();
10812 if (documentElement
) {
10813 eventTarget
= documentElement
;
10816 nsContentUtils::DispatchTrustedEvent(mDoc
, eventTarget
, name
, true, false);
10819 class NotifyIdleObserverRunnable
: public nsRunnable
10822 NotifyIdleObserverRunnable(nsIIdleObserver
* aIdleObserver
,
10825 nsGlobalWindow
* aIdleWindow
)
10826 : mIdleObserver(aIdleObserver
), mTimeInS(aTimeInS
), mIdleWindow(aIdleWindow
),
10827 mCallOnidle(aCallOnidle
)
10832 if (mIdleWindow
->ContainsIdleObserver(mIdleObserver
, mTimeInS
)) {
10833 return mCallOnidle
? mIdleObserver
->Onidle() : mIdleObserver
->Onactive();
10839 nsCOMPtr
<nsIIdleObserver
> mIdleObserver
;
10841 nsRefPtr
<nsGlobalWindow
> mIdleWindow
;
10843 // If false then call on active
10848 nsGlobalWindow::NotifyIdleObserver(IdleObserverHolder
* aIdleObserverHolder
,
10851 MOZ_ASSERT(aIdleObserverHolder
);
10852 aIdleObserverHolder
->mPrevNotificationIdle
= aCallOnidle
;
10854 nsCOMPtr
<nsIRunnable
> caller
=
10855 new NotifyIdleObserverRunnable(aIdleObserverHolder
->mIdleObserver
,
10856 aIdleObserverHolder
->mTimeInS
,
10857 aCallOnidle
, this);
10858 if (NS_FAILED(NS_DispatchToCurrentThread(caller
))) {
10859 NS_WARNING("Failed to dispatch thread for idle observer notification.");
10864 nsGlobalWindow::ContainsIdleObserver(nsIIdleObserver
* aIdleObserver
, uint32_t aTimeInS
)
10866 MOZ_ASSERT(aIdleObserver
, "Idle observer not instantiated.");
10867 bool found
= false;
10868 nsTObserverArray
<IdleObserverHolder
>::ForwardIterator
iter(mIdleObservers
);
10869 while (iter
.HasMore()) {
10870 IdleObserverHolder
& idleObserver
= iter
.GetNext();
10871 if (idleObserver
.mIdleObserver
== aIdleObserver
&&
10872 idleObserver
.mTimeInS
== aTimeInS
) {
10881 IdleActiveTimerCallback(nsITimer
* aTimer
, void* aClosure
)
10883 nsRefPtr
<nsGlobalWindow
> idleWindow
= static_cast<nsGlobalWindow
*>(aClosure
);
10884 MOZ_ASSERT(idleWindow
, "Idle window has not been instantiated.");
10885 idleWindow
->HandleIdleActiveEvent();
10889 IdleObserverTimerCallback(nsITimer
* aTimer
, void* aClosure
)
10891 nsRefPtr
<nsGlobalWindow
> idleWindow
= static_cast<nsGlobalWindow
*>(aClosure
);
10892 MOZ_ASSERT(idleWindow
, "Idle window has not been instantiated.");
10893 idleWindow
->HandleIdleObserverCallback();
10897 nsGlobalWindow::HandleIdleObserverCallback()
10899 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
10900 MOZ_ASSERT(static_cast<uint32_t>(mIdleCallbackIndex
) < mIdleObservers
.Length(),
10901 "Idle callback index exceeds array bounds!");
10902 IdleObserverHolder
& idleObserver
= mIdleObservers
.ElementAt(mIdleCallbackIndex
);
10903 NotifyIdleObserver(&idleObserver
, true);
10904 mIdleCallbackIndex
++;
10905 if (NS_FAILED(ScheduleNextIdleObserverCallback())) {
10906 NS_WARNING("Failed to set next idle observer callback.");
10911 nsGlobalWindow::ScheduleNextIdleObserverCallback()
10913 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
10914 MOZ_ASSERT(mIdleService
, "No idle service!");
10916 if (mIdleCallbackIndex
< 0 ||
10917 static_cast<uint32_t>(mIdleCallbackIndex
) >= mIdleObservers
.Length()) {
10921 IdleObserverHolder
& idleObserver
=
10922 mIdleObservers
.ElementAt(mIdleCallbackIndex
);
10924 uint32_t userIdleTimeMS
= 0;
10925 nsresult rv
= mIdleService
->GetIdleTime(&userIdleTimeMS
);
10926 NS_ENSURE_SUCCESS(rv
, rv
);
10928 uint32_t callbackTimeMS
= 0;
10929 if (idleObserver
.mTimeInS
* 1000 + mIdleFuzzFactor
> userIdleTimeMS
) {
10930 callbackTimeMS
= idleObserver
.mTimeInS
* 1000 - userIdleTimeMS
+ mIdleFuzzFactor
;
10933 mIdleTimer
->Cancel();
10934 rv
= mIdleTimer
->InitWithFuncCallback(IdleObserverTimerCallback
,
10937 nsITimer::TYPE_ONE_SHOT
);
10938 NS_ENSURE_SUCCESS(rv
, rv
);
10944 nsGlobalWindow::GetFuzzTimeMS()
10946 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
10948 if (sIdleObserversAPIFuzzTimeDisabled
) {
10952 uint32_t randNum
= MAX_IDLE_FUZZ_TIME_MS
;
10953 size_t nbytes
= PR_GetRandomNoise(&randNum
, sizeof(randNum
));
10954 if (nbytes
!= sizeof(randNum
)) {
10955 NS_WARNING("PR_GetRandomNoise(...) Not implemented or no available noise!");
10956 return MAX_IDLE_FUZZ_TIME_MS
;
10959 if (randNum
> MAX_IDLE_FUZZ_TIME_MS
) {
10960 randNum
%= MAX_IDLE_FUZZ_TIME_MS
;
10967 nsGlobalWindow::ScheduleActiveTimerCallback()
10969 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
10971 if (!mAddActiveEventFuzzTime
) {
10972 return HandleIdleActiveEvent();
10975 MOZ_ASSERT(mIdleTimer
);
10976 mIdleTimer
->Cancel();
10978 uint32_t fuzzFactorInMS
= GetFuzzTimeMS();
10979 nsresult rv
= mIdleTimer
->InitWithFuncCallback(IdleActiveTimerCallback
,
10982 nsITimer::TYPE_ONE_SHOT
);
10983 NS_ENSURE_SUCCESS(rv
, rv
);
10988 nsGlobalWindow::HandleIdleActiveEvent()
10990 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
10992 if (mCurrentlyIdle
) {
10993 mIdleCallbackIndex
= 0;
10994 mIdleFuzzFactor
= GetFuzzTimeMS();
10995 nsresult rv
= ScheduleNextIdleObserverCallback();
10996 NS_ENSURE_SUCCESS(rv
, rv
);
11000 mIdleCallbackIndex
= -1;
11001 MOZ_ASSERT(mIdleTimer
);
11002 mIdleTimer
->Cancel();
11003 nsTObserverArray
<IdleObserverHolder
>::ForwardIterator
iter(mIdleObservers
);
11004 while (iter
.HasMore()) {
11005 IdleObserverHolder
& idleObserver
= iter
.GetNext();
11006 if (idleObserver
.mPrevNotificationIdle
) {
11007 NotifyIdleObserver(&idleObserver
, false);
11014 nsGlobalWindow::SlowScriptResponse
11015 nsGlobalWindow::ShowSlowScriptDialog()
11017 MOZ_ASSERT(IsInnerWindow());
11022 // If it isn't safe to run script, then it isn't safe to bring up the prompt
11023 // (since that spins the event loop). In that (rare) case, we just kill the
11024 // script and report a warning.
11025 if (!nsContentUtils::IsSafeToRunScript()) {
11026 JS_ReportWarning(cx
, "A long running script was terminated");
11027 return KillSlowScript
;
11030 // If our document is not active, just kill the script: we've been unloaded
11031 if (!HasActiveDocument()) {
11032 return KillSlowScript
;
11035 // Get the nsIPrompt interface from the docshell
11036 nsCOMPtr
<nsIDocShell
> ds
= GetDocShell();
11037 NS_ENSURE_TRUE(ds
, KillSlowScript
);
11038 nsCOMPtr
<nsIPrompt
> prompt
= do_GetInterface(ds
);
11039 NS_ENSURE_TRUE(prompt
, KillSlowScript
);
11041 // Check if we should offer the option to debug
11042 JS::AutoFilename filename
;
11044 bool hasFrame
= JS::DescribeScriptedCaller(cx
, &filename
, &lineno
);
11046 // Prioritize the SlowScriptDebug interface over JSD1.
11047 nsCOMPtr
<nsISlowScriptDebugCallback
> debugCallback
;
11050 const char *debugCID
= "@mozilla.org/dom/slow-script-debug;1";
11051 nsCOMPtr
<nsISlowScriptDebug
> debugService
= do_GetService(debugCID
, &rv
);
11052 if (NS_SUCCEEDED(rv
)) {
11053 debugService
->GetActivationHandler(getter_AddRefs(debugCallback
));
11057 bool showDebugButton
= !!debugCallback
;
11059 // Get localizable strings
11060 nsXPIDLString title
, msg
, stopButton
, waitButton
, debugButton
, neverShowDlg
;
11062 rv
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
11066 nsresult tmp
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
11067 "StopScriptButton",
11069 if (NS_FAILED(tmp
)) {
11073 tmp
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
11074 "WaitForScriptButton",
11076 if (NS_FAILED(tmp
)) {
11080 tmp
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
11083 if (NS_FAILED(tmp
)) {
11088 if (showDebugButton
) {
11089 tmp
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
11090 "DebugScriptButton",
11092 if (NS_FAILED(tmp
)) {
11096 tmp
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
11097 "KillScriptWithDebugMessage",
11099 if (NS_FAILED(tmp
)) {
11104 tmp
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
11105 "KillScriptMessage",
11107 if (NS_FAILED(tmp
)) {
11112 // GetStringFromName can return NS_OK and still give nullptr string
11113 if (NS_FAILED(rv
) || !title
|| !msg
|| !stopButton
|| !waitButton
||
11114 (!debugButton
&& showDebugButton
) || !neverShowDlg
) {
11115 NS_ERROR("Failed to get localized strings.");
11116 return ContinueSlowScript
;
11119 // Append file and line number information, if available
11120 if (filename
.get()) {
11121 nsXPIDLString scriptLocation
;
11122 NS_ConvertUTF8toUTF16
filenameUTF16(filename
.get());
11123 const char16_t
*formatParams
[] = { filenameUTF16
.get() };
11124 rv
= nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
11125 "KillScriptLocation",
11129 if (NS_SUCCEEDED(rv
) && scriptLocation
) {
11130 msg
.AppendLiteral("\n\n");
11131 msg
.Append(scriptLocation
);
11133 msg
.AppendInt(lineno
);
11137 int32_t buttonPressed
= 0; // In case the user exits dialog by clicking X.
11138 bool neverShowDlgChk
= false;
11139 uint32_t buttonFlags
= nsIPrompt::BUTTON_POS_1_DEFAULT
+
11140 (nsIPrompt::BUTTON_TITLE_IS_STRING
*
11141 (nsIPrompt::BUTTON_POS_0
+ nsIPrompt::BUTTON_POS_1
));
11143 // Add a third button if necessary.
11144 if (showDebugButton
)
11145 buttonFlags
+= nsIPrompt::BUTTON_TITLE_IS_STRING
* nsIPrompt::BUTTON_POS_2
;
11147 // Null out the operation callback while we're re-entering JS here.
11148 JSRuntime
* rt
= JS_GetRuntime(cx
);
11149 JSInterruptCallback old
= JS_SetInterruptCallback(rt
, nullptr);
11151 // Open the dialog.
11152 rv
= prompt
->ConfirmEx(title
, msg
, buttonFlags
, waitButton
, stopButton
,
11153 debugButton
, neverShowDlg
, &neverShowDlgChk
,
11156 JS_SetInterruptCallback(rt
, old
);
11158 if (NS_SUCCEEDED(rv
) && (buttonPressed
== 0)) {
11159 return neverShowDlgChk
? AlwaysContinueSlowScript
: ContinueSlowScript
;
11161 if (buttonPressed
== 2) {
11162 if (debugCallback
) {
11163 rv
= debugCallback
->HandleSlowScriptDebug(this);
11164 return NS_SUCCEEDED(rv
) ? ContinueSlowScript
: KillSlowScript
;
11167 JS_ClearPendingException(cx
);
11168 return KillSlowScript
;
11172 nsGlobalWindow::FindInsertionIndex(IdleObserverHolder
* aIdleObserver
)
11174 MOZ_ASSERT(IsInnerWindow());
11175 MOZ_ASSERT(aIdleObserver
, "Idle observer not instantiated.");
11178 nsTObserverArray
<IdleObserverHolder
>::ForwardIterator
iter(mIdleObservers
);
11179 while (iter
.HasMore()) {
11180 IdleObserverHolder
& idleObserver
= iter
.GetNext();
11181 if (idleObserver
.mTimeInS
> aIdleObserver
->mTimeInS
) {
11185 MOZ_ASSERT(i
<= mIdleObservers
.Length(), "Array index out of bounds error.");
11192 nsGlobalWindow::RegisterIdleObserver(nsIIdleObserver
* aIdleObserver
)
11194 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
11197 if (mIdleObservers
.IsEmpty()) {
11198 mIdleService
= do_GetService("@mozilla.org/widget/idleservice;1", &rv
);
11199 NS_ENSURE_SUCCESS(rv
, rv
);
11201 rv
= mIdleService
->AddIdleObserver(mObserver
, MIN_IDLE_NOTIFICATION_TIME_S
);
11202 NS_ENSURE_SUCCESS(rv
, rv
);
11205 mIdleTimer
= do_CreateInstance(NS_TIMER_CONTRACTID
, &rv
);
11206 NS_ENSURE_SUCCESS(rv
, rv
);
11208 mIdleTimer
->Cancel();
11212 MOZ_ASSERT(mIdleService
);
11213 MOZ_ASSERT(mIdleTimer
);
11215 IdleObserverHolder tmpIdleObserver
;
11216 tmpIdleObserver
.mIdleObserver
= aIdleObserver
;
11217 rv
= aIdleObserver
->GetTime(&tmpIdleObserver
.mTimeInS
);
11218 NS_ENSURE_SUCCESS(rv
, rv
);
11219 NS_ENSURE_ARG_MAX(tmpIdleObserver
.mTimeInS
, UINT32_MAX
/ 1000);
11220 NS_ENSURE_ARG_MIN(tmpIdleObserver
.mTimeInS
, MIN_IDLE_NOTIFICATION_TIME_S
);
11222 uint32_t insertAtIndex
= FindInsertionIndex(&tmpIdleObserver
);
11223 if (insertAtIndex
== mIdleObservers
.Length()) {
11224 mIdleObservers
.AppendElement(tmpIdleObserver
);
11227 mIdleObservers
.InsertElementAt(insertAtIndex
, tmpIdleObserver
);
11230 bool userIsIdle
= false;
11231 rv
= nsContentUtils::IsUserIdle(MIN_IDLE_NOTIFICATION_TIME_S
, &userIsIdle
);
11232 NS_ENSURE_SUCCESS(rv
, rv
);
11234 // Special case. First idle observer added to empty list while the user is idle.
11235 // Haven't received 'idle' topic notification from slow idle service yet.
11236 // Need to wait for the idle notification and then notify idle observers in the list.
11237 if (userIsIdle
&& mIdleCallbackIndex
== -1) {
11241 if (!mCurrentlyIdle
) {
11245 MOZ_ASSERT(mIdleCallbackIndex
>= 0);
11247 if (static_cast<int32_t>(insertAtIndex
) < mIdleCallbackIndex
) {
11248 IdleObserverHolder
& idleObserver
= mIdleObservers
.ElementAt(insertAtIndex
);
11249 NotifyIdleObserver(&idleObserver
, true);
11250 mIdleCallbackIndex
++;
11254 if (static_cast<int32_t>(insertAtIndex
) == mIdleCallbackIndex
) {
11255 mIdleTimer
->Cancel();
11256 rv
= ScheduleNextIdleObserverCallback();
11257 NS_ENSURE_SUCCESS(rv
, rv
);
11263 nsGlobalWindow::FindIndexOfElementToRemove(nsIIdleObserver
* aIdleObserver
,
11264 int32_t* aRemoveElementIndex
)
11266 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
11267 MOZ_ASSERT(aIdleObserver
, "Idle observer not instantiated.");
11269 *aRemoveElementIndex
= 0;
11270 if (mIdleObservers
.IsEmpty()) {
11271 return NS_ERROR_FAILURE
;
11274 uint32_t aIdleObserverTimeInS
;
11275 nsresult rv
= aIdleObserver
->GetTime(&aIdleObserverTimeInS
);
11276 NS_ENSURE_SUCCESS(rv
, rv
);
11277 NS_ENSURE_ARG_MIN(aIdleObserverTimeInS
, MIN_IDLE_NOTIFICATION_TIME_S
);
11279 nsTObserverArray
<IdleObserverHolder
>::ForwardIterator
iter(mIdleObservers
);
11280 while (iter
.HasMore()) {
11281 IdleObserverHolder
& idleObserver
= iter
.GetNext();
11282 if (idleObserver
.mTimeInS
== aIdleObserverTimeInS
&&
11283 idleObserver
.mIdleObserver
== aIdleObserver
) {
11286 (*aRemoveElementIndex
)++;
11288 return static_cast<uint32_t>(*aRemoveElementIndex
) >= mIdleObservers
.Length() ?
11289 NS_ERROR_FAILURE
: NS_OK
;
11293 nsGlobalWindow::UnregisterIdleObserver(nsIIdleObserver
* aIdleObserver
)
11295 MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
11297 int32_t removeElementIndex
;
11298 nsresult rv
= FindIndexOfElementToRemove(aIdleObserver
, &removeElementIndex
);
11299 if (NS_FAILED(rv
)) {
11300 NS_WARNING("Idle observer not found in list of idle observers. No idle observer removed.");
11303 mIdleObservers
.RemoveElementAt(removeElementIndex
);
11305 MOZ_ASSERT(mIdleTimer
);
11306 if (mIdleObservers
.IsEmpty() && mIdleService
) {
11307 rv
= mIdleService
->RemoveIdleObserver(mObserver
, MIN_IDLE_NOTIFICATION_TIME_S
);
11308 NS_ENSURE_SUCCESS(rv
, rv
);
11309 mIdleService
= nullptr;
11311 mIdleTimer
->Cancel();
11312 mIdleCallbackIndex
= -1;
11316 if (!mCurrentlyIdle
) {
11320 if (removeElementIndex
< mIdleCallbackIndex
) {
11321 mIdleCallbackIndex
--;
11325 if (removeElementIndex
!= mIdleCallbackIndex
) {
11329 mIdleTimer
->Cancel();
11331 // If the last element in the array had been notified then decrement
11332 // mIdleCallbackIndex because an idle was removed from the list of
11334 // Example: add idle observer with time 1, 2, 3,
11335 // Idle notifications for idle observers with time 1, 2, 3 are complete
11336 // Remove idle observer with time 3 while the user is still idle.
11337 // The user never transitioned to active state.
11338 // Add an idle observer with idle time 4
11339 if (static_cast<uint32_t>(mIdleCallbackIndex
) == mIdleObservers
.Length()) {
11340 mIdleCallbackIndex
--;
11342 rv
= ScheduleNextIdleObserverCallback();
11343 NS_ENSURE_SUCCESS(rv
, rv
);
11349 nsGlobalWindow::Observe(nsISupports
* aSubject
, const char* aTopic
,
11350 const char16_t
* aData
)
11352 if (!nsCRT::strcmp(aTopic
, NS_IOSERVICE_OFFLINE_STATUS_TOPIC
)) {
11354 // if an even number of notifications arrive while we're frozen,
11355 // we don't need to fire.
11356 mFireOfflineStatusChangeEventOnThaw
= !mFireOfflineStatusChangeEventOnThaw
;
11358 FireOfflineStatusEvent();
11363 if (!nsCRT::strcmp(aTopic
, OBSERVER_TOPIC_IDLE
)) {
11364 mCurrentlyIdle
= true;
11366 // need to fire only one idle event while the window is frozen.
11367 mNotifyIdleObserversIdleOnThaw
= true;
11368 mNotifyIdleObserversActiveOnThaw
= false;
11369 } else if (IsCurrentInnerWindow()) {
11370 HandleIdleActiveEvent();
11375 if (!nsCRT::strcmp(aTopic
, OBSERVER_TOPIC_ACTIVE
)) {
11376 mCurrentlyIdle
= false;
11378 mNotifyIdleObserversActiveOnThaw
= true;
11379 mNotifyIdleObserversIdleOnThaw
= false;
11380 } else if (IsCurrentInnerWindow()) {
11381 MOZ_ASSERT(IsInnerWindow());
11382 ScheduleActiveTimerCallback();
11387 if (!nsCRT::strcmp(aTopic
, "dom-storage2-changed")) {
11388 if (!IsInnerWindow() || !IsCurrentInnerWindow()) {
11392 nsIPrincipal
*principal
;
11395 nsRefPtr
<StorageEvent
> event
= static_cast<StorageEvent
*>(aSubject
);
11397 return NS_ERROR_FAILURE
;
11400 nsRefPtr
<DOMStorage
> changingStorage
= event
->GetStorageArea();
11401 if (!changingStorage
) {
11402 return NS_ERROR_FAILURE
;
11405 nsCOMPtr
<nsIDOMStorage
> istorage
= changingStorage
.get();
11407 bool fireMozStorageChanged
= false;
11408 principal
= GetPrincipal();
11413 nsCOMPtr
<nsILoadContext
> loadContext
= do_QueryInterface(GetDocShell());
11414 bool isPrivate
= loadContext
&& loadContext
->UsePrivateBrowsing();
11415 if (changingStorage
->IsPrivate() != isPrivate
) {
11419 switch (changingStorage
->GetType())
11421 case DOMStorage::SessionStorage
:
11423 bool check
= false;
11425 nsCOMPtr
<nsIDOMStorageManager
> storageManager
= do_QueryInterface(GetDocShell());
11426 if (storageManager
) {
11427 rv
= storageManager
->CheckStorage(principal
, istorage
, &check
);
11428 if (NS_FAILED(rv
)) {
11434 // This storage event is not coming from our storage or is coming
11435 // from a different docshell, i.e. it is a clone, ignore this event.
11440 if (PR_LOG_TEST(gDOMLeakPRLog
, PR_LOG_DEBUG
)) {
11441 PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p",
11442 this, mSessionStorage
.get(), changingStorage
.get());
11446 fireMozStorageChanged
= mSessionStorage
== changingStorage
;
11450 case DOMStorage::LocalStorage
:
11452 // Allow event fire only for the same principal storages
11453 // XXX We have to use EqualsIgnoreDomain after bug 495337 lands
11454 nsIPrincipal
* storagePrincipal
= changingStorage
->GetPrincipal();
11456 bool equals
= false;
11457 rv
= storagePrincipal
->Equals(principal
, &equals
);
11458 NS_ENSURE_SUCCESS(rv
, rv
);
11463 fireMozStorageChanged
= mLocalStorage
== changingStorage
;
11470 // Clone the storage event included in the observer notification. We want
11471 // to dispatch clones rather than the original event.
11473 nsRefPtr
<StorageEvent
> newEvent
=
11474 CloneStorageEvent(fireMozStorageChanged
?
11475 NS_LITERAL_STRING("MozStorageChanged") :
11476 NS_LITERAL_STRING("storage"),
11478 if (error
.Failed()) {
11479 return error
.ErrorCode();
11482 newEvent
->SetTrusted(true);
11484 if (fireMozStorageChanged
) {
11485 WidgetEvent
* internalEvent
= newEvent
->GetInternalNSEvent();
11486 internalEvent
->mFlags
.mOnlyChromeDispatch
= true;
11490 // This window is frozen, rather than firing the events here,
11491 // store the domain in which the change happened and fire the
11492 // events if we're ever thawed.
11494 mPendingStorageEvents
.AppendElement(newEvent
);
11498 bool defaultActionEnabled
;
11499 DispatchEvent(newEvent
, &defaultActionEnabled
);
11504 if (!nsCRT::strcmp(aTopic
, "offline-cache-update-added")) {
11505 if (mApplicationCache
)
11508 // Instantiate the application object now. It observes update belonging to
11509 // this window's document and correctly updates the applicationCache object
11511 nsCOMPtr
<nsIDOMOfflineResourceList
> applicationCache
;
11512 GetApplicationCache(getter_AddRefs(applicationCache
));
11513 nsCOMPtr
<nsIObserver
> observer
= do_QueryInterface(applicationCache
);
11515 observer
->Observe(aSubject
, aTopic
, aData
);
11521 if (!nsCRT::strcmp(aTopic
, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC
) ||
11522 !nsCRT::strcmp(aTopic
, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC
)) {
11523 MOZ_ASSERT(IsInnerWindow());
11524 if (!IsCurrentInnerWindow()) {
11528 nsCOMPtr
<nsIDOMEvent
> event
;
11529 NS_NewDOMEvent(getter_AddRefs(event
), this, nullptr, nullptr);
11530 nsresult rv
= event
->InitEvent(
11531 !nsCRT::strcmp(aTopic
, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC
)
11532 ? NETWORK_UPLOAD_EVENT_NAME
11533 : NETWORK_DOWNLOAD_EVENT_NAME
,
11535 NS_ENSURE_SUCCESS(rv
, rv
);
11537 event
->SetTrusted(true);
11540 return DispatchEvent(event
, &dummy
);
11544 if (!nsCRT::strcmp(aTopic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
)) {
11545 MOZ_ASSERT(!NS_strcmp(aData
, MOZ_UTF16("intl.accept_languages")));
11546 MOZ_ASSERT(IsInnerWindow());
11548 // The user preferred languages have changed, we need to fire an event on
11549 // Window object and invalidate the cache for navigator.languages. It is
11550 // done for every change which can be a waste of cycles but those should be
11552 // We MUST invalidate navigator.languages before sending the event in the
11553 // very likely situation where an event handler will try to read its value.
11556 NavigatorBinding::ClearCachedLanguageValue(mNavigator
);
11557 NavigatorBinding::ClearCachedLanguagesValue(mNavigator
);
11560 nsCOMPtr
<nsIDOMEvent
> event
;
11561 NS_NewDOMEvent(getter_AddRefs(event
), this, nullptr, nullptr);
11562 nsresult rv
= event
->InitEvent(NS_LITERAL_STRING("languagechange"), false, false);
11563 NS_ENSURE_SUCCESS(rv
, rv
);
11565 event
->SetTrusted(true);
11568 return DispatchEvent(event
, &dummy
);
11571 NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
11572 return NS_ERROR_FAILURE
;
11575 already_AddRefed
<StorageEvent
>
11576 nsGlobalWindow::CloneStorageEvent(const nsAString
& aType
,
11577 const nsRefPtr
<StorageEvent
>& aEvent
,
11580 MOZ_ASSERT(IsInnerWindow());
11582 StorageEventInit dict
;
11584 dict
.mBubbles
= aEvent
->Bubbles();
11585 dict
.mCancelable
= aEvent
->Cancelable();
11586 aEvent
->GetKey(dict
.mKey
);
11587 aEvent
->GetOldValue(dict
.mOldValue
);
11588 aEvent
->GetNewValue(dict
.mNewValue
);
11589 aEvent
->GetUrl(dict
.mUrl
);
11591 nsRefPtr
<DOMStorage
> storageArea
= aEvent
->GetStorageArea();
11592 MOZ_ASSERT(storageArea
);
11594 nsRefPtr
<DOMStorage
> storage
;
11595 if (storageArea
->GetType() == DOMStorage::LocalStorage
) {
11596 storage
= GetLocalStorage(aRv
);
11598 MOZ_ASSERT(storageArea
->GetType() == DOMStorage::SessionStorage
);
11599 storage
= GetSessionStorage(aRv
);
11602 if (aRv
.Failed() || !storage
) {
11606 MOZ_ASSERT(storage
);
11607 MOZ_ASSERT(storage
->IsForkOf(storageArea
));
11609 dict
.mStorageArea
= storage
;
11611 nsRefPtr
<StorageEvent
> event
= StorageEvent::Constructor(this, aType
, dict
);
11612 return event
.forget();
11616 nsGlobalWindow::FireDelayedDOMEvents()
11618 FORWARD_TO_INNER(FireDelayedDOMEvents
, (), NS_ERROR_UNEXPECTED
);
11620 for (uint32_t i
= 0, len
= mPendingStorageEvents
.Length(); i
< len
; ++i
) {
11621 Observe(mPendingStorageEvents
[i
], "dom-storage2-changed", nullptr);
11624 if (mApplicationCache
) {
11625 static_cast<nsDOMOfflineResourceList
*>(mApplicationCache
.get())->FirePendingEvents();
11628 if (mFireOfflineStatusChangeEventOnThaw
) {
11629 mFireOfflineStatusChangeEventOnThaw
= false;
11630 FireOfflineStatusEvent();
11633 if (mNotifyIdleObserversIdleOnThaw
) {
11634 mNotifyIdleObserversIdleOnThaw
= false;
11635 HandleIdleActiveEvent();
11638 if (mNotifyIdleObserversActiveOnThaw
) {
11639 mNotifyIdleObserversActiveOnThaw
= false;
11640 ScheduleActiveTimerCallback();
11643 nsCOMPtr
<nsIDocShell
> docShell
= GetDocShell();
11645 int32_t childCount
= 0;
11646 docShell
->GetChildCount(&childCount
);
11648 for (int32_t i
= 0; i
< childCount
; ++i
) {
11649 nsCOMPtr
<nsIDocShellTreeItem
> childShell
;
11650 docShell
->GetChildAt(i
, getter_AddRefs(childShell
));
11651 NS_ASSERTION(childShell
, "null child shell");
11653 nsCOMPtr
<nsPIDOMWindow
> pWin
= childShell
->GetWindow();
11655 nsGlobalWindow
*win
=
11656 static_cast<nsGlobalWindow
*>
11657 (static_cast<nsPIDOMWindow
*>(pWin
));
11658 win
->FireDelayedDOMEvents();
11666 //*****************************************************************************
11667 // nsGlobalWindow: Window Control Functions
11668 //*****************************************************************************
11671 nsGlobalWindow::GetParentInternal()
11673 if (IsInnerWindow()) {
11674 nsGlobalWindow
* outer
= GetOuterWindowInternal();
11676 NS_WARNING("No outer window available!");
11679 return outer
->GetParentInternal();
11682 nsCOMPtr
<nsIDOMWindow
> parent
;
11683 GetParent(getter_AddRefs(parent
));
11685 if (parent
&& parent
!= static_cast<nsIDOMWindow
*>(this)) {
11693 nsGlobalWindow::UnblockScriptedClosing()
11695 MOZ_ASSERT(IsOuterWindow());
11696 mBlockScriptedClosingFlag
= false;
11699 class AutoUnblockScriptClosing
11702 nsRefPtr
<nsGlobalWindow
> mWin
;
11704 explicit AutoUnblockScriptClosing(nsGlobalWindow
* aWin
)
11708 MOZ_ASSERT(mWin
->IsOuterWindow());
11710 ~AutoUnblockScriptClosing()
11712 void (nsGlobalWindow::*run
)() = &nsGlobalWindow::UnblockScriptedClosing
;
11713 NS_DispatchToCurrentThread(NS_NewRunnableMethod(mWin
, run
));
11718 nsGlobalWindow::OpenInternal(const nsAString
& aUrl
, const nsAString
& aName
,
11719 const nsAString
& aOptions
, bool aDialog
,
11720 bool aContentModal
, bool aCalledNoScript
,
11721 bool aDoJSFixups
, bool aNavigate
,
11723 nsISupports
*aExtraArgument
,
11724 nsIPrincipal
*aCalleePrincipal
,
11725 JSContext
*aJSCallerContext
,
11726 nsIDOMWindow
**aReturn
)
11728 MOZ_ASSERT(IsOuterWindow());
11733 argv
->GetLength(&argc
);
11735 NS_PRECONDITION(!aExtraArgument
|| (!argv
&& argc
== 0),
11736 "Can't pass in arguments both ways");
11737 NS_PRECONDITION(!aCalledNoScript
|| (!argv
&& argc
== 0),
11738 "Can't pass JS args when called via the noscript methods");
11739 NS_PRECONDITION(!aJSCallerContext
|| !aCalledNoScript
,
11740 "Shouldn't have caller context when called noscript");
11742 mozilla::Maybe
<AutoUnblockScriptClosing
> closeUnblocker
;
11744 // Calls to window.open from script should navigate.
11745 MOZ_ASSERT(aCalledNoScript
|| aNavigate
);
11747 *aReturn
= nullptr;
11749 nsCOMPtr
<nsIWebBrowserChrome
> chrome
= GetWebBrowserChrome();
11751 // No chrome means we don't want to go through with this open call
11752 // -- see nsIWindowWatcher.idl
11753 return NS_ERROR_NOT_AVAILABLE
;
11756 NS_ASSERTION(mDocShell
, "Must have docshell here");
11758 // Popups from apps are never blocked.
11759 bool isApp
= false;
11761 isApp
= mDoc
->NodePrincipal()->GetAppStatus() >=
11762 nsIPrincipal::APP_STATUS_INSTALLED
;
11765 const bool checkForPopup
= !nsContentUtils::IsCallerChrome() &&
11766 !isApp
&& !aDialog
&& !WindowExists(aName
, !aCalledNoScript
);
11768 // Note: it's very important that this be an nsXPIDLCString, since we want
11769 // .get() on it to return nullptr until we write stuff to it. The window
11770 // watcher expects a null URL string if there is no URL to load.
11771 nsXPIDLCString url
;
11772 nsresult rv
= NS_OK
;
11774 // It's important to do this security check before determining whether this
11775 // window opening should be blocked, to ensure that we don't FireAbuseEvents
11776 // for a window opening that wouldn't have succeeded in the first place.
11777 if (!aUrl
.IsEmpty()) {
11778 AppendUTF16toUTF8(aUrl
, url
);
11780 // It's safe to skip the security check below if we're not a dialog
11781 // because window.openDialog is not callable from content script. See bug
11784 // If we're not navigating, we assume that whoever *does* navigate the
11785 // window will do a security check of their own.
11786 if (url
.get() && !aDialog
&& aNavigate
)
11787 rv
= SecurityCheckURL(url
.get());
11793 PopupControlState abuseLevel
= gPopupControlState
;
11794 if (checkForPopup
) {
11795 abuseLevel
= RevisePopupAbuseLevel(abuseLevel
);
11796 if (abuseLevel
>= openAbused
) {
11797 if (aJSCallerContext
) {
11798 // If script in some other window is doing a window.open on us and
11799 // it's being blocked, then it's OK to close us afterwards, probably.
11800 // But if we're doing a window.open on ourselves and block the popup,
11801 // prevent this window from closing until after this script terminates
11802 // so that whatever popup blocker UI the app has will be visible.
11803 if (mContext
== GetScriptContextFromJSContext(aJSCallerContext
)) {
11804 mBlockScriptedClosingFlag
= true;
11805 closeUnblocker
.emplace(this);
11809 FireAbuseEvents(true, false, aUrl
, aName
, aOptions
);
11810 return aDoJSFixups
? NS_OK
: NS_ERROR_FAILURE
;
11814 nsCOMPtr
<nsIDOMWindow
> domReturn
;
11816 nsCOMPtr
<nsIWindowWatcher
> wwatch
=
11817 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
11818 NS_ENSURE_TRUE(wwatch
, rv
);
11820 NS_ConvertUTF16toUTF8
options(aOptions
);
11821 NS_ConvertUTF16toUTF8
name(aName
);
11823 const char *options_ptr
= aOptions
.IsEmpty() ? nullptr : options
.get();
11824 const char *name_ptr
= aName
.IsEmpty() ? nullptr : name
.get();
11826 nsCOMPtr
<nsPIWindowWatcher
> pwwatch(do_QueryInterface(wwatch
));
11827 NS_ENSURE_STATE(pwwatch
);
11830 // Reset popup state while opening a window to prevent the
11831 // current state from being active the whole time a modal
11833 nsAutoPopupStatePusher
popupStatePusher(openAbused
, true);
11835 if (!aCalledNoScript
) {
11836 // We asserted at the top of this function that aNavigate is true for
11837 // !aCalledNoScript.
11838 rv
= pwwatch
->OpenWindow2(this, url
.get(), name_ptr
, options_ptr
,
11839 /* aCalledFromScript = */ true,
11840 aDialog
, aNavigate
, nullptr, argv
,
11841 getter_AddRefs(domReturn
));
11843 // Force a system caller here so that the window watcher won't screw us
11844 // up. We do NOT want this case looking at the JS context on the stack
11845 // when searching. Compare comments on
11846 // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
11848 // Note: Because nsWindowWatcher is so broken, it's actually important
11849 // that we don't force a system caller here, because that screws it up
11850 // when it tries to compute the caller principal to associate with dialog
11851 // arguments. That whole setup just really needs to be rewritten. :-(
11852 Maybe
<AutoNoJSAPI
> nojsapi
;
11853 if (!aContentModal
) {
11858 rv
= pwwatch
->OpenWindow2(this, url
.get(), name_ptr
, options_ptr
,
11859 /* aCalledFromScript = */ false,
11860 aDialog
, aNavigate
, nullptr, aExtraArgument
,
11861 getter_AddRefs(domReturn
));
11866 NS_ENSURE_SUCCESS(rv
, rv
);
11870 NS_ENSURE_TRUE(domReturn
, NS_OK
);
11871 domReturn
.swap(*aReturn
);
11874 nsCOMPtr
<nsIDOMChromeWindow
> chrome_win(do_QueryInterface(*aReturn
));
11876 // A new non-chrome window was created from a call to
11877 // window.open() from JavaScript, make sure there's a document in
11878 // the new window. We do this by simply asking the new window for
11879 // its document, this will synchronously create an empty document
11880 // if there is no document in the window.
11881 // XXXbz should this just use EnsureInnerWindow()?
11884 nsCOMPtr
<nsPIDOMWindow
> pidomwin(do_QueryInterface(*aReturn
));
11885 NS_ASSERTION(pidomwin
->GetExtantDoc(), "No document in new window!!!");
11889 nsCOMPtr
<nsIDOMDocument
> doc
;
11890 (*aReturn
)->GetDocument(getter_AddRefs(doc
));
11894 if (checkForPopup
) {
11895 if (abuseLevel
>= openControlled
) {
11896 nsGlobalWindow
*opened
= static_cast<nsGlobalWindow
*>(*aReturn
);
11897 if (!opened
->IsPopupSpamWindow()) {
11898 opened
->SetPopupSpamWindow(true);
11899 ++gOpenPopupSpamCount
;
11902 if (abuseLevel
>= openAbused
)
11903 FireAbuseEvents(false, true, aUrl
, aName
, aOptions
);
11909 //*****************************************************************************
11910 // nsGlobalWindow: Timeout Functions
11911 //*****************************************************************************
11913 uint32_t sNestingLevel
;
11916 nsGlobalWindow::InnerForSetTimeoutOrInterval(ErrorResult
& aError
)
11918 nsGlobalWindow
* currentInner
;
11919 nsGlobalWindow
* forwardTo
;
11920 if (IsInnerWindow()) {
11921 nsGlobalWindow
* outer
= GetOuterWindowInternal();
11922 currentInner
= outer
? outer
->GetCurrentInnerWindowInternal() : this;
11926 currentInner
= GetCurrentInnerWindowInternal();
11928 // This needs to forward to the inner window, but since the current
11929 // inner may not be the inner in the calling scope, we need to treat
11930 // this specially here as we don't want timeouts registered in a
11931 // dying inner window to get registered and run on the current inner
11932 // window. To get this right, we need to forward this call to the
11933 // inner window that's calling window.setTimeout().
11935 forwardTo
= CallerInnerWindow();
11936 if (!forwardTo
&& nsContentUtils::IsCallerChrome()) {
11937 forwardTo
= currentInner
;
11940 aError
.Throw(NS_ERROR_NOT_AVAILABLE
);
11944 // If the caller and the callee share the same outer window, forward to the
11945 // caller inner. Else, we forward to the current inner (e.g. someone is
11946 // calling setTimeout() on a reference to some other window).
11947 if (forwardTo
->GetOuterWindow() != this || !forwardTo
->IsInnerWindow()) {
11948 if (!currentInner
) {
11949 NS_WARNING("No inner window available!");
11950 aError
.Throw(NS_ERROR_NOT_INITIALIZED
);
11954 return currentInner
;
11958 // If forwardTo is not the window with an active document then we want the
11959 // call to setTimeout/Interval to be a noop, so return null but don't set an
11961 return forwardTo
->HasActiveDocument() ? currentInner
: nullptr;
11965 nsGlobalWindow::SetTimeout(JSContext
* aCx
, Function
& aFunction
,
11967 const Sequence
<JS::Value
>& aArguments
,
11968 ErrorResult
& aError
)
11970 return SetTimeoutOrInterval(aFunction
, aTimeout
, aArguments
, false, aError
);
11974 nsGlobalWindow::SetTimeout(JSContext
* aCx
, const nsAString
& aHandler
,
11976 const Sequence
<JS::Value
>& /* unused */,
11977 ErrorResult
& aError
)
11979 return SetTimeoutOrInterval(aCx
, aHandler
, aTimeout
, false, aError
);
11983 IsInterval(const Optional
<int32_t>& aTimeout
, int32_t& aResultTimeout
)
11985 if (aTimeout
.WasPassed()) {
11986 aResultTimeout
= aTimeout
.Value();
11990 // If no interval was specified, treat this like a timeout, to avoid setting
11991 // an interval of 0 milliseconds.
11992 aResultTimeout
= 0;
11997 nsGlobalWindow::SetInterval(JSContext
* aCx
, Function
& aFunction
,
11998 const Optional
<int32_t>& aTimeout
,
11999 const Sequence
<JS::Value
>& aArguments
,
12000 ErrorResult
& aError
)
12003 bool isInterval
= IsInterval(aTimeout
, timeout
);
12004 return SetTimeoutOrInterval(aFunction
, timeout
, aArguments
, isInterval
,
12009 nsGlobalWindow::SetInterval(JSContext
* aCx
, const nsAString
& aHandler
,
12010 const Optional
<int32_t>& aTimeout
,
12011 const Sequence
<JS::Value
>& /* unused */,
12012 ErrorResult
& aError
)
12015 bool isInterval
= IsInterval(aTimeout
, timeout
);
12016 return SetTimeoutOrInterval(aCx
, aHandler
, timeout
, isInterval
, aError
);
12020 nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler
*aHandler
,
12022 bool aIsInterval
, int32_t *aReturn
)
12024 MOZ_ASSERT(IsInnerWindow());
12026 // If we don't have a document (we could have been unloaded since
12027 // the call to setTimeout was made), do nothing.
12032 // Disallow negative intervals. If aIsInterval also disallow 0,
12033 // because we use that as a "don't repeat" flag.
12034 interval
= std::max(aIsInterval
? 1 : 0, interval
);
12036 // Make sure we don't proceed with an interval larger than our timer
12037 // code can handle. (Note: we already forced |interval| to be non-negative,
12038 // so the uint32_t cast (to avoid compiler warnings) is ok.)
12039 uint32_t maxTimeoutMs
= PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE
);
12040 if (static_cast<uint32_t>(interval
) > maxTimeoutMs
) {
12041 interval
= maxTimeoutMs
;
12044 nsRefPtr
<nsTimeout
> timeout
= new nsTimeout();
12045 timeout
->mIsInterval
= aIsInterval
;
12046 timeout
->mInterval
= interval
;
12047 timeout
->mScriptHandler
= aHandler
;
12049 // Now clamp the actual interval we will use for the timer based on
12050 uint32_t nestingLevel
= sNestingLevel
+ 1;
12051 uint32_t realInterval
= interval
;
12052 if (aIsInterval
|| nestingLevel
>= DOM_CLAMP_TIMEOUT_NESTING_LEVEL
) {
12053 // Don't allow timeouts less than DOMMinTimeoutValue() from
12055 realInterval
= std::max(realInterval
, uint32_t(DOMMinTimeoutValue()));
12058 // Get principal of currently executing code, save for execution of timeout.
12059 // If our principals subsume the subject principal then use the subject
12060 // principal. Otherwise, use our principal to avoid running script in
12061 // elevated principals.
12063 // Note the direction of this test: We don't allow setTimeouts running with
12064 // chrome privileges on content windows, but we do allow setTimeouts running
12065 // with content privileges on chrome windows (where they can't do very much,
12067 nsCOMPtr
<nsIPrincipal
> subjectPrincipal
= nsContentUtils::SubjectPrincipal();
12068 nsCOMPtr
<nsIPrincipal
> ourPrincipal
= GetPrincipal();
12069 if (ourPrincipal
->Subsumes(subjectPrincipal
)) {
12070 timeout
->mPrincipal
= subjectPrincipal
;
12072 timeout
->mPrincipal
= ourPrincipal
;
12075 ++gTimeoutsRecentlySet
;
12076 TimeDuration delta
= TimeDuration::FromMilliseconds(realInterval
);
12078 if (!IsFrozen() && !mTimeoutsSuspendDepth
) {
12079 // If we're not currently frozen, then we set timeout->mWhen to be the
12080 // actual firing time of the timer (i.e., now + delta). We also actually
12081 // create a timer and fire it off.
12083 timeout
->mWhen
= TimeStamp::Now() + delta
;
12086 timeout
->mTimer
= do_CreateInstance("@mozilla.org/timer;1", &rv
);
12087 if (NS_FAILED(rv
)) {
12091 nsRefPtr
<nsTimeout
> copy
= timeout
;
12093 rv
= timeout
->InitTimer(TimerCallback
, realInterval
);
12094 if (NS_FAILED(rv
)) {
12098 // The timeout is now also held in the timer's closure.
12099 unused
<< copy
.forget();
12101 // If we are frozen, however, then we instead simply set
12102 // timeout->mTimeRemaining to be the "time remaining" in the timeout (i.e.,
12103 // the interval itself). We don't create a timer for it, since that will
12104 // happen when we are thawed and the timeout will then get a timer and run
12107 timeout
->mTimeRemaining
= delta
;
12110 timeout
->mWindow
= this;
12112 if (!aIsInterval
) {
12113 timeout
->mNestingLevel
= nestingLevel
;
12116 // No popups from timeouts by default
12117 timeout
->mPopupState
= openAbused
;
12119 if (gRunningTimeoutDepth
== 0 && gPopupControlState
< openAbused
) {
12120 // This timeout is *not* set from another timeout and it's set
12121 // while popups are enabled. Propagate the state to the timeout if
12122 // its delay (interval) is equal to or less than what
12123 // "dom.disable_open_click_delay" is set to (in ms).
12126 Preferences::GetInt("dom.disable_open_click_delay");
12128 // This is checking |interval|, not realInterval, on purpose,
12129 // because our lower bound for |realInterval| could be pretty high
12131 if (interval
<= delay
) {
12132 timeout
->mPopupState
= gPopupControlState
;
12136 InsertTimeoutIntoList(timeout
);
12138 timeout
->mPublicId
= ++mTimeoutPublicIdCounter
;
12139 *aReturn
= timeout
->mPublicId
;
12146 nsGlobalWindow::SetTimeoutOrInterval(bool aIsInterval
, int32_t *aReturn
)
12148 // This needs to forward to the inner window, but since the current
12149 // inner may not be the inner in the calling scope, we need to treat
12150 // this specially here as we don't want timeouts registered in a
12151 // dying inner window to get registered and run on the current inner
12152 // window. To get this right, we need to forward this call to the
12153 // inner window that's calling window.setTimeout().
12155 if (IsOuterWindow()) {
12156 nsGlobalWindow
* callerInner
= CallerInnerWindow();
12157 NS_ENSURE_TRUE(callerInner
|| nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE
);
12159 // If the caller and the callee share the same outer window,
12160 // forward to the callee inner. Else, we forward to the current
12161 // inner (e.g. someone is calling setTimeout() on a reference to
12162 // some other window).
12165 callerInner
->GetOuterWindow() == this &&
12166 callerInner
->IsInnerWindow()) {
12167 return callerInner
->SetTimeoutOrInterval(aIsInterval
, aReturn
);
12170 FORWARD_TO_INNER(SetTimeoutOrInterval
, (aIsInterval
, aReturn
),
12171 NS_ERROR_NOT_INITIALIZED
);
12174 int32_t interval
= 0;
12175 bool isInterval
= aIsInterval
;
12176 nsCOMPtr
<nsIScriptTimeoutHandler
> handler
;
12177 nsresult rv
= NS_CreateJSTimeoutHandler(this,
12180 getter_AddRefs(handler
));
12186 return SetTimeoutOrInterval(handler
, interval
, isInterval
, aReturn
);
12190 nsGlobalWindow::SetTimeoutOrInterval(Function
& aFunction
, int32_t aTimeout
,
12191 const Sequence
<JS::Value
>& aArguments
,
12192 bool aIsInterval
, ErrorResult
& aError
)
12194 nsGlobalWindow
* inner
= InnerForSetTimeoutOrInterval(aError
);
12199 if (inner
!= this) {
12200 return inner
->SetTimeoutOrInterval(aFunction
, aTimeout
, aArguments
,
12201 aIsInterval
, aError
);
12204 nsCOMPtr
<nsIScriptTimeoutHandler
> handler
=
12205 NS_CreateJSTimeoutHandler(this, aFunction
, aArguments
, aError
);
12211 aError
= SetTimeoutOrInterval(handler
, aTimeout
, aIsInterval
, &result
);
12216 nsGlobalWindow::SetTimeoutOrInterval(JSContext
* aCx
, const nsAString
& aHandler
,
12217 int32_t aTimeout
, bool aIsInterval
,
12218 ErrorResult
& aError
)
12220 nsGlobalWindow
* inner
= InnerForSetTimeoutOrInterval(aError
);
12225 if (inner
!= this) {
12226 return inner
->SetTimeoutOrInterval(aCx
, aHandler
, aTimeout
, aIsInterval
,
12230 nsCOMPtr
<nsIScriptTimeoutHandler
> handler
=
12231 NS_CreateJSTimeoutHandler(aCx
, this, aHandler
, aError
);
12237 aError
= SetTimeoutOrInterval(handler
, aTimeout
, aIsInterval
, &result
);
12242 nsGlobalWindow::RunTimeoutHandler(nsTimeout
* aTimeout
,
12243 nsIScriptContext
* aScx
)
12245 // Hold on to the timeout in case mExpr or mFunObj releases its
12247 nsRefPtr
<nsTimeout
> timeout
= aTimeout
;
12248 nsTimeout
* last_running_timeout
= mRunningTimeout
;
12249 mRunningTimeout
= timeout
;
12250 timeout
->mRunning
= true;
12252 // Push this timeout's popup control state, which should only be
12253 // eabled the first time a timeout fires that was created while
12254 // popups were enabled and with a delay less than
12255 // "dom.disable_open_click_delay".
12256 nsAutoPopupStatePusher
popupStatePusher(timeout
->mPopupState
);
12258 // Clear the timeout's popup state, if any, to prevent interval
12259 // timeouts from repeatedly opening poups.
12260 timeout
->mPopupState
= openAbused
;
12262 ++gRunningTimeoutDepth
;
12263 ++mTimeoutFiringDepth
;
12265 bool trackNestingLevel
= !timeout
->mIsInterval
;
12266 uint32_t nestingLevel
;
12267 if (trackNestingLevel
) {
12268 nestingLevel
= sNestingLevel
;
12269 sNestingLevel
= timeout
->mNestingLevel
;
12272 nsCOMPtr
<nsIScriptTimeoutHandler
> handler(timeout
->mScriptHandler
);
12273 nsRefPtr
<Function
> callback
= handler
->GetCallback();
12275 // Evaluate the timeout expression.
12276 const char16_t
* script
= handler
->GetHandlerText();
12277 NS_ASSERTION(script
, "timeout has no script nor handler text!");
12279 const char* filename
= nullptr;
12280 uint32_t lineNo
= 0;
12281 handler
->GetLocation(&filename
, &lineNo
);
12283 // New script entry point required, due to the "Create a script" sub-step of
12284 // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialization-steps
12285 AutoEntryScript
entryScript(this, true, aScx
->GetNativeContext());
12286 JS::CompileOptions
options(entryScript
.cx());
12287 options
.setFileAndLine(filename
, lineNo
)
12288 .setVersion(JSVERSION_DEFAULT
);
12289 JS::Rooted
<JSObject
*> global(entryScript
.cx(), FastGetGlobalJSObject());
12290 nsJSUtils::EvaluateString(entryScript
.cx(), nsDependentString(script
),
12293 // Hold strong ref to ourselves while we call the callback.
12294 nsCOMPtr
<nsISupports
> me(static_cast<nsIDOMWindow
*>(this));
12295 ErrorResult ignored
;
12296 JS::Rooted
<JS::Value
> ignoredVal(CycleCollectedJSRuntime::Get()->Runtime());
12297 callback
->Call(me
, handler
->GetArgs(), &ignoredVal
, ignored
);
12300 // We ignore any failures from calling EvaluateString() on the context or
12301 // Call() on a Function here since we're in a loop
12302 // where we're likely to be running timeouts whose OS timers
12303 // didn't fire in time and we don't want to not fire those timers
12304 // now just because execution of one timer failed. We can't
12305 // propagate the error to anyone who cares about it from this
12306 // point anyway, and the script context should have already reported
12307 // the script error in the usual way - so we just drop it.
12309 if (trackNestingLevel
) {
12310 sNestingLevel
= nestingLevel
;
12313 --mTimeoutFiringDepth
;
12314 --gRunningTimeoutDepth
;
12316 mRunningTimeout
= last_running_timeout
;
12317 timeout
->mRunning
= false;
12318 return timeout
->mCleared
;
12322 nsGlobalWindow::RescheduleTimeout(nsTimeout
* aTimeout
, const TimeStamp
& now
,
12323 bool aRunningPendingTimeouts
)
12325 if (!aTimeout
->mIsInterval
) {
12326 if (aTimeout
->mTimer
) {
12327 // The timeout still has an OS timer, and it's not an interval,
12328 // that means that the OS timer could still fire; cancel the OS
12329 // timer and release its reference to the timeout.
12330 aTimeout
->mTimer
->Cancel();
12331 aTimeout
->mTimer
= nullptr;
12332 aTimeout
->Release();
12337 // Compute time to next timeout for interval timer.
12338 // Make sure nextInterval is at least DOMMinTimeoutValue().
12339 TimeDuration nextInterval
=
12340 TimeDuration::FromMilliseconds(std::max(aTimeout
->mInterval
,
12341 uint32_t(DOMMinTimeoutValue())));
12343 // If we're running pending timeouts, set the next interval to be
12344 // relative to "now", and not to when the timeout that was pending
12345 // should have fired.
12346 TimeStamp firingTime
;
12347 if (aRunningPendingTimeouts
) {
12348 firingTime
= now
+ nextInterval
;
12350 firingTime
= aTimeout
->mWhen
+ nextInterval
;
12353 TimeStamp currentNow
= TimeStamp::Now();
12354 TimeDuration delay
= firingTime
- currentNow
;
12356 // And make sure delay is nonnegative; that might happen if the timer
12357 // thread is firing our timers somewhat early or if they're taking a long
12358 // time to run the callback.
12359 if (delay
< TimeDuration(0)) {
12360 delay
= TimeDuration(0);
12363 if (!aTimeout
->mTimer
) {
12364 NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth
,
12365 "How'd our timer end up null if we're not frozen or "
12368 aTimeout
->mTimeRemaining
= delay
;
12372 aTimeout
->mWhen
= currentNow
+ delay
;
12374 // Reschedule the OS timer. Don't bother returning any error codes if
12375 // this fails since the callers of this method don't care about them.
12376 nsresult rv
= aTimeout
->InitTimer(TimerCallback
, delay
.ToMilliseconds());
12378 if (NS_FAILED(rv
)) {
12379 NS_ERROR("Error initializing timer for DOM timeout!");
12381 // We failed to initialize the new OS timer, this timer does
12382 // us no good here so we just cancel it (just in case) and
12383 // null out the pointer to the OS timer, this will release the
12384 // OS timer. As we continue executing the code below we'll end
12385 // up deleting the timeout since it's not an interval timeout
12386 // any more (since timeout->mTimer == nullptr).
12387 aTimeout
->mTimer
->Cancel();
12388 aTimeout
->mTimer
= nullptr;
12390 // Now that the OS timer no longer has a reference to the
12391 // timeout we need to drop that reference.
12392 aTimeout
->Release();
12401 nsGlobalWindow::RunTimeout(nsTimeout
*aTimeout
)
12403 // If a modal dialog is open for this window, return early. Pending
12404 // timeouts will run when the modal dialog is dismissed.
12405 if (IsInModalState() || mTimeoutsSuspendDepth
) {
12409 NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
12410 NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
12412 nsTimeout
*nextTimeout
;
12413 nsTimeout
*last_expired_timeout
, *last_insertion_point
;
12414 uint32_t firingDepth
= mTimeoutFiringDepth
+ 1;
12416 // Make sure that the window and the script context don't go away as
12417 // a result of running timeouts
12418 nsCOMPtr
<nsIScriptGlobalObject
> windowKungFuDeathGrip(this);
12420 // A native timer has gone off. See which of our timeouts need
12422 TimeStamp now
= TimeStamp::Now();
12423 TimeStamp deadline
;
12425 if (aTimeout
&& aTimeout
->mWhen
> now
) {
12426 // The OS timer fired early (which can happen due to the timers
12427 // having lower precision than TimeStamp does). Set |deadline| to
12428 // be the time when the OS timer *should* have fired so that any
12429 // timers that *should* have fired before aTimeout *will* be fired
12432 deadline
= aTimeout
->mWhen
;
12437 // The timeout list is kept in deadline order. Discover the latest
12438 // timeout whose deadline has expired. On some platforms, native
12439 // timeout events fire "early", so we need to test the timer as well
12440 // as the deadline.
12441 last_expired_timeout
= nullptr;
12442 for (nsTimeout
*timeout
= mTimeouts
.getFirst(); timeout
; timeout
= timeout
->getNext()) {
12443 if (((timeout
== aTimeout
) || (timeout
->mWhen
<= deadline
)) &&
12444 (timeout
->mFiringDepth
== 0)) {
12445 // Mark any timeouts that are on the list to be fired with the
12446 // firing depth so that we can reentrantly run timeouts
12447 timeout
->mFiringDepth
= firingDepth
;
12448 last_expired_timeout
= timeout
;
12452 // Maybe the timeout that the event was fired for has been deleted
12453 // and there are no others timeouts with deadlines that make them
12454 // eligible for execution yet. Go away.
12455 if (!last_expired_timeout
) {
12459 // Record telemetry information about timers set recently.
12460 TimeDuration recordingInterval
= TimeDuration::FromMilliseconds(STATISTICS_INTERVAL
);
12461 if (gLastRecordedRecentTimeouts
.IsNull() ||
12462 now
- gLastRecordedRecentTimeouts
> recordingInterval
) {
12463 uint32_t count
= gTimeoutsRecentlySet
;
12464 gTimeoutsRecentlySet
= 0;
12465 Telemetry::Accumulate(Telemetry::DOM_TIMERS_RECENTLY_SET
, count
);
12466 gLastRecordedRecentTimeouts
= now
;
12469 // Insert a dummy timeout into the list of timeouts between the
12470 // portion of the list that we are about to process now and those
12471 // timeouts that will be processed in a future call to
12472 // win_run_timeout(). This dummy timeout serves as the head of the
12473 // list for any timeouts inserted as a result of running a timeout.
12474 nsRefPtr
<nsTimeout
> dummy_timeout
= new nsTimeout();
12475 dummy_timeout
->mFiringDepth
= firingDepth
;
12476 dummy_timeout
->mWhen
= now
;
12477 last_expired_timeout
->setNext(dummy_timeout
);
12478 dummy_timeout
->AddRef();
12480 last_insertion_point
= mTimeoutInsertionPoint
;
12481 // If we ever start setting mTimeoutInsertionPoint to a non-dummy timeout,
12482 // the logic in ResetTimersForNonBackgroundWindow will need to change.
12483 mTimeoutInsertionPoint
= dummy_timeout
;
12485 Telemetry::AutoCounter
<Telemetry::DOM_TIMERS_FIRED_PER_NATIVE_TIMEOUT
> timeoutsRan
;
12487 for (nsTimeout
*timeout
= mTimeouts
.getFirst();
12488 timeout
!= dummy_timeout
&& !IsFrozen();
12489 timeout
= nextTimeout
) {
12490 nextTimeout
= timeout
->getNext();
12492 if (timeout
->mFiringDepth
!= firingDepth
) {
12493 // We skip the timeout since it's on the list to run at another
12499 if (mTimeoutsSuspendDepth
) {
12500 // Some timer did suspend us. Make sure the
12501 // rest of the timers get executed later.
12502 timeout
->mFiringDepth
= 0;
12506 // The timeout is on the list to run at this depth, go ahead and
12509 // Get the script context (a strong ref to prevent it going away)
12510 // for this timeout and ensure the script language is enabled.
12511 nsCOMPtr
<nsIScriptContext
> scx
= GetContextInternal();
12514 // No context means this window was closed or never properly
12515 // initialized for this language.
12519 // This timeout is good to run
12521 bool timeout_was_cleared
= RunTimeoutHandler(timeout
, scx
);
12523 if (timeout_was_cleared
) {
12524 // The running timeout's window was cleared, this means that
12525 // ClearAllTimeouts() was called from a *nested* call, possibly
12526 // through a timeout that fired while a modal (to this window)
12527 // dialog was open or through other non-obvious paths.
12528 MOZ_ASSERT(dummy_timeout
->HasRefCntOne(), "dummy_timeout may leak");
12530 mTimeoutInsertionPoint
= last_insertion_point
;
12535 // If we have a regular interval timer, we re-schedule the
12536 // timeout, accounting for clock drift.
12537 bool needsReinsertion
= RescheduleTimeout(timeout
, now
, !aTimeout
);
12539 // Running a timeout can cause another timeout to be deleted, so
12540 // we need to reset the pointer to the following timeout.
12541 nextTimeout
= timeout
->getNext();
12545 if (needsReinsertion
) {
12546 // Insert interval timeout onto list sorted in deadline order.
12547 // AddRefs timeout.
12548 InsertTimeoutIntoList(timeout
);
12551 // Release the timeout struct since it's possibly out of the list
12552 timeout
->Release();
12555 // Take the dummy timeout off the head of the list
12556 dummy_timeout
->remove();
12557 dummy_timeout
->Release();
12558 MOZ_ASSERT(dummy_timeout
->HasRefCntOne(), "dummy_timeout may leak");
12560 mTimeoutInsertionPoint
= last_insertion_point
;
12564 nsGlobalWindow::ClearTimeoutOrInterval(int32_t aTimerID
, ErrorResult
& aError
)
12566 FORWARD_TO_INNER_OR_THROW(ClearTimeoutOrInterval
, (aTimerID
, aError
),
12569 uint32_t public_id
= (uint32_t)aTimerID
;
12570 nsTimeout
*timeout
;
12572 for (timeout
= mTimeouts
.getFirst(); timeout
; timeout
= timeout
->getNext()) {
12573 if (timeout
->mPublicId
== public_id
) {
12574 if (timeout
->mRunning
) {
12575 /* We're running from inside the timeout. Mark this
12576 timeout for deferred deletion by the code in
12578 timeout
->mIsInterval
= false;
12581 /* Delete the timeout from the pending timeout list */
12584 if (timeout
->mTimer
) {
12585 timeout
->mTimer
->Cancel();
12586 timeout
->mTimer
= nullptr;
12587 timeout
->Release();
12589 timeout
->Release();
12596 nsresult
nsGlobalWindow::ResetTimersForNonBackgroundWindow()
12598 FORWARD_TO_INNER(ResetTimersForNonBackgroundWindow
, (),
12599 NS_ERROR_NOT_INITIALIZED
);
12601 if (IsFrozen() || mTimeoutsSuspendDepth
) {
12605 TimeStamp now
= TimeStamp::Now();
12607 // If mTimeoutInsertionPoint is non-null, we're in the middle of firing
12608 // timers and the timers we're planning to fire all come before
12609 // mTimeoutInsertionPoint; mTimeoutInsertionPoint itself is a dummy timeout
12610 // with an mWhen that may be semi-bogus. In that case, we don't need to do
12611 // anything with mTimeoutInsertionPoint or anything before it, so should
12612 // start at the timer after mTimeoutInsertionPoint, if there is one.
12613 // Otherwise, start at the beginning of the list.
12614 for (nsTimeout
*timeout
= mTimeoutInsertionPoint
?
12615 mTimeoutInsertionPoint
->getNext() : mTimeouts
.getFirst();
12617 // It's important that this check be <= so that we guarantee that
12618 // taking std::max with |now| won't make a quantity equal to
12619 // timeout->mWhen below.
12620 if (timeout
->mWhen
<= now
) {
12621 timeout
= timeout
->getNext();
12625 if (timeout
->mWhen
- now
>
12626 TimeDuration::FromMilliseconds(gMinBackgroundTimeoutValue
)) {
12627 // No need to loop further. Timeouts are sorted in mWhen order
12628 // and the ones after this point were all set up for at least
12629 // gMinBackgroundTimeoutValue ms and hence were not clamped.
12633 /* We switched from background. Re-init the timer appropriately */
12634 // Compute the interval the timer should have had if it had not been set in a
12635 // background window
12636 TimeDuration interval
=
12637 TimeDuration::FromMilliseconds(std::max(timeout
->mInterval
,
12638 uint32_t(DOMMinTimeoutValue())));
12639 uint32_t oldIntervalMillisecs
= 0;
12640 timeout
->mTimer
->GetDelay(&oldIntervalMillisecs
);
12641 TimeDuration oldInterval
= TimeDuration::FromMilliseconds(oldIntervalMillisecs
);
12642 if (oldInterval
> interval
) {
12644 TimeStamp firingTime
=
12645 std::max(timeout
->mWhen
- oldInterval
+ interval
, now
);
12647 NS_ASSERTION(firingTime
< timeout
->mWhen
,
12648 "Our firing time should strictly decrease!");
12650 TimeDuration delay
= firingTime
- now
;
12651 timeout
->mWhen
= firingTime
;
12653 // Since we reset mWhen we need to move |timeout| to the right
12654 // place in the list so that it remains sorted by mWhen.
12656 // Get the pointer to the next timeout now, before we move the
12657 // current timeout in the list.
12658 nsTimeout
* nextTimeout
= timeout
->getNext();
12660 // It is safe to remove and re-insert because mWhen is now
12661 // strictly smaller than it used to be, so we know we'll insert
12662 // |timeout| before nextTimeout.
12663 NS_ASSERTION(!nextTimeout
||
12664 timeout
->mWhen
< nextTimeout
->mWhen
, "How did that happen?");
12666 // InsertTimeoutIntoList will addref |timeout| and reset
12667 // mFiringDepth. Make sure to undo that after calling it.
12668 uint32_t firingDepth
= timeout
->mFiringDepth
;
12669 InsertTimeoutIntoList(timeout
);
12670 timeout
->mFiringDepth
= firingDepth
;
12671 timeout
->Release();
12673 nsresult rv
= timeout
->InitTimer(TimerCallback
, delay
.ToMilliseconds());
12675 if (NS_FAILED(rv
)) {
12676 NS_WARNING("Error resetting non background timer for DOM timeout!");
12680 timeout
= nextTimeout
;
12682 timeout
= timeout
->getNext();
12690 nsGlobalWindow::ClearAllTimeouts()
12692 nsTimeout
*timeout
, *nextTimeout
;
12694 for (timeout
= mTimeouts
.getFirst(); timeout
; timeout
= nextTimeout
) {
12695 /* If RunTimeout() is higher up on the stack for this
12696 window, e.g. as a result of document.write from a timeout,
12697 then we need to reset the list insertion point for
12698 newly-created timeouts in case the user adds a timeout,
12699 before we pop the stack back to RunTimeout. */
12700 if (mRunningTimeout
== timeout
)
12701 mTimeoutInsertionPoint
= nullptr;
12703 nextTimeout
= timeout
->getNext();
12705 if (timeout
->mTimer
) {
12706 timeout
->mTimer
->Cancel();
12707 timeout
->mTimer
= nullptr;
12709 // Drop the count since the timer isn't going to hold on
12711 timeout
->Release();
12714 // Set timeout->mCleared to true to indicate that the timeout was
12715 // cleared and taken out of the list of timeouts
12716 timeout
->mCleared
= true;
12718 // Drop the count since we're removing it from the list.
12719 timeout
->Release();
12722 // Clear out our list
12727 nsGlobalWindow::InsertTimeoutIntoList(nsTimeout
*aTimeout
)
12729 NS_ASSERTION(IsInnerWindow(),
12730 "InsertTimeoutIntoList() called on outer window!");
12732 // Start at mLastTimeout and go backwards. Don't go further than
12733 // mTimeoutInsertionPoint, though. This optimizes for the common case of
12734 // insertion at the end.
12735 nsTimeout
* prevSibling
;
12736 for (prevSibling
= mTimeouts
.getLast();
12737 prevSibling
&& prevSibling
!= mTimeoutInsertionPoint
&&
12738 // This condition needs to match the one in SetTimeoutOrInterval that
12739 // determines whether to set mWhen or mTimeRemaining.
12740 ((IsFrozen() || mTimeoutsSuspendDepth
) ?
12741 prevSibling
->mTimeRemaining
> aTimeout
->mTimeRemaining
:
12742 prevSibling
->mWhen
> aTimeout
->mWhen
);
12743 prevSibling
= prevSibling
->getPrevious()) {
12744 /* Do nothing; just searching */
12747 // Now link in aTimeout after prevSibling.
12749 prevSibling
->setNext(aTimeout
);
12751 mTimeouts
.insertFront(aTimeout
);
12754 aTimeout
->mFiringDepth
= 0;
12756 // Increment the timeout's reference count since it's now held on to
12758 aTimeout
->AddRef();
12763 nsGlobalWindow::TimerCallback(nsITimer
*aTimer
, void *aClosure
)
12765 nsRefPtr
<nsTimeout
> timeout
= (nsTimeout
*)aClosure
;
12767 timeout
->mWindow
->RunTimeout(timeout
);
12770 //*****************************************************************************
12771 // nsGlobalWindow: Helper Functions
12772 //*****************************************************************************
12774 already_AddRefed
<nsIDocShellTreeOwner
>
12775 nsGlobalWindow::GetTreeOwner()
12777 FORWARD_TO_OUTER(GetTreeOwner
, (), nullptr);
12779 // If there's no docShellAsItem, this window must have been closed,
12780 // in that case there is no tree owner.
12786 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
12787 mDocShell
->GetTreeOwner(getter_AddRefs(treeOwner
));
12788 return treeOwner
.forget();
12791 already_AddRefed
<nsIBaseWindow
>
12792 nsGlobalWindow::GetTreeOwnerWindow()
12794 MOZ_ASSERT(IsOuterWindow());
12796 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
12798 // If there's no mDocShell, this window must have been closed,
12799 // in that case there is no tree owner.
12802 mDocShell
->GetTreeOwner(getter_AddRefs(treeOwner
));
12805 nsCOMPtr
<nsIBaseWindow
> baseWindow
= do_QueryInterface(treeOwner
);
12806 return baseWindow
.forget();
12809 already_AddRefed
<nsIWebBrowserChrome
>
12810 nsGlobalWindow::GetWebBrowserChrome()
12812 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
= GetTreeOwner();
12814 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome
= do_GetInterface(treeOwner
);
12815 return browserChrome
.forget();
12818 nsIScrollableFrame
*
12819 nsGlobalWindow::GetScrollFrame()
12821 FORWARD_TO_OUTER(GetScrollFrame
, (), nullptr);
12827 nsCOMPtr
<nsIPresShell
> presShell
= mDocShell
->GetPresShell();
12829 return presShell
->GetRootScrollFrameAsScrollable();
12835 nsGlobalWindow::SecurityCheckURL(const char *aURL
)
12837 nsCOMPtr
<nsPIDOMWindow
> sourceWindow
= do_QueryInterface(GetEntryGlobal());
12838 if (!sourceWindow
) {
12839 sourceWindow
= this;
12842 nsGlobalWindow
* sourceWin
= static_cast<nsGlobalWindow
*>(sourceWindow
.get());
12843 JSAutoCompartment
ac(cx
, sourceWin
->GetGlobalJSObject());
12845 // Resolve the baseURI, which could be relative to the calling window.
12847 // Note the algorithm to get the base URI should match the one
12848 // used to actually kick off the load in nsWindowWatcher.cpp.
12849 nsCOMPtr
<nsIDocument
> doc
= sourceWindow
->GetDoc();
12850 nsIURI
* baseURI
= nullptr;
12851 nsAutoCString
charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
12853 baseURI
= doc
->GetDocBaseURI();
12854 charset
= doc
->GetDocumentCharacterSet();
12856 nsCOMPtr
<nsIURI
> uri
;
12857 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), nsDependentCString(aURL
),
12858 charset
.get(), baseURI
);
12859 if (NS_WARN_IF(NS_FAILED(rv
))) {
12863 if (NS_FAILED(nsContentUtils::GetSecurityManager()->
12864 CheckLoadURIFromScript(cx
, uri
))) {
12865 return NS_ERROR_FAILURE
;
12872 nsGlobalWindow::FlushPendingNotifications(mozFlushType aType
)
12875 mDoc
->FlushPendingNotifications(aType
);
12880 nsGlobalWindow::EnsureSizeUpToDate()
12882 MOZ_ASSERT(IsOuterWindow());
12884 // If we're a subframe, make sure our size is up to date. It's OK that this
12885 // crosses the content/chrome boundary, since chrome can have pending reflows
12887 nsGlobalWindow
*parent
=
12888 static_cast<nsGlobalWindow
*>(GetPrivateParent());
12890 parent
->FlushPendingNotifications(Flush_Layout
);
12894 already_AddRefed
<nsISupports
>
12895 nsGlobalWindow::SaveWindowState()
12897 NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
12899 if (!mContext
|| !GetWrapperPreserveColor()) {
12900 // The window may be getting torn down; don't bother saving state.
12904 nsGlobalWindow
*inner
= GetCurrentInnerWindowInternal();
12905 NS_ASSERTION(inner
, "No inner window to save");
12907 // Don't do anything else to this inner window! After this point, all
12908 // calls to SetTimeoutOrInterval will create entries in the timeout
12909 // list that will only run after this window has come out of the bfcache.
12910 // Also, while we're frozen, we won't dispatch online/offline events
12914 nsCOMPtr
<nsISupports
> state
= new WindowStateHolder(mContext
, inner
);
12916 #ifdef DEBUG_PAGE_CACHE
12917 printf("saving window state, state = %p\n", (void*)state
);
12920 return state
.forget();
12924 nsGlobalWindow::RestoreWindowState(nsISupports
*aState
)
12926 NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
12928 if (!mContext
|| !GetWrapperPreserveColor()) {
12929 // The window may be getting torn down; don't bother restoring state.
12933 nsCOMPtr
<WindowStateHolder
> holder
= do_QueryInterface(aState
);
12934 NS_ENSURE_TRUE(holder
, NS_ERROR_FAILURE
);
12936 #ifdef DEBUG_PAGE_CACHE
12937 printf("restoring window state, state = %p\n", (void*)holder
);
12940 // And we're ready to go!
12941 nsGlobalWindow
*inner
= GetCurrentInnerWindowInternal();
12943 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
12944 // it easy to tell which link was last clicked when going back a page.
12945 nsIContent
* focusedNode
= inner
->GetFocusedNode();
12946 if (IsLink(focusedNode
)) {
12947 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
12949 nsCOMPtr
<nsIDOMElement
> focusedElement(do_QueryInterface(focusedNode
));
12950 fm
->SetFocus(focusedElement
, nsIFocusManager::FLAG_NOSCROLL
|
12951 nsIFocusManager::FLAG_SHOWRING
);
12957 holder
->DidRestoreWindow();
12963 nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease
,
12964 bool aFreezeChildren
)
12966 FORWARD_TO_INNER_VOID(SuspendTimeouts
, (aIncrease
, aFreezeChildren
));
12968 bool suspended
= (mTimeoutsSuspendDepth
!= 0);
12969 mTimeoutsSuspendDepth
+= aIncrease
;
12972 nsCOMPtr
<nsIDeviceSensors
> ac
= do_GetService(NS_DEVICE_SENSORS_CONTRACTID
);
12974 for (uint32_t i
= 0; i
< mEnabledSensors
.Length(); i
++)
12975 ac
->RemoveWindowListener(mEnabledSensors
[i
], this);
12977 DisableGamepadUpdates();
12979 // Suspend all of the workers for this window.
12980 mozilla::dom::workers::SuspendWorkersForWindow(this);
12982 TimeStamp now
= TimeStamp::Now();
12983 for (nsTimeout
*t
= mTimeouts
.getFirst(); t
; t
= t
->getNext()) {
12984 // Set mTimeRemaining to be the time remaining for this timer.
12985 if (t
->mWhen
> now
)
12986 t
->mTimeRemaining
= t
->mWhen
- now
;
12988 t
->mTimeRemaining
= TimeDuration(0);
12990 // Drop the XPCOM timer; we'll reschedule when restoring the state.
12992 t
->mTimer
->Cancel();
12993 t
->mTimer
= nullptr;
12995 // Drop the reference that the timer's closure had on this timeout, we'll
12996 // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
12997 // passing null for the context, since this shouldn't actually release this
13003 // Suspend all of the AudioContexts for this window
13004 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
13005 mAudioContexts
[i
]->Suspend();
13009 // Suspend our children as well.
13010 nsCOMPtr
<nsIDocShell
> docShell
= GetDocShell();
13012 int32_t childCount
= 0;
13013 docShell
->GetChildCount(&childCount
);
13015 for (int32_t i
= 0; i
< childCount
; ++i
) {
13016 nsCOMPtr
<nsIDocShellTreeItem
> childShell
;
13017 docShell
->GetChildAt(i
, getter_AddRefs(childShell
));
13018 NS_ASSERTION(childShell
, "null child shell");
13020 nsCOMPtr
<nsPIDOMWindow
> pWin
= childShell
->GetWindow();
13022 nsGlobalWindow
*win
=
13023 static_cast<nsGlobalWindow
*>
13024 (static_cast<nsPIDOMWindow
*>(pWin
));
13025 NS_ASSERTION(win
->IsOuterWindow(), "Expected outer window");
13026 nsGlobalWindow
* inner
= win
->GetCurrentInnerWindowInternal();
13028 // This is a bit hackish. Only freeze/suspend windows which are truly our
13030 nsCOMPtr
<Element
> frame
= pWin
->GetFrameElementInternal();
13031 if (!mDoc
|| !frame
|| mDoc
!= frame
->OwnerDoc() || !inner
) {
13035 win
->SuspendTimeouts(aIncrease
, aFreezeChildren
);
13037 if (inner
&& aFreezeChildren
) {
13046 nsGlobalWindow::ResumeTimeouts(bool aThawChildren
)
13048 FORWARD_TO_INNER(ResumeTimeouts
, (), NS_ERROR_NOT_INITIALIZED
);
13050 NS_ASSERTION(mTimeoutsSuspendDepth
, "Mismatched calls to ResumeTimeouts!");
13051 --mTimeoutsSuspendDepth
;
13052 bool shouldResume
= (mTimeoutsSuspendDepth
== 0) && !mInnerObjectsFreed
;
13055 if (shouldResume
) {
13056 nsCOMPtr
<nsIDeviceSensors
> ac
= do_GetService(NS_DEVICE_SENSORS_CONTRACTID
);
13058 for (uint32_t i
= 0; i
< mEnabledSensors
.Length(); i
++)
13059 ac
->AddWindowListener(mEnabledSensors
[i
], this);
13061 EnableGamepadUpdates();
13063 // Resume all of the AudioContexts for this window
13064 for (uint32_t i
= 0; i
< mAudioContexts
.Length(); ++i
) {
13065 mAudioContexts
[i
]->Resume();
13068 // Resume all of the workers for this window.
13069 mozilla::dom::workers::ResumeWorkersForWindow(this);
13071 // Restore all of the timeouts, using the stored time remaining
13072 // (stored in timeout->mTimeRemaining).
13074 TimeStamp now
= TimeStamp::Now();
13077 bool _seenDummyTimeout
= false;
13080 for (nsTimeout
*t
= mTimeouts
.getFirst(); t
; t
= t
->getNext()) {
13081 // There's a chance we're being called with RunTimeout on the stack in which
13082 // case we have a dummy timeout in the list that *must not* be resumed. It
13083 // can be identified by a null mWindow.
13086 NS_ASSERTION(!_seenDummyTimeout
, "More than one dummy timeout?!");
13087 _seenDummyTimeout
= true;
13092 // XXXbz the combination of the way |delay| and |t->mWhen| are set here
13093 // makes no sense. Are we trying to impose that min timeout value or
13096 std::max(int32_t(t
->mTimeRemaining
.ToMilliseconds()),
13097 DOMMinTimeoutValue());
13099 // Set mWhen back to the time when the timer is supposed to
13101 t
->mWhen
= now
+ t
->mTimeRemaining
;
13103 t
->mTimer
= do_CreateInstance("@mozilla.org/timer;1");
13104 NS_ENSURE_TRUE(t
->mTimer
, NS_ERROR_OUT_OF_MEMORY
);
13106 rv
= t
->InitTimer(TimerCallback
, delay
);
13107 if (NS_FAILED(rv
)) {
13108 t
->mTimer
= nullptr;
13112 // Add a reference for the new timer's closure.
13117 // Resume our children as well.
13118 nsCOMPtr
<nsIDocShell
> docShell
= GetDocShell();
13120 int32_t childCount
= 0;
13121 docShell
->GetChildCount(&childCount
);
13123 for (int32_t i
= 0; i
< childCount
; ++i
) {
13124 nsCOMPtr
<nsIDocShellTreeItem
> childShell
;
13125 docShell
->GetChildAt(i
, getter_AddRefs(childShell
));
13126 NS_ASSERTION(childShell
, "null child shell");
13128 nsCOMPtr
<nsPIDOMWindow
> pWin
= childShell
->GetWindow();
13130 nsGlobalWindow
*win
=
13131 static_cast<nsGlobalWindow
*>
13132 (static_cast<nsPIDOMWindow
*>(pWin
));
13134 NS_ASSERTION(win
->IsOuterWindow(), "Expected outer window");
13135 nsGlobalWindow
* inner
= win
->GetCurrentInnerWindowInternal();
13137 // This is a bit hackish. Only thaw/resume windows which are truly our
13139 nsCOMPtr
<Element
> frame
= pWin
->GetFrameElementInternal();
13140 if (!mDoc
|| !frame
|| mDoc
!= frame
->OwnerDoc() || !inner
) {
13144 if (inner
&& aThawChildren
) {
13148 rv
= win
->ResumeTimeouts(aThawChildren
);
13149 NS_ENSURE_SUCCESS(rv
, rv
);
13158 nsGlobalWindow::TimeoutSuspendCount()
13160 FORWARD_TO_INNER(TimeoutSuspendCount
, (), 0);
13161 return mTimeoutsSuspendDepth
;
13165 nsGlobalWindow::EnableDeviceSensor(uint32_t aType
)
13167 MOZ_ASSERT(IsInnerWindow());
13169 bool alreadyEnabled
= false;
13170 for (uint32_t i
= 0; i
< mEnabledSensors
.Length(); i
++) {
13171 if (mEnabledSensors
[i
] == aType
) {
13172 alreadyEnabled
= true;
13177 mEnabledSensors
.AppendElement(aType
);
13179 if (alreadyEnabled
) {
13183 nsCOMPtr
<nsIDeviceSensors
> ac
= do_GetService(NS_DEVICE_SENSORS_CONTRACTID
);
13185 ac
->AddWindowListener(aType
, this);
13190 nsGlobalWindow::DisableDeviceSensor(uint32_t aType
)
13192 MOZ_ASSERT(IsInnerWindow());
13194 int32_t doomedElement
= -1;
13195 int32_t listenerCount
= 0;
13196 for (uint32_t i
= 0; i
< mEnabledSensors
.Length(); i
++) {
13197 if (mEnabledSensors
[i
] == aType
) {
13203 if (doomedElement
== -1) {
13207 mEnabledSensors
.RemoveElementAt(doomedElement
);
13209 if (listenerCount
> 1) {
13213 nsCOMPtr
<nsIDeviceSensors
> ac
= do_GetService(NS_DEVICE_SENSORS_CONTRACTID
);
13215 ac
->RemoveWindowListener(aType
, this);
13220 nsGlobalWindow::SetHasGamepadEventListener(bool aHasGamepad
/* = true*/)
13222 MOZ_ASSERT(IsInnerWindow());
13223 mHasGamepad
= aHasGamepad
;
13225 EnableGamepadUpdates();
13230 nsGlobalWindow::EnableTimeChangeNotifications()
13232 mozilla::time::AddWindowListener(this);
13236 nsGlobalWindow::DisableTimeChangeNotifications()
13238 mozilla::time::RemoveWindowListener(this);
13241 static PLDHashOperator
13242 CollectSizeAndListenerCount(
13243 nsPtrHashKey
<DOMEventTargetHelper
>* aEntry
,
13246 nsWindowSizes
* windowSizes
= static_cast<nsWindowSizes
*>(arg
);
13248 DOMEventTargetHelper
* et
= aEntry
->GetKey();
13250 if (nsCOMPtr
<nsISizeOfEventTarget
> iSizeOf
= do_QueryObject(et
)) {
13251 windowSizes
->mDOMEventTargetsSize
+=
13252 iSizeOf
->SizeOfEventTargetIncludingThis(windowSizes
->mMallocSizeOf
);
13255 if (EventListenerManager
* elm
= et
->GetExistingListenerManager()) {
13256 windowSizes
->mDOMEventListenersCount
+= elm
->ListenerCount();
13259 return PL_DHASH_NEXT
;
13263 nsGlobalWindow::AddSizeOfIncludingThis(nsWindowSizes
* aWindowSizes
) const
13265 aWindowSizes
->mDOMOtherSize
+= aWindowSizes
->mMallocSizeOf(this);
13267 if (IsInnerWindow()) {
13268 EventListenerManager
* elm
= GetExistingListenerManager();
13270 aWindowSizes
->mDOMOtherSize
+=
13271 elm
->SizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
);
13272 aWindowSizes
->mDOMEventListenersCount
+=
13273 elm
->ListenerCount();
13276 mDoc
->DocAddSizeOfIncludingThis(aWindowSizes
);
13281 aWindowSizes
->mDOMOtherSize
+=
13282 mNavigator
->SizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
);
13285 // The things pointed to by the entries will be measured below, so we
13286 // use nullptr for the callback here.
13287 aWindowSizes
->mDOMEventTargetsSize
+=
13288 mEventTargetObjects
.SizeOfExcludingThis(nullptr,
13289 aWindowSizes
->mMallocSizeOf
);
13290 aWindowSizes
->mDOMEventTargetsCount
+=
13291 const_cast<nsTHashtable
<nsPtrHashKey
<DOMEventTargetHelper
> >*>
13292 (&mEventTargetObjects
)->EnumerateEntries(CollectSizeAndListenerCount
,
13299 nsGlobalWindow::AddGamepad(uint32_t aIndex
, Gamepad
* aGamepad
)
13301 MOZ_ASSERT(IsInnerWindow());
13302 mGamepads
.Put(aIndex
, aGamepad
);
13306 nsGlobalWindow::RemoveGamepad(uint32_t aIndex
)
13308 MOZ_ASSERT(IsInnerWindow());
13309 mGamepads
.Remove(aIndex
);
13314 nsGlobalWindow::EnumGamepadsForGet(const uint32_t& aKey
, Gamepad
* aData
,
13317 nsTArray
<nsRefPtr
<Gamepad
> >* array
=
13318 static_cast<nsTArray
<nsRefPtr
<Gamepad
> >*>(aUserArg
);
13319 array
->EnsureLengthAtLeast(aKey
+ 1);
13320 (*array
)[aKey
] = aData
;
13321 return PL_DHASH_NEXT
;
13325 nsGlobalWindow::GetGamepads(nsTArray
<nsRefPtr
<Gamepad
> >& aGamepads
)
13327 MOZ_ASSERT(IsInnerWindow());
13329 // mGamepads.Count() may not be sufficient, but it's not harmful.
13330 aGamepads
.SetCapacity(mGamepads
.Count());
13331 mGamepads
.EnumerateRead(EnumGamepadsForGet
, &aGamepads
);
13334 already_AddRefed
<Gamepad
>
13335 nsGlobalWindow::GetGamepad(uint32_t aIndex
)
13337 MOZ_ASSERT(IsInnerWindow());
13338 nsRefPtr
<Gamepad
> gamepad
;
13339 if (mGamepads
.Get(aIndex
, getter_AddRefs(gamepad
))) {
13340 return gamepad
.forget();
13347 nsGlobalWindow::SetHasSeenGamepadInput(bool aHasSeen
)
13349 MOZ_ASSERT(IsInnerWindow());
13350 mHasSeenGamepadInput
= aHasSeen
;
13354 nsGlobalWindow::HasSeenGamepadInput()
13356 MOZ_ASSERT(IsInnerWindow());
13357 return mHasSeenGamepadInput
;
13362 nsGlobalWindow::EnumGamepadsForSync(const uint32_t& aKey
, Gamepad
* aData
,
13365 nsRefPtr
<GamepadService
> gamepadsvc(GamepadService::GetService());
13366 gamepadsvc
->SyncGamepadState(aKey
, aData
);
13367 return PL_DHASH_NEXT
;
13371 nsGlobalWindow::SyncGamepadState()
13373 MOZ_ASSERT(IsInnerWindow());
13374 if (mHasSeenGamepadInput
) {
13375 mGamepads
.EnumerateRead(EnumGamepadsForSync
, nullptr);
13379 // nsGlobalChromeWindow implementation
13381 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow
)
13383 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow
,
13385 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserDOMWindow
)
13386 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager
)
13387 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGroupMessageManagers
)
13388 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
13391 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalChromeWindow
,
13393 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserDOMWindow
)
13394 if (tmp
->mMessageManager
) {
13395 static_cast<nsFrameMessageManager
*>(
13396 tmp
->mMessageManager
.get())->Disconnect();
13397 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager
)
13400 tmp
->mGroupMessageManagers
.EnumerateRead(DisconnectGroupMessageManager
, nullptr);
13401 tmp
->mGroupMessageManagers
.Clear();
13402 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGroupMessageManagers
)
13403 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
13405 DOMCI_DATA(ChromeWindow
, nsGlobalChromeWindow
)
13407 // QueryInterface implementation for nsGlobalChromeWindow
13408 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow
)
13409 NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow
)
13410 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow
)
13411 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow
)
13413 NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow
, nsGlobalWindow
)
13414 NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow
, nsGlobalWindow
)
13417 nsGlobalChromeWindow::GetWindowState(uint16_t* aWindowState
)
13419 *aWindowState
= WindowState();
13424 nsGlobalWindow::WindowState()
13426 nsCOMPtr
<nsIWidget
> widget
= GetMainWidget();
13428 int32_t mode
= widget
? widget
->SizeMode() : 0;
13431 case nsSizeMode_Minimized
:
13432 return nsIDOMChromeWindow::STATE_MINIMIZED
;
13433 case nsSizeMode_Maximized
:
13434 return nsIDOMChromeWindow::STATE_MAXIMIZED
;
13435 case nsSizeMode_Fullscreen
:
13436 return nsIDOMChromeWindow::STATE_FULLSCREEN
;
13437 case nsSizeMode_Normal
:
13438 return nsIDOMChromeWindow::STATE_NORMAL
;
13440 NS_WARNING("Illegal window state for this chrome window");
13444 return nsIDOMChromeWindow::STATE_NORMAL
;
13448 nsGlobalChromeWindow::Maximize()
13452 return rv
.ErrorCode();
13456 nsGlobalWindow::Maximize(ErrorResult
& aError
)
13458 nsCOMPtr
<nsIWidget
> widget
= GetMainWidget();
13461 aError
= widget
->SetSizeMode(nsSizeMode_Maximized
);
13466 nsGlobalChromeWindow::Minimize()
13470 return rv
.ErrorCode();
13474 nsGlobalWindow::Minimize(ErrorResult
& aError
)
13476 nsCOMPtr
<nsIWidget
> widget
= GetMainWidget();
13479 aError
= widget
->SetSizeMode(nsSizeMode_Minimized
);
13484 nsGlobalChromeWindow::Restore()
13488 return rv
.ErrorCode();
13492 nsGlobalWindow::Restore(ErrorResult
& aError
)
13494 nsCOMPtr
<nsIWidget
> widget
= GetMainWidget();
13497 aError
= widget
->SetSizeMode(nsSizeMode_Normal
);
13502 nsGlobalChromeWindow::GetAttention()
13506 return rv
.ErrorCode();
13510 nsGlobalWindow::GetAttention(ErrorResult
& aResult
)
13512 return GetAttentionWithCycleCount(-1, aResult
);
13516 nsGlobalChromeWindow::GetAttentionWithCycleCount(int32_t aCycleCount
)
13519 GetAttentionWithCycleCount(aCycleCount
, rv
);
13520 return rv
.ErrorCode();
13524 nsGlobalWindow::GetAttentionWithCycleCount(int32_t aCycleCount
,
13525 ErrorResult
& aError
)
13527 nsCOMPtr
<nsIWidget
> widget
= GetMainWidget();
13530 aError
= widget
->GetAttention(aCycleCount
);
13535 nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent
*aMouseDownEvent
, nsIDOMElement
* aPanel
)
13537 NS_ENSURE_TRUE(aMouseDownEvent
, NS_ERROR_FAILURE
);
13538 Event
* mouseDownEvent
= aMouseDownEvent
->InternalDOMEvent();
13539 NS_ENSURE_TRUE(mouseDownEvent
, NS_ERROR_FAILURE
);
13541 nsCOMPtr
<Element
> panel
= do_QueryInterface(aPanel
);
13542 NS_ENSURE_TRUE(panel
|| !aPanel
, NS_ERROR_FAILURE
);
13545 BeginWindowMove(*mouseDownEvent
, panel
, rv
);
13546 return rv
.ErrorCode();
13550 nsGlobalWindow::BeginWindowMove(Event
& aMouseDownEvent
, Element
* aPanel
,
13551 ErrorResult
& aError
)
13553 nsCOMPtr
<nsIWidget
> widget
;
13555 // if a panel was supplied, use its widget instead.
13558 nsIFrame
* frame
= aPanel
->GetPrimaryFrame();
13559 if (!frame
|| frame
->GetType() != nsGkAtoms::menuPopupFrame
) {
13563 widget
= (static_cast<nsMenuPopupFrame
*>(frame
))->GetWidget();
13567 widget
= GetMainWidget();
13576 WidgetMouseEvent
* mouseEvent
=
13577 aMouseDownEvent
.GetInternalNSEvent()->AsMouseEvent();
13578 if (!mouseEvent
|| mouseEvent
->mClass
!= eMouseEventClass
) {
13579 aError
.Throw(NS_ERROR_FAILURE
);
13583 aError
= widget
->BeginMoveDrag(mouseEvent
);
13586 //Note: This call will lock the cursor, it will not change as it moves.
13587 //To unlock, the cursor must be set back to CURSOR_AUTO.
13589 nsGlobalChromeWindow::SetCursor(const nsAString
& aCursor
)
13592 SetCursor(aCursor
, rv
);
13593 return rv
.ErrorCode();
13597 nsGlobalWindow::SetCursor(const nsAString
& aCursor
, ErrorResult
& aError
)
13599 FORWARD_TO_OUTER_OR_THROW(SetCursor
, (aCursor
, aError
), aError
, );
13603 if (aCursor
.EqualsLiteral("auto"))
13604 cursor
= NS_STYLE_CURSOR_AUTO
;
13606 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(aCursor
);
13607 if (eCSSKeyword_UNKNOWN
== keyword
||
13608 !nsCSSProps::FindKeyword(keyword
, nsCSSProps::kCursorKTable
, cursor
)) {
13613 nsRefPtr
<nsPresContext
> presContext
;
13615 mDocShell
->GetPresContext(getter_AddRefs(presContext
));
13619 // Need root widget.
13620 nsCOMPtr
<nsIPresShell
> presShell
= mDocShell
->GetPresShell();
13622 aError
.Throw(NS_ERROR_FAILURE
);
13626 nsViewManager
* vm
= presShell
->GetViewManager();
13628 aError
.Throw(NS_ERROR_FAILURE
);
13632 nsView
* rootView
= vm
->GetRootView();
13634 aError
.Throw(NS_ERROR_FAILURE
);
13638 nsIWidget
* widget
= rootView
->GetNearestWidget(nullptr);
13640 aError
.Throw(NS_ERROR_FAILURE
);
13644 // Call esm and set cursor.
13645 aError
= presContext
->EventStateManager()->SetCursor(cursor
, nullptr,
13652 nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow
**aBrowserWindow
)
13655 NS_IF_ADDREF(*aBrowserWindow
= GetBrowserDOMWindow(rv
));
13656 return rv
.ErrorCode();
13659 nsIBrowserDOMWindow
*
13660 nsGlobalWindow::GetBrowserDOMWindow(ErrorResult
& aError
)
13662 FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindow
, (aError
), aError
, nullptr);
13664 MOZ_ASSERT(IsChromeWindow());
13665 return static_cast<nsGlobalChromeWindow
*>(this)->mBrowserDOMWindow
;
13669 nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow
*aBrowserWindow
)
13672 SetBrowserDOMWindow(aBrowserWindow
, rv
);
13673 return rv
.ErrorCode();
13677 nsGlobalWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow
* aBrowserWindow
,
13678 ErrorResult
& aError
)
13680 FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindow
, (aBrowserWindow
, aError
),
13682 MOZ_ASSERT(IsChromeWindow());
13683 static_cast<nsGlobalChromeWindow
*>(this)->mBrowserDOMWindow
= aBrowserWindow
;
13687 nsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement
* aDefaultButton
)
13689 nsCOMPtr
<Element
> defaultButton
= do_QueryInterface(aDefaultButton
);
13690 NS_ENSURE_ARG(defaultButton
);
13693 NotifyDefaultButtonLoaded(*defaultButton
, rv
);
13694 return rv
.ErrorCode();
13698 nsGlobalWindow::NotifyDefaultButtonLoaded(Element
& aDefaultButton
,
13699 ErrorResult
& aError
)
13702 // Don't snap to a disabled button.
13703 nsCOMPtr
<nsIDOMXULControlElement
> xulControl
=
13704 do_QueryInterface(&aDefaultButton
);
13706 aError
.Throw(NS_ERROR_FAILURE
);
13710 aError
= xulControl
->GetDisabled(&disabled
);
13711 if (aError
.Failed() || disabled
) {
13715 // Get the button rect in screen coordinates.
13716 nsIFrame
*frame
= aDefaultButton
.GetPrimaryFrame();
13718 aError
.Throw(NS_ERROR_FAILURE
);
13721 nsIntRect buttonRect
= frame
->GetScreenRect();
13723 // Get the widget rect in screen coordinates.
13724 nsIWidget
*widget
= GetNearestWidget();
13726 aError
.Throw(NS_ERROR_FAILURE
);
13729 nsIntRect widgetRect
;
13730 aError
= widget
->GetScreenBounds(widgetRect
);
13731 if (aError
.Failed()) {
13735 // Convert the buttonRect coordinates from screen to the widget.
13736 buttonRect
-= widgetRect
.TopLeft();
13737 nsresult rv
= widget
->OnDefaultButtonLoaded(buttonRect
);
13738 if (NS_FAILED(rv
) && rv
!= NS_ERROR_NOT_IMPLEMENTED
) {
13742 aError
.Throw(NS_ERROR_NOT_IMPLEMENTED
);
13747 nsGlobalChromeWindow::GetMessageManager(nsIMessageBroadcaster
** aManager
)
13750 NS_IF_ADDREF(*aManager
= GetMessageManager(rv
));
13751 return rv
.ErrorCode();
13754 nsIMessageBroadcaster
*
13755 nsGlobalWindow::GetMessageManager(ErrorResult
& aError
)
13757 FORWARD_TO_INNER_OR_THROW(GetMessageManager
, (aError
), aError
, nullptr);
13758 MOZ_ASSERT(IsChromeWindow());
13759 nsGlobalChromeWindow
* myself
= static_cast<nsGlobalChromeWindow
*>(this);
13760 if (!myself
->mMessageManager
) {
13761 nsCOMPtr
<nsIMessageBroadcaster
> globalMM
=
13762 do_GetService("@mozilla.org/globalmessagemanager;1");
13763 myself
->mMessageManager
=
13764 new nsFrameMessageManager(nullptr,
13765 static_cast<nsFrameMessageManager
*>(globalMM
.get()),
13766 MM_CHROME
| MM_BROADCASTER
);
13768 return myself
->mMessageManager
;
13772 nsGlobalChromeWindow::GetGroupMessageManager(const nsAString
& aGroup
,
13773 nsIMessageBroadcaster
** aManager
)
13776 NS_IF_ADDREF(*aManager
= GetGroupMessageManager(aGroup
, rv
));
13777 return rv
.ErrorCode();
13780 nsIMessageBroadcaster
*
13781 nsGlobalWindow::GetGroupMessageManager(const nsAString
& aGroup
,
13782 ErrorResult
& aError
)
13784 FORWARD_TO_INNER_OR_THROW(GetGroupMessageManager
, (aGroup
, aError
), aError
, nullptr);
13785 MOZ_ASSERT(IsChromeWindow());
13787 nsGlobalChromeWindow
* myself
= static_cast<nsGlobalChromeWindow
*>(this);
13788 nsCOMPtr
<nsIMessageBroadcaster
> messageManager
=
13789 myself
->mGroupMessageManagers
.Get(aGroup
);
13791 if (!messageManager
) {
13792 nsFrameMessageManager
* parent
=
13793 static_cast<nsFrameMessageManager
*>(GetMessageManager(aError
));
13795 messageManager
= new nsFrameMessageManager(nullptr,
13797 MM_CHROME
| MM_BROADCASTER
);
13798 myself
->mGroupMessageManagers
.Put(aGroup
, messageManager
);
13801 return messageManager
;
13804 // nsGlobalModalWindow implementation
13806 // QueryInterface implementation for nsGlobalModalWindow
13807 DOMCI_DATA(ModalContentWindow
, nsGlobalModalWindow
)
13809 NS_INTERFACE_MAP_BEGIN(nsGlobalModalWindow
)
13810 NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow
)
13811 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow
)
13812 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow
)
13814 NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow
, nsGlobalWindow
)
13815 NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow
, nsGlobalWindow
)
13819 nsGlobalWindow::GetDialogArguments(JSContext
* aCx
,
13820 JS::MutableHandle
<JS::Value
> aRetval
,
13821 ErrorResult
& aError
)
13823 FORWARD_TO_OUTER_OR_THROW(GetDialogArguments
, (aCx
, aRetval
, aError
),
13826 MOZ_ASSERT(IsModalContentWindow(),
13827 "This should only be called on modal windows!");
13829 if (!mDialogArguments
) {
13830 MOZ_ASSERT(mIsClosed
, "This window should be closed!");
13831 aRetval
.setUndefined();
13835 // This does an internal origin check, and returns undefined if the subject
13836 // does not subsumes the origin of the arguments.
13837 JS::Rooted
<JSObject
*> wrapper(aCx
, GetWrapper());
13838 JSAutoCompartment
ac(aCx
, wrapper
);
13839 mDialogArguments
->Get(aCx
, wrapper
, nsContentUtils::SubjectPrincipal(),
13844 nsGlobalModalWindow::GetDialogArguments(nsIVariant
**aArguments
)
13846 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetDialogArguments
, (aArguments
),
13847 NS_ERROR_NOT_INITIALIZED
);
13849 // This does an internal origin check, and returns undefined if the subject
13850 // does not subsumes the origin of the arguments.
13851 return mDialogArguments
->Get(nsContentUtils::SubjectPrincipal(), aArguments
);
13855 nsGlobalWindow::GetReturnValue(JSContext
* aCx
,
13856 JS::MutableHandle
<JS::Value
> aReturnValue
,
13857 ErrorResult
& aError
)
13859 FORWARD_TO_OUTER_OR_THROW(GetReturnValue
, (aCx
, aReturnValue
, aError
),
13862 MOZ_ASSERT(IsModalContentWindow(),
13863 "This should only be called on modal windows!");
13865 if (mReturnValue
) {
13866 JS::Rooted
<JSObject
*> wrapper(aCx
, GetWrapper());
13867 JSAutoCompartment
ac(aCx
, wrapper
);
13868 mReturnValue
->Get(aCx
, wrapper
, nsContentUtils::SubjectPrincipal(),
13869 aReturnValue
, aError
);
13871 aReturnValue
.setUndefined();
13876 nsGlobalModalWindow::GetReturnValue(nsIVariant
**aRetVal
)
13878 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue
, (aRetVal
), NS_OK
);
13880 nsCOMPtr
<nsIVariant
> result
;
13881 if (!mReturnValue
) {
13882 nsCOMPtr
<nsIVariant
> variant
= CreateVoidVariant();
13883 variant
.forget(aRetVal
);
13886 return mReturnValue
->Get(nsContentUtils::SubjectPrincipal(), aRetVal
);
13890 nsGlobalWindow::SetReturnValue(JSContext
* aCx
,
13891 JS::Handle
<JS::Value
> aReturnValue
,
13892 ErrorResult
& aError
)
13894 FORWARD_TO_OUTER_OR_THROW(SetReturnValue
, (aCx
, aReturnValue
, aError
),
13897 MOZ_ASSERT(IsModalContentWindow(),
13898 "This should only be called on modal windows!");
13900 nsCOMPtr
<nsIVariant
> returnValue
;
13902 nsContentUtils::XPConnect()->JSToVariant(aCx
, aReturnValue
,
13903 getter_AddRefs(returnValue
));
13904 if (!aError
.Failed()) {
13905 mReturnValue
= new DialogValueHolder(nsContentUtils::SubjectPrincipal(),
13911 nsGlobalModalWindow::SetReturnValue(nsIVariant
*aRetVal
)
13913 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue
, (aRetVal
), NS_OK
);
13915 mReturnValue
= new DialogValueHolder(nsContentUtils::SubjectPrincipal(),
13922 nsGlobalWindow::IsModalContentWindow(JSContext
* aCx
, JSObject
* aGlobal
)
13924 // For now, have to deal with XPConnect objects here.
13925 return xpc::WindowOrNull(aGlobal
)->IsModalContentWindow();
13929 nsGlobalWindow::GetConsole(JSContext
* aCx
,
13930 JS::MutableHandle
<JS::Value
> aConsole
)
13933 nsRefPtr
<Console
> console
= GetConsole(rv
);
13935 return rv
.ErrorCode();
13938 if (!WrapNewBindingObject(aCx
, console
, aConsole
)) {
13939 return NS_ERROR_FAILURE
;
13946 nsGlobalWindow::SetConsole(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
)
13948 JS::Rooted
<JSObject
*> thisObj(aCx
, GetWrapper());
13950 return NS_ERROR_UNEXPECTED
;
13953 if (!JS_WrapObject(aCx
, &thisObj
) ||
13954 !JS_DefineProperty(aCx
, thisObj
, "console", aValue
,
13955 JSPROP_ENUMERATE
, JS_PropertyStub
,
13956 JS_StrictPropertyStub
)) {
13957 return NS_ERROR_FAILURE
;
13964 nsGlobalWindow::GetConsole(ErrorResult
& aRv
)
13966 FORWARD_TO_INNER_OR_THROW(GetConsole
, (aRv
), aRv
, nullptr);
13969 mConsole
= new Console(this);
13975 already_AddRefed
<External
>
13976 nsGlobalWindow::GetExternal(ErrorResult
& aRv
)
13978 FORWARD_TO_INNER_OR_THROW(GetExternal
, (aRv
), aRv
, nullptr);
13980 #ifdef HAVE_SIDEBAR
13983 JS::Rooted
<JSObject
*> jsImplObj(cx
);
13984 ConstructJSImplementation(cx
, "@mozilla.org/sidebar;1",
13985 this, &jsImplObj
, aRv
);
13986 if (aRv
.Failed()) {
13989 mExternal
= new External(jsImplObj
, this);
13992 nsRefPtr
<External
> external
= static_cast<External
*>(mExternal
.get());
13993 return external
.forget();
13995 aRv
.Throw(NS_ERROR_NOT_IMPLEMENTED
);
14001 nsGlobalWindow::GetSidebar(OwningExternalOrWindowProxy
& aResult
,
14004 FORWARD_TO_INNER_OR_THROW(GetSidebar
, (aResult
, aRv
), aRv
, );
14006 #ifdef HAVE_SIDEBAR
14007 // First check for a named frame named "sidebar"
14008 nsCOMPtr
<nsIDOMWindow
> domWindow
= GetChildWindow(NS_LITERAL_STRING("sidebar"));
14010 aResult
.SetAsWindowProxy() = domWindow
.forget();
14014 nsRefPtr
<External
> external
= GetExternal(aRv
);
14016 aResult
.SetAsExternal() = external
;
14019 aRv
.Throw(NS_ERROR_NOT_IMPLEMENTED
);
14025 nsGlobalWindow::WindowOnWebIDL(JSContext
* aCx
, JSObject
* aObj
)
14027 DebugOnly
<nsGlobalWindow
*> win
;
14028 MOZ_ASSERT_IF(IsDOMObject(aObj
),
14029 NS_SUCCEEDED(UNWRAP_OBJECT(Window
, aObj
, win
)));
14031 return IsDOMObject(aObj
);
14036 nsGlobalWindow::EnableNetworkEvent(uint32_t aType
)
14038 MOZ_ASSERT(IsInnerWindow());
14040 nsCOMPtr
<nsIPermissionManager
> permMgr
=
14041 services::GetPermissionManager();
14043 NS_ERROR("No PermissionManager available!");
14047 uint32_t permission
= nsIPermissionManager::DENY_ACTION
;
14048 permMgr
->TestExactPermissionFromPrincipal(GetPrincipal(), "network-events",
14051 if (permission
!= nsIPermissionManager::ALLOW_ACTION
) {
14055 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
14057 NS_ERROR("ObserverService should be available!");
14062 case NS_NETWORK_UPLOAD_EVENT
:
14063 if (!mNetworkUploadObserverEnabled
) {
14064 mNetworkUploadObserverEnabled
= true;
14065 os
->AddObserver(mObserver
, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC
, false);
14068 case NS_NETWORK_DOWNLOAD_EVENT
:
14069 if (!mNetworkDownloadObserverEnabled
) {
14070 mNetworkDownloadObserverEnabled
= true;
14071 os
->AddObserver(mObserver
, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC
, false);
14078 nsGlobalWindow::DisableNetworkEvent(uint32_t aType
)
14080 MOZ_ASSERT(IsInnerWindow());
14082 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
14088 case NS_NETWORK_UPLOAD_EVENT
:
14089 if (mNetworkUploadObserverEnabled
) {
14090 mNetworkUploadObserverEnabled
= false;
14091 os
->RemoveObserver(mObserver
, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC
);
14094 case NS_NETWORK_DOWNLOAD_EVENT
:
14095 if (mNetworkDownloadObserverEnabled
) {
14096 mNetworkDownloadObserverEnabled
= false;
14097 os
->RemoveObserver(mObserver
, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC
);
14104 #define EVENT(name_, id_, type_, struct_) \
14105 NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
14106 JS::MutableHandle<JS::Value> vp) { \
14107 EventHandlerNonNull* h = GetOn##name_(); \
14108 vp.setObjectOrNull(h ? h->Callable().get() : nullptr); \
14111 NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
14112 JS::Handle<JS::Value> v) { \
14113 nsRefPtr<EventHandlerNonNull> handler; \
14114 JS::Rooted<JSObject*> callable(cx); \
14115 if (v.isObject() && \
14116 JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
14117 handler = new EventHandlerNonNull(callable, GetIncumbentGlobal()); \
14119 SetOn##name_(handler); \
14122 #define ERROR_EVENT(name_, id_, type_, struct_) \
14123 NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
14124 JS::MutableHandle<JS::Value> vp) { \
14125 EventListenerManager *elm = GetExistingListenerManager(); \
14127 OnErrorEventHandlerNonNull* h = elm->GetOnErrorEventHandler(); \
14129 vp.setObject(*h->Callable()); \
14136 NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
14137 JS::Handle<JS::Value> v) { \
14138 EventListenerManager *elm = GetOrCreateListenerManager(); \
14140 return NS_ERROR_OUT_OF_MEMORY; \
14143 nsRefPtr<OnErrorEventHandlerNonNull> handler; \
14144 JS::Rooted<JSObject*> callable(cx); \
14145 if (v.isObject() && \
14146 JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
14147 handler = new OnErrorEventHandlerNonNull(callable, GetIncumbentGlobal()); \
14149 elm->SetEventHandler(handler); \
14152 #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
14153 NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
14154 JS::MutableHandle<JS::Value> vp) { \
14155 EventListenerManager *elm = GetExistingListenerManager(); \
14157 OnBeforeUnloadEventHandlerNonNull* h = \
14158 elm->GetOnBeforeUnloadEventHandler(); \
14160 vp.setObject(*h->Callable()); \
14167 NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
14168 JS::Handle<JS::Value> v) { \
14169 EventListenerManager *elm = GetOrCreateListenerManager(); \
14171 return NS_ERROR_OUT_OF_MEMORY; \
14174 nsRefPtr<OnBeforeUnloadEventHandlerNonNull> handler; \
14175 JS::Rooted<JSObject*> callable(cx); \
14176 if (v.isObject() && \
14177 JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
14178 handler = new OnBeforeUnloadEventHandlerNonNull(callable, GetIncumbentGlobal()); \
14180 elm->SetEventHandler(handler); \
14183 #define WINDOW_ONLY_EVENT EVENT
14184 #define TOUCH_EVENT EVENT
14185 #include "mozilla/EventNameList.h"
14187 #undef WINDOW_ONLY_EVENT
14188 #undef BEFOREUNLOAD_EVENT
14193 #error "Never include windows.h in this file!"