Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/RefPtr.h
Warning:line 314, column 5
Undefined or garbage value returned to caller

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nsGlobalWindowOuter.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -resource-dir /usr/lib/llvm-20/lib/clang/20 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/battery -I /var/lib/jenkins/workspace/firefox-scan-build/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/dom/media -I /var/lib/jenkins/workspace/firefox-scan-build/dom/network -I /var/lib/jenkins/workspace/firefox-scan-build/caps -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/file -I /var/lib/jenkins/workspace/firefox-scan-build/dom/geolocation -I /var/lib/jenkins/workspace/firefox-scan-build/dom/html -I /var/lib/jenkins/workspace/firefox-scan-build/dom/ipc -I /var/lib/jenkins/workspace/firefox-scan-build/dom/storage -I /var/lib/jenkins/workspace/firefox-scan-build/dom/svg -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xml -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xslt/xpath -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xul -I /var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/src -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/2d -I /var/lib/jenkins/workspace/firefox-scan-build/image -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/loader -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/src -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/layout/base -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/layout/style -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/base -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/url-classifier -I /var/lib/jenkins/workspace/firefox-scan-build/parser/htmlparser -I /var/lib/jenkins/workspace/firefox-scan-build/security/manager/ssl -I /var/lib/jenkins/workspace/firefox-scan-build/third_party/xsimd/include -I /var/lib/jenkins/workspace/firefox-scan-build/widget -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/build -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/ds -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/sctp/datachannel -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gtk-3.0/unix-print -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-20/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-01-20-090804-167946-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp

/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include "mozilla/Assertions.h"
8#include "mozilla/ScopeExit.h"
9#include "nsGlobalWindowOuter.h"
10#include "nsGlobalWindowInner.h"
11
12#include <algorithm>
13
14#include "mozilla/MemoryReporting.h"
15
16// Local Includes
17#include "Navigator.h"
18#include "nsContentSecurityManager.h"
19#include "nsGlobalWindowOuter.h"
20#include "nsScreen.h"
21#include "nsHistory.h"
22#include "nsDOMNavigationTiming.h"
23#include "nsIDOMStorageManager.h"
24#include "nsISecureBrowserUI.h"
25#include "nsIWebProgressListener.h"
26#include "mozilla/AntiTrackingUtils.h"
27#include "mozilla/Result.h"
28#include "mozilla/dom/AutoPrintEventDispatcher.h"
29#include "mozilla/dom/BindingUtils.h"
30#include "mozilla/dom/BrowserChild.h"
31#include "mozilla/dom/BrowsingContextBinding.h"
32#include "mozilla/dom/CanonicalBrowsingContext.h"
33#include "mozilla/dom/ContentChild.h"
34#include "mozilla/dom/ContentFrameMessageManager.h"
35#include "mozilla/dom/DocumentInlines.h"
36#include "mozilla/dom/EventTarget.h"
37#include "mozilla/dom/HTMLIFrameElement.h"
38#include "mozilla/dom/LocalStorage.h"
39#include "mozilla/dom/LSObject.h"
40#include "mozilla/dom/Storage.h"
41#include "mozilla/dom/MaybeCrossOriginObject.h"
42#include "mozilla/dom/Performance.h"
43#include "mozilla/dom/ProxyHandlerUtils.h"
44#include "mozilla/dom/StorageEvent.h"
45#include "mozilla/dom/StorageEventBinding.h"
46#include "mozilla/dom/StorageNotifierService.h"
47#include "mozilla/dom/StorageUtils.h"
48#include "mozilla/dom/Timeout.h"
49#include "mozilla/dom/TimeoutHandler.h"
50#include "mozilla/dom/TimeoutManager.h"
51#include "mozilla/dom/UserActivation.h"
52#include "mozilla/dom/WindowContext.h"
53#include "mozilla/dom/WindowFeatures.h" // WindowFeatures
54#include "mozilla/dom/WindowProxyHolder.h"
55#include "mozilla/IntegerPrintfMacros.h"
56#include "mozilla/StorageAccessAPIHelper.h"
57#include "nsBaseCommandController.h"
58#include "nsError.h"
59#include "nsICookieService.h"
60#include "nsISizeOfEventTarget.h"
61#include "nsDOMJSUtils.h"
62#include "nsArrayUtils.h"
63#include "nsIDocShellTreeOwner.h"
64#include "nsIInterfaceRequestorUtils.h"
65#include "nsIPermissionManager.h"
66#include "nsIScriptContext.h"
67#include "nsWindowMemoryReporter.h"
68#include "nsWindowSizes.h"
69#include "nsWindowWatcher.h"
70#include "WindowNamedPropertiesHandler.h"
71#include "nsFrameSelection.h"
72#include "nsNetUtil.h"
73#include "nsVariant.h"
74#include "nsPrintfCString.h"
75#include "mozilla/intl/LocaleService.h"
76#include "WindowDestroyedEvent.h"
77#include "nsDocShellLoadState.h"
78#include "mozilla/dom/WindowGlobalChild.h"
79
80// Helper Classes
81#include "nsJSUtils.h"
82#include "jsapi.h"
83#include "jsfriendapi.h"
84#include "js/CallAndConstruct.h" // JS::Call
85#include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
86#include "js/friend/WindowProxy.h" // js::IsWindowProxy, js::SetWindowProxy
87#include "js/PropertyAndElement.h" // JS_DefineObject, JS_GetProperty
88#include "js/PropertySpec.h"
89#include "js/RealmIterators.h"
90#include "js/Wrapper.h"
91#include "nsLayoutUtils.h"
92#include "nsReadableUtils.h"
93#include "nsJSEnvironment.h"
94#include "mozilla/dom/ScriptSettings.h"
95#include "mozilla/Preferences.h"
96#include "mozilla/Likely.h"
97#include "mozilla/SchedulerGroup.h"
98#include "mozilla/SpinEventLoopUntil.h"
99#include "mozilla/Sprintf.h"
100#include "mozilla/Unused.h"
101
102// Other Classes
103#include "mozilla/dom/BarProps.h"
104#include "nsLayoutStatics.h"
105#include "nsCCUncollectableMarker.h"
106#include "mozilla/dom/WorkerCommon.h"
107#include "mozilla/dom/ToJSValue.h"
108#include "nsJSPrincipals.h"
109#include "mozilla/Attributes.h"
110#include "mozilla/Components.h"
111#include "mozilla/Debug.h"
112#include "mozilla/EventListenerManager.h"
113#include "mozilla/MouseEvents.h"
114#include "mozilla/PresShell.h"
115#include "mozilla/ProcessHangMonitor.h"
116#include "mozilla/StaticPrefs_dom.h"
117#include "mozilla/StaticPrefs_full_screen_api.h"
118#include "mozilla/StaticPrefs_print.h"
119#include "mozilla/StaticPrefs_fission.h"
120#include "mozilla/ThrottledEventQueue.h"
121#include "AudioChannelService.h"
122#include "nsAboutProtocolUtils.h"
123#include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE
124#include "PostMessageEvent.h"
125#include "mozilla/dom/DocGroup.h"
126#include "mozilla/net/CookieJarSettings.h"
127
128// Interfaces Needed
129#include "nsIFrame.h"
130#include "nsCanvasFrame.h"
131#include "nsIWidget.h"
132#include "nsIWidgetListener.h"
133#include "nsIBaseWindow.h"
134#include "nsIDeviceSensors.h"
135#include "nsIContent.h"
136#include "nsIDocShell.h"
137#include "mozilla/dom/Document.h"
138#include "Crypto.h"
139#include "nsDOMString.h"
140#include "nsThreadUtils.h"
141#include "nsILoadContext.h"
142#include "nsView.h"
143#include "nsViewManager.h"
144#include "nsIPrompt.h"
145#include "nsIPromptService.h"
146#include "nsIPromptFactory.h"
147#include "nsIWritablePropertyBag2.h"
148#include "nsIWebNavigation.h"
149#include "nsIWebBrowserChrome.h"
150#include "nsIWebBrowserFind.h" // For window.find()
151#include "nsComputedDOMStyle.h"
152#include "nsDOMCID.h"
153#include "nsDOMWindowUtils.h"
154#include "nsIWindowWatcher.h"
155#include "nsPIWindowWatcher.h"
156#include "nsIDocumentViewer.h"
157#include "nsIScriptError.h"
158#include "nsISHistory.h"
159#include "nsIControllers.h"
160#include "nsGlobalWindowCommands.h"
161#include "nsQueryObject.h"
162#include "nsContentUtils.h"
163#include "nsCSSProps.h"
164#include "nsIURIFixup.h"
165#include "nsIURIMutator.h"
166#include "mozilla/EventDispatcher.h"
167#include "mozilla/EventStateManager.h"
168#include "mozilla/ScrollContainerFrame.h"
169#include "nsIObserverService.h"
170#include "nsFocusManager.h"
171#include "nsIAppWindow.h"
172#include "nsServiceManagerUtils.h"
173#include "mozilla/dom/CustomEvent.h"
174#include "nsIScreenManager.h"
175#include "nsIClassifiedChannel.h"
176#include "nsIXULRuntime.h"
177#include "xpcprivate.h"
178
179#ifdef NS_PRINTING1
180# include "nsIPrintSettings.h"
181# include "nsIPrintSettingsService.h"
182# include "nsIWebBrowserPrint.h"
183#endif
184
185#include "nsWindowRoot.h"
186#include "nsNetCID.h"
187#include "nsIArray.h"
188
189#include "nsIDOMXULCommandDispatcher.h"
190
191#include "mozilla/GlobalKeyListener.h"
192
193#include "nsIDragService.h"
194#include "mozilla/dom/Element.h"
195#include "mozilla/dom/Selection.h"
196#include "nsFrameLoader.h"
197#include "nsFrameLoaderOwner.h"
198#include "nsXPCOMCID.h"
199#include "mozilla/Logging.h"
200#include "mozilla/ProfilerMarkers.h"
201#include "prenv.h"
202
203#include "mozilla/dom/IDBFactory.h"
204#include "mozilla/dom/MessageChannel.h"
205#include "mozilla/dom/Promise.h"
206
207#include "mozilla/dom/Gamepad.h"
208#include "mozilla/dom/GamepadManager.h"
209
210#include "gfxVR.h"
211#include "VRShMem.h"
212#include "FxRWindowManager.h"
213#include "mozilla/dom/VRDisplay.h"
214#include "mozilla/dom/VRDisplayEvent.h"
215#include "mozilla/dom/VRDisplayEventBinding.h"
216#include "mozilla/dom/VREventObserver.h"
217
218#include "nsRefreshDriver.h"
219
220#include "mozilla/extensions/WebExtensionPolicy.h"
221
222#include "mozilla/BasePrincipal.h"
223#include "mozilla/Services.h"
224#include "mozilla/Telemetry.h"
225#include "mozilla/dom/Location.h"
226#include "nsHTMLDocument.h"
227#include "nsWrapperCacheInlines.h"
228#include "mozilla/DOMEventTargetHelper.h"
229#include "prrng.h"
230#include "nsSandboxFlags.h"
231#include "nsXULControllers.h"
232#include "mozilla/dom/AudioContext.h"
233#include "mozilla/dom/BrowserElementDictionariesBinding.h"
234#include "mozilla/dom/BrowsingContextGroup.h"
235#include "mozilla/dom/cache/CacheStorage.h"
236#include "mozilla/dom/Console.h"
237#include "mozilla/dom/Fetch.h"
238#include "mozilla/dom/FunctionBinding.h"
239#include "mozilla/dom/HashChangeEvent.h"
240#include "mozilla/dom/IntlUtils.h"
241#include "mozilla/dom/PopStateEvent.h"
242#include "mozilla/dom/PopupBlockedEvent.h"
243#include "mozilla/dom/PrimitiveConversions.h"
244#include "mozilla/dom/WindowBinding.h"
245#include "nsIBrowserChild.h"
246#include "mozilla/dom/MediaQueryList.h"
247#include "mozilla/dom/NavigatorBinding.h"
248#include "mozilla/dom/ImageBitmap.h"
249#include "mozilla/dom/ImageBitmapBinding.h"
250#include "mozilla/dom/ServiceWorkerRegistration.h"
251#include "mozilla/dom/WebIDLGlobalNameHash.h"
252#include "mozilla/dom/Worklet.h"
253#include "AccessCheck.h"
254
255#ifdef MOZ_WEBSPEECH1
256# include "mozilla/dom/SpeechSynthesis.h"
257#endif
258
259#ifdef ANDROID
260# include <android/log.h>
261#endif
262
263#ifdef XP_WIN
264# include <process.h>
265# define getpid _getpid
266#else
267# include <unistd.h> // for getpid()
268#endif
269
270using namespace mozilla;
271using namespace mozilla::dom;
272using namespace mozilla::dom::ipc;
273using mozilla::BasePrincipal;
274using mozilla::OriginAttributes;
275using mozilla::TimeStamp;
276using mozilla::layout::RemotePrintJobChild;
277
278static inline nsGlobalWindowInner* GetCurrentInnerWindowInternal(
279 const nsGlobalWindowOuter* aOuter) {
280 return nsGlobalWindowInner::Cast(aOuter->GetCurrentInnerWindow());
281}
282
283#define FORWARD_TO_INNER(method, args, err_rval)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 283); return err_rval; } return GetCurrentInnerWindowInternal
(this)->method args; } while (0)
\
284 PR_BEGIN_MACROdo { \
285 if (!mInnerWindow) { \
286 NS_WARNING("No inner window available!")NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 286)
; \
287 return err_rval; \
288 } \
289 return GetCurrentInnerWindowInternal(this)->method args; \
290 PR_END_MACRO} while (0)
291
292#define FORWARD_TO_INNER_VOID(method, args)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 292); return; } GetCurrentInnerWindowInternal(this)->method
args; return; } while (0)
\
293 PR_BEGIN_MACROdo { \
294 if (!mInnerWindow) { \
295 NS_WARNING("No inner window available!")NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 295)
; \
296 return; \
297 } \
298 GetCurrentInnerWindowInternal(this)->method args; \
299 return; \
300 PR_END_MACRO} while (0)
301
302// Same as FORWARD_TO_INNER, but this will create a fresh inner if an
303// inner doesn't already exists.
304#define FORWARD_TO_INNER_CREATE(method, args, err_rval)do { if (!mInnerWindow) { if (mIsClosed) { return err_rval; }
nsCOMPtr<Document> kungFuDeathGrip = GetDoc(); ::mozilla
::Unused << kungFuDeathGrip; if (!mInnerWindow) { return
err_rval; } } return GetCurrentInnerWindowInternal(this)->
method args; } while (0)
\
305 PR_BEGIN_MACROdo { \
306 if (!mInnerWindow) { \
307 if (mIsClosed) { \
308 return err_rval; \
309 } \
310 nsCOMPtr<Document> kungFuDeathGrip = GetDoc(); \
311 ::mozilla::Unused << kungFuDeathGrip; \
312 if (!mInnerWindow) { \
313 return err_rval; \
314 } \
315 } \
316 return GetCurrentInnerWindowInternal(this)->method args; \
317 PR_END_MACRO} while (0)
318
319static LazyLogModule gDOMLeakPRLogOuter("DOMLeakOuter");
320extern LazyLogModule gPageCacheLog;
321
322#ifdef DEBUG1
323static LazyLogModule gDocShellAndDOMWindowLeakLogging(
324 "DocShellAndDOMWindowLeak");
325#endif
326
327nsGlobalWindowOuter::OuterWindowByIdTable*
328 nsGlobalWindowOuter::sOuterWindowsById = nullptr;
329
330/* static */
331nsPIDOMWindowOuter* nsPIDOMWindowOuter::GetFromCurrentInner(
332 nsPIDOMWindowInner* aInner) {
333 if (!aInner) {
334 return nullptr;
335 }
336
337 nsPIDOMWindowOuter* outer = aInner->GetOuterWindow();
338 if (!outer || outer->GetCurrentInnerWindow() != aInner) {
339 return nullptr;
340 }
341
342 return outer;
343}
344
345//*****************************************************************************
346// nsOuterWindowProxy: Outer Window Proxy
347//*****************************************************************************
348
349// Give OuterWindowProxyClass 2 reserved slots, like the other wrappers, so
350// JSObject::swap can swap it with CrossCompartmentWrappers without requiring
351// malloc.
352//
353// We store the nsGlobalWindowOuter* in our first slot.
354//
355// We store our holder weakmap in the second slot.
356const JSClass OuterWindowProxyClass = PROXY_CLASS_DEF({"Proxy", JSClass::NON_NATIVE | JSCLASS_IS_PROXY | JSCLASS_DELAY_METADATA_BUILDER
| js::CheckProxyFlags<JSCLASS_HAS_RESERVED_SLOTS(2)>()
, &js::ProxyClassOps, JS_NULL_CLASS_SPEC, &js::ProxyClassExtension
, &js::ProxyObjectOps}
357 "Proxy", JSCLASS_HAS_RESERVED_SLOTS(2)){"Proxy", JSClass::NON_NATIVE | JSCLASS_IS_PROXY | JSCLASS_DELAY_METADATA_BUILDER
| js::CheckProxyFlags<JSCLASS_HAS_RESERVED_SLOTS(2)>()
, &js::ProxyClassOps, JS_NULL_CLASS_SPEC, &js::ProxyClassExtension
, &js::ProxyObjectOps}
; /* additional class flags */
358
359static const size_t OUTER_WINDOW_SLOT = 0;
360static const size_t HOLDER_WEAKMAP_SLOT = 1;
361
362class nsOuterWindowProxy : public MaybeCrossOriginObject<js::Wrapper> {
363 using Base = MaybeCrossOriginObject<js::Wrapper>;
364
365 public:
366 constexpr nsOuterWindowProxy() : Base(0) {}
367
368 bool finalizeInBackground(const JS::Value& priv) const override {
369 return false;
370 }
371
372 // Standard internal methods
373 /**
374 * Implementation of [[GetOwnProperty]] as defined at
375 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty
376 *
377 * "proxy" is the WindowProxy object involved. It may not be same-compartment
378 * with cx.
379 */
380 bool getOwnPropertyDescriptor(
381 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
382 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const override;
383
384 /*
385 * Implementation of the same-origin case of
386 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty>.
387 */
388 bool definePropertySameOrigin(JSContext* cx, JS::Handle<JSObject*> proxy,
389 JS::Handle<jsid> id,
390 JS::Handle<JS::PropertyDescriptor> desc,
391 JS::ObjectOpResult& result) const override;
392
393 /**
394 * Implementation of [[OwnPropertyKeys]] as defined at
395 *
396 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys
397 *
398 * "proxy" is the WindowProxy object involved. It may not be same-compartment
399 * with cx.
400 */
401 bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
402 JS::MutableHandleVector<jsid> props) const override;
403 /**
404 * Implementation of [[Delete]] as defined at
405 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-delete
406 *
407 * "proxy" is the WindowProxy object involved. It may not be same-compartment
408 * with cx.
409 */
410 bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
411 JS::ObjectOpResult& result) const override;
412
413 /**
414 * Implementaton of hook for superclass getPrototype() method.
415 */
416 JSObject* getSameOriginPrototype(JSContext* cx) const override;
417
418 /**
419 * Implementation of [[HasProperty]] internal method as defined at
420 * https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p
421 *
422 * "proxy" is the WindowProxy object involved. It may not be same-compartment
423 * with cx.
424 *
425 * Note that the HTML spec does not define an override for this internal
426 * method, so we just want the "normal object" behavior. We have to override
427 * it, because js::Wrapper also overrides, with "not normal" behavior.
428 */
429 bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
430 bool* bp) const override;
431
432 /**
433 * Implementation of [[Get]] internal method as defined at
434 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-get>.
435 *
436 * "proxy" is the WindowProxy object involved. It may or may not be
437 * same-compartment with "cx".
438 *
439 * "receiver" is the receiver ("this") for the get. It will be
440 * same-compartment with "cx".
441 *
442 * "vp" is the return value. It will be same-compartment with "cx".
443 */
444 bool get(JSContext* cx, JS::Handle<JSObject*> proxy,
445 JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
446 JS::MutableHandle<JS::Value> vp) const override;
447
448 /**
449 * Implementation of [[Set]] internal method as defined at
450 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-set>.
451 *
452 * "proxy" is the WindowProxy object involved. It may or may not be
453 * same-compartment with "cx".
454 *
455 * "v" is the value being set. It will be same-compartment with "cx".
456 *
457 * "receiver" is the receiver ("this") for the set. It will be
458 * same-compartment with "cx".
459 */
460 bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
461 JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
462 JS::ObjectOpResult& result) const override;
463
464 // SpiderMonkey extensions
465 /**
466 * Implementation of SpiderMonkey extension which just checks whether this
467 * object has the property. Basically Object.getOwnPropertyDescriptor(obj,
468 * prop) !== undefined. but does not require reifying the descriptor.
469 *
470 * We have to override this because js::Wrapper overrides it, but we want
471 * different behavior from js::Wrapper.
472 *
473 * "proxy" is the WindowProxy object involved. It may not be same-compartment
474 * with cx.
475 */
476 bool hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
477 bool* bp) const override;
478
479 /**
480 * Implementation of SpiderMonkey extension which is used as a fast path for
481 * enumerating.
482 *
483 * We have to override this because js::Wrapper overrides it, but we want
484 * different behavior from js::Wrapper.
485 *
486 * "proxy" is the WindowProxy object involved. It may not be same-compartment
487 * with cx.
488 */
489 bool getOwnEnumerablePropertyKeys(
490 JSContext* cx, JS::Handle<JSObject*> proxy,
491 JS::MutableHandleVector<jsid> props) const override;
492
493 /**
494 * Hook used by SpiderMonkey to implement Object.prototype.toString.
495 */
496 const char* className(JSContext* cx,
497 JS::Handle<JSObject*> wrapper) const override;
498
499 void finalize(JS::GCContext* gcx, JSObject* proxy) const override;
500 size_t objectMoved(JSObject* proxy, JSObject* old) const override;
501
502 bool isCallable(JSObject* obj) const override { return false; }
503 bool isConstructor(JSObject* obj) const override { return false; }
504
505 static const nsOuterWindowProxy singleton;
506
507 static nsGlobalWindowOuter* GetOuterWindow(JSObject* proxy) {
508 nsGlobalWindowOuter* outerWindow =
509 nsGlobalWindowOuter::FromSupports(static_cast<nsISupports*>(
510 js::GetProxyReservedSlot(proxy, OUTER_WINDOW_SLOT).toPrivate()));
511 return outerWindow;
512 }
513
514 protected:
515 // False return value means we threw an exception. True return value
516 // but false "found" means we didn't have a subframe at that index.
517 bool GetSubframeWindow(JSContext* cx, JS::Handle<JSObject*> proxy,
518 JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
519 bool& found) const;
520
521 // Returns a non-null window only if id is an index and we have a
522 // window at that index.
523 Nullable<WindowProxyHolder> GetSubframeWindow(JSContext* cx,
524 JS::Handle<JSObject*> proxy,
525 JS::Handle<jsid> id) const;
526
527 bool AppendIndexedPropertyNames(JSObject* proxy,
528 JS::MutableHandleVector<jsid> props) const;
529
530 using MaybeCrossOriginObjectMixins::EnsureHolder;
531 bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> proxy,
532 JS::MutableHandle<JSObject*> holder) const override;
533
534 // Helper method for creating a special "print" method that allows printing
535 // our PDF-viewer documents even if you're not same-origin with them.
536 //
537 // aProxy must be our nsOuterWindowProxy. It will not be same-compartment
538 // with aCx, since we only use this on the different-origin codepath!
539 //
540 // Can return true without filling in aDesc, which corresponds to not exposing
541 // a "print" method.
542 static bool MaybeGetPDFJSPrintMethod(
543 JSContext* cx, JS::Handle<JSObject*> proxy,
544 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc);
545
546 // The actual "print" method we use for the PDFJS case.
547 static bool PDFJSPrintMethod(JSContext* cx, unsigned argc, JS::Value* vp);
548
549 // Helper method to get the pre-PDF-viewer-messing-with-it principal from an
550 // inner window. Will return null if this is not a PDF-viewer inner or if the
551 // principal could not be found for some reason.
552 static already_AddRefed<nsIPrincipal> GetNoPDFJSPrincipal(
553 nsGlobalWindowInner* inner);
554};
555
556const char* nsOuterWindowProxy::className(JSContext* cx,
557 JS::Handle<JSObject*> proxy) const {
558 MOZ_ASSERT(js::IsProxy(proxy))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(js::IsProxy(proxy))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsProxy(proxy)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("js::IsProxy(proxy)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsProxy(proxy)"
")"); do { *((volatile int*)__null) = 558; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
559
560 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
561 return "Object";
562 }
563
564 return "Window";
565}
566
567void nsOuterWindowProxy::finalize(JS::GCContext* gcx, JSObject* proxy) const {
568 nsGlobalWindowOuter* outerWindow = GetOuterWindow(proxy);
569 if (outerWindow) {
570 outerWindow->ClearWrapper(proxy);
571 BrowsingContext* bc = outerWindow->GetBrowsingContext();
572 if (bc) {
573 bc->ClearWindowProxy();
574 }
575
576 // Ideally we would use OnFinalize here, but it's possible that
577 // EnsureScriptEnvironment will later be called on the window, and we don't
578 // want to create a new script object in that case. Therefore, we need to
579 // write a non-null value that will reliably crash when dereferenced.
580 outerWindow->PoisonOuterWindowProxy(proxy);
581 }
582}
583
584bool nsOuterWindowProxy::getOwnPropertyDescriptor(
585 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
586 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const {
587 // First check for indexed access. This is
588 // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty
589 // step 2, mostly.
590 JS::Rooted<JS::Value> subframe(cx);
591 bool found;
592 if (!GetSubframeWindow(cx, proxy, id, &subframe, found)) {
593 return false;
594 }
595 if (found) {
596 // Step 2.4.
597
598 desc.set(Some(JS::PropertyDescriptor::Data(
599 subframe, {
600 JS::PropertyAttribute::Configurable,
601 JS::PropertyAttribute::Enumerable,
602 })));
603 return true;
604 }
605
606 bool isSameOrigin = IsPlatformObjectSameOrigin(cx, proxy);
607
608 // If we did not find a subframe, we could still have an indexed property
609 // access. In that case we should throw a SecurityError in the cross-origin
610 // case.
611 if (!isSameOrigin && IsArrayIndex(GetArrayIndexFromId(id))) {
612 // Step 2.5.2.
613 return ReportCrossOriginDenial(cx, id, "access"_ns);
614 }
615
616 // Step 2.5.1 is handled via the forwarding to js::Wrapper; it saves us an
617 // IsArrayIndex(GetArrayIndexFromId(id)) here. We'll never have a property on
618 // the Window whose name is an index, because our defineProperty doesn't pass
619 // those on to the Window.
620
621 // Step 3.
622 if (isSameOrigin) {
623 if (StaticPrefs::dom_missing_prop_counters_enabled() && id.isAtom()) {
624 Window_Binding::CountMaybeMissingProperty(proxy, id);
625 }
626
627 // Fall through to js::Wrapper.
628 { // Scope for JSAutoRealm while we are dealing with js::Wrapper.
629 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
630 // for now. That's what js::Wrapper expects, and since we're same-origin
631 // anyway this is not changing any security behavior.
632 JSAutoRealm ar(cx, proxy);
633 JS_MarkCrossZoneId(cx, id);
634 bool ok = js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
635 if (!ok) {
636 return false;
637 }
638
639#if 0
640 // See https://github.com/tc39/ecma262/issues/672 for more information.
641 if (desc.isSome() &&
642 !IsNonConfigurableReadonlyPrimitiveGlobalProp(cx, id)) {
643 (*desc).setConfigurable(true);
644 }
645#endif
646 }
647
648 // Now wrap our descriptor back into the Realm that asked for it.
649 return JS_WrapPropertyDescriptor(cx, desc);
650 }
651
652 // Step 4.
653 if (!CrossOriginGetOwnPropertyHelper(cx, proxy, id, desc)) {
654 return false;
655 }
656
657 // Step 5
658 if (desc.isSome()) {
659 return true;
660 }
661
662 // Non-spec step for the PDF viewer's window.print(). This comes before we
663 // check for named subframes, because in the same-origin case print() would
664 // shadow those.
665 if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_PRINT)) {
666 if (!MaybeGetPDFJSPrintMethod(cx, proxy, desc)) {
667 return false;
668 }
669
670 if (desc.isSome()) {
671 return true;
672 }
673 }
674
675 // Step 6 -- check for named subframes.
676 if (id.isString()) {
677 nsAutoJSString name;
678 if (!name.init(cx, id.toString())) {
679 return false;
680 }
681 nsGlobalWindowOuter* win = GetOuterWindow(proxy);
682 if (RefPtr<BrowsingContext> childDOMWin = win->GetChildWindow(name)) {
683 JS::Rooted<JS::Value> childValue(cx);
684 if (!ToJSValue(cx, WindowProxyHolder(childDOMWin), &childValue)) {
685 return false;
686 }
687 desc.set(Some(JS::PropertyDescriptor::Data(
688 childValue, {JS::PropertyAttribute::Configurable})));
689 return true;
690 }
691 }
692
693 // And step 7.
694 return CrossOriginPropertyFallback(cx, proxy, id, desc);
695}
696
697bool nsOuterWindowProxy::definePropertySameOrigin(
698 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
699 JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result) const {
700 if (IsArrayIndex(GetArrayIndexFromId(id))) {
701 // Spec says to Reject whether this is a supported index or not,
702 // since we have no indexed setter or indexed creator. It is up
703 // to the caller to decide whether to throw a TypeError.
704 return result.failCantDefineWindowElement();
705 }
706
707 JS::ObjectOpResult ourResult;
708 bool ok = js::Wrapper::defineProperty(cx, proxy, id, desc, ourResult);
709 if (!ok) {
710 return false;
711 }
712
713 if (!ourResult.ok()) {
714 // It's possible that this failed because the page got the existing
715 // descriptor (which we force to claim to be configurable) and then tried to
716 // redefine the property with the descriptor it got but a different value.
717 // We want to allow this case to succeed, so check for it and if we're in
718 // that case try again but now with an attempt to define a non-configurable
719 // property.
720 if (!desc.hasConfigurable() || !desc.configurable()) {
721 // The incoming descriptor was not explicitly marked "configurable: true",
722 // so it failed for some other reason. Just propagate that reason out.
723 result = ourResult;
724 return true;
725 }
726
727 JS::Rooted<Maybe<JS::PropertyDescriptor>> existingDesc(cx);
728 ok = js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, &existingDesc);
729 if (!ok) {
730 return false;
731 }
732 if (existingDesc.isNothing() || existingDesc->configurable()) {
733 // We have no existing property, or its descriptor is already configurable
734 // (on the Window itself, where things really can be non-configurable).
735 // So we failed for some other reason, which we should propagate out.
736 result = ourResult;
737 return true;
738 }
739
740 JS::Rooted<JS::PropertyDescriptor> updatedDesc(cx, desc);
741 updatedDesc.setConfigurable(false);
742
743 JS::ObjectOpResult ourNewResult;
744 ok = js::Wrapper::defineProperty(cx, proxy, id, updatedDesc, ourNewResult);
745 if (!ok) {
746 return false;
747 }
748
749 if (!ourNewResult.ok()) {
750 // Twiddling the configurable flag didn't help. Just return this failure
751 // out to the caller.
752 result = ourNewResult;
753 return true;
754 }
755 }
756
757#if 0
758 // See https://github.com/tc39/ecma262/issues/672 for more information.
759 if (desc.hasConfigurable() && !desc.configurable() &&
760 !IsNonConfigurableReadonlyPrimitiveGlobalProp(cx, id)) {
761 // Give callers a way to detect that they failed to "really" define a
762 // non-configurable property.
763 result.failCantDefineWindowNonConfigurable();
764 return true;
765 }
766#endif
767
768 result.succeed();
769 return true;
770}
771
772bool nsOuterWindowProxy::ownPropertyKeys(
773 JSContext* cx, JS::Handle<JSObject*> proxy,
774 JS::MutableHandleVector<jsid> props) const {
775 // Just our indexed stuff followed by our "normal" own property names.
776 if (!AppendIndexedPropertyNames(proxy, props)) {
777 return false;
778 }
779
780 if (IsPlatformObjectSameOrigin(cx, proxy)) {
781 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
782 // for now. That's what js::Wrapper expects, and since we're same-origin
783 // anyway this is not changing any security behavior.
784 JS::RootedVector<jsid> innerProps(cx);
785 { // Scope for JSAutoRealm so we can mark the ids once we exit it
786 JSAutoRealm ar(cx, proxy);
787 if (!js::Wrapper::ownPropertyKeys(cx, proxy, &innerProps)) {
788 return false;
789 }
790 }
791 for (auto& id : innerProps) {
792 JS_MarkCrossZoneId(cx, id);
793 }
794 return js::AppendUnique(cx, props, innerProps);
795 }
796
797 // In the cross-origin case we purposefully exclude subframe names from the
798 // list of property names we report here.
799 JS::Rooted<JSObject*> holder(cx);
800 if (!EnsureHolder(cx, proxy, &holder)) {
801 return false;
802 }
803
804 JS::RootedVector<jsid> crossOriginProps(cx);
805 if (!js::GetPropertyKeys(cx, holder,
806 JSITER_OWNONLY0x8 | JSITER_HIDDEN0x10 | JSITER_SYMBOLS0x20,
807 &crossOriginProps) ||
808 !js::AppendUnique(cx, props, crossOriginProps)) {
809 return false;
810 }
811
812 // Add the "print" property if needed.
813 nsGlobalWindowOuter* outer = GetOuterWindow(proxy);
814 nsGlobalWindowInner* inner =
815 nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
816 if (inner) {
817 nsCOMPtr<nsIPrincipal> targetPrincipal = GetNoPDFJSPrincipal(inner);
818 if (targetPrincipal &&
819 nsContentUtils::SubjectPrincipal(cx)->Equals(targetPrincipal)) {
820 JS::RootedVector<jsid> printProp(cx);
821 if (!printProp.append(GetJSIDByIndex(cx, XPCJSContext::IDX_PRINT)) ||
822 !js::AppendUnique(cx, props, printProp)) {
823 return false;
824 }
825 }
826 }
827
828 return xpc::AppendCrossOriginWhitelistedPropNames(cx, props);
829}
830
831bool nsOuterWindowProxy::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
832 JS::Handle<jsid> id,
833 JS::ObjectOpResult& result) const {
834 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
835 return ReportCrossOriginDenial(cx, id, "delete"_ns);
836 }
837
838 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
839 // Fail (which means throw if strict, else return false).
840 return result.failCantDeleteWindowElement();
841 }
842
843 if (IsArrayIndex(GetArrayIndexFromId(id))) {
844 // Indexed, but not supported. Spec says return true.
845 return result.succeed();
846 }
847
848 // We're same-origin, so it should be safe to enter the Realm of "proxy".
849 // Let's do that, just in case, to avoid cross-compartment issues in our
850 // js::Wrapper caller..
851 JSAutoRealm ar(cx, proxy);
852 JS_MarkCrossZoneId(cx, id);
853 return js::Wrapper::delete_(cx, proxy, id, result);
854}
855
856JSObject* nsOuterWindowProxy::getSameOriginPrototype(JSContext* cx) const {
857 return Window_Binding::GetProtoObjectHandle(cx);
858}
859
860bool nsOuterWindowProxy::has(JSContext* cx, JS::Handle<JSObject*> proxy,
861 JS::Handle<jsid> id, bool* bp) const {
862 // We could just directly forward this method to js::BaseProxyHandler, but
863 // that involves reifying the actual property descriptor, which might be more
864 // work than we have to do for has() on the Window.
865
866 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
867 // In the cross-origin case we only have own properties. Just call hasOwn
868 // directly.
869 return hasOwn(cx, proxy, id, bp);
870 }
871
872 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
873 *bp = true;
874 return true;
875 }
876
877 // Just to be safe in terms of compartment asserts, enter the Realm of
878 // "proxy". We're same-origin with it, so this should be safe.
879 JSAutoRealm ar(cx, proxy);
880 JS_MarkCrossZoneId(cx, id);
881 return js::Wrapper::has(cx, proxy, id, bp);
882}
883
884bool nsOuterWindowProxy::hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy,
885 JS::Handle<jsid> id, bool* bp) const {
886 // We could just directly forward this method to js::BaseProxyHandler, but
887 // that involves reifying the actual property descriptor, which might be more
888 // work than we have to do for hasOwn() on the Window.
889
890 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
891 // Avoiding reifying the property descriptor here would require duplicating
892 // a bunch of "is this property exposed cross-origin" logic, which is
893 // probably not worth it. Just forward this along to the base
894 // implementation.
895 //
896 // It's very important to not forward this to js::Wrapper, because that will
897 // not do the right security and cross-origin checks and will pass through
898 // the call to the Window.
899 //
900 // The BaseProxyHandler code is OK with this happening without entering the
901 // compartment of "proxy".
902 return js::BaseProxyHandler::hasOwn(cx, proxy, id, bp);
903 }
904
905 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
906 *bp = true;
907 return true;
908 }
909
910 // Just to be safe in terms of compartment asserts, enter the Realm of
911 // "proxy". We're same-origin with it, so this should be safe.
912 JSAutoRealm ar(cx, proxy);
913 JS_MarkCrossZoneId(cx, id);
914 return js::Wrapper::hasOwn(cx, proxy, id, bp);
915}
916
917bool nsOuterWindowProxy::get(JSContext* cx, JS::Handle<JSObject*> proxy,
918 JS::Handle<JS::Value> receiver,
919 JS::Handle<jsid> id,
920 JS::MutableHandle<JS::Value> vp) const {
921 if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
922 xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
923 vp.set(JS::ObjectValue(*proxy));
924 return MaybeWrapValue(cx, vp);
925 }
926
927 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
928 return CrossOriginGet(cx, proxy, receiver, id, vp);
929 }
930
931 bool found;
932 if (!GetSubframeWindow(cx, proxy, id, vp, found)) {
933 return false;
934 }
935
936 if (found) {
937 return true;
938 }
939
940 if (StaticPrefs::dom_missing_prop_counters_enabled() && id.isAtom()) {
941 Window_Binding::CountMaybeMissingProperty(proxy, id);
942 }
943
944 { // Scope for JSAutoRealm
945 // Enter "proxy"'s Realm. We're in the same-origin case, so this should be
946 // safe.
947 JSAutoRealm ar(cx, proxy);
948
949 JS_MarkCrossZoneId(cx, id);
950
951 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
952 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
953 return false;
954 }
955
956 // Fall through to js::Wrapper.
957 if (!js::Wrapper::get(cx, proxy, wrappedReceiver, id, vp)) {
958 return false;
959 }
960 }
961
962 // Make sure our return value is in the caller compartment.
963 return MaybeWrapValue(cx, vp);
964}
965
966bool nsOuterWindowProxy::set(JSContext* cx, JS::Handle<JSObject*> proxy,
967 JS::Handle<jsid> id, JS::Handle<JS::Value> v,
968 JS::Handle<JS::Value> receiver,
969 JS::ObjectOpResult& result) const {
970 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
971 return CrossOriginSet(cx, proxy, id, v, receiver, result);
972 }
973
974 if (IsArrayIndex(GetArrayIndexFromId(id))) {
975 // Reject the set. It's up to the caller to decide whether to throw a
976 // TypeError. If the caller is strict mode JS code, it'll throw.
977 return result.failReadOnly();
978 }
979
980 // Do the rest in the Realm of "proxy", since we're in the same-origin case.
981 JSAutoRealm ar(cx, proxy);
982 JS::Rooted<JS::Value> wrappedArg(cx, v);
983 if (!MaybeWrapValue(cx, &wrappedArg)) {
984 return false;
985 }
986 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
987 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
988 return false;
989 }
990
991 JS_MarkCrossZoneId(cx, id);
992
993 return js::Wrapper::set(cx, proxy, id, wrappedArg, wrappedReceiver, result);
994}
995
996bool nsOuterWindowProxy::getOwnEnumerablePropertyKeys(
997 JSContext* cx, JS::Handle<JSObject*> proxy,
998 JS::MutableHandleVector<jsid> props) const {
999 // We could just stop overring getOwnEnumerablePropertyKeys and let our
1000 // superclasses deal (by falling back on the BaseProxyHandler implementation
1001 // that uses a combination of ownPropertyKeys and getOwnPropertyDescriptor to
1002 // only return the enumerable ones. But maybe there's value in having
1003 // somewhat faster for-in iteration on Window objects...
1004
1005 // Like ownPropertyKeys, our indexed stuff followed by our "normal" enumerable
1006 // own property names.
1007 if (!AppendIndexedPropertyNames(proxy, props)) {
1008 return false;
1009 }
1010
1011 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
1012 // All the cross-origin properties other than the indexed props are
1013 // non-enumerable, so we're done here.
1014 return true;
1015 }
1016
1017 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
1018 // for now. That's what js::Wrapper expects, and since we're same-origin
1019 // anyway this is not changing any security behavior.
1020 JS::RootedVector<jsid> innerProps(cx);
1021 { // Scope for JSAutoRealm so we can mark the ids once we exit it.
1022 JSAutoRealm ar(cx, proxy);
1023 if (!js::Wrapper::getOwnEnumerablePropertyKeys(cx, proxy, &innerProps)) {
1024 return false;
1025 }
1026 }
1027
1028 for (auto& id : innerProps) {
1029 JS_MarkCrossZoneId(cx, id);
1030 }
1031
1032 return js::AppendUnique(cx, props, innerProps);
1033}
1034
1035bool nsOuterWindowProxy::GetSubframeWindow(JSContext* cx,
1036 JS::Handle<JSObject*> proxy,
1037 JS::Handle<jsid> id,
1038 JS::MutableHandle<JS::Value> vp,
1039 bool& found) const {
1040 Nullable<WindowProxyHolder> frame = GetSubframeWindow(cx, proxy, id);
1041 if (frame.IsNull()) {
1042 found = false;
1043 return true;
1044 }
1045
1046 found = true;
1047 return WrapObject(cx, frame.Value(), vp);
1048}
1049
1050Nullable<WindowProxyHolder> nsOuterWindowProxy::GetSubframeWindow(
1051 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const {
1052 uint32_t index = GetArrayIndexFromId(id);
1053 if (!IsArrayIndex(index)) {
1054 return nullptr;
1055 }
1056
1057 nsGlobalWindowOuter* win = GetOuterWindow(proxy);
1058 return win->IndexedGetterOuter(index);
1059}
1060
1061bool nsOuterWindowProxy::AppendIndexedPropertyNames(
1062 JSObject* proxy, JS::MutableHandleVector<jsid> props) const {
1063 uint32_t length = GetOuterWindow(proxy)->Length();
1064 MOZ_ASSERT(int32_t(length) >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(length) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(length) >= 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(length) >= 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1064); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(length) >= 0"
")"); do { *((volatile int*)__null) = 1064; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1065 if (!props.reserve(props.length() + length)) {
1066 return false;
1067 }
1068 for (int32_t i = 0; i < int32_t(length); ++i) {
1069 if (!props.append(JS::PropertyKey::Int(i))) {
1070 return false;
1071 }
1072 }
1073
1074 return true;
1075}
1076
1077bool nsOuterWindowProxy::EnsureHolder(
1078 JSContext* cx, JS::Handle<JSObject*> proxy,
1079 JS::MutableHandle<JSObject*> holder) const {
1080 return EnsureHolder(cx, proxy, HOLDER_WEAKMAP_SLOT,
1081 Window_Binding::sCrossOriginProperties, holder);
1082}
1083
1084size_t nsOuterWindowProxy::objectMoved(JSObject* obj, JSObject* old) const {
1085 nsGlobalWindowOuter* outerWindow = GetOuterWindow(obj);
1086 if (outerWindow) {
1087 outerWindow->UpdateWrapper(obj, old);
1088 BrowsingContext* bc = outerWindow->GetBrowsingContext();
1089 if (bc) {
1090 bc->UpdateWindowProxy(obj, old);
1091 }
1092 }
1093 return 0;
1094}
1095
1096enum { PDFJS_SLOT_CALLEE = 0 };
1097
1098// static
1099bool nsOuterWindowProxy::MaybeGetPDFJSPrintMethod(
1100 JSContext* cx, JS::Handle<JSObject*> proxy,
1101 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) {
1102 MOZ_ASSERT(proxy)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(proxy)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(proxy))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("proxy", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "proxy" ")")
; do { *((volatile int*)__null) = 1102; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1103 MOZ_ASSERT(!desc.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!desc.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!desc.isSome()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!desc.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!desc.isSome()"
")"); do { *((volatile int*)__null) = 1103; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1104
1105 nsGlobalWindowOuter* outer = GetOuterWindow(proxy);
1106 nsGlobalWindowInner* inner =
1107 nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
1108 if (!inner) {
1109 // No print method to expose.
1110 return true;
1111 }
1112
1113 nsCOMPtr<nsIPrincipal> targetPrincipal = GetNoPDFJSPrincipal(inner);
1114 if (!targetPrincipal) {
1115 // Nothing special to be done.
1116 return true;
1117 }
1118
1119 if (!nsContentUtils::SubjectPrincipal(cx)->Equals(targetPrincipal)) {
1120 // Not our origin's PDF document.
1121 return true;
1122 }
1123
1124 // Get the function we plan to actually call.
1125 JS::Rooted<JSObject*> innerObj(cx, inner->GetGlobalJSObject());
1126 if (!innerObj) {
1127 // Really should not happen, but ok, let's just return.
1128 return true;
1129 }
1130
1131 JS::Rooted<JS::Value> targetFunc(cx);
1132 {
1133 JSAutoRealm ar(cx, innerObj);
1134 if (!JS_GetProperty(cx, innerObj, "print", &targetFunc)) {
1135 return false;
1136 }
1137 }
1138
1139 if (!targetFunc.isObject()) {
1140 // Who knows what's going on. Just return.
1141 return true;
1142 }
1143
1144 // The Realm of cx is the realm our caller is in and the realm we
1145 // should create our function in. Note that we can't use the
1146 // standard XPConnect function forwarder machinery because our
1147 // "this" is cross-origin, so we have to do thus by hand.
1148
1149 // Make sure targetFunc is wrapped into the right compartment.
1150 if (!MaybeWrapValue(cx, &targetFunc)) {
1151 return false;
1152 }
1153
1154 JSFunction* fun =
1155 js::NewFunctionWithReserved(cx, PDFJSPrintMethod, 0, 0, "print");
1156 if (!fun) {
1157 return false;
1158 }
1159
1160 JS::Rooted<JSObject*> funObj(cx, JS_GetFunctionObject(fun));
1161 js::SetFunctionNativeReserved(funObj, PDFJS_SLOT_CALLEE, targetFunc);
1162
1163 // { value: <print>, writable: true, enumerable: true, configurable: true }
1164 // because that's what it would have been in the same-origin case without
1165 // the PDF viewer messing with things.
1166 desc.set(Some(JS::PropertyDescriptor::Data(
1167 JS::ObjectValue(*funObj),
1168 {JS::PropertyAttribute::Configurable, JS::PropertyAttribute::Enumerable,
1169 JS::PropertyAttribute::Writable})));
1170 return true;
1171}
1172
1173// static
1174bool nsOuterWindowProxy::PDFJSPrintMethod(JSContext* cx, unsigned argc,
1175 JS::Value* vp) {
1176 JS::CallArgs args = CallArgsFromVp(argc, vp);
1177
1178 JS::Rooted<JSObject*> realCallee(
1179 cx, &js::GetFunctionNativeReserved(&args.callee(), PDFJS_SLOT_CALLEE)
1180 .toObject());
1181 // Unchecked unwrap, because we want to extract the thing we really had
1182 // before.
1183 realCallee = js::UncheckedUnwrap(realCallee);
1184
1185 JS::Rooted<JS::Value> thisv(cx, args.thisv());
1186 if (thisv.isNullOrUndefined()) {
1187 // Replace it with the global of our stashed callee, simulating the
1188 // global-assuming behavior of DOM methods.
1189 JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(realCallee));
1190 if (!MaybeWrapObject(cx, &global)) {
1191 return false;
1192 }
1193 thisv.setObject(*global);
1194 } else if (!thisv.isObject()) {
1195 return ThrowInvalidThis(cx, args, false, prototypes::id::Window);
1196 }
1197
1198 // We want to do an UncheckedUnwrap here, because we're going to directly
1199 // examine the principal of the inner window, if we have an inner window.
1200 JS::Rooted<JSObject*> unwrappedObj(cx,
1201 js::UncheckedUnwrap(&thisv.toObject()));
1202 nsGlobalWindowInner* inner = nullptr;
1203 {
1204 // Do the unwrap in the Realm of the object we're looking at.
1205 JSAutoRealm ar(cx, unwrappedObj);
1206 UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT(Window, &unwrappedObj, inner, cx)mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Window
, mozilla::dom::Window_Binding::NativeType>( &unwrappedObj
, inner, cx)
;
1207 }
1208 if (!inner) {
1209 return ThrowInvalidThis(cx, args, false, prototypes::id::Window);
1210 }
1211
1212 nsIPrincipal* callerPrincipal = nsContentUtils::SubjectPrincipal(cx);
1213 if (!callerPrincipal->SubsumesConsideringDomain(inner->GetPrincipal())) {
1214 // Check whether it's a PDF viewer from our origin.
1215 nsCOMPtr<nsIPrincipal> pdfPrincipal = GetNoPDFJSPrincipal(inner);
1216 if (!pdfPrincipal || !callerPrincipal->Equals(pdfPrincipal)) {
1217 // Security error.
1218 return ThrowInvalidThis(cx, args, true, prototypes::id::Window);
1219 }
1220 }
1221
1222 // Go ahead and enter the Realm of our real callee to call it. We'll pass it
1223 // our "thisv", just in case someone grabs a "print" method off one PDF
1224 // document and .call()s it on another one.
1225 {
1226 JSAutoRealm ar(cx, realCallee);
1227 if (!MaybeWrapValue(cx, &thisv)) {
1228 return false;
1229 }
1230
1231 // Don't bother passing through the args; they will get ignored anyway.
1232
1233 if (!JS::Call(cx, thisv, realCallee, JS::HandleValueArray::empty(),
1234 args.rval())) {
1235 return false;
1236 }
1237 }
1238
1239 // Wrap the return value (not that there should be any!) into the right
1240 // compartment.
1241 return MaybeWrapValue(cx, args.rval());
1242}
1243
1244// static
1245already_AddRefed<nsIPrincipal> nsOuterWindowProxy::GetNoPDFJSPrincipal(
1246 nsGlobalWindowInner* inner) {
1247 if (!nsContentUtils::IsPDFJS(inner->GetPrincipal())) {
1248 return nullptr;
1249 }
1250
1251 if (Document* doc = inner->GetExtantDoc()) {
1252 if (nsCOMPtr<nsIPropertyBag2> propBag =
1253 do_QueryInterface(doc->GetChannel())) {
1254 nsCOMPtr<nsIPrincipal> principal(
1255 do_GetProperty(propBag, u"noPDFJSPrincipal"_ns));
1256 return principal.forget();
1257 }
1258 }
1259 return nullptr;
1260}
1261
1262const nsOuterWindowProxy nsOuterWindowProxy::singleton;
1263
1264class nsChromeOuterWindowProxy : public nsOuterWindowProxy {
1265 public:
1266 constexpr nsChromeOuterWindowProxy() = default;
1267
1268 const char* className(JSContext* cx,
1269 JS::Handle<JSObject*> wrapper) const override;
1270
1271 static const nsChromeOuterWindowProxy singleton;
1272};
1273
1274const char* nsChromeOuterWindowProxy::className(
1275 JSContext* cx, JS::Handle<JSObject*> proxy) const {
1276 MOZ_ASSERT(js::IsProxy(proxy))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(js::IsProxy(proxy))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsProxy(proxy)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("js::IsProxy(proxy)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1276); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsProxy(proxy)"
")"); do { *((volatile int*)__null) = 1276; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1277
1278 return "ChromeWindow";
1279}
1280
1281const nsChromeOuterWindowProxy nsChromeOuterWindowProxy::singleton;
1282
1283static JSObject* NewOuterWindowProxy(JSContext* cx,
1284 JS::Handle<JSObject*> global,
1285 bool isChrome) {
1286 MOZ_ASSERT(JS_IsGlobalObject(global))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(JS_IsGlobalObject(global))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JS_IsGlobalObject(global))))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("JS_IsGlobalObject(global)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1286); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JS_IsGlobalObject(global)"
")"); do { *((volatile int*)__null) = 1286; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1287
1288 JSAutoRealm ar(cx, global);
1289
1290 js::WrapperOptions options;
1291 options.setClass(&OuterWindowProxyClass);
1292 JSObject* obj =
1293 js::Wrapper::New(cx, global,
1294 isChrome ? &nsChromeOuterWindowProxy::singleton
1295 : &nsOuterWindowProxy::singleton,
1296 options);
1297 MOZ_ASSERT_IF(obj, js::IsWindowProxy(obj))do { if (obj) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(js::IsWindowProxy(obj))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsWindowProxy(obj)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("js::IsWindowProxy(obj)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1297); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(obj)"
")"); do { *((volatile int*)__null) = 1297; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1298 return obj;
1299}
1300
1301//*****************************************************************************
1302//*** nsGlobalWindowOuter: Object Management
1303//*****************************************************************************
1304
1305nsGlobalWindowOuter::nsGlobalWindowOuter(uint64_t aWindowID)
1306 : nsPIDOMWindowOuter(aWindowID),
1307 mFullscreenHasChangedDuringProcessing(false),
1308 mForceFullScreenInWidget(false),
1309 mIsClosed(false),
1310 mInClose(false),
1311 mHavePendingClose(false),
1312 mBlockScriptedClosingFlag(false),
1313 mWasOffline(false),
1314 mCreatingInnerWindow(false),
1315 mIsChrome(false),
1316 mAllowScriptsToClose(false),
1317 mTopLevelOuterContentWindow(false),
1318 mDelayedPrintUntilAfterLoad(false),
1319 mDelayedCloseForPrinting(false),
1320 mShouldDelayPrintUntilAfterLoad(false),
1321#ifdef DEBUG1
1322 mSerial(0),
1323 mSetOpenerWindowCalled(false),
1324#endif
1325 mCleanedUp(false),
1326 mCanSkipCCGeneration(0),
1327 mAutoActivateVRDisplayID(0) {
1328 AssertIsOnMainThread();
1329 SetIsOnMainThread();
1330 nsLayoutStatics::AddRef();
1331
1332 // Initialize the PRCList (this).
1333 PR_INIT_CLIST(this)do { (this)->next = (this); (this)->prev = (this); } while
(0)
;
1334
1335 // |this| is an outer window. Outer windows start out frozen and
1336 // remain frozen until they get an inner window.
1337 MOZ_ASSERT(IsFrozen())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFrozen())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsFrozen()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("IsFrozen()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1337); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFrozen()"
")"); do { *((volatile int*)__null) = 1337; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1338
1339 // We could have failed the first time through trying
1340 // to create the entropy collector, so we should
1341 // try to get one until we succeed.
1342
1343#ifdef DEBUG1
1344 mSerial = nsContentUtils::InnerOrOuterWindowCreated();
1345
1346 MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n"
, nsContentUtils::GetCurrentInnerOrOuterWindowCount(), static_cast
<void*>(ToCanonicalSupports(this)), getpid(), mSerial, nullptr
); } } while (0)
1347 ("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n"
, nsContentUtils::GetCurrentInnerOrOuterWindowCount(), static_cast
<void*>(ToCanonicalSupports(this)), getpid(), mSerial, nullptr
); } } while (0)
1348 nsContentUtils::GetCurrentInnerOrOuterWindowCount(),do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n"
, nsContentUtils::GetCurrentInnerOrOuterWindowCount(), static_cast
<void*>(ToCanonicalSupports(this)), getpid(), mSerial, nullptr
); } } while (0)
1349 static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n"
, nsContentUtils::GetCurrentInnerOrOuterWindowCount(), static_cast
<void*>(ToCanonicalSupports(this)), getpid(), mSerial, nullptr
); } } while (0)
1350 nullptr))do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n"
, nsContentUtils::GetCurrentInnerOrOuterWindowCount(), static_cast
<void*>(ToCanonicalSupports(this)), getpid(), mSerial, nullptr
); } } while (0)
;
1351#endif
1352
1353 MOZ_LOG(gDOMLeakPRLogOuter, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDOMLeakPRLogOuter
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOMWINDOW %p created outer=nullptr", this
); } } while (0)
1354 ("DOMWINDOW %p created outer=nullptr", this))do { const ::mozilla::LogModule* moz_real_module = gDOMLeakPRLogOuter
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOMWINDOW %p created outer=nullptr", this
); } } while (0)
;
1355
1356 // Add ourselves to the outer windows list.
1357 MOZ_ASSERT(sOuterWindowsById, "Outer Windows hash table must be created!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sOuterWindowsById)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sOuterWindowsById))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("sOuterWindowsById"
" (" "Outer Windows hash table must be created!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sOuterWindowsById"
") (" "Outer Windows hash table must be created!" ")"); do {
*((volatile int*)__null) = 1357; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1358
1359 // |this| is an outer window, add to the outer windows list.
1360 MOZ_ASSERT(!sOuterWindowsById->Contains(mWindowID),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sOuterWindowsById->Contains(mWindowID))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!sOuterWindowsById->Contains(mWindowID)))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!sOuterWindowsById->Contains(mWindowID)"
" (" "This window shouldn't be in the hash table yet!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sOuterWindowsById->Contains(mWindowID)"
") (" "This window shouldn't be in the hash table yet!" ")")
; do { *((volatile int*)__null) = 1361; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1361 "This window shouldn't be in the hash table yet!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sOuterWindowsById->Contains(mWindowID))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!sOuterWindowsById->Contains(mWindowID)))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!sOuterWindowsById->Contains(mWindowID)"
" (" "This window shouldn't be in the hash table yet!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sOuterWindowsById->Contains(mWindowID)"
") (" "This window shouldn't be in the hash table yet!" ")")
; do { *((volatile int*)__null) = 1361; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1362 // We seem to see crashes in release builds because of null
1363 // |sOuterWindowsById|.
1364 if (sOuterWindowsById) {
1365 sOuterWindowsById->InsertOrUpdate(mWindowID, this);
1366 }
1367}
1368
1369#ifdef DEBUG1
1370
1371/* static */
1372void nsGlobalWindowOuter::AssertIsOnMainThread() {
1373 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1373); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 1373; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1374}
1375
1376#endif // DEBUG
1377
1378/* static */
1379void nsGlobalWindowOuter::Init() {
1380 AssertIsOnMainThread();
1381
1382 NS_ASSERTION(gDOMLeakPRLogOuter,do { if (!(gDOMLeakPRLogOuter)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "gDOMLeakPRLogOuter should have been initialized!", "gDOMLeakPRLogOuter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1383); MOZ_PretendNoReturn(); } } while (0)
1383 "gDOMLeakPRLogOuter should have been initialized!")do { if (!(gDOMLeakPRLogOuter)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "gDOMLeakPRLogOuter should have been initialized!", "gDOMLeakPRLogOuter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1383); MOZ_PretendNoReturn(); } } while (0)
;
1384
1385 sOuterWindowsById = new OuterWindowByIdTable();
1386}
1387
1388nsGlobalWindowOuter::~nsGlobalWindowOuter() {
1389 AssertIsOnMainThread();
1390
1391 if (sOuterWindowsById) {
1392 sOuterWindowsById->Remove(mWindowID);
1393 }
1394
1395 nsContentUtils::InnerOrOuterWindowDestroyed();
1396
1397#ifdef DEBUG1
1398 if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)(__builtin_expect(!!(mozilla::detail::log_test(gDocShellAndDOMWindowLeakLogging
, LogLevel::Info)), 0))
) {
1399 nsAutoCString url;
1400 if (mLastOpenedURI) {
1401 url = mLastOpenedURI->GetSpecOrDefault();
1402
1403 // Data URLs can be very long, so truncate to avoid flooding the log.
1404 const uint32_t maxURLLength = 1000;
1405 if (url.Length() > maxURLLength) {
1406 url.Truncate(maxURLLength);
1407 }
1408 }
1409
1410 MOZ_LOG(do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1411 gDocShellAndDOMWindowLeakLogging, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1412 ("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1413 "%s]\n",do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1414 nsContentUtils::GetCurrentInnerOrOuterWindowCount(),do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1415 static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
1416 nullptr, url.get()))do { const ::mozilla::LogModule* moz_real_module = gDocShellAndDOMWindowLeakLogging
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
"%s]\n", nsContentUtils::GetCurrentInnerOrOuterWindowCount()
, static_cast<void*>(ToCanonicalSupports(this)), getpid
(), mSerial, nullptr, url.get()); } } while (0)
;
1417 }
1418#endif
1419
1420 MOZ_LOG(gDOMLeakPRLogOuter, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gDOMLeakPRLogOuter
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOMWINDOW %p destroyed", this); } } while
(0)
1421 ("DOMWINDOW %p destroyed", this))do { const ::mozilla::LogModule* moz_real_module = gDOMLeakPRLogOuter
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "DOMWINDOW %p destroyed", this); } } while
(0)
;
1422
1423 JSObject* proxy = GetWrapperMaybeDead();
1424 if (proxy) {
1425 if (mBrowsingContext && mBrowsingContext->GetUnbarrieredWindowProxy()) {
1426 nsGlobalWindowOuter* outer = nsOuterWindowProxy::GetOuterWindow(
1427 mBrowsingContext->GetUnbarrieredWindowProxy());
1428 // Check that the current WindowProxy object corresponds to this
1429 // nsGlobalWindowOuter, because we don't want to clear the WindowProxy if
1430 // we've replaced it with a cross-process WindowProxy.
1431 if (outer == this) {
1432 mBrowsingContext->ClearWindowProxy();
1433 }
1434 }
1435 js::SetProxyReservedSlot(proxy, OUTER_WINDOW_SLOT,
1436 JS::PrivateValue(nullptr));
1437 }
1438
1439 // An outer window is destroyed with inner windows still possibly
1440 // alive, iterate through the inner windows and null out their
1441 // back pointer to this outer, and pull them out of the list of
1442 // inner windows.
1443 //
1444 // Our linked list of inner windows both contains (an nsGlobalWindowOuter),
1445 // and our inner windows (nsGlobalWindowInners). This means that we need to
1446 // use PRCList*. We can then compare that PRCList* to `this` to see if its an
1447 // inner or outer window.
1448 PRCList* w;
1449 while ((w = PR_LIST_HEAD(this)(this)->next) != this) {
1450 PR_REMOVE_AND_INIT_LINK(w)do { (w)->prev->next = (w)->next; (w)->next->prev
= (w)->prev; (w)->next = (w); (w)->prev = (w); } while
(0)
;
1451 }
1452
1453 DropOuterWindowDocs();
1454
1455 // Outer windows are always supposed to call CleanUp before letting themselves
1456 // be destroyed.
1457 MOZ_ASSERT(mCleanedUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCleanedUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCleanedUp))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mCleanedUp", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1457); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCleanedUp"
")"); do { *((volatile int*)__null) = 1457; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1458
1459 nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID"@mozilla.org/devicesensors;1");
1460 if (ac) ac->RemoveWindowAsListener(this);
1461
1462 nsLayoutStatics::Release();
1463}
1464
1465// static
1466void nsGlobalWindowOuter::ShutDown() {
1467 AssertIsOnMainThread();
1468
1469 delete sOuterWindowsById;
1470 sOuterWindowsById = nullptr;
1471}
1472
1473void nsGlobalWindowOuter::DropOuterWindowDocs() {
1474 MOZ_ASSERT_IF(mDoc, !mDoc->EventHandlingSuppressed())do { if (mDoc) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!mDoc->EventHandlingSuppressed())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!mDoc->EventHandlingSuppressed()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mDoc->EventHandlingSuppressed()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1474); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDoc->EventHandlingSuppressed()"
")"); do { *((volatile int*)__null) = 1474; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1475 mDoc = nullptr;
1476 mSuspendedDocs.Clear();
1477}
1478
1479void nsGlobalWindowOuter::CleanUp() {
1480 // Guarantee idempotence.
1481 if (mCleanedUp) return;
1482 mCleanedUp = true;
1483
1484 StartDying();
1485
1486 mWindowUtils = nullptr;
1487
1488 ClearControllers();
1489
1490 mContext = nullptr; // Forces Release
1491 mChromeEventHandler = nullptr; // Forces Release
1492 mParentTarget = nullptr;
1493 mMessageManager = nullptr;
1494
1495 mArguments = nullptr;
1496}
1497
1498void nsGlobalWindowOuter::ClearControllers() {
1499 if (mControllers) {
1500 uint32_t count;
1501 mControllers->GetControllerCount(&count);
1502
1503 while (count--) {
1504 nsCOMPtr<nsIController> controller;
1505 mControllers->GetControllerAt(count, getter_AddRefs(controller));
1506
1507 nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
1508 if (context) context->SetCommandContext(nullptr);
1509 }
1510
1511 mControllers = nullptr;
1512 }
1513}
1514
1515//*****************************************************************************
1516// nsGlobalWindowOuter::nsISupports
1517//*****************************************************************************
1518
1519// QueryInterface implementation for nsGlobalWindowOuter
1520NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowOuter)nsresult nsGlobalWindowOuter::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1520); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = nsGlobalWindowOuter::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = nsGlobalWindowOuter::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
1521 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRYif (aIID.Equals((nsWrapperCache::COMTypeInfo<nsWrapperCache
, void>::kIID))) { *aInstancePtr = static_cast<nsWrapperCache
*>(this); return NS_OK; } else
1522 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<EventTarget*>(this)); else
1523 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIDOMWindow>)) foundInterface = static_cast
<nsIDOMWindow*>(this); else
1524 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIGlobalObject>)) foundInterface
= static_cast<nsIGlobalObject*>(this); else
1525 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIScriptGlobalObject>)) foundInterface
= static_cast<nsIScriptGlobalObject*>(this); else
1526 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIScriptObjectPrincipal>)) foundInterface
= static_cast<nsIScriptObjectPrincipal*>(this); else
1527 NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, mozilla::dom::EventTarget>)) foundInterface
= static_cast<mozilla::dom::EventTarget*>(this); else
1528 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowOuter)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsPIDOMWindowOuter>)) foundInterface
= static_cast<nsPIDOMWindowOuter*>(this); else
1529 NS_INTERFACE_MAP_ENTRY(mozIDOMWindowProxy)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, mozIDOMWindowProxy>)) foundInterface
= static_cast<mozIDOMWindowProxy*>(this); else
1530 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
1531 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIInterfaceRequestor>)) foundInterface
= static_cast<nsIInterfaceRequestor*>(this); else
1532NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1532); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 1532; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
1533
1534NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowOuter)MozExternalRefCountType nsGlobalWindowOuter::AddRef(void) { static_assert
(!std::is_destructible_v<nsGlobalWindowOuter>, "Reference-counted class "
"nsGlobalWindowOuter" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1534; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); _mOwningThread.AssertOwnership("nsGlobalWindowOuter"
" not thread-safe"); nsISupports* base = nsGlobalWindowOuter
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr
(base); NS_LogAddRef((this), (count), ("nsGlobalWindowOuter")
, (uint32_t)(sizeof(*this))); return count; }
1535NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindowOuter)MozExternalRefCountType nsGlobalWindowOuter::Release(void) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1535); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 1535
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("nsGlobalWindowOuter"
" not thread-safe"); nsISupports* base = nsGlobalWindowOuter
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.decr
(base); NS_LogRelease((this), (count), ("nsGlobalWindowOuter"
)); return count; } void nsGlobalWindowOuter::DeleteCycleCollectable
(void) { delete (this); }
1536
1537NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipReal(void* p
, bool aRemovingAllowed) { nsGlobalWindowOuter* tmp = DowncastCCParticipant
<nsGlobalWindowOuter>(p);
1538 if (tmp->IsBlackForCC(false)) {
1539 if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
1540 return true;
1541 }
1542 tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
1543 if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
1544 elm->MarkForCC();
1545 }
1546 return true;
1547 }
1548NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END(void)tmp; return false; }
1549
1550NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipInCCReal(void
* p) { nsGlobalWindowOuter* tmp = DowncastCCParticipant<nsGlobalWindowOuter
>(p);
1551 return tmp->IsBlackForCC(true);
1552NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END(void)tmp; return false; }
1553
1554NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipThisReal(void
* p) { nsGlobalWindowOuter* tmp = DowncastCCParticipant<nsGlobalWindowOuter
>(p);
1555 return tmp->IsBlackForCC(false);
1556NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END(void)tmp; return false; }
1557
1558NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowOuter)nsGlobalWindowOuter::cycleCollection nsGlobalWindowOuter::_cycleCollectorGlobal
;
1559
1560NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowOuter)nsresult nsGlobalWindowOuter::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1561 if (MOZ_UNLIKELY(cb.WantDebugInfo())(__builtin_expect(!!(cb.WantDebugInfo()), 0))) {
1562 char name[512];
1563 nsAutoCString uri;
1564 if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
1565 uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
1566 }
1567 SprintfLiteral(name, "nsGlobalWindowOuter # %" PRIu64"l" "u" " outer %s",
1568 tmp->mWindowID, uri.get());
1569 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
1570 } else {
1571 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowOuter, tmp->mRefCnt.get())cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "nsGlobalWindowOuter"
);
1572 }
1573
1574 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)ImplCycleCollectionTraverse(cb, tmp->mContext, "mContext",
0);
1575
1576 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)ImplCycleCollectionTraverse(cb, tmp->mControllers, "mControllers"
, 0);
1577 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)ImplCycleCollectionTraverse(cb, tmp->mArguments, "mArguments"
, 0);
1578
1579 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)ImplCycleCollectionTraverse(cb, tmp->mLocalStorage, "mLocalStorage"
, 0);
1580 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDocs)ImplCycleCollectionTraverse(cb, tmp->mSuspendedDocs, "mSuspendedDocs"
, 0);
1581 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentPrincipal, "mDocumentPrincipal"
, 0);
1582 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCookiePrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentCookiePrincipal
, "mDocumentCookiePrincipal", 0);
1583 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentStoragePrincipal
, "mDocumentStoragePrincipal", 0);
1584 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPartitionedPrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentPartitionedPrincipal
, "mDocumentPartitionedPrincipal", 0);
1585 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)ImplCycleCollectionTraverse(cb, tmp->mDoc, "mDoc", 0);
1586
1587 // Traverse stuff from nsPIDOMWindow
1588 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)ImplCycleCollectionTraverse(cb, tmp->mChromeEventHandler, "mChromeEventHandler"
, 0);
1589 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)ImplCycleCollectionTraverse(cb, tmp->mParentTarget, "mParentTarget"
, 0);
1590 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)ImplCycleCollectionTraverse(cb, tmp->mMessageManager, "mMessageManager"
, 0);
1591 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)ImplCycleCollectionTraverse(cb, tmp->mFrameElement, "mFrameElement"
, 0);
1592
1593 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell)ImplCycleCollectionTraverse(cb, tmp->mDocShell, "mDocShell"
, 0);
1594 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)ImplCycleCollectionTraverse(cb, tmp->mBrowsingContext, "mBrowsingContext"
, 0);
1595
1596 tmp->TraverseObjectsInGlobal(cb);
1597
1598 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mBrowserDOMWindow)ImplCycleCollectionTraverse(cb, tmp->mChromeFields.mBrowserDOMWindow
, "mChromeFields.mBrowserDOMWindow", 0);
1599NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END(void)tmp; return NS_OK; }
1600
1601NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowOuter)void nsGlobalWindowOuter::cycleCollection::Unlink(void* p) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1602 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCEtmp->ClearWeakReferences();
1603 if (sOuterWindowsById) {
1604 sOuterWindowsById->Remove(tmp->mWindowID);
1605 }
1606
1607 NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)ImplCycleCollectionUnlink(tmp->mContext);
1608
1609 NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)ImplCycleCollectionUnlink(tmp->mControllers);
1610 NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)ImplCycleCollectionUnlink(tmp->mArguments);
1611
1612 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)ImplCycleCollectionUnlink(tmp->mLocalStorage);
1613 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDocs)ImplCycleCollectionUnlink(tmp->mSuspendedDocs);
1614 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)ImplCycleCollectionUnlink(tmp->mDocumentPrincipal);
1615 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCookiePrincipal)ImplCycleCollectionUnlink(tmp->mDocumentCookiePrincipal);
1616 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)ImplCycleCollectionUnlink(tmp->mDocumentStoragePrincipal);
1617 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPartitionedPrincipal)ImplCycleCollectionUnlink(tmp->mDocumentPartitionedPrincipal
);
1618 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)ImplCycleCollectionUnlink(tmp->mDoc);
1619
1620 // Unlink stuff from nsPIDOMWindow
1621 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)ImplCycleCollectionUnlink(tmp->mChromeEventHandler);
1622 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)ImplCycleCollectionUnlink(tmp->mParentTarget);
1623 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)ImplCycleCollectionUnlink(tmp->mMessageManager);
1624 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)ImplCycleCollectionUnlink(tmp->mFrameElement);
1625
1626 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)ImplCycleCollectionUnlink(tmp->mDocShell);
1627 if (tmp->mBrowsingContext) {
1628 if (tmp->mBrowsingContext->GetUnbarrieredWindowProxy()) {
1629 nsGlobalWindowOuter* outer = nsOuterWindowProxy::GetOuterWindow(
1630 tmp->mBrowsingContext->GetUnbarrieredWindowProxy());
1631 // Check that the current WindowProxy object corresponds to this
1632 // nsGlobalWindowOuter, because we don't want to clear the WindowProxy if
1633 // we've replaced it with a cross-process WindowProxy.
1634 if (outer == tmp) {
1635 tmp->mBrowsingContext->ClearWindowProxy();
1636 }
1637 }
1638 tmp->mBrowsingContext = nullptr;
1639 }
1640
1641 tmp->UnlinkObjectsInGlobal();
1642
1643 if (tmp->IsChromeWindow()) {
1644 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mBrowserDOMWindow)ImplCycleCollectionUnlink(tmp->mChromeFields.mBrowserDOMWindow
);
1645 }
1646
1647 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPERtmp->ReleaseWrapper(p);
1648NS_IMPL_CYCLE_COLLECTION_UNLINK_END(void)tmp; }
1649
1650NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowOuter)void nsGlobalWindowOuter::cycleCollection::Trace( void* p, const
TraceCallbacks& aCallbacks, void* aClosure) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1651 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPERtmp->TraceWrapper(aCallbacks, aClosure);
1652NS_IMPL_CYCLE_COLLECTION_TRACE_END(void)tmp; }
1653
1654bool nsGlobalWindowOuter::IsBlackForCC(bool aTracingNeeded) {
1655 if (!nsCCUncollectableMarker::sGeneration) {
1656 return false;
1657 }
1658
1659 // Unlike most wrappers, the outer window wrapper is not a wrapper for
1660 // the outer window. Instead, the outer window wrapper holds the inner
1661 // window binding object, which in turn holds the nsGlobalWindowInner, which
1662 // has a strong reference to the nsGlobalWindowOuter. We're using the
1663 // mInnerWindow pointer as a flag for that whole chain.
1664 return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
1665 (mInnerWindow && HasKnownLiveWrapper())) &&
1666 (!aTracingNeeded || HasNothingToTrace(ToSupports(this)));
1667}
1668
1669//*****************************************************************************
1670// nsGlobalWindowOuter::nsIScriptGlobalObject
1671//*****************************************************************************
1672
1673bool nsGlobalWindowOuter::ShouldResistFingerprinting(RFPTarget aTarget) const {
1674 if (mDoc) {
1675 return mDoc->ShouldResistFingerprinting(aTarget);
1676 }
1677 return nsContentUtils::ShouldResistFingerprinting(
1678 "If we do not have a document then we do not have any context"
1679 "to make an informed RFP choice, so we fall back to the global pref",
1680 aTarget);
1681}
1682
1683OriginTrials nsGlobalWindowOuter::Trials() const {
1684 return mInnerWindow ? nsGlobalWindowInner::Cast(mInnerWindow)->Trials()
1685 : OriginTrials();
1686}
1687
1688FontFaceSet* nsGlobalWindowOuter::GetFonts() {
1689 if (mDoc) {
1690 return mDoc->Fonts();
1691 }
1692 return nullptr;
1693}
1694
1695nsresult nsGlobalWindowOuter::EnsureScriptEnvironment() {
1696 if (GetWrapperPreserveColor()) {
1697 return NS_OK;
1698 }
1699
1700 NS_ENSURE_STATE(!mCleanedUp)do { if ((__builtin_expect(!!(!(!mCleanedUp)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!mCleanedUp" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1700); return NS_ERROR_UNEXPECTED; } } while (false)
;
1701
1702 NS_ASSERTION(!GetCurrentInnerWindowInternal(this),do { if (!(!GetCurrentInnerWindowInternal(this))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "No cached wrapper, but we have an inner window?"
, "!GetCurrentInnerWindowInternal(this)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1703); MOZ_PretendNoReturn(); } } while (0)
1703 "No cached wrapper, but we have an inner window?")do { if (!(!GetCurrentInnerWindowInternal(this))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "No cached wrapper, but we have an inner window?"
, "!GetCurrentInnerWindowInternal(this)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1703); MOZ_PretendNoReturn(); } } while (0)
;
1704 NS_ASSERTION(!mContext, "Will overwrite mContext!")do { if (!(!mContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Will overwrite mContext!"
, "!mContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1704); MOZ_PretendNoReturn(); } } while (0)
;
1705
1706 // If this window is an [i]frame, don't bother GC'ing when the frame's context
1707 // is destroyed since a GC will happen when the frameset or host document is
1708 // destroyed anyway.
1709 mContext = new nsJSContext(mBrowsingContext->IsTop(), this);
1710 return NS_OK;
1711}
1712
1713nsIScriptContext* nsGlobalWindowOuter::GetScriptContext() { return mContext; }
1714
1715bool nsGlobalWindowOuter::WouldReuseInnerWindow(Document* aNewDocument) {
1716 // We reuse the inner window when:
1717 // a. We are currently at our original document.
1718 // b. At least one of the following conditions are true:
1719 // -- The new document is the same as the old document. This means that we're
1720 // getting called from document.open().
1721 // -- The new document has the same origin as what we have loaded right now.
1722
1723 if (!mDoc || !aNewDocument) {
1724 return false;
1725 }
1726
1727 if (!mDoc->IsInitialDocument()) {
1728 return false;
1729 }
1730
1731#ifdef DEBUG1
1732 {
1733 nsCOMPtr<nsIURI> uri;
1734 NS_GetURIWithoutRef(mDoc->GetDocumentURI(), getter_AddRefs(uri));
1735 NS_ASSERTION(NS_IsAboutBlank(uri), "How'd this happen?")do { if (!(NS_IsAboutBlank(uri))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "How'd this happen?", "NS_IsAboutBlank(uri)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1735); MOZ_PretendNoReturn(); } } while (0)
;
1736 }
1737#endif
1738
1739 // Great, we're the original document, check for one of the other
1740 // conditions.
1741
1742 if (mDoc == aNewDocument) {
1743 return true;
1744 }
1745
1746 if (aNewDocument->IsStaticDocument()) {
1747 return false;
1748 }
1749
1750 if (BasePrincipal::Cast(mDoc->NodePrincipal())
1751 ->FastEqualsConsideringDomain(aNewDocument->NodePrincipal())) {
1752 // The origin is the same.
1753 return true;
1754 }
1755
1756 return false;
1757}
1758
1759void nsGlobalWindowOuter::SetInitialPrincipal(
1760 nsIPrincipal* aNewWindowPrincipal, nsIContentSecurityPolicy* aCSP,
1761 const Maybe<nsILoadInfo::CrossOriginEmbedderPolicy>& aCOEP) {
1762 // We should never create windows with an expanded principal.
1763 // If we have a system principal, make sure we're not using it for a content
1764 // docshell.
1765 // NOTE: Please keep this logic in sync with
1766 // nsAppShellService::JustCreateTopWindow
1767 if (nsContentUtils::IsExpandedPrincipal(aNewWindowPrincipal) ||
1768 (aNewWindowPrincipal->IsSystemPrincipal() &&
1769 GetBrowsingContext()->IsContent())) {
1770 aNewWindowPrincipal = nullptr;
1771 }
1772
1773 // If there's an existing document, bail if it either:
1774 if (mDoc) {
1775 // (a) is not an initial about:blank document, or
1776 if (!mDoc->IsInitialDocument()) return;
1777 // (b) already has the correct principal.
1778 if (mDoc->NodePrincipal() == aNewWindowPrincipal) return;
1779
1780#ifdef DEBUG1
1781 // If we have a document loaded at this point, it had better be about:blank.
1782 // Otherwise, something is really weird. An about:blank page has a
1783 // NullPrincipal.
1784 bool isNullPrincipal;
1785 MOZ_ASSERT(NS_SUCCEEDED(mDoc->NodePrincipal()->GetIsNullPrincipal(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->
NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal)
)), 1))) && isNullPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(((bool)(__builtin_expect(!!(
!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal
( &isNullPrincipal))), 1))) && isNullPrincipal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1787); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1787; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1786 &isNullPrincipal)) &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->
NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal)
)), 1))) && isNullPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(((bool)(__builtin_expect(!!(
!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal
( &isNullPrincipal))), 1))) && isNullPrincipal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1787); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1787; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1787 isNullPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->
NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal)
)), 1))) && isNullPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(((bool)(__builtin_expect(!!(
!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal
( &isNullPrincipal))), 1))) && isNullPrincipal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1787); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1787; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1788#endif
1789 }
1790
1791 // Use the subject (or system) principal as the storage principal too until
1792 // the new window finishes navigating and gets a real storage principal.
1793 nsDocShell::Cast(GetDocShell())
1794 ->CreateAboutBlankDocumentViewer(aNewWindowPrincipal, aNewWindowPrincipal,
1795 aCSP, nullptr,
1796 /* aIsInitialDocument */ true, aCOEP);
1797
1798 if (mDoc) {
1799 MOZ_ASSERT(mDoc->IsInitialDocument(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDoc->IsInitialDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDoc->IsInitialDocument()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDoc->IsInitialDocument()" " (" "document should be initial document"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc->IsInitialDocument()"
") (" "document should be initial document" ")"); do { *((volatile
int*)__null) = 1800; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
1800 "document should be initial document")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDoc->IsInitialDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDoc->IsInitialDocument()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDoc->IsInitialDocument()" " (" "document should be initial document"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc->IsInitialDocument()"
") (" "document should be initial document" ")"); do { *((volatile
int*)__null) = 1800; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1801 }
1802
1803 RefPtr<PresShell> presShell = GetDocShell()->GetPresShell();
1804 if (presShell && !presShell->DidInitialize()) {
1805 // Ensure that if someone plays with this document they will get
1806 // layout happening.
1807 presShell->Initialize();
1808 }
1809}
1810
1811#define WINDOWSTATEHOLDER_IID{ 0x0b917c3e, 0xbd50, 0x4683, { 0xaf, 0xc9, 0xc7, 0x81, 0x07,
0xae, 0x33, 0x26 } }
\
1812 { \
1813 0x0b917c3e, 0xbd50, 0x4683, { \
1814 0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26 \
1815 } \
1816 }
1817
1818class WindowStateHolder final : public nsISupports {
1819 public:
1820 NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)template <typename T, typename U> struct COMTypeInfo;
1821 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
1822
1823 explicit WindowStateHolder(nsGlobalWindowInner* aWindow);
1824
1825 nsGlobalWindowInner* GetInnerWindow() { return mInnerWindow; }
1826
1827 void DidRestoreWindow() {
1828 mInnerWindow = nullptr;
1829 mInnerWindowReflector = nullptr;
1830 }
1831
1832 protected:
1833 ~WindowStateHolder();
1834
1835 nsGlobalWindowInner* mInnerWindow;
1836 // We hold onto this to make sure the inner window doesn't go away. The outer
1837 // window ends up recalculating it anyway.
1838 JS::PersistentRooted<JSObject*> mInnerWindowReflector;
1839};
1840
1841NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)template <typename T> struct WindowStateHolder::COMTypeInfo
<WindowStateHolder, T> { static const nsIID kIID __attribute__
((visibility("hidden"))); }; template <typename T> const
nsIID WindowStateHolder::COMTypeInfo<WindowStateHolder, T
>::kIID __attribute__((visibility("hidden"))) = { 0x0b917c3e
, 0xbd50, 0x4683, { 0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33,
0x26 } };
1842
1843WindowStateHolder::WindowStateHolder(nsGlobalWindowInner* aWindow)
1844 : mInnerWindow(aWindow),
1845 mInnerWindowReflector(RootingCx(), aWindow->GetWrapper()) {
1846 MOZ_ASSERT(aWindow, "null window")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWindow" " (" "null window"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1846); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ") ("
"null window" ")"); do { *((volatile int*)__null) = 1846; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
1847
1848 aWindow->Suspend();
1849
1850 // When a global goes into the bfcache, we disable script.
1851 xpc::Scriptability::Get(mInnerWindowReflector).SetWindowAllowsScript(false);
1852}
1853
1854WindowStateHolder::~WindowStateHolder() {
1855 if (mInnerWindow) {
1856 // This window was left in the bfcache and is now going away. We need to
1857 // free it up.
1858 // Note that FreeInnerObjects may already have been called on the
1859 // inner window if its outer has already had SetDocShell(null)
1860 // called.
1861 mInnerWindow->FreeInnerObjects();
1862 }
1863}
1864
1865NS_IMPL_ISUPPORTS(WindowStateHolder, WindowStateHolder)MozExternalRefCountType WindowStateHolder::AddRef(void) { static_assert
(!std::is_destructible_v<WindowStateHolder>, "Reference-counted class "
"WindowStateHolder" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1865; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WindowStateHolder" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WindowStateHolder" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WindowStateHolder\" != nullptr" " (" "Must specify a name"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WindowStateHolder\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1865; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("WindowStateHolder" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("WindowStateHolder"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
WindowStateHolder::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 1865
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WindowStateHolder" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WindowStateHolder" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WindowStateHolder\" != nullptr" " (" "Must specify a name"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WindowStateHolder\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1865; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("WindowStateHolder" " not thread-safe"); const
char* const nametmp = "WindowStateHolder"; nsrefcnt count = --
mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult WindowStateHolder::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1865); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<WindowStateHolder, WindowStateHolder>
, int32_t( reinterpret_cast<char*>(static_cast<WindowStateHolder
*>((WindowStateHolder*)0x1000)) - reinterpret_cast<char
*>((WindowStateHolder*)0x1000))}, {&mozilla::detail::kImplementedIID
<WindowStateHolder, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
WindowStateHolder*>((WindowStateHolder*)0x1000))) - reinterpret_cast
<char*>((WindowStateHolder*)0x1000))}, { nullptr, 0 } }
; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
1866
1867bool nsGlobalWindowOuter::ComputeIsSecureContext(Document* aDocument,
1868 SecureContextFlags aFlags) {
1869 nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
1870 if (principal->IsSystemPrincipal()) {
1871 return true;
1872 }
1873
1874 // Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object
1875 // With some modifications to allow for aFlags.
1876
1877 bool hadNonSecureContextCreator = false;
1878
1879 if (WindowContext* parentWindow =
1880 GetBrowsingContext()->GetParentWindowContext()) {
1881 hadNonSecureContextCreator = !parentWindow->GetIsSecureContext();
1882 }
1883
1884 if (hadNonSecureContextCreator) {
1885 return false;
1886 }
1887
1888 if (nsContentUtils::HttpsStateIsModern(aDocument)) {
1889 return true;
1890 }
1891
1892 if (principal->GetIsNullPrincipal()) {
1893 // If the NullPrincipal has a valid precursor URI we want to use it to
1894 // construct the principal otherwise we fall back to the original document
1895 // URI.
1896 nsCOMPtr<nsIPrincipal> precursorPrin = principal->GetPrecursorPrincipal();
1897 nsCOMPtr<nsIURI> uri = precursorPrin ? precursorPrin->GetURI() : nullptr;
1898 if (!uri) {
1899 uri = aDocument->GetOriginalURI();
1900 }
1901 // IsOriginPotentiallyTrustworthy doesn't care about origin attributes so
1902 // it doesn't actually matter what we use here, but reusing the document
1903 // principal's attributes is convenient.
1904 const OriginAttributes& attrs = principal->OriginAttributesRef();
1905 // CreateContentPrincipal correctly gets a useful principal for blob: and
1906 // other URI_INHERITS_SECURITY_CONTEXT URIs.
1907 principal = BasePrincipal::CreateContentPrincipal(uri, attrs);
1908 if (NS_WARN_IF(!principal)NS_warn_if_impl(!principal, "!principal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1908)
) {
1909 return false;
1910 }
1911 }
1912
1913 return principal->GetIsOriginPotentiallyTrustworthy();
1914}
1915
1916static bool InitializeLegacyNetscapeObject(JSContext* aCx,
1917 JS::Handle<JSObject*> aGlobal) {
1918 JSAutoRealm ar(aCx, aGlobal);
1919
1920 // Note: MathJax depends on window.netscape being exposed. See bug 791526.
1921 JS::Rooted<JSObject*> obj(aCx);
1922 obj = JS_DefineObject(aCx, aGlobal, "netscape", nullptr);
1923 NS_ENSURE_TRUE(obj, false)do { if ((__builtin_expect(!!(!(obj)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "obj" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1923); return false; } } while (false)
;
1924
1925 obj = JS_DefineObject(aCx, obj, "security", nullptr);
1926 NS_ENSURE_TRUE(obj, false)do { if ((__builtin_expect(!!(!(obj)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "obj" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1926); return false; } } while (false)
;
1927
1928 return true;
1929}
1930
1931struct MOZ_STACK_CLASS CompartmentFinderState {
1932 explicit CompartmentFinderState(nsIPrincipal* aPrincipal)
1933 : principal(aPrincipal), compartment(nullptr) {}
1934
1935 // Input: we look for a compartment which is same-origin with the
1936 // given principal.
1937 nsIPrincipal* principal;
1938
1939 // Output: We set this member if we find a compartment.
1940 JS::Compartment* compartment;
1941};
1942
1943static JS::CompartmentIterResult FindSameOriginCompartment(
1944 JSContext* aCx, void* aData, JS::Compartment* aCompartment) {
1945 auto* data = static_cast<CompartmentFinderState*>(aData);
1946 MOZ_ASSERT(!data->compartment, "Why are we getting called?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!data->compartment)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!data->compartment))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!data->compartment"
" (" "Why are we getting called?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!data->compartment"
") (" "Why are we getting called?" ")"); do { *((volatile int
*)__null) = 1946; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1947
1948 // If this compartment is not safe to share across globals, don't do
1949 // anything with it; in particular we should not be getting a
1950 // CompartmentPrivate from such a compartment, because it may be in
1951 // the middle of being collected and its CompartmentPrivate may no
1952 // longer be valid.
1953 if (!js::IsSharableCompartment(aCompartment)) {
1954 return JS::CompartmentIterResult::KeepGoing;
1955 }
1956
1957 auto* compartmentPrivate = xpc::CompartmentPrivate::Get(aCompartment);
1958 if (!compartmentPrivate->CanShareCompartmentWith(data->principal)) {
1959 // Can't reuse this one, keep going.
1960 return JS::CompartmentIterResult::KeepGoing;
1961 }
1962
1963 // We have a winner!
1964 data->compartment = aCompartment;
1965 return JS::CompartmentIterResult::Stop;
1966}
1967
1968static JS::RealmCreationOptions& SelectZone(
1969 JSContext* aCx, nsIPrincipal* aPrincipal, nsGlobalWindowInner* aNewInner,
1970 JS::RealmCreationOptions& aOptions) {
1971 // Use the shared system compartment for chrome windows.
1972 if (aPrincipal->IsSystemPrincipal()) {
1973 return aOptions.setExistingCompartment(xpc::PrivilegedJunkScope());
1974 }
1975
1976 BrowsingContext* bc = aNewInner->GetBrowsingContext();
1977 if (bc->IsTop()) {
1978 // We're a toplevel load. Use a new zone. This way, when we do
1979 // zone-based compartment sharing we won't share compartments
1980 // across navigations.
1981 return aOptions.setNewCompartmentAndZone();
1982 }
1983
1984 // Find the in-process ancestor highest in the hierarchy.
1985 nsGlobalWindowInner* ancestor = nullptr;
1986 for (WindowContext* wc = bc->GetParentWindowContext(); wc;
1987 wc = wc->GetParentWindowContext()) {
1988 if (nsGlobalWindowInner* win = wc->GetInnerWindow()) {
1989 ancestor = win;
1990 }
1991 }
1992
1993 // If we have an ancestor window, use its zone.
1994 if (ancestor && ancestor->GetGlobalJSObject()) {
1995 JS::Zone* zone = JS::GetObjectZone(ancestor->GetGlobalJSObject());
1996 // Now try to find an existing compartment that's same-origin
1997 // with our principal.
1998 CompartmentFinderState data(aPrincipal);
1999 JS_IterateCompartmentsInZone(aCx, zone, &data, FindSameOriginCompartment);
2000 if (data.compartment) {
2001 return aOptions.setExistingCompartment(data.compartment);
2002 }
2003 return aOptions.setNewCompartmentInExistingZone(
2004 ancestor->GetGlobalJSObject());
2005 }
2006
2007 return aOptions.setNewCompartmentAndZone();
2008}
2009
2010/**
2011 * Create a new global object that will be used for an inner window.
2012 * Return the native global and an nsISupports 'holder' that can be used
2013 * to manage the lifetime of it.
2014 */
2015static nsresult CreateNativeGlobalForInner(
2016 JSContext* aCx, nsGlobalWindowInner* aNewInner, Document* aDocument,
2017 JS::MutableHandle<JSObject*> aGlobal, bool aIsSecureContext,
2018 bool aDefineSharedArrayBufferConstructor) {
2019 MOZ_ASSERT(aCx)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aCx)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aCx))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aCx", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCx" ")"); do
{ *((volatile int*)__null) = 2019; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2020 MOZ_ASSERT(aNewInner)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewInner)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewInner))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNewInner", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewInner" ")"
); do { *((volatile int*)__null) = 2020; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2021
2022 nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI();
2023 nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
2024 MOZ_ASSERT(principal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(principal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(principal))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("principal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2024); AnnotateMozCrashReason("MOZ_ASSERT" "(" "principal" ")"
); do { *((volatile int*)__null) = 2024; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2025
2026 // DOMWindow with nsEP is not supported, we have to make sure
2027 // no one creates one accidentally.
2028 nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(principal);
2029 MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!nsEP)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(!nsEP))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("!nsEP" " (" "DOMWindow with nsEP is not supported"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2029); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!nsEP"
") (" "DOMWindow with nsEP is not supported" ")"); do { *((volatile
int*)__null) = 2029; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2030
2031 JS::RealmOptions options;
2032 JS::RealmCreationOptions& creationOptions = options.creationOptions();
2033
2034 SelectZone(aCx, principal, aNewInner, creationOptions);
2035
2036 // Define the SharedArrayBuffer global constructor property only if shared
2037 // memory may be used and structured-cloned (e.g. through postMessage).
2038 //
2039 // When the global constructor property isn't defined, the SharedArrayBuffer
2040 // constructor can still be reached through Web Assembly. Omitting the global
2041 // property just prevents feature-tests from being misled. See bug 1624266.
2042 creationOptions.setDefineSharedArrayBufferConstructor(
2043 aDefineSharedArrayBufferConstructor);
2044
2045 xpc::InitGlobalObjectOptions(
2046 options, principal->IsSystemPrincipal(), aIsSecureContext,
2047 aDocument->ShouldResistFingerprinting(RFPTarget::JSDateTimeUTC),
2048 aDocument->ShouldResistFingerprinting(RFPTarget::JSMathFdlibm),
2049 aDocument->ShouldResistFingerprinting(RFPTarget::JSLocale));
2050
2051 // Determine if we need the Components object.
2052 bool needComponents = principal->IsSystemPrincipal();
2053 uint32_t flags = needComponents ? 0 : xpc::OMIT_COMPONENTS_OBJECT;
2054 flags |= xpc::DONT_FIRE_ONNEWGLOBALHOOK;
2055
2056 if (!Window_Binding::Wrap(aCx, aNewInner, aNewInner, options,
2057 nsJSPrincipals::get(principal), aGlobal) ||
2058 !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
2059 return NS_ERROR_FAILURE;
2060 }
2061
2062 MOZ_ASSERT(aNewInner->GetWrapperPreserveColor() == aGlobal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewInner->GetWrapperPreserveColor() == aGlobal)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aNewInner->GetWrapperPreserveColor() == aGlobal))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aNewInner->GetWrapperPreserveColor() == aGlobal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewInner->GetWrapperPreserveColor() == aGlobal"
")"); do { *((volatile int*)__null) = 2062; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2063
2064 // Set the location information for the new global, so that tools like
2065 // about:memory may use that information
2066 xpc::SetLocationForGlobal(aGlobal, uri);
2067
2068 if (!InitializeLegacyNetscapeObject(aCx, aGlobal)) {
2069 return NS_ERROR_FAILURE;
2070 }
2071
2072 return NS_OK;
2073}
2074
2075nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
2076 nsISupports* aState,
2077 bool aForceReuseInnerWindow,
2078 WindowGlobalChild* aActor) {
2079 MOZ_ASSERT(mDocumentPrincipal == nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentPrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentPrincipal == nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDocumentPrincipal == nullptr" " (" "mDocumentPrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPrincipal == nullptr"
") (" "mDocumentPrincipal prematurely set!" ")"); do { *((volatile
int*)__null) = 2080; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
2080 "mDocumentPrincipal prematurely set!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentPrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentPrincipal == nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDocumentPrincipal == nullptr" " (" "mDocumentPrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPrincipal == nullptr"
") (" "mDocumentPrincipal prematurely set!" ")"); do { *((volatile
int*)__null) = 2080; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2081 MOZ_ASSERT(mDocumentCookiePrincipal == nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentCookiePrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentCookiePrincipal == nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDocumentCookiePrincipal == nullptr" " (" "mDocumentCookiePrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentCookiePrincipal == nullptr"
") (" "mDocumentCookiePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2082; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2082 "mDocumentCookiePrincipal prematurely set!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentCookiePrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentCookiePrincipal == nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mDocumentCookiePrincipal == nullptr" " (" "mDocumentCookiePrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentCookiePrincipal == nullptr"
") (" "mDocumentCookiePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2082; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2083 MOZ_ASSERT(mDocumentStoragePrincipal == nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentStoragePrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentStoragePrincipal ==
nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDocumentStoragePrincipal == nullptr" " (" "mDocumentStoragePrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2084); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentStoragePrincipal == nullptr"
") (" "mDocumentStoragePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2084; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2084 "mDocumentStoragePrincipal prematurely set!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentStoragePrincipal == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocumentStoragePrincipal ==
nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDocumentStoragePrincipal == nullptr" " (" "mDocumentStoragePrincipal prematurely set!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2084); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentStoragePrincipal == nullptr"
") (" "mDocumentStoragePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2084; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2085 MOZ_ASSERT(mDocumentPartitionedPrincipal == nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentPartitionedPrincipal == nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mDocumentPartitionedPrincipal == nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mDocumentPartitionedPrincipal == nullptr"
" (" "mDocumentPartitionedPrincipal prematurely set!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPartitionedPrincipal == nullptr"
") (" "mDocumentPartitionedPrincipal prematurely set!" ")");
do { *((volatile int*)__null) = 2086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2086 "mDocumentPartitionedPrincipal prematurely set!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocumentPartitionedPrincipal == nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mDocumentPartitionedPrincipal == nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mDocumentPartitionedPrincipal == nullptr"
" (" "mDocumentPartitionedPrincipal prematurely set!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPartitionedPrincipal == nullptr"
") (" "mDocumentPartitionedPrincipal prematurely set!" ")");
do { *((volatile int*)__null) = 2086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2087 MOZ_ASSERT(aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocument))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2087); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")"
); do { *((volatile int*)__null) = 2087; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2088
2089 // Bail out early if we're in process of closing down the window.
2090 NS_ENSURE_STATE(!mCleanedUp)do { if ((__builtin_expect(!!(!(!mCleanedUp)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!mCleanedUp" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2090); return NS_ERROR_UNEXPECTED; } } while (false)
;
2091
2092 NS_ASSERTION(!GetCurrentInnerWindow() ||do { if (!(!GetCurrentInnerWindow() || GetCurrentInnerWindow(
)->GetExtantDoc() == mDoc)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Uh, mDoc doesn't match the current inner window " "document!"
, "!GetCurrentInnerWindow() || GetCurrentInnerWindow()->GetExtantDoc() == mDoc"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2095); MOZ_PretendNoReturn(); } } while (0)
2093 GetCurrentInnerWindow()->GetExtantDoc() == mDoc,do { if (!(!GetCurrentInnerWindow() || GetCurrentInnerWindow(
)->GetExtantDoc() == mDoc)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Uh, mDoc doesn't match the current inner window " "document!"
, "!GetCurrentInnerWindow() || GetCurrentInnerWindow()->GetExtantDoc() == mDoc"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2095); MOZ_PretendNoReturn(); } } while (0)
2094 "Uh, mDoc doesn't match the current inner window "do { if (!(!GetCurrentInnerWindow() || GetCurrentInnerWindow(
)->GetExtantDoc() == mDoc)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Uh, mDoc doesn't match the current inner window " "document!"
, "!GetCurrentInnerWindow() || GetCurrentInnerWindow()->GetExtantDoc() == mDoc"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2095); MOZ_PretendNoReturn(); } } while (0)
2095 "document!")do { if (!(!GetCurrentInnerWindow() || GetCurrentInnerWindow(
)->GetExtantDoc() == mDoc)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Uh, mDoc doesn't match the current inner window " "document!"
, "!GetCurrentInnerWindow() || GetCurrentInnerWindow()->GetExtantDoc() == mDoc"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2095); MOZ_PretendNoReturn(); } } while (0)
;
2096 bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
2097 if (aForceReuseInnerWindow && !wouldReuseInnerWindow && mDoc &&
2098 mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
2099 NS_ERROR("Attempted forced inner window reuse while changing principal")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Attempted forced inner window reuse while changing principal"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2099); MOZ_PretendNoReturn(); } while (0)
;
2100 return NS_ERROR_UNEXPECTED;
2101 }
2102
2103 if (!mBrowsingContext->AncestorsAreCurrent()) {
2104 return NS_ERROR_NOT_AVAILABLE;
2105 }
2106
2107 RefPtr<Document> oldDoc = mDoc;
2108 MOZ_RELEASE_ASSERT(oldDoc != aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(oldDoc != aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(oldDoc != aDocument))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("oldDoc != aDocument"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2108); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "oldDoc != aDocument"
")"); do { *((volatile int*)__null) = 2108; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2109
2110 AutoJSAPI jsapi;
2111 jsapi.Init();
2112 JSContext* cx = jsapi.cx();
2113
2114 // Check if we're anywhere near the stack limit before we reach the
2115 // transplanting code, since it has no good way to handle errors. This uses
2116 // the untrusted script limit, which is not strictly necessary since no
2117 // actual script should run.
2118 js::AutoCheckRecursionLimit recursion(cx);
2119 if (!recursion.checkConservativeDontReport(cx)) {
2120 NS_WARNING("Overrecursion in SetNewDocument")NS_DebugBreak(NS_DEBUG_WARNING, "Overrecursion in SetNewDocument"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2120)
;
2121 return NS_ERROR_FAILURE;
2122 }
2123
2124 if (!mDoc) {
2125 // First document load.
2126
2127 // Get our private root. If it is equal to us, then we need to
2128 // attach our global key bindings that handles browser scrolling
2129 // and other browser commands.
2130 nsPIDOMWindowOuter* privateRoot = GetPrivateRoot();
2131
2132 if (privateRoot == this) {
2133 RootWindowGlobalKeyListener::AttachKeyHandler(mChromeEventHandler);
2134 }
2135 }
2136
2137 MaybeResetWindowName(aDocument);
2138
2139 /* No mDocShell means we're already been partially closed down. When that
2140 happens, setting status isn't a big requirement, so don't. (Doesn't happen
2141 under normal circumstances, but bug 49615 describes a case.) */
2142
2143 nsContentUtils::AddScriptRunner(
2144 NewRunnableMethod("nsGlobalWindowOuter::ClearStatus", this,
2145 &nsGlobalWindowOuter::ClearStatus));
2146
2147 // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner
2148 // window (see bug 776497). Be safe.
2149 bool reUseInnerWindow = (aForceReuseInnerWindow || wouldReuseInnerWindow) &&
2150 GetCurrentInnerWindowInternal(this);
2151
2152 nsresult rv;
2153
2154 // We set mDoc even though this is an outer window to avoid
2155 // having to *always* reach into the inner window to find the
2156 // document.
2157 mDoc = aDocument;
2158
2159 nsDocShell::Cast(mDocShell)->MaybeRestoreWindowName();
2160
2161 // We drop the print request for the old document on the floor, it never made
2162 // it. We don't close the window here either even if we were asked to.
2163 mShouldDelayPrintUntilAfterLoad = true;
2164 mDelayedCloseForPrinting = false;
2165 mDelayedPrintUntilAfterLoad = false;
2166
2167 // Take this opportunity to clear mSuspendedDocs. Our old inner window is now
2168 // responsible for unsuspending it.
2169 mSuspendedDocs.Clear();
2170
2171#ifdef DEBUG1
2172 mLastOpenedURI = aDocument->GetDocumentURI();
2173#endif
2174
2175 RefPtr<nsGlobalWindowInner> currentInner =
2176 GetCurrentInnerWindowInternal(this);
2177
2178 if (currentInner && currentInner->mNavigator) {
2179 currentInner->mNavigator->OnNavigation();
2180 }
2181
2182 RefPtr<nsGlobalWindowInner> newInnerWindow;
2183 bool createdInnerWindow = false;
2184
2185 bool thisChrome = IsChromeWindow();
2186
2187 nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
2188 NS_ASSERTION(!aState || wsh,do { if (!(!aState || wsh)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "What kind of weird state are you giving me here?", "!aState || wsh"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2189); MOZ_PretendNoReturn(); } } while (0)
2189 "What kind of weird state are you giving me here?")do { if (!(!aState || wsh)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "What kind of weird state are you giving me here?", "!aState || wsh"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2189); MOZ_PretendNoReturn(); } } while (0)
;
2190
2191 bool doomCurrentInner = false;
2192
2193 // Only non-gray (i.e. exposed to JS) objects should be assigned to
2194 // newInnerGlobal.
2195 JS::Rooted<JSObject*> newInnerGlobal(cx);
2196 if (reUseInnerWindow) {
2197 // We're reusing the current inner window.
2198 NS_ASSERTION(!currentInner->IsFrozen(),do { if (!(!currentInner->IsFrozen())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We should never be reusing a shared inner window", "!currentInner->IsFrozen()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2199); MOZ_PretendNoReturn(); } } while (0)
2199 "We should never be reusing a shared inner window")do { if (!(!currentInner->IsFrozen())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We should never be reusing a shared inner window", "!currentInner->IsFrozen()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2199); MOZ_PretendNoReturn(); } } while (0)
;
2200 newInnerWindow = currentInner;
2201 newInnerGlobal = currentInner->GetWrapper();
2202
2203 // We're reusing the inner window, but this still counts as a navigation,
2204 // so all expandos and such defined on the outer window should go away.
2205 // Force all Xray wrappers to be recomputed.
2206 JS::Rooted<JSObject*> rootedObject(cx, GetWrapper());
2207 if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
2208 return NS_ERROR_FAILURE;
2209 }
2210
2211 // Inner windows are only reused for same-origin principals, but the
2212 // principals don't necessarily match exactly. Update the principal on the
2213 // realm to match the new document. NB: We don't just call
2214 // currentInner->RefreshRealmPrincipals() here because we haven't yet set
2215 // its mDoc to aDocument.
2216 JS::Realm* realm = js::GetNonCCWObjectRealm(newInnerGlobal);
2217#ifdef DEBUG1
2218 bool sameOrigin = false;
2219 nsIPrincipal* existing = nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
2220 aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
2221 MOZ_ASSERT(sameOrigin)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sameOrigin)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sameOrigin))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("sameOrigin", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sameOrigin"
")"); do { *((volatile int*)__null) = 2221; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2222#endif
2223 JS::SetRealmPrincipals(realm,
2224 nsJSPrincipals::get(aDocument->NodePrincipal()));
2225 } else {
2226 if (aState) {
2227 newInnerWindow = wsh->GetInnerWindow();
2228 newInnerGlobal = newInnerWindow->GetWrapper();
2229 } else {
2230 newInnerWindow = nsGlobalWindowInner::Create(this, thisChrome, aActor);
2231 if (StaticPrefs::dom_timeout_defer_during_load()) {
2232 // ensure the initial loading state is known
2233 newInnerWindow->SetActiveLoadingState(
2234 aDocument->GetReadyStateEnum() ==
2235 Document::ReadyState::READYSTATE_LOADING);
2236 }
2237
2238 // The outer window is automatically treated as frozen when we
2239 // null out the inner window. As a result, initializing classes
2240 // on the new inner won't end up reaching into the old inner
2241 // window for classes etc.
2242 //
2243 // [This happens with Object.prototype when XPConnect creates
2244 // a temporary global while initializing classes; the reason
2245 // being that xpconnect creates the temp global w/o a parent
2246 // and proto, which makes the JS engine look up classes in
2247 // cx->globalObject, i.e. this outer window].
2248
2249 mInnerWindow = nullptr;
2250
2251 mCreatingInnerWindow = true;
2252
2253 // The SharedArrayBuffer global constructor property should not be present
2254 // in a fresh global object when shared memory objects aren't allowed
2255 // (because COOP/COEP support isn't enabled, or because COOP/COEP don't
2256 // act to isolate this page to a separate process).
2257
2258 // Every script context we are initialized with must create a
2259 // new global.
2260 rv = CreateNativeGlobalForInner(
2261 cx, newInnerWindow, aDocument, &newInnerGlobal,
2262 ComputeIsSecureContext(aDocument),
2263 newInnerWindow->IsSharedMemoryAllowedInternal(
2264 aDocument->NodePrincipal()));
2265 NS_ASSERTION(do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor
() == newInnerGlobal)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to get script global"
, "NS_SUCCEEDED(rv) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2268); MOZ_PretendNoReturn(); } } while (0)
2266 NS_SUCCEEDED(rv) && newInnerGlobal &&do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor
() == newInnerGlobal)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to get script global"
, "NS_SUCCEEDED(rv) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2268); MOZ_PretendNoReturn(); } } while (0)
2267 newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor
() == newInnerGlobal)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to get script global"
, "NS_SUCCEEDED(rv) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2268); MOZ_PretendNoReturn(); } } while (0)
2268 "Failed to get script global")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor
() == newInnerGlobal)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to get script global"
, "NS_SUCCEEDED(rv) && newInnerGlobal && newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2268); MOZ_PretendNoReturn(); } } while (0)
;
2269
2270 mCreatingInnerWindow = false;
2271 createdInnerWindow = true;
2272
2273 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2273); return rv; } } while (false)
;
2274 }
2275
2276 if (currentInner && currentInner->GetWrapperPreserveColor()) {
2277 // Don't free objects on our current inner window if it's going to be
2278 // held in the bfcache.
2279 if (!currentInner->IsFrozen()) {
2280 doomCurrentInner = true;
2281 }
2282 }
2283
2284 mInnerWindow = newInnerWindow;
2285 MOZ_ASSERT(mInnerWindow)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mInnerWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mInnerWindow))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mInnerWindow", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mInnerWindow"
")"); do { *((volatile int*)__null) = 2285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2286 mInnerWindow->TryToCacheTopInnerWindow();
2287
2288 if (!GetWrapperPreserveColor()) {
2289 JS::Rooted<JSObject*> outer(
2290 cx, NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
2291 NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(outer)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "outer" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2291); return NS_ERROR_FAILURE; } } while (false)
;
2292
2293 mBrowsingContext->CleanUpDanglingRemoteOuterWindowProxies(cx, &outer);
2294 MOZ_ASSERT(js::IsWindowProxy(outer))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(js::IsWindowProxy(outer))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsWindowProxy(outer)))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("js::IsWindowProxy(outer)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2294); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(outer)"
")"); do { *((volatile int*)__null) = 2294; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2295
2296 js::SetProxyReservedSlot(outer, OUTER_WINDOW_SLOT,
2297 JS::PrivateValue(ToSupports(this)));
2298
2299 // Inform the nsJSContext, which is the canonical holder of the outer.
2300 mContext->SetWindowProxy(outer);
2301
2302 SetWrapper(mContext->GetWindowProxy());
2303 } else {
2304 JS::Rooted<JSObject*> outerObject(
2305 cx, NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
2306 if (!outerObject) {
2307 NS_ERROR("out of memory")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "out of memory", "Error"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2307); MOZ_PretendNoReturn(); } while (0)
;
2308 return NS_ERROR_FAILURE;
2309 }
2310
2311 JS::Rooted<JSObject*> obj(cx, GetWrapper());
2312
2313 MOZ_ASSERT(js::IsWindowProxy(obj))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(js::IsWindowProxy(obj))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsWindowProxy(obj)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("js::IsWindowProxy(obj)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(obj)"
")"); do { *((volatile int*)__null) = 2313; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2314
2315 js::SetProxyReservedSlot(obj, OUTER_WINDOW_SLOT,
2316 JS::PrivateValue(nullptr));
2317 js::SetProxyReservedSlot(outerObject, OUTER_WINDOW_SLOT,
2318 JS::PrivateValue(nullptr));
2319 js::SetProxyReservedSlot(obj, HOLDER_WEAKMAP_SLOT, JS::UndefinedValue());
2320
2321 outerObject = xpc::TransplantObjectNukingXrayWaiver(cx, obj, outerObject);
2322
2323 if (!outerObject) {
2324 mBrowsingContext->ClearWindowProxy();
2325 NS_ERROR("unable to transplant wrappers, probably OOM")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "unable to transplant wrappers, probably OOM"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2325); MOZ_PretendNoReturn(); } while (0)
;
2326 return NS_ERROR_FAILURE;
2327 }
2328
2329 js::SetProxyReservedSlot(outerObject, OUTER_WINDOW_SLOT,
2330 JS::PrivateValue(ToSupports(this)));
2331
2332 SetWrapper(outerObject);
2333
2334 MOZ_ASSERT(JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2334); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal"
")"); do { *((volatile int*)__null) = 2334; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2335
2336 // Inform the nsJSContext, which is the canonical holder of the outer.
2337 mContext->SetWindowProxy(outerObject);
2338 }
2339
2340 // Enter the new global's realm.
2341 JSAutoRealm ar(cx, GetWrapperPreserveColor());
2342
2343 {
2344 JS::Rooted<JSObject*> outer(cx, GetWrapperPreserveColor());
2345 js::SetWindowProxy(cx, newInnerGlobal, outer);
2346 mBrowsingContext->SetWindowProxy(outer);
2347 }
2348
2349 // Set scriptability based on the state of the WindowContext.
2350 WindowContext* wc = mInnerWindow->GetWindowContext();
2351 bool allow =
2352 wc ? wc->CanExecuteScripts() : mBrowsingContext->CanExecuteScripts();
2353 xpc::Scriptability::Get(GetWrapperPreserveColor())
2354 .SetWindowAllowsScript(allow);
2355
2356 if (!aState) {
2357 // Get the "window" property once so it will be cached on our inner. We
2358 // have to do this here, not in binding code, because this has to happen
2359 // after we've created the outer window proxy and stashed it in the outer
2360 // nsGlobalWindowOuter, so GetWrapperPreserveColor() on that outer
2361 // nsGlobalWindowOuter doesn't return null and
2362 // nsGlobalWindowOuter::OuterObject works correctly.
2363 JS::Rooted<JS::Value> unused(cx);
2364 if (!JS_GetProperty(cx, newInnerGlobal, "window", &unused)) {
2365 NS_ERROR("can't create the 'window' property")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "can't create the 'window' property"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2365); MOZ_PretendNoReturn(); } while (0)
;
2366 return NS_ERROR_FAILURE;
2367 }
2368
2369 // And same thing for the "self" property.
2370 if (!JS_GetProperty(cx, newInnerGlobal, "self", &unused)) {
2371 NS_ERROR("can't create the 'self' property")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "can't create the 'self' property"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2371); MOZ_PretendNoReturn(); } while (0)
;
2372 return NS_ERROR_FAILURE;
2373 }
2374 }
2375 }
2376
2377 JSAutoRealm ar(cx, GetWrapperPreserveColor());
2378
2379 if (!aState && !reUseInnerWindow) {
2380 // Loading a new page and creating a new inner window, *not*
2381 // restoring from session history.
2382
2383 // Now that both the the inner and outer windows are initialized
2384 // let the script context do its magic to hook them together.
2385 MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mContext->GetWindowProxy() == GetWrapperPreserveColor
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mContext->GetWindowProxy() == GetWrapperPreserveColor
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mContext->GetWindowProxy() == GetWrapperPreserveColor()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2385); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mContext->GetWindowProxy() == GetWrapperPreserveColor()"
")"); do { *((volatile int*)__null) = 2385; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2386#ifdef DEBUG1
2387 JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
2388 JS::Rooted<JSObject*> proto1(cx), proto2(cx);
2389 JS_GetPrototype(cx, rootedJSObject, &proto1);
2390 JS_GetPrototype(cx, newInnerGlobal, &proto2);
2391 NS_ASSERTION(proto1 == proto2,do { if (!(proto1 == proto2)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "outer and inner globals should have the same prototype", "proto1 == proto2"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2392); MOZ_PretendNoReturn(); } } while (0)
2392 "outer and inner globals should have the same prototype")do { if (!(proto1 == proto2)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "outer and inner globals should have the same prototype", "proto1 == proto2"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2392); MOZ_PretendNoReturn(); } } while (0)
;
2393#endif
2394
2395 mInnerWindow->SyncStateFromParentWindow();
2396 }
2397
2398 // Add an extra ref in case we release mContext during GC.
2399 nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
2400
2401 // Make sure the inner's document is set correctly before we call
2402 // SetScriptGlobalObject, because that might try to examine document-dependent
2403 // state. Unfortunately, we can't do some of the other clearing/resetting
2404 // work we do below until after SetScriptGlobalObject(), because it might
2405 // depend on the document having the right scope object.
2406 if (aState) {
2407 MOZ_RELEASE_ASSERT(newInnerWindow->mDoc == aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newInnerWindow->mDoc == aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newInnerWindow->mDoc == aDocument
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"newInnerWindow->mDoc == aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2407); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc == aDocument"
")"); do { *((volatile int*)__null) = 2407; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2408 } else {
2409 if (reUseInnerWindow) {
2410 MOZ_RELEASE_ASSERT(newInnerWindow->mDoc != aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newInnerWindow->mDoc != aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newInnerWindow->mDoc != aDocument
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"newInnerWindow->mDoc != aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2410); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc != aDocument"
")"); do { *((volatile int*)__null) = 2410; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2411 }
2412 newInnerWindow->mDoc = aDocument;
2413 }
2414
2415 aDocument->SetScriptGlobalObject(newInnerWindow);
2416
2417 MOZ_RELEASE_ASSERT(newInnerWindow->mDoc == aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newInnerWindow->mDoc == aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newInnerWindow->mDoc == aDocument
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"newInnerWindow->mDoc == aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2417); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc == aDocument"
")"); do { *((volatile int*)__null) = 2417; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2418
2419 if (mBrowsingContext->IsTopContent()) {
2420 net::CookieJarSettings::Cast(aDocument->CookieJarSettings())
2421 ->SetTopLevelWindowContextId(aDocument->InnerWindowID());
2422 }
2423
2424 newInnerWindow->RefreshReduceTimerPrecisionCallerType();
2425
2426 if (!aState) {
2427 if (reUseInnerWindow) {
2428 // The StorageAccess state may have changed. Invalidate the cached
2429 // StorageAllowed field, so that the next call to StorageAllowedForWindow
2430 // recomputes it.
2431 newInnerWindow->ClearStorageAllowedCache();
2432
2433 // The storage objects contain the URL of the window. We have to
2434 // recreate them when the innerWindow is reused.
2435 newInnerWindow->mLocalStorage = nullptr;
2436 newInnerWindow->mSessionStorage = nullptr;
2437 newInnerWindow->mPerformance = nullptr;
2438
2439 // This must be called after nullifying the internal objects because
2440 // here we could recreate them, calling the getter methods, and store
2441 // them into the JS slots. If we nullify them after, the slot values and
2442 // the objects will be out of sync.
2443 newInnerWindow->ClearDocumentDependentSlots(cx);
2444 } else {
2445 newInnerWindow->InitDocumentDependentState(cx);
2446
2447 // Initialize DOM classes etc on the inner window.
2448 JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
2449 rv = kungFuDeathGrip->InitClasses(obj);
2450 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2450); return rv; } } while (false)
;
2451 }
2452
2453 // When replacing an initial about:blank document we call
2454 // ExecutionReady again to update the client creation URL.
2455 rv = newInnerWindow->ExecutionReady();
2456 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2456); return rv; } } while (false)
;
2457
2458 if (mArguments) {
2459 newInnerWindow->DefineArgumentsProperty(mArguments);
2460 mArguments = nullptr;
2461 }
2462
2463 // Give the new inner window our chrome event handler (since it
2464 // doesn't have one).
2465 newInnerWindow->mChromeEventHandler = mChromeEventHandler;
2466 }
2467
2468 if (!aState && reUseInnerWindow) {
2469 // Notify our WindowGlobalChild that it has a new document. If `aState` was
2470 // passed, we're restoring the window from the BFCache, so the document
2471 // hasn't changed.
2472 // If we didn't have a window global child before, then initializing
2473 // it will have set all the required state, so we don't need to do
2474 // it again.
2475 mInnerWindow->GetWindowGlobalChild()->OnNewDocument(aDocument);
2476 }
2477
2478 // Update the current window for our BrowsingContext.
2479 RefPtr<BrowsingContext> bc = GetBrowsingContext();
2480
2481 if (bc->IsOwnedByProcess()) {
2482 MOZ_ALWAYS_SUCCEEDS(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))
), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash
("" "NS_SUCCEEDED(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2482); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))"
")"); do { *((volatile int*)__null) = 2482; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
2483 }
2484
2485 // We no longer need the old inner window. Start its destruction if
2486 // its not being reused and clear our reference.
2487 if (doomCurrentInner) {
2488 currentInner->FreeInnerObjects();
2489 }
2490 currentInner = nullptr;
2491
2492 // We wait to fire the debugger hook until the window is all set up and hooked
2493 // up with the outer. See bug 969156.
2494 if (createdInnerWindow) {
2495 nsContentUtils::AddScriptRunner(NewRunnableMethod(
2496 "nsGlobalWindowInner::FireOnNewGlobalObject", newInnerWindow,
2497 &nsGlobalWindowInner::FireOnNewGlobalObject));
2498 }
2499
2500 if (!newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
2501 // We should probably notify. However if this is the, arguably bad,
2502 // situation when we're creating a temporary non-chrome-about-blank
2503 // document in a chrome docshell, don't notify just yet. Instead wait
2504 // until we have a real chrome doc.
2505 const bool isContentAboutBlankInChromeDocshell = [&] {
2506 if (!mDocShell) {
2507 return false;
2508 }
2509
2510 RefPtr<BrowsingContext> bc = mDocShell->GetBrowsingContext();
2511 if (!bc || bc->GetType() != BrowsingContext::Type::Chrome) {
2512 return false;
2513 }
2514
2515 return !mDoc->NodePrincipal()->IsSystemPrincipal();
2516 }();
2517
2518 if (!isContentAboutBlankInChromeDocshell) {
2519 newInnerWindow->mHasNotifiedGlobalCreated = true;
2520 nsContentUtils::AddScriptRunner(NewRunnableMethod(
2521 "nsGlobalWindowOuter::DispatchDOMWindowCreated", this,
2522 &nsGlobalWindowOuter::DispatchDOMWindowCreated));
2523 }
2524 }
2525
2526 PreloadLocalStorage();
2527
2528 // Do this here rather than in say the Document constructor, since
2529 // we need a WindowContext available.
2530 mDoc->InitUseCounters();
2531
2532 return NS_OK;
2533}
2534
2535/* static */
2536void nsGlobalWindowOuter::PrepareForProcessChange(JSObject* aProxy) {
2537 JS::Rooted<JSObject*> localProxy(RootingCx(), aProxy);
2538 MOZ_ASSERT(js::IsWindowProxy(localProxy))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(js::IsWindowProxy(localProxy))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(js::IsWindowProxy(localProxy
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("js::IsWindowProxy(localProxy)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(localProxy)"
")"); do { *((volatile int*)__null) = 2538; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2539
2540 RefPtr<nsGlobalWindowOuter> outerWindow =
2541 nsOuterWindowProxy::GetOuterWindow(localProxy);
2542 if (!outerWindow) {
2543 return;
2544 }
2545
2546 AutoJSAPI jsapi;
2547 jsapi.Init();
2548 JSContext* cx = jsapi.cx();
2549
2550 JSAutoRealm ar(cx, localProxy);
2551
2552 // Clear out existing references from the browsing context and outer window to
2553 // the proxy, and from the proxy to the outer window. These references will
2554 // become invalid once the proxy is transplanted. Clearing the window proxy
2555 // from the browsing context is also necessary to indicate that it is for an
2556 // out of process window.
2557 outerWindow->ClearWrapper(localProxy);
2558 RefPtr<BrowsingContext> bc = outerWindow->GetBrowsingContext();
2559 MOZ_ASSERT(bc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(bc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("bc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2559); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc" ")"); do
{ *((volatile int*)__null) = 2559; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2560 MOZ_ASSERT(bc->GetWindowProxy() == localProxy)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc->GetWindowProxy() == localProxy)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(bc->GetWindowProxy() == localProxy))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("bc->GetWindowProxy() == localProxy"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2560); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc->GetWindowProxy() == localProxy"
")"); do { *((volatile int*)__null) = 2560; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2561 bc->ClearWindowProxy();
2562 js::SetProxyReservedSlot(localProxy, OUTER_WINDOW_SLOT,
2563 JS::PrivateValue(nullptr));
2564 js::SetProxyReservedSlot(localProxy, HOLDER_WEAKMAP_SLOT,
2565 JS::UndefinedValue());
2566
2567 // Create a new remote outer window proxy, and transplant to it.
2568 JS::Rooted<JSObject*> remoteProxy(cx);
2569
2570 if (!mozilla::dom::GetRemoteOuterWindowProxy(cx, bc, localProxy,
2571 &remoteProxy)) {
2572 MOZ_CRASH("PrepareForProcessChange GetRemoteOuterWindowProxy")do { do { } while (false); MOZ_ReportCrash("" "PrepareForProcessChange GetRemoteOuterWindowProxy"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2572); AnnotateMozCrashReason("MOZ_CRASH(" "PrepareForProcessChange GetRemoteOuterWindowProxy"
")"); do { *((volatile int*)__null) = 2572; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2573 }
2574
2575 if (!xpc::TransplantObjectNukingXrayWaiver(cx, localProxy, remoteProxy)) {
2576 MOZ_CRASH("PrepareForProcessChange TransplantObject")do { do { } while (false); MOZ_ReportCrash("" "PrepareForProcessChange TransplantObject"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2576); AnnotateMozCrashReason("MOZ_CRASH(" "PrepareForProcessChange TransplantObject"
")"); do { *((volatile int*)__null) = 2576; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2577 }
2578}
2579
2580void nsGlobalWindowOuter::PreloadLocalStorage() {
2581 if (!Storage::StoragePrefIsEnabled()) {
2582 return;
2583 }
2584
2585 if (IsChromeWindow()) {
2586 return;
2587 }
2588
2589 nsIPrincipal* principal = GetPrincipal();
2590 nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
2591 if (!principal || !storagePrincipal) {
2592 return;
2593 }
2594
2595 nsresult rv;
2596
2597 nsCOMPtr<nsIDOMStorageManager> storageManager =
2598 do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
2599 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2600 return;
2601 }
2602
2603 // private browsing windows do not persist local storage to disk so we should
2604 // only try to precache storage when we're not a private browsing window.
2605 if (!principal->GetIsInPrivateBrowsing()) {
2606 RefPtr<Storage> storage;
2607 rv = storageManager->PrecacheStorage(principal, storagePrincipal,
2608 getter_AddRefs(storage));
2609 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2610 mLocalStorage = storage;
2611 }
2612 }
2613}
2614
2615void nsGlobalWindowOuter::DispatchDOMWindowCreated() {
2616 if (!mDoc) {
2617 return;
2618 }
2619
2620 // Fire DOMWindowCreated at chrome event listeners
2621 nsContentUtils::DispatchChromeEvent(mDoc, mDoc, u"DOMWindowCreated"_ns,
2622 CanBubble::eYes, Cancelable::eNo);
2623
2624 nsCOMPtr<nsIObserverService> observerService =
2625 mozilla::services::GetObserverService();
2626
2627 // The event dispatching could possibly cause docshell destory, and
2628 // consequently cause mDoc to be set to nullptr by DropOuterWindowDocs(),
2629 // so check it again here.
2630 if (observerService && mDoc) {
2631 nsAutoString origin;
2632 nsIPrincipal* principal = mDoc->NodePrincipal();
2633 nsContentUtils::GetWebExposedOriginSerialization(principal, origin);
2634 observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
2635 principal->IsSystemPrincipal()
2636 ? "chrome-document-global-created"
2637 : "content-document-global-created",
2638 origin.get());
2639 }
2640}
2641
2642void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); }
2643
2644void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) {
2645 MOZ_ASSERT(aDocShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocShell))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2645); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocShell" ")"
); do { *((volatile int*)__null) = 2645; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2646
2647 if (aDocShell == mDocShell) {
2648 return;
2649 }
2650
2651 mDocShell = aDocShell;
2652 mBrowsingContext = aDocShell->GetBrowsingContext();
2653
2654 RefPtr<BrowsingContext> parentContext = mBrowsingContext->GetParent();
2655
2656 MOZ_RELEASE_ASSERT(!parentContext ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!parentContext || GetBrowsingContextGroup() == parentContext
->Group())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!parentContext || GetBrowsingContextGroup
() == parentContext->Group()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2657); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
")"); do { *((volatile int*)__null) = 2657; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2657 GetBrowsingContextGroup() == parentContext->Group())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!parentContext || GetBrowsingContextGroup() == parentContext
->Group())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!parentContext || GetBrowsingContextGroup
() == parentContext->Group()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2657); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
")"); do { *((volatile int*)__null) = 2657; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2658
2659 mTopLevelOuterContentWindow = mBrowsingContext->IsTopContent();
2660
2661 // Get our enclosing chrome shell and retrieve its global window impl, so
2662 // that we can do some forwarding to the chrome document.
2663 RefPtr<EventTarget> chromeEventHandler;
2664 mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2665 mChromeEventHandler = chromeEventHandler;
2666 if (!mChromeEventHandler) {
2667 // We have no chrome event handler. If we have a parent,
2668 // get our chrome event handler from the parent. If
2669 // we don't have a parent, then we need to make a new
2670 // window root object that will function as a chrome event
2671 // handler and receive all events that occur anywhere inside
2672 // our window.
2673 nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetInProcessParent();
2674 if (parentWindow.get() != this) {
2675 mChromeEventHandler = parentWindow->GetChromeEventHandler();
2676 } else {
2677 mChromeEventHandler = NS_NewWindowRoot(this);
2678 mIsRootOuterWindow = true;
2679 }
2680 }
2681
2682 SetIsBackgroundInternal(!mBrowsingContext->IsActive());
2683}
2684
2685void nsGlobalWindowOuter::DetachFromDocShell(bool aIsBeingDiscarded) {
2686 // DetachFromDocShell means the window is being torn down. Drop our
2687 // reference to the script context, allowing it to be deleted
2688 // later. Meanwhile, keep our weak reference to the script object
2689 // so that it can be retrieved later (until it is finalized by the JS GC).
2690
2691 // Call FreeInnerObjects on all inner windows, not just the current
2692 // one, since some could be held by WindowStateHolder objects that
2693 // are GC-owned.
2694 RefPtr<nsGlobalWindowInner> inner;
2695 for (PRCList* node = PR_LIST_HEAD(this)(this)->next; node != this;
2696 node = PR_NEXT_LINK(inner)((inner)->next)) {
2697 // This cast is safe because `node != this`. Non-this nodes are inner
2698 // windows.
2699 inner = static_cast<nsGlobalWindowInner*>(node);
2700 MOZ_ASSERT(!inner->mOuterWindow || inner->mOuterWindow == this)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inner->mOuterWindow || inner->mOuterWindow ==
this)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!inner->mOuterWindow || inner->mOuterWindow ==
this))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!inner->mOuterWindow || inner->mOuterWindow == this",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2700); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inner->mOuterWindow || inner->mOuterWindow == this"
")"); do { *((volatile int*)__null) = 2700; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2701 inner->FreeInnerObjects();
2702 }
2703
2704 // Don't report that we were detached to the nsWindowMemoryReporter, as it
2705 // only tracks inner windows.
2706
2707 NotifyWindowIDDestroyed("outer-window-destroyed");
2708
2709 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(this);
2710
2711 if (currentInner) {
2712 NS_ASSERTION(mDoc, "Must have doc!")do { if (!(mDoc)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Must have doc!"
, "mDoc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2712); MOZ_PretendNoReturn(); } } while (0)
;
2713
2714 // Remember the document's principal and URI.
2715 mDocumentPrincipal = mDoc->NodePrincipal();
2716 mDocumentCookiePrincipal = mDoc->EffectiveCookiePrincipal();
2717 mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
2718 mDocumentPartitionedPrincipal = mDoc->PartitionedPrincipal();
2719 mDocumentURI = mDoc->GetDocumentURI();
2720
2721 // Release our document reference
2722 DropOuterWindowDocs();
2723 }
2724
2725 ClearControllers();
2726
2727 mChromeEventHandler = nullptr; // force release now
2728
2729 if (mContext) {
2730 // When we're about to destroy a top level content window
2731 // (for example a tab), we trigger a full GC by passing null as the last
2732 // param. We also trigger a full GC for chrome windows.
2733 nsJSContext::PokeGC(JS::GCReason::SET_DOC_SHELL,
2734 (mTopLevelOuterContentWindow || mIsChrome)
2735 ? nullptr
2736 : GetWrapperPreserveColor());
2737 mContext = nullptr;
2738 }
2739
2740 if (aIsBeingDiscarded) {
2741 // If our BrowsingContext is being discarded, make a note that our current
2742 // inner window was active at the time it went away.
2743 if (nsGlobalWindowInner* currentInner =
2744 GetCurrentInnerWindowInternal(this)) {
2745 currentInner->SetWasCurrentInnerWindow();
2746 }
2747 }
2748
2749 mDocShell = nullptr;
2750 mBrowsingContext->ClearDocShell();
2751
2752 CleanUp();
2753}
2754
2755void nsGlobalWindowOuter::UpdateParentTarget() {
2756 // NOTE: This method is nearly identical to
2757 // nsGlobalWindowInner::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
2758 // UPDATE THE OTHER ONE TOO! The one difference is that this method updates
2759 // mMessageManager as well, which inner windows don't have.
2760
2761 // Try to get our frame element's tab child global (its in-process message
2762 // manager). If that fails, fall back to the chrome event handler's tab
2763 // child global, and if it doesn't have one, just use the chrome event
2764 // handler itself.
2765
2766 nsCOMPtr<Element> frameElement = GetFrameElementInternal();
2767 mMessageManager = nsContentUtils::TryGetBrowserChildGlobal(frameElement);
2768
2769 if (!mMessageManager) {
2770 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
2771 if (topWin) {
2772 frameElement = topWin->GetFrameElementInternal();
2773 mMessageManager = nsContentUtils::TryGetBrowserChildGlobal(frameElement);
2774 }
2775 }
2776
2777 if (!mMessageManager) {
2778 mMessageManager =
2779 nsContentUtils::TryGetBrowserChildGlobal(mChromeEventHandler);
2780 }
2781
2782 if (mMessageManager) {
2783 mParentTarget = mMessageManager;
2784 } else {
2785 mParentTarget = mChromeEventHandler;
2786 }
2787}
2788
2789EventTarget* nsGlobalWindowOuter::GetTargetForEventTargetChain() {
2790 return GetCurrentInnerWindowInternal(this);
2791}
2792
2793void nsGlobalWindowOuter::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
2794 MOZ_CRASH("The outer window should not be part of an event path")do { do { } while (false); MOZ_ReportCrash("" "The outer window should not be part of an event path"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2794); AnnotateMozCrashReason("MOZ_CRASH(" "The outer window should not be part of an event path"
")"); do { *((volatile int*)__null) = 2794; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2795}
2796
2797bool nsGlobalWindowOuter::ShouldPromptToBlockDialogs() {
2798 if (!nsContentUtils::GetCurrentJSContext()) {
2799 return false; // non-scripted caller.
2800 }
2801
2802 BrowsingContextGroup* group = GetBrowsingContextGroup();
2803 if (!group) {
2804 return true;
2805 }
2806
2807 return group->DialogsAreBeingAbused();
2808}
2809
2810bool nsGlobalWindowOuter::AreDialogsEnabled() {
2811 BrowsingContextGroup* group = mBrowsingContext->Group();
2812 if (!group) {
2813 NS_ERROR("AreDialogsEnabled() called without a browsing context group?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "AreDialogsEnabled() called without a browsing context group?"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2813); MOZ_PretendNoReturn(); } while (0)
;
2814 return false;
2815 }
2816
2817 // Dialogs are blocked if the content viewer is hidden
2818 if (mDocShell) {
2819 nsCOMPtr<nsIDocumentViewer> viewer;
2820 mDocShell->GetDocViewer(getter_AddRefs(viewer));
2821
2822 bool isHidden;
2823 viewer->GetIsHidden(&isHidden);
2824 if (isHidden) {
2825 return false;
2826 }
2827 }
2828
2829 // Dialogs are also blocked if the document is sandboxed with SANDBOXED_MODALS
2830 // (or if we have no document, of course). Which document? Who knows; the
2831 // spec is daft. See <https://github.com/whatwg/html/issues/1206>. For now
2832 // just go ahead and check mDoc, since in everything except edge cases in
2833 // which a frame is allow-same-origin but not allow-scripts and is being poked
2834 // at by some other window this should be the right thing anyway.
2835 if (!mDoc || (mDoc->GetSandboxFlags() & SANDBOXED_MODALS)) {
2836 return false;
2837 }
2838
2839 return group->GetAreDialogsEnabled();
2840}
2841
2842void nsGlobalWindowOuter::DisableDialogs() {
2843 BrowsingContextGroup* group = mBrowsingContext->Group();
2844 if (!group) {
2845 NS_ERROR("DisableDialogs() called without a browsing context group?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "DisableDialogs() called without a browsing context group?"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2845); MOZ_PretendNoReturn(); } while (0)
;
2846 return;
2847 }
2848
2849 if (group) {
2850 group->SetAreDialogsEnabled(false);
2851 }
2852}
2853
2854void nsGlobalWindowOuter::EnableDialogs() {
2855 BrowsingContextGroup* group = mBrowsingContext->Group();
2856 if (!group) {
2857 NS_ERROR("EnableDialogs() called without a browsing context group?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "EnableDialogs() called without a browsing context group?"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2857); MOZ_PretendNoReturn(); } while (0)
;
2858 return;
2859 }
2860
2861 if (group) {
2862 group->SetAreDialogsEnabled(true);
2863 }
2864}
2865
2866nsresult nsGlobalWindowOuter::PostHandleEvent(EventChainPostVisitor& aVisitor) {
2867 MOZ_CRASH("The outer window should not be part of an event path")do { do { } while (false); MOZ_ReportCrash("" "The outer window should not be part of an event path"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2867); AnnotateMozCrashReason("MOZ_CRASH(" "The outer window should not be part of an event path"
")"); do { *((volatile int*)__null) = 2867; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2868}
2869
2870void nsGlobalWindowOuter::PoisonOuterWindowProxy(JSObject* aObject) {
2871 if (aObject == GetWrapperMaybeDead()) {
2872 PoisonWrapper();
2873 }
2874}
2875
2876nsresult nsGlobalWindowOuter::SetArguments(nsIArray* aArguments) {
2877 nsresult rv;
2878
2879 // We've now mostly separated them, but the difference is still opaque to
2880 // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
2881 // embedding waltz we do here).
2882 //
2883 // So we need to demultiplex the two cases here.
2884 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(this);
2885
2886 mArguments = aArguments;
2887 rv = currentInner->DefineArgumentsProperty(aArguments);
2888 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2888); return rv; } } while (false)
;
2889
2890 return NS_OK;
2891}
2892
2893//*****************************************************************************
2894// nsGlobalWindowOuter::nsIScriptObjectPrincipal
2895//*****************************************************************************
2896
2897nsIPrincipal* nsGlobalWindowOuter::GetPrincipal() {
2898 if (mDoc) {
2899 // If we have a document, get the principal from the document
2900 return mDoc->NodePrincipal();
2901 }
2902
2903 if (mDocumentPrincipal) {
2904 return mDocumentPrincipal;
2905 }
2906
2907 // If we don't have a principal and we don't have a document we
2908 // ask the parent window for the principal. This can happen when
2909 // loading a frameset that has a <frame src="javascript:xxx">, in
2910 // that case the global window is used in JS before we've loaded
2911 // a document into the window.
2912
2913 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2914 do_QueryInterface(GetInProcessParentInternal());
2915
2916 if (objPrincipal) {
2917 return objPrincipal->GetPrincipal();
2918 }
2919
2920 return nullptr;
2921}
2922
2923nsIPrincipal* nsGlobalWindowOuter::GetEffectiveCookiePrincipal() {
2924 if (mDoc) {
2925 // If we have a document, get the principal from the document
2926 return mDoc->EffectiveCookiePrincipal();
2927 }
2928
2929 if (mDocumentCookiePrincipal) {
2930 return mDocumentCookiePrincipal;
2931 }
2932
2933 // If we don't have a cookie principal and we don't have a document we ask
2934 // the parent window for the cookie principal.
2935
2936 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2937 do_QueryInterface(GetInProcessParentInternal());
2938
2939 if (objPrincipal) {
2940 return objPrincipal->GetEffectiveCookiePrincipal();
2941 }
2942
2943 return nullptr;
2944}
2945
2946nsIPrincipal* nsGlobalWindowOuter::GetEffectiveStoragePrincipal() {
2947 if (mDoc) {
2948 // If we have a document, get the principal from the document
2949 return mDoc->EffectiveStoragePrincipal();
2950 }
2951
2952 if (mDocumentStoragePrincipal) {
2953 return mDocumentStoragePrincipal;
2954 }
2955
2956 // If we don't have a storage principal and we don't have a document we ask
2957 // the parent window for the storage principal.
2958
2959 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2960 do_QueryInterface(GetInProcessParentInternal());
2961
2962 if (objPrincipal) {
2963 return objPrincipal->GetEffectiveStoragePrincipal();
2964 }
2965
2966 return nullptr;
2967}
2968
2969nsIPrincipal* nsGlobalWindowOuter::PartitionedPrincipal() {
2970 if (mDoc) {
2971 // If we have a document, get the principal from the document
2972 return mDoc->PartitionedPrincipal();
2973 }
2974
2975 if (mDocumentPartitionedPrincipal) {
2976 return mDocumentPartitionedPrincipal;
2977 }
2978
2979 // If we don't have a partitioned principal and we don't have a document we
2980 // ask the parent window for the partitioned principal.
2981
2982 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2983 do_QueryInterface(GetInProcessParentInternal());
2984
2985 if (objPrincipal) {
2986 return objPrincipal->PartitionedPrincipal();
2987 }
2988
2989 return nullptr;
2990}
2991
2992//*****************************************************************************
2993// nsGlobalWindowOuter::nsIDOMWindow
2994//*****************************************************************************
2995
2996Element* nsPIDOMWindowOuter::GetFrameElementInternal() const {
2997 return mFrameElement;
2998}
2999
3000void nsPIDOMWindowOuter::SetFrameElementInternal(Element* aFrameElement) {
3001 mFrameElement = aFrameElement;
3002}
3003
3004Navigator* nsGlobalWindowOuter::GetNavigator() {
3005 FORWARD_TO_INNER(Navigator, (), nullptr)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3005); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Navigator (); } while (0)
;
3006}
3007
3008nsScreen* nsGlobalWindowOuter::GetScreen() {
3009 FORWARD_TO_INNER(Screen, (), nullptr)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3009); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Screen (); } while (0)
;
3010}
3011
3012void nsPIDOMWindowOuter::ActivateMediaComponents() {
3013 if (!ShouldDelayMediaFromStart()) {
3014 return;
3015 }
3016 MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = AudioChannelService
::GetAudioChannelLog(); if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "nsPIDOMWindowOuter, ActiveMediaComponents, "
"no longer to delay media from start, this = %p\n", this); }
} while (0)
3017 ("nsPIDOMWindowOuter, ActiveMediaComponents, "do { const ::mozilla::LogModule* moz_real_module = AudioChannelService
::GetAudioChannelLog(); if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "nsPIDOMWindowOuter, ActiveMediaComponents, "
"no longer to delay media from start, this = %p\n", this); }
} while (0)
3018 "no longer to delay media from start, this = %p\n",do { const ::mozilla::LogModule* moz_real_module = AudioChannelService
::GetAudioChannelLog(); if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "nsPIDOMWindowOuter, ActiveMediaComponents, "
"no longer to delay media from start, this = %p\n", this); }
} while (0)
3019 this))do { const ::mozilla::LogModule* moz_real_module = AudioChannelService
::GetAudioChannelLog(); if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "nsPIDOMWindowOuter, ActiveMediaComponents, "
"no longer to delay media from start, this = %p\n", this); }
} while (0)
;
3020 if (BrowsingContext* bc = GetBrowsingContext()) {
3021 Unused << bc->Top()->SetShouldDelayMediaFromStart(false);
3022 }
3023 NotifyResumingDelayedMedia();
3024}
3025
3026bool nsPIDOMWindowOuter::ShouldDelayMediaFromStart() const {
3027 BrowsingContext* bc = GetBrowsingContext();
3028 return bc && bc->Top()->GetShouldDelayMediaFromStart();
3029}
3030
3031void nsPIDOMWindowOuter::NotifyResumingDelayedMedia() {
3032 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
3033 if (service) {
3034 service->NotifyResumingDelayedMedia(this);
3035 }
3036}
3037
3038bool nsPIDOMWindowOuter::GetAudioMuted() const {
3039 BrowsingContext* bc = GetBrowsingContext();
3040 return bc && bc->Top()->GetMuted();
3041}
3042
3043void nsPIDOMWindowOuter::RefreshMediaElementsVolume() {
3044 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
3045 if (service) {
3046 // TODO: RefreshAgentsVolume can probably be simplified further.
3047 service->RefreshAgentsVolume(this, 1.0f, GetAudioMuted());
3048 }
3049}
3050
3051mozilla::dom::BrowsingContextGroup*
3052nsPIDOMWindowOuter::GetBrowsingContextGroup() const {
3053 return mBrowsingContext ? mBrowsingContext->Group() : nullptr;
3054}
3055
3056Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetParentOuter() {
3057 BrowsingContext* bc = GetBrowsingContext();
3058 return bc ? bc->GetParent(IgnoreErrors()) : nullptr;
3059}
3060
3061/**
3062 * GetInProcessScriptableParent used to be called when a script read
3063 * window.parent. Under Fission, that is now handled by
3064 * BrowsingContext::GetParent, and the result is a WindowProxyHolder rather than
3065 * an actual global window. This method still exists for legacy callers which
3066 * relied on the old logic, and require in-process windows. However, it only
3067 * works correctly when no out-of-process frames exist between this window and
3068 * the top-level window, so it should not be used in new code.
3069 *
3070 * In contrast to GetRealParent, GetInProcessScriptableParent respects <iframe
3071 * mozbrowser> boundaries, so if |this| is contained by an <iframe
3072 * mozbrowser>, we will return |this| as its own parent.
3073 */
3074nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableParent() {
3075 if (!mDocShell) {
3076 return nullptr;
3077 }
3078
3079 if (BrowsingContext* parentBC = GetBrowsingContext()->GetParent()) {
3080 if (nsCOMPtr<nsPIDOMWindowOuter> parent = parentBC->GetDOMWindow()) {
3081 return parent;
3082 }
3083 }
3084 return this;
3085}
3086
3087/**
3088 * Behavies identically to GetInProcessScriptableParent extept that it returns
3089 * null if GetInProcessScriptableParent would return this window.
3090 */
3091nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableParentOrNull() {
3092 nsPIDOMWindowOuter* parent = GetInProcessScriptableParent();
3093 return (nsGlobalWindowOuter::Cast(parent) == this) ? nullptr : parent;
3094}
3095
3096already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetInProcessParent() {
3097 if (!mDocShell) {
3098 return nullptr;
3099 }
3100
3101 if (auto* parentBC = GetBrowsingContext()->GetParent()) {
3102 if (auto* parent = parentBC->GetDOMWindow()) {
3103 return do_AddRef(parent);
3104 }
3105 }
3106 return do_AddRef(this);
3107}
3108
3109static nsresult GetTopImpl(nsGlobalWindowOuter* aWin, nsIURI* aURIBeingLoaded,
3110 nsPIDOMWindowOuter** aTop, bool aScriptable,
3111 bool aExcludingExtensionAccessibleContentFrames) {
3112 *aTop = nullptr;
3113
3114 MOZ_ASSERT_IF(aExcludingExtensionAccessibleContentFrames, !aScriptable)do { if (aExcludingExtensionAccessibleContentFrames) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(!aScriptable
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aScriptable))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aScriptable", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3114); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aScriptable"
")"); do { *((volatile int*)__null) = 3114; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3115
3116 // Walk up the parent chain.
3117
3118 nsCOMPtr<nsPIDOMWindowOuter> prevParent = aWin;
3119 nsCOMPtr<nsPIDOMWindowOuter> parent = aWin;
3120 do {
3121 if (!parent) {
3122 break;
3123 }
3124
3125 prevParent = parent;
3126
3127 if (aScriptable) {
3128 parent = parent->GetInProcessScriptableParent();
3129 } else {
3130 parent = parent->GetInProcessParent();
3131 }
3132
3133 if (aExcludingExtensionAccessibleContentFrames) {
3134 if (auto* p = nsGlobalWindowOuter::Cast(parent)) {
3135 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(p);
3136 nsIURI* uri = prevParent->GetDocumentURI();
3137 if (!uri) {
3138 // If our parent doesn't have a URI yet, we have a document that is in
3139 // the process of being loaded. In that case, our caller is
3140 // responsible for passing in the URI for the document that is being
3141 // loaded, so we fall back to using that URI here.
3142 uri = aURIBeingLoaded;
3143 }
3144
3145 if (currentInner && uri) {
3146 // If we find an inner window, we better find the uri for the current
3147 // window we're looking at. If we can't find it directly, it is the
3148 // responsibility of our caller to provide it to us.
3149 MOZ_DIAGNOSTIC_ASSERT(uri)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(uri)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(uri))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("uri", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3149); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "uri"
")"); do { *((volatile int*)__null) = 3149; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3150
3151 // If the new parent has permission to load the current page, we're
3152 // at a moz-extension:// frame which has a host permission that allows
3153 // it to load the document that we've loaded. In that case, stop at
3154 // this frame and consider it the top-level frame.
3155 //
3156 // Note that it's possible for the set of URIs accepted by
3157 // AddonAllowsLoad() to change at runtime, but we don't need to cache
3158 // the result of this check, since the important consumer of this code
3159 // (which is nsIHttpChannelInternal.topWindowURI) already caches the
3160 // result after computing it the first time.
3161 if (BasePrincipal::Cast(p->GetPrincipal())
3162 ->AddonAllowsLoad(uri, true)) {
3163 parent = prevParent;
3164 break;
3165 }
3166 }
3167 }
3168 }
3169
3170 } while (parent != prevParent);
3171
3172 if (parent) {
3173 parent.swap(*aTop);
3174 }
3175
3176 return NS_OK;
3177}
3178
3179/**
3180 * GetInProcessScriptableTop used to be called when a script read window.top.
3181 * Under Fission, that is now handled by BrowsingContext::Top, and the result is
3182 * a WindowProxyHolder rather than an actual global window. This method still
3183 * exists for legacy callers which relied on the old logic, and require
3184 * in-process windows. However, it only works correctly when no out-of-process
3185 * frames exist between this window and the top-level window, so it should not
3186 * be used in new code.
3187 *
3188 * In contrast to GetRealTop, GetInProcessScriptableTop respects <iframe
3189 * mozbrowser> boundaries. If we encounter a window owned by an <iframe
3190 * mozbrowser> while walking up the window hierarchy, we'll stop and return that
3191 * window.
3192 */
3193nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableTop() {
3194 nsCOMPtr<nsPIDOMWindowOuter> window;
3195 GetTopImpl(this, /* aURIBeingLoaded = */ nullptr, getter_AddRefs(window),
3196 /* aScriptable = */ true,
3197 /* aExcludingExtensionAccessibleContentFrames = */ false);
3198 return window.get();
3199}
3200
3201already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetInProcessTop() {
3202 nsCOMPtr<nsPIDOMWindowOuter> window;
3203 GetTopImpl(this, /* aURIBeingLoaded = */ nullptr, getter_AddRefs(window),
3204 /* aScriptable = */ false,
3205 /* aExcludingExtensionAccessibleContentFrames = */ false);
3206 return window.forget();
3207}
3208
3209already_AddRefed<nsPIDOMWindowOuter>
3210nsGlobalWindowOuter::GetTopExcludingExtensionAccessibleContentFrames(
3211 nsIURI* aURIBeingLoaded) {
3212 // There is a parent-process equivalent of this in DocumentLoadListener.cpp
3213 // GetTopWindowExcludingExtensionAccessibleContentFrames
3214 nsCOMPtr<nsPIDOMWindowOuter> window;
3215 GetTopImpl(this, aURIBeingLoaded, getter_AddRefs(window),
3216 /* aScriptable = */ false,
3217 /* aExcludingExtensionAccessibleContentFrames = */ true);
3218 return window.forget();
3219}
3220
3221void nsGlobalWindowOuter::GetContentOuter(JSContext* aCx,
3222 JS::MutableHandle<JSObject*> aRetval,
3223 CallerType aCallerType,
3224 ErrorResult& aError) {
3225 RefPtr<BrowsingContext> content = GetContentInternal(aCallerType, aError);
3226 if (aError.Failed()) {
3227 return;
3228 }
3229
3230 if (!content) {
3231 aRetval.set(nullptr);
3232 return;
3233 }
3234
3235 JS::Rooted<JS::Value> val(aCx);
3236 if (!ToJSValue(aCx, WindowProxyHolder{content}, &val)) {
3237 aError.Throw(NS_ERROR_UNEXPECTED);
3238 return;
3239 }
3240
3241 MOZ_ASSERT(val.isObjectOrNull())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(val.isObjectOrNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(val.isObjectOrNull()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("val.isObjectOrNull()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3241); AnnotateMozCrashReason("MOZ_ASSERT" "(" "val.isObjectOrNull()"
")"); do { *((volatile int*)__null) = 3241; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3242 aRetval.set(val.toObjectOrNull());
3243}
3244
3245already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetContentInternal(
3246 CallerType aCallerType, ErrorResult& aError) {
3247 // First check for a named frame named "content"
3248 if (RefPtr<BrowsingContext> named = GetChildWindow(u"content"_ns)) {
3249 return named.forget();
3250 }
3251
3252 // If we're in the parent process, and being called by system code, `content`
3253 // should return the current primary content frame (if it's in-process).
3254 //
3255 // We return `nullptr` if the current primary content frame is out-of-process,
3256 // rather than a remote window proxy, as that is the existing behaviour as of
3257 // bug 1597437.
3258 if (XRE_IsParentProcess() && aCallerType == CallerType::System) {
3259 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
3260 if (!treeOwner) {
3261 aError.Throw(NS_ERROR_FAILURE);
3262 return nullptr;
3263 }
3264
3265 nsCOMPtr<nsIDocShellTreeItem> primaryContent;
3266 treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
3267 if (!primaryContent) {
3268 return nullptr;
3269 }
3270
3271 return do_AddRef(primaryContent->GetBrowsingContext());
3272 }
3273
3274 // For legacy untrusted callers we always return the same value as
3275 // `window.top`
3276 if (mDoc && aCallerType != CallerType::System) {
3277 mDoc->WarnOnceAbout(DeprecatedOperations::eWindowContentUntrusted);
3278 }
3279
3280 MOZ_ASSERT(mBrowsingContext->IsContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mBrowsingContext->IsContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mBrowsingContext->IsContent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mBrowsingContext->IsContent()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3280); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBrowsingContext->IsContent()"
")"); do { *((volatile int*)__null) = 3280; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3281 return do_AddRef(mBrowsingContext->Top());
3282}
3283
3284nsresult nsGlobalWindowOuter::GetPrompter(nsIPrompt** aPrompt) {
3285 if (!mDocShell) return NS_ERROR_FAILURE;
3286
3287 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
3288 NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE)do { if ((__builtin_expect(!!(!(prompter)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "prompter" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3288); return NS_ERROR_NO_INTERFACE; } } while (false)
;
3289
3290 prompter.forget(aPrompt);
3291 return NS_OK;
3292}
3293
3294bool nsGlobalWindowOuter::GetClosedOuter() {
3295 // If someone called close(), or if we don't have a docshell, we're closed.
3296 return mIsClosed || !mDocShell;
3297}
3298
3299bool nsGlobalWindowOuter::Closed() { return GetClosedOuter(); }
3300
3301Nullable<WindowProxyHolder> nsGlobalWindowOuter::IndexedGetterOuter(
3302 uint32_t aIndex) {
3303 BrowsingContext* bc = GetBrowsingContext();
3304 NS_ENSURE_TRUE(bc, nullptr)do { if ((__builtin_expect(!!(!(bc)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "bc" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3304); return nullptr; } } while (false)
;
3305
3306 Span<RefPtr<BrowsingContext>> children = bc->NonSyntheticChildren();
3307
3308 if (aIndex < children.Length()) {
3309 return WindowProxyHolder(children[aIndex]);
3310 }
3311 return nullptr;
3312}
3313
3314nsIControllers* nsGlobalWindowOuter::GetControllersOuter(ErrorResult& aError) {
3315 if (!mControllers) {
3316 mControllers = new nsXULControllers();
3317 if (!mControllers) {
3318 aError.Throw(NS_ERROR_FAILURE);
3319 return nullptr;
3320 }
3321
3322 // Add in the default controller
3323 RefPtr<nsBaseCommandController> commandController =
3324 nsBaseCommandController::CreateWindowController();
3325 if (!commandController) {
3326 aError.Throw(NS_ERROR_FAILURE);
3327 return nullptr;
3328 }
3329
3330 mControllers->InsertControllerAt(0, commandController);
3331 commandController->SetCommandContext(static_cast<nsIDOMWindow*>(this));
3332 }
3333
3334 return mControllers;
3335}
3336
3337nsresult nsGlobalWindowOuter::GetControllers(nsIControllers** aResult) {
3338 FORWARD_TO_INNER(GetControllers, (aResult), NS_ERROR_UNEXPECTED)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3338); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetControllers (aResult); } while (0)
;
3339}
3340
3341already_AddRefed<BrowsingContext>
3342nsGlobalWindowOuter::GetOpenerBrowsingContext() {
3343 RefPtr<BrowsingContext> opener = GetBrowsingContext()->GetOpener();
3344 MOZ_DIAGNOSTIC_ASSERT(!opener ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!opener || opener->Group() == GetBrowsingContext(
)->Group())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!opener || opener->Group() == GetBrowsingContext
()->Group()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!opener || opener->Group() == GetBrowsingContext()->Group()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3345); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!opener || opener->Group() == GetBrowsingContext()->Group()"
")"); do { *((volatile int*)__null) = 3345; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3345 opener->Group() == GetBrowsingContext()->Group())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!opener || opener->Group() == GetBrowsingContext(
)->Group())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!opener || opener->Group() == GetBrowsingContext
()->Group()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!opener || opener->Group() == GetBrowsingContext()->Group()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3345); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!opener || opener->Group() == GetBrowsingContext()->Group()"
")"); do { *((volatile int*)__null) = 3345; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3346 if (!opener || opener->Group() != GetBrowsingContext()->Group()) {
3347 return nullptr;
3348 }
3349
3350 // Catch the case where we're chrome but the opener is not...
3351 if (nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
3352 GetPrincipal() == nsContentUtils::GetSystemPrincipal()) {
3353 auto* openerWin = nsGlobalWindowOuter::Cast(opener->GetDOMWindow());
3354 if (!openerWin ||
3355 openerWin->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
3356 return nullptr;
3357 }
3358 }
3359
3360 return opener.forget();
3361}
3362
3363nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSameProcessOpener() {
3364 if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
3365 return opener->GetDOMWindow();
3366 }
3367 return nullptr;
3368}
3369
3370Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpenerWindowOuter() {
3371 if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
3372 return WindowProxyHolder(std::move(opener));
3373 }
3374 return nullptr;
3375}
3376
3377Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpener() {
3378 return GetOpenerWindowOuter();
3379}
3380
3381void nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus) {
3382 aStatus = mStatus;
3383}
3384
3385void nsGlobalWindowOuter::SetStatusOuter(const nsAString& aStatus) {
3386 mStatus = aStatus;
3387
3388 // We don't support displaying window.status in the UI, so there's nothing
3389 // left to do here.
3390}
3391
3392void nsGlobalWindowOuter::GetNameOuter(nsAString& aName) {
3393 if (mDocShell) {
3394 mDocShell->GetName(aName);
3395 }
3396}
3397
3398void nsGlobalWindowOuter::SetNameOuter(const nsAString& aName,
3399 mozilla::ErrorResult& aError) {
3400 if (mDocShell) {
3401 aError = mDocShell->SetName(aName);
3402 }
3403}
3404
3405// NOTE: The idea of this function is that it should return the same as
3406// nsPresContext::CSSToDeviceScale() if it was in aWindow synchronously. For
3407// that, we use the UnscaledDevicePixelsPerCSSPixel() (which contains the device
3408// scale and the OS zoom scale) and then account for the browsing context full
3409// zoom. See the declaration of this function for context about why this is
3410// needed.
3411CSSToLayoutDeviceScale nsGlobalWindowOuter::CSSToDevScaleForBaseWindow(
3412 nsIBaseWindow* aWindow) {
3413 MOZ_ASSERT(aWindow)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWindow", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3413); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { *((volatile int*)__null) = 3413; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3414 auto scale = aWindow->UnscaledDevicePixelsPerCSSPixel();
3415 if (mBrowsingContext) {
3416 scale.scale *= mBrowsingContext->FullZoom();
3417 }
3418 return scale;
3419}
3420
3421nsresult nsGlobalWindowOuter::GetInnerSize(CSSSize& aSize) {
3422 EnsureSizeAndPositionUpToDate();
3423
3424 NS_ENSURE_STATE(mDocShell)do { if ((__builtin_expect(!!(!(mDocShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3424); return NS_ERROR_UNEXPECTED; } } while (false)
;
3425
3426 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3427 PresShell* presShell = mDocShell->GetPresShell();
3428
3429 if (!presContext || !presShell) {
3430 aSize = {};
3431 return NS_OK;
3432 }
3433
3434 // Whether or not the css viewport has been overridden, we can get the
3435 // correct value by looking at the visible area of the presContext.
3436 if (RefPtr<nsViewManager> viewManager = presShell->GetViewManager()) {
3437 viewManager->FlushDelayedResize();
3438 }
3439
3440 // FIXME: Bug 1598487 - Return the layout viewport instead of the ICB.
3441 nsSize viewportSize = presContext->GetVisibleArea().Size();
3442 if (presContext->GetDynamicToolbarState() == DynamicToolbarState::Collapsed) {
3443 viewportSize =
3444 nsLayoutUtils::ExpandHeightForViewportUnits(presContext, viewportSize);
3445 }
3446
3447 aSize = CSSPixel::FromAppUnits(viewportSize);
3448
3449 switch (StaticPrefs::dom_innerSize_rounding()) {
3450 case 1:
3451 aSize.width = std::roundf(aSize.width);
3452 aSize.height = std::roundf(aSize.height);
3453 break;
3454 case 2:
3455 aSize.width = std::truncf(aSize.width);
3456 aSize.height = std::truncf(aSize.height);
3457 break;
3458 default:
3459 break;
3460 }
3461
3462 return NS_OK;
3463}
3464
3465double nsGlobalWindowOuter::GetInnerWidthOuter(ErrorResult& aError) {
3466 CSSSize size;
3467 aError = GetInnerSize(size);
3468 return size.width;
3469}
3470
3471nsresult nsGlobalWindowOuter::GetInnerWidth(double* aInnerWidth) {
3472 FORWARD_TO_INNER(GetInnerWidth, (aInnerWidth), NS_ERROR_UNEXPECTED)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3472); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetInnerWidth (aInnerWidth); } while (0)
;
3473}
3474
3475double nsGlobalWindowOuter::GetInnerHeightOuter(ErrorResult& aError) {
3476 CSSSize size;
3477 aError = GetInnerSize(size);
3478 return size.height;
3479}
3480
3481nsresult nsGlobalWindowOuter::GetInnerHeight(double* aInnerHeight) {
3482 FORWARD_TO_INNER(GetInnerHeight, (aInnerHeight), NS_ERROR_UNEXPECTED)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3482); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetInnerHeight (aInnerHeight); } while (0)
;
3483}
3484
3485CSSIntSize nsGlobalWindowOuter::GetOuterSize(CallerType aCallerType,
3486 ErrorResult& aError) {
3487 if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
3488 RFPTarget::WindowOuterSize)) {
3489 if (BrowsingContext* bc = GetBrowsingContext()) {
3490 return bc->Top()->GetTopInnerSizeForRFP();
3491 }
3492 return {};
3493 }
3494
3495 // Windows showing documents in RDM panes and any subframes within them
3496 // return the simulated device size.
3497 if (mDoc) {
3498 Maybe<CSSIntSize> deviceSize = GetRDMDeviceSize(*mDoc);
3499 if (deviceSize.isSome()) {
3500 return *deviceSize;
3501 }
3502 }
3503
3504 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3505 if (!treeOwnerAsWin) {
3506 aError.Throw(NS_ERROR_FAILURE);
3507 return {};
3508 }
3509
3510 return RoundedToInt(treeOwnerAsWin->GetSize() /
3511 CSSToDevScaleForBaseWindow(treeOwnerAsWin));
3512}
3513
3514int32_t nsGlobalWindowOuter::GetOuterWidthOuter(CallerType aCallerType,
3515 ErrorResult& aError) {
3516 return GetOuterSize(aCallerType, aError).width;
3517}
3518
3519int32_t nsGlobalWindowOuter::GetOuterHeightOuter(CallerType aCallerType,
3520 ErrorResult& aError) {
3521 return GetOuterSize(aCallerType, aError).height;
3522}
3523
3524CSSPoint nsGlobalWindowOuter::ScreenEdgeSlop() {
3525 if (NS_WARN_IF(!mDocShell)NS_warn_if_impl(!mDocShell, "!mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3525)
) {
3526 return {};
3527 }
3528 RefPtr<nsPresContext> pc = mDocShell->GetPresContext();
3529 if (NS_WARN_IF(!pc)NS_warn_if_impl(!pc, "!pc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3529)
) {
3530 return {};
3531 }
3532 nsCOMPtr<nsIWidget> widget = GetMainWidget();
3533 if (NS_WARN_IF(!widget)NS_warn_if_impl(!widget, "!widget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3533)
) {
3534 return {};
3535 }
3536 LayoutDeviceIntPoint pt = widget->GetScreenEdgeSlop();
3537 auto auPoint =
3538 LayoutDeviceIntPoint::ToAppUnits(pt, pc->AppUnitsPerDevPixel());
3539 return CSSPoint::FromAppUnits(auPoint);
3540}
3541
3542CSSIntPoint nsGlobalWindowOuter::GetScreenXY(CallerType aCallerType,
3543 ErrorResult& aError) {
3544 // When resisting fingerprinting, always return (0,0)
3545 if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
3546 RFPTarget::WindowScreenXY)) {
3547 return CSSIntPoint(0, 0);
3548 }
3549
3550 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3551 if (!treeOwnerAsWin) {
3552 aError.Throw(NS_ERROR_FAILURE);
3553 return CSSIntPoint(0, 0);
3554 }
3555
3556 LayoutDeviceIntPoint windowPos;
3557 aError = treeOwnerAsWin->GetPosition(&windowPos.x.value, &windowPos.y.value);
3558
3559 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3560 if (!presContext) {
3561 // XXX Fishy LayoutDevice to CSS conversion?
3562 return CSSIntPoint(windowPos.x, windowPos.y);
3563 }
3564
3565 nsDeviceContext* context = presContext->DeviceContext();
3566 auto windowPosAppUnits = LayoutDeviceIntPoint::ToAppUnits(
3567 windowPos, context->AppUnitsPerDevPixel());
3568 return CSSIntPoint::FromAppUnitsRounded(windowPosAppUnits);
3569}
3570
3571int32_t nsGlobalWindowOuter::GetScreenXOuter(CallerType aCallerType,
3572 ErrorResult& aError) {
3573 return GetScreenXY(aCallerType, aError).x;
3574}
3575
3576nsRect nsGlobalWindowOuter::GetInnerScreenRect() {
3577 if (!mDocShell) {
3578 return nsRect();
3579 }
3580
3581 EnsureSizeAndPositionUpToDate();
3582
3583 if (!mDocShell) {
3584 return nsRect();
3585 }
3586
3587 PresShell* presShell = mDocShell->GetPresShell();
3588 if (!presShell) {
3589 return nsRect();
3590 }
3591 nsIFrame* rootFrame = presShell->GetRootFrame();
3592 if (!rootFrame) {
3593 return nsRect();
3594 }
3595
3596 return rootFrame->GetScreenRectInAppUnits();
3597}
3598
3599Maybe<CSSIntSize> nsGlobalWindowOuter::GetRDMDeviceSize(
3600 const Document& aDocument) {
3601 // RDM device size should reflect the simulated device resolution, and
3602 // be independent of any full zoom or resolution zoom applied to the
3603 // content. To get this value, we get the "unscaled" browser child size,
3604 // and divide by the full zoom. "Unscaled" in this case means unscaled
3605 // from device to screen but it has been affected (multiplied) by the
3606 // full zoom and we need to compensate for that.
3607 MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3607); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3607; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3608
3609 // Bug 1576256: This does not work for cross-process subframes.
3610 const Document* topInProcessContentDoc =
3611 aDocument.GetTopLevelContentDocumentIfSameProcess();
3612 BrowsingContext* bc = topInProcessContentDoc
3613 ? topInProcessContentDoc->GetBrowsingContext()
3614 : nullptr;
3615 if (bc && bc->InRDMPane()) {
3616 nsIDocShell* docShell = topInProcessContentDoc->GetDocShell();
3617 if (docShell) {
3618 nsPresContext* presContext = docShell->GetPresContext();
3619 if (presContext) {
3620 nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild();
3621 if (child) {
3622 // We intentionally use GetFullZoom here instead of
3623 // GetDeviceFullZoom, because the unscaledInnerSize is based
3624 // on the full zoom and not the device full zoom (which is
3625 // rounded to result in integer device pixels).
3626 float zoom = presContext->GetFullZoom();
3627 BrowserChild* bc = static_cast<BrowserChild*>(child.get());
3628 CSSSize unscaledSize = bc->GetUnscaledInnerSize();
3629 return Some(CSSIntSize(gfx::RoundedToInt(unscaledSize / zoom)));
3630 }
3631 }
3632 }
3633 }
3634 return Nothing();
3635}
3636
3637float nsGlobalWindowOuter::GetMozInnerScreenXOuter(CallerType aCallerType) {
3638 // When resisting fingerprinting, always return 0.
3639 if (nsIGlobalObject::ShouldResistFingerprinting(
3640 aCallerType, RFPTarget::WindowInnerScreenXY)) {
3641 return 0.0;
3642 }
3643
3644 nsRect r = GetInnerScreenRect();
3645 return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3646}
3647
3648float nsGlobalWindowOuter::GetMozInnerScreenYOuter(CallerType aCallerType) {
3649 // Return 0 to prevent fingerprinting.
3650 if (nsIGlobalObject::ShouldResistFingerprinting(
3651 aCallerType, RFPTarget::WindowInnerScreenXY)) {
3652 return 0.0;
3653 }
3654
3655 nsRect r = GetInnerScreenRect();
3656 return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3657}
3658
3659int32_t nsGlobalWindowOuter::GetScreenYOuter(CallerType aCallerType,
3660 ErrorResult& aError) {
3661 return GetScreenXY(aCallerType, aError).y;
3662}
3663
3664// NOTE: Arguments to this function should have values scaled to
3665// CSS pixels, not device pixels.
3666void nsGlobalWindowOuter::CheckSecurityWidthAndHeight(int32_t* aWidth,
3667 int32_t* aHeight,
3668 CallerType aCallerType) {
3669 if (aCallerType != CallerType::System) {
3670 // if attempting to resize the window, hide any open popups
3671 nsContentUtils::HidePopupsInDocument(mDoc);
3672 }
3673
3674 // This one is easy. Just ensure the variable is greater than 100;
3675 if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
3676 // Check security state for use in determing window dimensions
3677
3678 if (aCallerType != CallerType::System) {
3679 // sec check failed
3680 if (aWidth && *aWidth < 100) {
3681 *aWidth = 100;
3682 }
3683 if (aHeight && *aHeight < 100) {
3684 *aHeight = 100;
3685 }
3686 }
3687 }
3688}
3689
3690// NOTE: Arguments to this function should have values in app units
3691void nsGlobalWindowOuter::SetCSSViewportWidthAndHeight(nscoord aInnerWidth,
3692 nscoord aInnerHeight) {
3693 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3694
3695 nsRect shellArea = presContext->GetVisibleArea();
3696 shellArea.SetHeight(aInnerHeight);
3697 shellArea.SetWidth(aInnerWidth);
3698
3699 // FIXME(emilio): This doesn't seem to be ok, this doesn't reflow or
3700 // anything... Should go through PresShell::ResizeReflow.
3701 //
3702 // But I don't think this can be reached by content, as we don't allow to set
3703 // inner{Width,Height}.
3704 presContext->SetVisibleArea(shellArea);
3705}
3706
3707// NOTE: Arguments to this function should have values scaled to
3708// CSS pixels, not device pixels.
3709void nsGlobalWindowOuter::CheckSecurityLeftAndTop(int32_t* aLeft, int32_t* aTop,
3710 CallerType aCallerType) {
3711 // This one is harder. We have to get the screen size and window dimensions.
3712
3713 // Check security state for use in determing window dimensions
3714
3715 if (aCallerType != CallerType::System) {
3716 // if attempting to move the window, hide any open popups
3717 nsContentUtils::HidePopupsInDocument(mDoc);
3718
3719 if (nsGlobalWindowOuter* rootWindow =
3720 nsGlobalWindowOuter::Cast(GetPrivateRoot())) {
3721 rootWindow->FlushPendingNotifications(FlushType::Layout);
3722 }
3723
3724 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3725
3726 RefPtr<nsScreen> screen = GetScreen();
3727
3728 if (treeOwnerAsWin && screen) {
3729 CSSToLayoutDeviceScale scale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
3730 CSSIntRect winRect =
3731 CSSIntRect::Round(treeOwnerAsWin->GetPositionAndSize() / scale);
3732
3733 // Get the screen dimensions
3734 // XXX This should use nsIScreenManager once it's fully fleshed out.
3735 int32_t screenLeft = screen->AvailLeft();
3736 int32_t screenWidth = screen->AvailWidth();
3737 int32_t screenHeight = screen->AvailHeight();
3738#if defined(XP_MACOSX)
3739 /* The mac's coordinate system is different from the assumed Windows'
3740 system. It offsets by the height of the menubar so that a window
3741 placed at (0,0) will be entirely visible. Unfortunately that
3742 correction is made elsewhere (in Widget) and the meaning of
3743 the Avail... coordinates is overloaded. Here we allow a window
3744 to be placed at (0,0) because it does make sense to do so.
3745 */
3746 int32_t screenTop = screen->Top();
3747#else
3748 int32_t screenTop = screen->AvailTop();
3749#endif
3750
3751 if (aLeft) {
3752 if (screenLeft + screenWidth < *aLeft + winRect.width)
3753 *aLeft = screenLeft + screenWidth - winRect.width;
3754 if (screenLeft > *aLeft) *aLeft = screenLeft;
3755 }
3756 if (aTop) {
3757 if (screenTop + screenHeight < *aTop + winRect.height)
3758 *aTop = screenTop + screenHeight - winRect.height;
3759 if (screenTop > *aTop) *aTop = screenTop;
3760 }
3761 } else {
3762 if (aLeft) *aLeft = 0;
3763 if (aTop) *aTop = 0;
3764 }
3765 }
3766}
3767
3768int32_t nsGlobalWindowOuter::GetScrollBoundaryOuter(Side aSide) {
3769 FlushPendingNotifications(FlushType::Layout);
3770 if (ScrollContainerFrame* sf = GetScrollContainerFrame()) {
3771 return nsPresContext::AppUnitsToIntCSSPixels(
3772 sf->GetScrollRange().Edge(aSide));
3773 }
3774 return 0;
3775}
3776
3777CSSPoint nsGlobalWindowOuter::GetScrollXY(bool aDoFlush) {
3778 if (aDoFlush) {
3779 FlushPendingNotifications(FlushType::Layout);
3780 } else {
3781 EnsureSizeAndPositionUpToDate();
3782 }
3783
3784 ScrollContainerFrame* sf = GetScrollContainerFrame();
3785 if (!sf) {
3786 return CSSIntPoint(0, 0);
3787 }
3788
3789 nsPoint scrollPos = sf->GetScrollPosition();
3790 if (scrollPos != nsPoint(0, 0) && !aDoFlush) {
3791 // Oh, well. This is the expensive case -- the window is scrolled and we
3792 // didn't actually flush yet. Repeat, but with a flush, since the content
3793 // may get shorter and hence our scroll position may decrease.
3794 return GetScrollXY(true);
3795 }
3796
3797 return CSSPoint::FromAppUnits(scrollPos);
3798}
3799
3800double nsGlobalWindowOuter::GetScrollXOuter() { return GetScrollXY(false).x; }
3801
3802double nsGlobalWindowOuter::GetScrollYOuter() { return GetScrollXY(false).y; }
3803
3804uint32_t nsGlobalWindowOuter::Length() {
3805 BrowsingContext* bc = GetBrowsingContext();
3806 return bc ? bc->NonSyntheticChildren().Length() : 0;
3807}
3808
3809Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetTopOuter() {
3810 BrowsingContext* bc = GetBrowsingContext();
3811 return bc ? bc->GetTop(IgnoreErrors()) : nullptr;
3812}
3813
3814already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetChildWindow(
3815 const nsAString& aName) {
3816 NS_ENSURE_TRUE(mBrowsingContext, nullptr)do { if ((__builtin_expect(!!(!(mBrowsingContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mBrowsingContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3816); return nullptr; } } while (false)
;
3817 NS_ENSURE_TRUE(mInnerWindow, nullptr)do { if ((__builtin_expect(!!(!(mInnerWindow)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mInnerWindow" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3817); return nullptr; } } while (false)
;
3818 NS_ENSURE_TRUE(mInnerWindow->GetWindowGlobalChild(), nullptr)do { if ((__builtin_expect(!!(!(mInnerWindow->GetWindowGlobalChild
())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"mInnerWindow->GetWindowGlobalChild()" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3818); return nullptr; } } while (false)
;
3819
3820 return do_AddRef(mBrowsingContext->FindChildWithName(
3821 aName, *mInnerWindow->GetWindowGlobalChild()));
3822}
3823
3824bool nsGlobalWindowOuter::DispatchCustomEvent(
3825 const nsAString& aEventName, ChromeOnlyDispatch aChromeOnlyDispatch) {
3826 bool defaultActionEnabled = true;
3827
3828 if (aChromeOnlyDispatch == ChromeOnlyDispatch::eYes) {
3829 nsContentUtils::DispatchEventOnlyToChrome(mDoc, this, aEventName,
3830 CanBubble::eYes, Cancelable::eYes,
3831 &defaultActionEnabled);
3832 } else {
3833 nsContentUtils::DispatchTrustedEvent(mDoc, this, aEventName,
3834 CanBubble::eYes, Cancelable::eYes,
3835 &defaultActionEnabled);
3836 }
3837
3838 return defaultActionEnabled;
3839}
3840
3841bool nsGlobalWindowOuter::DispatchResizeEvent(const CSSIntSize& aSize) {
3842 ErrorResult res;
3843 RefPtr<Event> domEvent =
3844 mDoc->CreateEvent(u"CustomEvent"_ns, CallerType::System, res);
3845 if (res.Failed()) {
3846 return false;
3847 }
3848
3849 // We don't init the AutoJSAPI with ourselves because we don't want it
3850 // reporting errors to our onerror handlers.
3851 AutoJSAPI jsapi;
3852 jsapi.Init();
3853 JSContext* cx = jsapi.cx();
3854 JSAutoRealm ar(cx, GetWrapperPreserveColor());
3855
3856 DOMWindowResizeEventDetail detail;
3857 detail.mWidth = aSize.width;
3858 detail.mHeight = aSize.height;
3859 JS::Rooted<JS::Value> detailValue(cx);
3860 if (!ToJSValue(cx, detail, &detailValue)) {
3861 return false;
3862 }
3863
3864 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
3865 customEvent->InitCustomEvent(cx, u"DOMWindowResize"_ns,
3866 /* aCanBubble = */ true,
3867 /* aCancelable = */ true, detailValue);
3868
3869 domEvent->SetTrusted(true);
3870 domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
3871
3872 nsCOMPtr<EventTarget> target = this;
3873 domEvent->SetTarget(target);
3874
3875 return target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
3876}
3877
3878bool nsGlobalWindowOuter::WindowExists(const nsAString& aName,
3879 bool aForceNoOpener,
3880 bool aLookForCallerOnJSStack) {
3881 MOZ_ASSERT(mDocShell, "Must have docshell")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDocShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDocShell))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mDocShell" " (" "Must have docshell"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3881); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocShell" ") ("
"Must have docshell" ")"); do { *((volatile int*)__null) = 3881
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3882
3883 if (aForceNoOpener) {
3884 return aName.LowerCaseEqualsLiteral("_self") ||
3885 aName.LowerCaseEqualsLiteral("_top") ||
3886 aName.LowerCaseEqualsLiteral("_parent");
3887 }
3888
3889 if (WindowGlobalChild* wgc = mInnerWindow->GetWindowGlobalChild()) {
3890 return wgc->FindBrowsingContextWithName(aName, aLookForCallerOnJSStack);
3891 }
3892 return false;
3893}
3894
3895already_AddRefed<nsIWidget> nsGlobalWindowOuter::GetMainWidget() {
3896 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3897
3898 nsCOMPtr<nsIWidget> widget;
3899
3900 if (treeOwnerAsWin) {
3901 treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
3902 }
3903
3904 return widget.forget();
3905}
3906
3907nsIWidget* nsGlobalWindowOuter::GetNearestWidget() const {
3908 nsIDocShell* docShell = GetDocShell();
3909 if (!docShell) {
3910 return nullptr;
3911 }
3912 PresShell* presShell = docShell->GetPresShell();
3913 if (!presShell) {
3914 return nullptr;
3915 }
3916 nsIFrame* rootFrame = presShell->GetRootFrame();
3917 if (!rootFrame) {
3918 return nullptr;
3919 }
3920 return rootFrame->GetView()->GetNearestWidget(nullptr);
3921}
3922
3923void nsGlobalWindowOuter::SetFullscreenOuter(bool aFullscreen,
3924 mozilla::ErrorResult& aError) {
3925 aError =
3926 SetFullscreenInternal(FullscreenReason::ForFullscreenMode, aFullscreen);
3927}
3928
3929nsresult nsGlobalWindowOuter::SetFullScreen(bool aFullscreen) {
3930 return SetFullscreenInternal(FullscreenReason::ForFullscreenMode,
3931 aFullscreen);
3932}
3933
3934static void FinishDOMFullscreenChange(Document* aDoc, bool aInDOMFullscreen) {
3935 if (aInDOMFullscreen) {
3936 // Ask the document to handle any pending DOM fullscreen change.
3937 if (!Document::HandlePendingFullscreenRequests(aDoc)) {
3938 // If we don't end up having anything in fullscreen,
3939 // async request exiting fullscreen.
3940 Document::AsyncExitFullscreen(aDoc);
3941 }
3942 } else {
3943 // If the window is leaving fullscreen state, also ask the document
3944 // to exit from DOM Fullscreen.
3945 Document::ExitFullscreenInDocTree(aDoc);
3946 }
3947}
3948
3949struct FullscreenTransitionDuration {
3950 // The unit of the durations is millisecond
3951 uint16_t mFadeIn = 0;
3952 uint16_t mFadeOut = 0;
3953 bool IsSuppressed() const { return mFadeIn == 0 && mFadeOut == 0; }
3954};
3955
3956static void GetFullscreenTransitionDuration(
3957 bool aEnterFullscreen, FullscreenTransitionDuration* aDuration) {
3958 const char* pref = aEnterFullscreen
3959 ? "full-screen-api.transition-duration.enter"
3960 : "full-screen-api.transition-duration.leave";
3961 nsAutoCString prefValue;
3962 Preferences::GetCString(pref, prefValue);
3963 if (!prefValue.IsEmpty()) {
3964 sscanf(prefValue.get(), "%hu%hu", &aDuration->mFadeIn,
3965 &aDuration->mFadeOut);
3966 }
3967}
3968
3969class FullscreenTransitionTask : public Runnable {
3970 public:
3971 FullscreenTransitionTask(const FullscreenTransitionDuration& aDuration,
3972 nsGlobalWindowOuter* aWindow, bool aFullscreen,
3973 nsIWidget* aWidget, nsISupports* aTransitionData)
3974 : mozilla::Runnable("FullscreenTransitionTask"),
3975 mWindow(aWindow),
3976 mWidget(aWidget),
3977 mTransitionData(aTransitionData),
3978 mDuration(aDuration),
3979 mStage(eBeforeToggle),
3980 mFullscreen(aFullscreen) {}
3981
3982 NS_IMETHODvirtual nsresult Run() override;
3983
3984 private:
3985 ~FullscreenTransitionTask() override = default;
3986
3987 /**
3988 * The flow of fullscreen transition:
3989 *
3990 * parent process | child process
3991 * ----------------------------------------------------------------
3992 *
3993 * | request/exit fullscreen
3994 * <-----|
3995 * BeforeToggle stage |
3996 * |
3997 * ToggleFullscreen stage *1 |----->
3998 * | HandleFullscreenRequests
3999 * |
4000 * <-----| MozAfterPaint event
4001 * AfterToggle stage *2 |
4002 * |
4003 * End stage |
4004 *
4005 * Note we also start a timer at *1 so that if we don't get MozAfterPaint
4006 * from the child process in time, we continue going to *2.
4007 */
4008 enum Stage {
4009 // BeforeToggle stage happens before we enter or leave fullscreen
4010 // state. In this stage, the task triggers the pre-toggle fullscreen
4011 // transition on the widget.
4012 eBeforeToggle,
4013 // ToggleFullscreen stage actually executes the fullscreen toggle,
4014 // and wait for the next paint on the content to continue.
4015 eToggleFullscreen,
4016 // AfterToggle stage happens after we toggle the fullscreen state.
4017 // In this stage, the task triggers the post-toggle fullscreen
4018 // transition on the widget.
4019 eAfterToggle,
4020 // End stage is triggered after the final transition finishes.
4021 eEnd
4022 };
4023
4024 class Observer final : public nsIObserver, public nsINamed {
4025 public:
4026 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
4027 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
4028 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
4029
4030 explicit Observer(FullscreenTransitionTask* aTask) : mTask(aTask) {}
4031
4032 private:
4033 ~Observer() = default;
4034
4035 RefPtr<FullscreenTransitionTask> mTask;
4036 };
4037
4038 static const char* const kPaintedTopic;
4039
4040 RefPtr<nsGlobalWindowOuter> mWindow;
4041 nsCOMPtr<nsIWidget> mWidget;
4042 nsCOMPtr<nsITimer> mTimer;
4043 nsCOMPtr<nsISupports> mTransitionData;
4044
4045 TimeStamp mFullscreenChangeStartTime;
4046 FullscreenTransitionDuration mDuration;
4047 Stage mStage;
4048 bool mFullscreen;
4049};
4050
4051const char* const FullscreenTransitionTask::kPaintedTopic =
4052 "fullscreen-painted";
4053
4054NS_IMETHODIMPnsresult
4055FullscreenTransitionTask::Run() {
4056 Stage stage = mStage;
4057 mStage = Stage(mStage + 1);
4058 if (MOZ_UNLIKELY(mWidget->Destroyed())(__builtin_expect(!!(mWidget->Destroyed()), 0))) {
4059 // If the widget has been destroyed before we get here, don't try to
4060 // do anything more. Just let it go and release ourselves.
4061 NS_WARNING("The widget to fullscreen has been destroyed")NS_DebugBreak(NS_DEBUG_WARNING, "The widget to fullscreen has been destroyed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4061)
;
4062 mWindow->mIsInFullScreenTransition = false;
4063 return NS_OK;
4064 }
4065 if (stage == eBeforeToggle) {
4066 PROFILER_MARKER_UNTYPED("Fullscreen transition start", DOM)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Fullscreen transition start", ::geckoprofiler::category::DOM
); } } while (false); } while (false)
;
4067
4068 mWindow->mIsInFullScreenTransition = true;
4069
4070 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4071 NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(obs)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "obs" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4071); return NS_ERROR_FAILURE; } } while (false)
;
4072 obs->NotifyObservers(nullptr, "fullscreen-transition-start", nullptr);
4073
4074 mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,
4075 mDuration.mFadeIn, mTransitionData,
4076 this);
4077 } else if (stage == eToggleFullscreen) {
4078 PROFILER_MARKER_UNTYPED("Fullscreen toggle start", DOM)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Fullscreen toggle start", ::geckoprofiler::category::DOM); }
} while (false); } while (false)
;
4079 mFullscreenChangeStartTime = TimeStamp::Now();
4080 // Toggle the fullscreen state on the widget
4081 if (!mWindow->SetWidgetFullscreen(FullscreenReason::ForFullscreenAPI,
4082 mFullscreen, mWidget)) {
4083 // Fail to setup the widget, call FinishFullscreenChange to
4084 // complete fullscreen change directly.
4085 mWindow->FinishFullscreenChange(mFullscreen);
4086 }
4087 // Set observer for the next content paint.
4088 nsCOMPtr<nsIObserver> observer = new Observer(this);
4089 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4090 obs->AddObserver(observer, kPaintedTopic, false);
4091 // There are several edge cases where we may never get the paint
4092 // notification, including:
4093 // 1. the window/tab is closed before the next paint;
4094 // 2. the user has switched to another tab before we get here.
4095 // Completely fixing those cases seems to be tricky, and since they
4096 // should rarely happen, it probably isn't worth to fix. Hence we
4097 // simply add a timeout here to ensure we never hang forever.
4098 // In addition, if the page is complicated or the machine is less
4099 // powerful, layout could take a long time, in which case, staying
4100 // in black screen for that long could hurt user experience even
4101 // more than exposing an intermediate state.
4102 uint32_t timeout =
4103 Preferences::GetUint("full-screen-api.transition.timeout", 1000);
4104 NS_NewTimerWithObserver(getter_AddRefs(mTimer), observer, timeout,
4105 nsITimer::TYPE_ONE_SHOT);
4106 } else if (stage == eAfterToggle) {
4107 Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,
4108 mFullscreenChangeStartTime);
4109 mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
4110 mDuration.mFadeOut, mTransitionData,
4111 this);
4112 } else if (stage == eEnd) {
4113 PROFILER_MARKER_UNTYPED("Fullscreen transition end", DOM)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Fullscreen transition end", ::geckoprofiler::category::DOM)
; } } while (false); } while (false)
;
4114
4115 mWindow->mIsInFullScreenTransition = false;
4116
4117 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4118 NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(obs)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "obs" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4118); return NS_ERROR_FAILURE; } } while (false)
;
4119 obs->NotifyObservers(nullptr, "fullscreen-transition-end", nullptr);
4120
4121 mWidget->CleanupFullscreenTransition();
4122 }
4123 return NS_OK;
4124}
4125
4126NS_IMPL_ISUPPORTS(FullscreenTransitionTask::Observer, nsIObserver, nsINamed)MozExternalRefCountType FullscreenTransitionTask::Observer::AddRef
(void) { static_assert(!std::is_destructible_v<FullscreenTransitionTask
::Observer>, "Reference-counted class " "FullscreenTransitionTask::Observer"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
4126; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("FullscreenTransitionTask::Observer" != nullptr)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("FullscreenTransitionTask::Observer" != nullptr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("\"FullscreenTransitionTask::Observer\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionTask::Observer\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 4126; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("FullscreenTransitionTask::Observer" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"FullscreenTransitionTask::Observer"), (uint32_t)(sizeof(*this
))); return count; } MozExternalRefCountType FullscreenTransitionTask
::Observer::Release(void) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 4126
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("FullscreenTransitionTask::Observer" != nullptr)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("FullscreenTransitionTask::Observer" != nullptr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("\"FullscreenTransitionTask::Observer\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionTask::Observer\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 4126; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("FullscreenTransitionTask::Observer" " not thread-safe"
); const char* const nametmp = "FullscreenTransitionTask::Observer"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult FullscreenTransitionTask::Observer
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4126); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<FullscreenTransitionTask::Observer, nsIObserver
>, int32_t( reinterpret_cast<char*>(static_cast<nsIObserver
*>((FullscreenTransitionTask::Observer*)0x1000)) - reinterpret_cast
<char*>((FullscreenTransitionTask::Observer*)0x1000))},
{&mozilla::detail::kImplementedIID<FullscreenTransitionTask
::Observer, nsINamed>, int32_t( reinterpret_cast<char*>
(static_cast<nsINamed*>((FullscreenTransitionTask::Observer
*)0x1000)) - reinterpret_cast<char*>((FullscreenTransitionTask
::Observer*)0x1000))}, {&mozilla::detail::kImplementedIID
<FullscreenTransitionTask::Observer, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIObserver*>((FullscreenTransitionTask::
Observer*)0x1000))) - reinterpret_cast<char*>((FullscreenTransitionTask
::Observer*)0x1000))}, { nullptr, 0 } } ; static_assert(std::
size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
4127
4128NS_IMETHODIMPnsresult
4129FullscreenTransitionTask::Observer::Observe(nsISupports* aSubject,
4130 const char* aTopic,
4131 const char16_t* aData) {
4132 bool shouldContinue = false;
4133 if (strcmp(aTopic, FullscreenTransitionTask::kPaintedTopic) == 0) {
4134 nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aSubject));
4135 nsCOMPtr<nsIWidget> widget =
4136 win ? nsGlobalWindowInner::Cast(win)->GetMainWidget() : nullptr;
4137 if (widget == mTask->mWidget) {
4138 // The paint notification arrives first. Cancel the timer.
4139 mTask->mTimer->Cancel();
4140 shouldContinue = true;
4141 PROFILER_MARKER_UNTYPED("Fullscreen toggle end", DOM)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Fullscreen toggle end", ::geckoprofiler::category::DOM); } }
while (false); } while (false)
;
4142 }
4143 } else {
4144#ifdef DEBUG1
4145 MOZ_ASSERT(strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC) == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(strcmp(aTopic, "timer-callback") == 0)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(strcmp(aTopic, "timer-callback") == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("strcmp(aTopic, \"timer-callback\") == 0"
" (" "Should only get fullscreen-painted or timer-callback" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"timer-callback\") == 0"
") (" "Should only get fullscreen-painted or timer-callback"
")"); do { *((volatile int*)__null) = 4146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4146 "Should only get fullscreen-painted or timer-callback")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(strcmp(aTopic, "timer-callback") == 0)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(strcmp(aTopic, "timer-callback") == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("strcmp(aTopic, \"timer-callback\") == 0"
" (" "Should only get fullscreen-painted or timer-callback" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"timer-callback\") == 0"
") (" "Should only get fullscreen-painted or timer-callback"
")"); do { *((volatile int*)__null) = 4146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4147 nsCOMPtr<nsITimer> timer(do_QueryInterface(aSubject));
4148 MOZ_ASSERT(timer && timer == mTask->mTimer,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(timer && timer == mTask->mTimer)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(timer && timer == mTask->mTimer))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("timer && timer == mTask->mTimer"
" (" "Should only trigger this with the timer the task created"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "timer && timer == mTask->mTimer"
") (" "Should only trigger this with the timer the task created"
")"); do { *((volatile int*)__null) = 4149; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4149 "Should only trigger this with the timer the task created")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(timer && timer == mTask->mTimer)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(timer && timer == mTask->mTimer))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("timer && timer == mTask->mTimer"
" (" "Should only trigger this with the timer the task created"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "timer && timer == mTask->mTimer"
") (" "Should only trigger this with the timer the task created"
")"); do { *((volatile int*)__null) = 4149; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4150#endif
4151 shouldContinue = true;
4152 PROFILER_MARKER_UNTYPED("Fullscreen toggle timeout", DOM)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Fullscreen toggle timeout", ::geckoprofiler::category::DOM)
; } } while (false); } while (false)
;
4153 }
4154 if (shouldContinue) {
4155 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4156 obs->RemoveObserver(this, kPaintedTopic);
4157 mTask->mTimer = nullptr;
4158 mTask->Run();
4159 }
4160 return NS_OK;
4161}
4162
4163NS_IMETHODIMPnsresult
4164FullscreenTransitionTask::Observer::GetName(nsACString& aName) {
4165 aName.AssignLiteral("FullscreenTransitionTask");
4166 return NS_OK;
4167}
4168
4169static bool MakeWidgetFullscreen(nsGlobalWindowOuter* aWindow,
4170 FullscreenReason aReason, bool aFullscreen) {
4171 nsCOMPtr<nsIWidget> widget = aWindow->GetMainWidget();
4172 if (!widget) {
4173 return false;
4174 }
4175
4176 FullscreenTransitionDuration duration;
4177 bool performTransition = false;
4178 nsCOMPtr<nsISupports> transitionData;
4179 if (aReason == FullscreenReason::ForFullscreenAPI) {
4180 GetFullscreenTransitionDuration(aFullscreen, &duration);
4181 if (!duration.IsSuppressed()) {
4182 performTransition = widget->PrepareForFullscreenTransition(
4183 getter_AddRefs(transitionData));
4184 }
4185 }
4186
4187 if (!performTransition) {
4188 return aWindow->SetWidgetFullscreen(aReason, aFullscreen, widget);
4189 }
4190
4191 nsCOMPtr<nsIRunnable> task = new FullscreenTransitionTask(
4192 duration, aWindow, aFullscreen, widget, transitionData);
4193 task->Run();
4194 return true;
4195}
4196
4197nsresult nsGlobalWindowOuter::ProcessWidgetFullscreenRequest(
4198 FullscreenReason aReason, bool aFullscreen) {
4199 mInProcessFullscreenRequest.emplace(aReason, aFullscreen);
4200
4201 // Prevent chrome documents which are still loading from resizing
4202 // the window after we set fullscreen mode.
4203 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4204 nsCOMPtr<nsIAppWindow> appWin(do_GetInterface(treeOwnerAsWin));
4205 if (aFullscreen && appWin) {
4206 appWin->SetIntrinsicallySized(false);
4207 }
4208
4209 // Sometimes we don't want the top-level widget to actually go fullscreen:
4210 // - in the B2G desktop client, we don't want the emulated screen dimensions
4211 // to appear to increase when entering fullscreen mode; we just want the
4212 // content to fill the entire client area of the emulator window.
4213 // - in FxR Desktop, we don't want fullscreen to take over the monitor, but
4214 // instead we want fullscreen to fill the FxR window in the the headset.
4215 if (!StaticPrefs::full_screen_api_ignore_widgets() &&
4216 !mForceFullScreenInWidget) {
4217 if (MakeWidgetFullscreen(this, aReason, aFullscreen)) {
4218 // The rest of code for switching fullscreen is in nsGlobalWindowOuter::
4219 // FinishFullscreenChange() which will be called after sizemodechange
4220 // event is dispatched.
4221 return NS_OK;
4222 }
4223 }
4224
4225#if defined(NIGHTLY_BUILD1) && defined(XP_WIN)
4226 if (FxRWindowManager::GetInstance()->IsFxRWindow(mWindowID)) {
4227 mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/);
4228 shmem.SendFullscreenState(mWindowID, aFullscreen);
4229 }
4230#endif // NIGHTLY_BUILD && XP_WIN
4231 FinishFullscreenChange(aFullscreen);
4232 return NS_OK;
4233}
4234
4235nsresult nsGlobalWindowOuter::SetFullscreenInternal(FullscreenReason aReason,
4236 bool aFullscreen) {
4237 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsContentUtils::IsSafeToRunScript())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::IsSafeToRunScript
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nsContentUtils::IsSafeToRunScript()" " (" "Requires safe to run script as it "
"may call FinishDOMFullscreenChange" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4239; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4238 "Requires safe to run script as it "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsContentUtils::IsSafeToRunScript())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::IsSafeToRunScript
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nsContentUtils::IsSafeToRunScript()" " (" "Requires safe to run script as it "
"may call FinishDOMFullscreenChange" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4239; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4239 "may call FinishDOMFullscreenChange")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsContentUtils::IsSafeToRunScript())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::IsSafeToRunScript
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nsContentUtils::IsSafeToRunScript()" " (" "Requires safe to run script as it "
"may call FinishDOMFullscreenChange" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4239); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4239; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4240
4241 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4241); return NS_ERROR_FAILURE; } } while (false)
;
4242
4243 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aReason != FullscreenReason::ForForceExitFullscreen ||
!aFullscreen)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aReason != FullscreenReason::ForForceExitFullscreen
|| !aFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
" (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4244 aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aReason != FullscreenReason::ForForceExitFullscreen ||
!aFullscreen)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aReason != FullscreenReason::ForForceExitFullscreen
|| !aFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
" (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4245 "FullscreenReason::ForForceExitFullscreen can "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aReason != FullscreenReason::ForForceExitFullscreen ||
!aFullscreen)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aReason != FullscreenReason::ForForceExitFullscreen
|| !aFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
" (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4246 "only be used with exiting fullscreen")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aReason != FullscreenReason::ForForceExitFullscreen ||
!aFullscreen)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aReason != FullscreenReason::ForForceExitFullscreen
|| !aFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
" (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4247
4248 // Only chrome can change our fullscreen mode. Otherwise, the state
4249 // can only be changed for DOM fullscreen.
4250 if (aReason == FullscreenReason::ForFullscreenMode &&
4251 !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
4252 return NS_OK;
4253 }
4254
4255 // SetFullscreen needs to be called on the root window, so get that
4256 // via the DocShell tree, and if we are not already the root,
4257 // call SetFullscreen on that window instead.
4258 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4259 mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
4260 nsCOMPtr<nsPIDOMWindowOuter> window =
4261 rootItem ? rootItem->GetWindow() : nullptr;
4262 if (!window) return NS_ERROR_FAILURE;
4263 if (rootItem != mDocShell)
4264 return window->SetFullscreenInternal(aReason, aFullscreen);
4265
4266 // make sure we don't try to set full screen on a non-chrome window,
4267 // which might happen in embedding world
4268 if (mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome)
4269 return NS_ERROR_FAILURE;
4270
4271 // FullscreenReason::ForForceExitFullscreen can only be used with exiting
4272 // fullscreen
4273 MOZ_ASSERT_IF(do { if (mFullscreen.isSome()) { do { static_assert( mozilla::
detail::AssertionConditionType<decltype(mFullscreen.value(
) != FullscreenReason::ForForceExitFullscreen)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFullscreen.value() != FullscreenReason
::ForForceExitFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4274 mFullscreen.isSome(),do { if (mFullscreen.isSome()) { do { static_assert( mozilla::
detail::AssertionConditionType<decltype(mFullscreen.value(
) != FullscreenReason::ForForceExitFullscreen)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFullscreen.value() != FullscreenReason
::ForForceExitFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4275 mFullscreen.value() != FullscreenReason::ForForceExitFullscreen)do { if (mFullscreen.isSome()) { do { static_assert( mozilla::
detail::AssertionConditionType<decltype(mFullscreen.value(
) != FullscreenReason::ForForceExitFullscreen)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFullscreen.value() != FullscreenReason
::ForForceExitFullscreen))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4276
4277 // If we are already in full screen mode, just return, we don't care about the
4278 // reason here, because,
4279 // - If we are in fullscreen mode due to browser fullscreen mode, requesting
4280 // DOM fullscreen does not change anything.
4281 // - If we are in fullscreen mode due to DOM fullscreen, requesting browser
4282 // fullscreen should not change anything, either. Note that we should not
4283 // update reason to ForFullscreenMode, otherwise the subsequent DOM
4284 // fullscreen exit will be ignored and user will be confused. And ideally
4285 // this should never happen as `window.fullscreen` returns `true` for DOM
4286 // fullscreen as well.
4287 if (mFullscreen.isSome() == aFullscreen) {
4288 // How come we get browser fullscreen request while we are already in DOM
4289 // fullscreen?
4290 MOZ_ASSERT_IF(aFullscreen && aReason == FullscreenReason::ForFullscreenMode,do { if (aFullscreen && aReason == FullscreenReason::
ForFullscreenMode) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(mFullscreen.value() != FullscreenReason::ForFullscreenAPI
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mFullscreen.value() != FullscreenReason::ForFullscreenAPI
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mFullscreen.value() != FullscreenReason::ForFullscreenAPI", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4291); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForFullscreenAPI"
")"); do { *((volatile int*)__null) = 4291; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4291 mFullscreen.value() != FullscreenReason::ForFullscreenAPI)do { if (aFullscreen && aReason == FullscreenReason::
ForFullscreenMode) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(mFullscreen.value() != FullscreenReason::ForFullscreenAPI
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mFullscreen.value() != FullscreenReason::ForFullscreenAPI
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mFullscreen.value() != FullscreenReason::ForFullscreenAPI", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4291); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForFullscreenAPI"
")"); do { *((volatile int*)__null) = 4291; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4292 return NS_OK;
4293 }
4294
4295 // Note that although entering DOM fullscreen could also cause
4296 // consequential calls to this method, those calls will be skipped
4297 // at the condition above.
4298 if (aReason == FullscreenReason::ForFullscreenMode) {
4299 if (!aFullscreen && mFullscreen &&
4300 mFullscreen.value() == FullscreenReason::ForFullscreenAPI) {
4301 // If we are exiting fullscreen mode, but we actually didn't
4302 // entered browser fullscreen mode, the fullscreen state was only for
4303 // the Fullscreen API. Change the reason here so that we can
4304 // perform transition for it.
4305 aReason = FullscreenReason::ForFullscreenAPI;
4306 }
4307 } else {
4308 // If we are exiting from DOM fullscreen while we initially make
4309 // the window fullscreen because of browser fullscreen mode, don't restore
4310 // the window. But we still need to exit the DOM fullscreen state.
4311 if (!aFullscreen && mFullscreen &&
4312 mFullscreen.value() == FullscreenReason::ForFullscreenMode) {
4313 // If there is a in-process fullscreen request, FinishDOMFullscreenChange
4314 // will be called when the request is finished.
4315 if (!mInProcessFullscreenRequest.isSome()) {
4316 FinishDOMFullscreenChange(mDoc, false);
4317 }
4318 return NS_OK;
4319 }
4320 }
4321
4322 // Set this before so if widget sends an event indicating its
4323 // gone full screen, the state trap above works.
4324 if (aFullscreen) {
4325 mFullscreen.emplace(aReason);
4326 } else {
4327 mFullscreen.reset();
4328 }
4329
4330 // If we are in process of fullscreen request, only keep the latest fullscreen
4331 // state, we will sync up later while the processing request is finished.
4332 if (mInProcessFullscreenRequest.isSome()) {
4333 mFullscreenHasChangedDuringProcessing = true;
4334 return NS_OK;
4335 }
4336
4337 return ProcessWidgetFullscreenRequest(aReason, aFullscreen);
4338}
4339
4340// Support a per-window, dynamic equivalent of enabling
4341// full-screen-api.ignore-widgets
4342void nsGlobalWindowOuter::ForceFullScreenInWidget() {
4343 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4343); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4343; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4344
4345 mForceFullScreenInWidget = true;
4346}
4347
4348bool nsGlobalWindowOuter::SetWidgetFullscreen(FullscreenReason aReason,
4349 bool aIsFullscreen,
4350 nsIWidget* aWidget) {
4351 MOZ_ASSERT(this == GetInProcessTopInternal(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(this == GetInProcessTopInternal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(this == GetInProcessTopInternal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("this == GetInProcessTopInternal()" " (" "Only topmost window should call this"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4352); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this == GetInProcessTopInternal()"
") (" "Only topmost window should call this" ")"); do { *((volatile
int*)__null) = 4352; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
4352 "Only topmost window should call this")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(this == GetInProcessTopInternal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(this == GetInProcessTopInternal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("this == GetInProcessTopInternal()" " (" "Only topmost window should call this"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4352); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this == GetInProcessTopInternal()"
") (" "Only topmost window should call this" ")"); do { *((volatile
int*)__null) = 4352; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4353 MOZ_ASSERT(!GetFrameElementInternal(), "Content window should not call this")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!GetFrameElementInternal())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!GetFrameElementInternal()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!GetFrameElementInternal()"
" (" "Content window should not call this" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetFrameElementInternal()"
") (" "Content window should not call this" ")"); do { *((volatile
int*)__null) = 4353; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4354 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_GetProcessType() == GeckoProcessType_Default)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(XRE_GetProcessType() == GeckoProcessType_Default))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_GetProcessType() == GeckoProcessType_Default"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_GetProcessType() == GeckoProcessType_Default"
")"); do { *((volatile int*)__null) = 4354; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4355
4356 if (!NS_WARN_IF(!IsChromeWindow())NS_warn_if_impl(!IsChromeWindow(), "!IsChromeWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4356)
) {
4357 if (!NS_WARN_IF(mChromeFields.mFullscreenPresShell)NS_warn_if_impl(mChromeFields.mFullscreenPresShell, "mChromeFields.mFullscreenPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4357)
) {
4358 if (PresShell* presShell = mDocShell->GetPresShell()) {
4359 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
4360 mChromeFields.mFullscreenPresShell = do_GetWeakReference(presShell);
4361 MOZ_ASSERT(mChromeFields.mFullscreenPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChromeFields.mFullscreenPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChromeFields.mFullscreenPresShell
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mChromeFields.mFullscreenPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChromeFields.mFullscreenPresShell"
")"); do { *((volatile int*)__null) = 4361; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4362 rd->SetIsResizeSuppressed();
4363 rd->Freeze();
4364 }
4365 }
4366 }
4367 }
4368 nsresult rv = aReason == FullscreenReason::ForFullscreenMode
4369 ?
4370 // If we enter fullscreen for fullscreen mode, we want
4371 // the native system behavior.
4372 aWidget->MakeFullScreenWithNativeTransition(aIsFullscreen)
4373 : aWidget->MakeFullScreen(aIsFullscreen);
4374 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
4375}
4376
4377/* virtual */
4378void nsGlobalWindowOuter::FullscreenWillChange(bool aIsFullscreen) {
4379 if (!mInProcessFullscreenRequest.isSome()) {
4380 // If there is no in-process fullscreen request, the fullscreen state change
4381 // is triggered from the OS directly, e.g. user use built-in window button
4382 // to enter/exit fullscreen on macOS.
4383 mInProcessFullscreenRequest.emplace(FullscreenReason::ForFullscreenMode,
4384 aIsFullscreen);
4385 if (mFullscreen.isSome() != aIsFullscreen) {
4386 if (aIsFullscreen) {
4387 mFullscreen.emplace(FullscreenReason::ForFullscreenMode);
4388 } else {
4389 mFullscreen.reset();
4390 }
4391 } else {
4392 // It is possible that FullscreenWillChange is notified with current
4393 // fullscreen state, e.g. browser goes into fullscreen when widget
4394 // fullscreen is prevented, and then user triggers fullscreen from the OS
4395 // directly again.
4396 MOZ_ASSERT(StaticPrefs::full_screen_api_ignore_widgets() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
" (" "This should only happen when widget fullscreen is prevented"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4398); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4398; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4397 mForceFullScreenInWidget,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
" (" "This should only happen when widget fullscreen is prevented"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4398); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4398; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4398 "This should only happen when widget fullscreen is prevented")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
" (" "This should only happen when widget fullscreen is prevented"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4398); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4398; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4399 }
4400 }
4401 if (aIsFullscreen) {
4402 DispatchCustomEvent(u"willenterfullscreen"_ns, ChromeOnlyDispatch::eYes);
4403 } else {
4404 DispatchCustomEvent(u"willexitfullscreen"_ns, ChromeOnlyDispatch::eYes);
4405 }
4406}
4407
4408/* virtual */
4409void nsGlobalWindowOuter::FinishFullscreenChange(bool aIsFullscreen) {
4410 mozilla::Maybe<FullscreenRequest> currentInProcessRequest =
4411 std::move(mInProcessFullscreenRequest);
4412 if (!mFullscreenHasChangedDuringProcessing &&
4413 aIsFullscreen != mFullscreen.isSome()) {
4414 NS_WARNING("Failed to toggle fullscreen state of the widget")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to toggle fullscreen state of the widget"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4414)
;
4415 // We failed to make the widget enter fullscreen.
4416 // Stop further changes and restore the state.
4417 if (!aIsFullscreen) {
4418 mFullscreen.reset();
4419 } else {
4420#ifndef XP_MACOSX
4421 MOZ_ASSERT_UNREACHABLE("Failed to exit fullscreen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Failed to exit fullscreen?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4421); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Failed to exit fullscreen?" ")")
; do { *((volatile int*)__null) = 4421; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4422#endif
4423 // Restore fullscreen state with FullscreenReason::ForFullscreenAPI reason
4424 // in order to make subsequent DOM fullscreen exit request can exit
4425 // browser fullscreen mode.
4426 mFullscreen.emplace(FullscreenReason::ForFullscreenAPI);
4427 }
4428 return;
4429 }
4430
4431 // Note that we must call this to toggle the DOM fullscreen state
4432 // of the document before dispatching the "fullscreen" event, so
4433 // that the chrome can distinguish between browser fullscreen mode
4434 // and DOM fullscreen.
4435 FinishDOMFullscreenChange(mDoc, aIsFullscreen);
4436
4437 // dispatch a "fullscreen" DOM event so that XUL apps can
4438 // respond visually if we are kicked into full screen mode
4439 DispatchCustomEvent(u"fullscreen"_ns, ChromeOnlyDispatch::eYes);
4440
4441 if (!NS_WARN_IF(!IsChromeWindow())NS_warn_if_impl(!IsChromeWindow(), "!IsChromeWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4441)
) {
4442 if (RefPtr<PresShell> presShell =
4443 do_QueryReferent(mChromeFields.mFullscreenPresShell)) {
4444 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
4445 rd->Thaw();
4446 }
4447 mChromeFields.mFullscreenPresShell = nullptr;
4448 }
4449 }
4450
4451 // If fullscreen state has changed during processing fullscreen request, we
4452 // need to ensure widget matches our latest fullscreen state here.
4453 if (mFullscreenHasChangedDuringProcessing) {
4454 mFullscreenHasChangedDuringProcessing = false;
4455 // Widget doesn't care about the reason that makes it entering/exiting
4456 // fullscreen, so here we just need to ensure the fullscreen state is
4457 // matched.
4458 if (aIsFullscreen != mFullscreen.isSome()) {
4459 // If we end up need to exit fullscreen, use the same reason that brings
4460 // us into fullscreen mode, so that we will perform the same fullscreen
4461 // transistion effect for exiting.
4462 ProcessWidgetFullscreenRequest(
4463 mFullscreen.isSome() ? mFullscreen.value()
4464 : currentInProcessRequest.value().mReason,
4465 mFullscreen.isSome());
4466 }
4467 }
4468}
4469
4470/* virtual */
4471void nsGlobalWindowOuter::MacFullscreenMenubarOverlapChanged(
4472 mozilla::DesktopCoord aOverlapAmount) {
4473 ErrorResult res;
4474 RefPtr<Event> domEvent =
4475 mDoc->CreateEvent(u"CustomEvent"_ns, CallerType::System, res);
4476 if (res.Failed()) {
4477 return;
4478 }
4479
4480 AutoJSAPI jsapi;
4481 jsapi.Init();
4482 JSContext* cx = jsapi.cx();
4483 JSAutoRealm ar(cx, GetWrapperPreserveColor());
4484
4485 JS::Rooted<JS::Value> detailValue(cx);
4486 if (!ToJSValue(cx, aOverlapAmount, &detailValue)) {
4487 return;
4488 }
4489
4490 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
4491 customEvent->InitCustomEvent(cx, u"MacFullscreenMenubarRevealUpdate"_ns,
4492 /* aCanBubble = */ true,
4493 /* aCancelable = */ true, detailValue);
4494 domEvent->SetTrusted(true);
4495 domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
4496
4497 nsCOMPtr<EventTarget> target = this;
4498 domEvent->SetTarget(target);
4499
4500 target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
4501}
4502
4503bool nsGlobalWindowOuter::Fullscreen() const {
4504 NS_ENSURE_TRUE(mDocShell, mFullscreen.isSome())do { if ((__builtin_expect(!!(!(mDocShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4504); return mFullscreen.isSome(); } } while (false)
;
4505
4506 // Get the fullscreen value of the root window, to always have the value
4507 // accurate, even when called from content.
4508 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4509 mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
4510 if (rootItem == mDocShell) {
4511 if (!XRE_IsContentProcess()) {
4512 // We are the root window. Return our internal value.
4513 return mFullscreen.isSome();
4514 }
4515 if (nsCOMPtr<nsIWidget> widget = GetNearestWidget()) {
4516 // We are in content process, figure out the value from
4517 // the sizemode of the puppet widget.
4518 return widget->SizeMode() == nsSizeMode_Fullscreen;
4519 }
4520 return false;
4521 }
4522
4523 nsCOMPtr<nsPIDOMWindowOuter> window = rootItem->GetWindow();
4524 NS_ENSURE_TRUE(window, mFullscreen.isSome())do { if ((__builtin_expect(!!(!(window)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "window" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4524); return mFullscreen.isSome(); } } while (false)
;
4525
4526 return nsGlobalWindowOuter::Cast(window)->Fullscreen();
4527}
4528
4529bool nsGlobalWindowOuter::GetFullscreenOuter() { return Fullscreen(); }
4530
4531bool nsGlobalWindowOuter::GetFullScreen() {
4532 FORWARD_TO_INNER(GetFullScreen, (), false)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4532); return false; } return GetCurrentInnerWindowInternal
(this)->GetFullScreen (); } while (0)
;
4533}
4534
4535void nsGlobalWindowOuter::EnsureReflowFlushAndPaint() {
4536 NS_ASSERTION(mDocShell,do { if (!(mDocShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "EnsureReflowFlushAndPaint() called with no "
"docshell!", "mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4538); MOZ_PretendNoReturn(); } } while (0)
4537 "EnsureReflowFlushAndPaint() called with no "do { if (!(mDocShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "EnsureReflowFlushAndPaint() called with no "
"docshell!", "mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4538); MOZ_PretendNoReturn(); } } while (0)
4538 "docshell!")do { if (!(mDocShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "EnsureReflowFlushAndPaint() called with no "
"docshell!", "mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4538); MOZ_PretendNoReturn(); } } while (0)
;
4539
4540 if (!mDocShell) return;
4541
4542 RefPtr<PresShell> presShell = mDocShell->GetPresShell();
4543 if (!presShell) {
4544 return;
4545 }
4546
4547 // Flush pending reflows.
4548 if (mDoc) {
4549 mDoc->FlushPendingNotifications(FlushType::Layout);
4550 }
4551
4552 // Unsuppress painting.
4553 presShell->UnsuppressPainting();
4554}
4555
4556// static
4557void nsGlobalWindowOuter::MakeMessageWithPrincipal(
4558 nsAString& aOutMessage, nsIPrincipal* aSubjectPrincipal, bool aUseHostPort,
4559 const char* aNullMessage, const char* aContentMessage,
4560 const char* aFallbackMessage) {
4561 MOZ_ASSERT(aSubjectPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubjectPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSubjectPrincipal))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aSubjectPrincipal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4561); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubjectPrincipal"
")"); do { *((volatile int*)__null) = 4561; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4562
4563 aOutMessage.Truncate();
4564
4565 // Try to get a host from the running principal -- this will do the
4566 // right thing for javascript: and data: documents.
4567
4568 nsAutoCString contentDesc;
4569
4570 if (aSubjectPrincipal->GetIsNullPrincipal()) {
4571 nsContentUtils::GetLocalizedString(
4572 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, aNullMessage, aOutMessage);
4573 } else {
4574 auto* addonPolicy = BasePrincipal::Cast(aSubjectPrincipal)->AddonPolicy();
4575 if (addonPolicy) {
4576 nsContentUtils::FormatLocalizedString(
4577 aOutMessage, nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4578 aContentMessage, addonPolicy->Name());
4579 } else {
4580 nsresult rv = NS_ERROR_FAILURE;
4581 if (aUseHostPort) {
4582 nsCOMPtr<nsIURI> uri = aSubjectPrincipal->GetURI();
4583 if (uri) {
4584 rv = uri->GetDisplayHostPort(contentDesc);
4585 }
4586 }
4587 if (!aUseHostPort || NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4588 rv = aSubjectPrincipal->GetExposablePrePath(contentDesc);
4589 }
4590 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !contentDesc.IsEmpty()) {
4591 NS_ConvertUTF8toUTF16 ucsPrePath(contentDesc);
4592 nsContentUtils::FormatLocalizedString(
4593 aOutMessage, nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4594 aContentMessage, ucsPrePath);
4595 }
4596 }
4597 }
4598
4599 if (aOutMessage.IsEmpty()) {
4600 // We didn't find a host so use the generic heading
4601 nsContentUtils::GetLocalizedString(
4602 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, aFallbackMessage,
4603 aOutMessage);
4604 }
4605
4606 // Just in case
4607 if (aOutMessage.IsEmpty()) {
4608 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "could not get ScriptDlgGenericHeading string from string bundle"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4609)
4609 "could not get ScriptDlgGenericHeading string from string bundle")NS_DebugBreak(NS_DEBUG_WARNING, "could not get ScriptDlgGenericHeading string from string bundle"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4609)
;
4610 aOutMessage.AssignLiteral("[Script]");
4611 }
4612}
4613
4614bool nsGlobalWindowOuter::CanMoveResizeWindows(CallerType aCallerType) {
4615 // When called from chrome, we can avoid the following checks.
4616 if (aCallerType != CallerType::System) {
4617 // Don't allow scripts to move or resize windows that were not opened by a
4618 // script.
4619 if (!mBrowsingContext->GetTopLevelCreatedByWebContent()) {
4620 return false;
4621 }
4622
4623 if (!CanSetProperty("dom.disable_window_move_resize")) {
4624 return false;
4625 }
4626
4627 // Ignore the request if we have more than one tab in the window.
4628 if (mBrowsingContext->Top()->HasSiblings()) {
4629 return false;
4630 }
4631 }
4632
4633 if (mDocShell) {
4634 bool allow;
4635 nsresult rv = mDocShell->GetAllowWindowControl(&allow);
4636 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !allow) return false;
4637 }
4638
4639 if (nsGlobalWindowInner::sMouseDown &&
4640 !nsGlobalWindowInner::sDragServiceDisabled) {
4641 nsCOMPtr<nsIDragService> ds =
4642 do_GetService("@mozilla.org/widget/dragservice;1");
4643 if (ds) {
4644 nsGlobalWindowInner::sDragServiceDisabled = true;
4645 ds->Suppress();
4646 }
4647 }
4648 return true;
4649}
4650
4651bool nsGlobalWindowOuter::AlertOrConfirm(bool aAlert, const nsAString& aMessage,
4652 nsIPrincipal& aSubjectPrincipal,
4653 ErrorResult& aError) {
4654 // XXX This method is very similar to nsGlobalWindowOuter::Prompt, make
4655 // sure any modifications here don't need to happen over there!
4656 if (!AreDialogsEnabled()) {
4657 // Just silently return. In the case of alert(), the return value is
4658 // ignored. In the case of confirm(), returning false is the same thing as
4659 // would happen if the user cancels.
4660 return false;
4661 }
4662
4663 // Reset popup state while opening a modal dialog, and firing events
4664 // about the dialog, to prevent the current state from being active
4665 // the whole time a modal dialog is open.
4666 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
4667
4668 // Before bringing up the window, unsuppress painting and flush
4669 // pending reflows.
4670 EnsureReflowFlushAndPaint();
4671
4672 nsAutoString title;
4673 MakeMessageWithPrincipal(title, &aSubjectPrincipal, false,
4674 "ScriptDlgNullPrincipalHeading", "ScriptDlgHeading",
4675 "ScriptDlgGenericHeading");
4676
4677 // Remove non-terminating null characters from the
4678 // string. See bug #310037.
4679 nsAutoString final;
4680 nsContentUtils::StripNullChars(aMessage, final);
4681 nsContentUtils::PlatformToDOMLineBreaks(final);
4682
4683 nsresult rv;
4684 nsCOMPtr<nsIPromptFactory> promptFac =
4685 do_GetService("@mozilla.org/prompter;1", &rv);
4686 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4687 aError.Throw(rv);
4688 return false;
4689 }
4690
4691 nsCOMPtr<nsIPrompt> prompt;
4692 aError =
4693 promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt)(nsIPrompt::COMTypeInfo<nsIPrompt, void>::kIID), getter_AddRefs(prompt));
4694 if (aError.Failed()) {
4695 return false;
4696 }
4697
4698 // Always allow content modal prompts for alert and confirm.
4699 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4700 promptBag->SetPropertyAsUint32(u"modalType"_ns,
4701 nsIPrompt::MODAL_TYPE_CONTENT);
4702 }
4703
4704 bool result = false;
4705 nsAutoSyncOperation sync(mDoc, SyncOperationBehavior::eSuspendInput);
4706 if (ShouldPromptToBlockDialogs()) {
4707 bool disallowDialog = false;
4708 nsAutoString label;
4709 MakeMessageWithPrincipal(
4710 label, &aSubjectPrincipal, true, "ScriptDialogLabelNullPrincipal",
4711 "ScriptDialogLabelContentPrincipal", "ScriptDialogLabelNullPrincipal");
4712
4713 aError = aAlert
4714 ? prompt->AlertCheck(title.get(), final.get(), label.get(),
4715 &disallowDialog)
4716 : prompt->ConfirmCheck(title.get(), final.get(), label.get(),
4717 &disallowDialog, &result);
4718
4719 if (disallowDialog) {
4720 DisableDialogs();
4721 }
4722 } else {
4723 aError = aAlert ? prompt->Alert(title.get(), final.get())
4724 : prompt->Confirm(title.get(), final.get(), &result);
4725 }
4726
4727 return result;
4728}
4729
4730void nsGlobalWindowOuter::AlertOuter(const nsAString& aMessage,
4731 nsIPrincipal& aSubjectPrincipal,
4732 ErrorResult& aError) {
4733 AlertOrConfirm(/* aAlert = */ true, aMessage, aSubjectPrincipal, aError);
4734}
4735
4736bool nsGlobalWindowOuter::ConfirmOuter(const nsAString& aMessage,
4737 nsIPrincipal& aSubjectPrincipal,
4738 ErrorResult& aError) {
4739 return AlertOrConfirm(/* aAlert = */ false, aMessage, aSubjectPrincipal,
4740 aError);
4741}
4742
4743void nsGlobalWindowOuter::PromptOuter(const nsAString& aMessage,
4744 const nsAString& aInitial,
4745 nsAString& aReturn,
4746 nsIPrincipal& aSubjectPrincipal,
4747 ErrorResult& aError) {
4748 // XXX This method is very similar to nsGlobalWindowOuter::AlertOrConfirm,
4749 // make sure any modifications here don't need to happen over there!
4750 SetDOMStringToNull(aReturn);
4751
4752 if (!AreDialogsEnabled()) {
4753 // Return null, as if the user just canceled the prompt.
4754 return;
4755 }
4756
4757 // Reset popup state while opening a modal dialog, and firing events
4758 // about the dialog, to prevent the current state from being active
4759 // the whole time a modal dialog is open.
4760 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
4761
4762 // Before bringing up the window, unsuppress painting and flush
4763 // pending reflows.
4764 EnsureReflowFlushAndPaint();
4765
4766 nsAutoString title;
4767 MakeMessageWithPrincipal(title, &aSubjectPrincipal, false,
4768 "ScriptDlgNullPrincipalHeading", "ScriptDlgHeading",
4769 "ScriptDlgGenericHeading");
4770
4771 // Remove non-terminating null characters from the
4772 // string. See bug #310037.
4773 nsAutoString fixedMessage, fixedInitial;
4774 nsContentUtils::StripNullChars(aMessage, fixedMessage);
4775 nsContentUtils::PlatformToDOMLineBreaks(fixedMessage);
4776 nsContentUtils::StripNullChars(aInitial, fixedInitial);
4777
4778 nsresult rv;
4779 nsCOMPtr<nsIPromptFactory> promptFac =
4780 do_GetService("@mozilla.org/prompter;1", &rv);
4781 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4782 aError.Throw(rv);
4783 return;
4784 }
4785
4786 nsCOMPtr<nsIPrompt> prompt;
4787 aError =
4788 promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt)(nsIPrompt::COMTypeInfo<nsIPrompt, void>::kIID), getter_AddRefs(prompt));
4789 if (aError.Failed()) {
4790 return;
4791 }
4792
4793 // Always allow content modal prompts for prompt.
4794 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4795 promptBag->SetPropertyAsUint32(u"modalType"_ns,
4796 nsIPrompt::MODAL_TYPE_CONTENT);
4797 }
4798
4799 // Pass in the default value, if any.
4800 char16_t* inoutValue = ToNewUnicode(fixedInitial);
4801 bool disallowDialog = false;
4802
4803 nsAutoString label;
4804 label.SetIsVoid(true);
4805 if (ShouldPromptToBlockDialogs()) {
4806 nsContentUtils::GetLocalizedString(
4807 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, "ScriptDialogLabel", label);
4808 }
4809
4810 nsAutoSyncOperation sync(mDoc, SyncOperationBehavior::eSuspendInput);
4811 bool ok;
4812 aError = prompt->Prompt(title.get(), fixedMessage.get(), &inoutValue,
4813 label.IsVoid() ? nullptr : label.get(),
4814 &disallowDialog, &ok);
4815
4816 if (disallowDialog) {
4817 DisableDialogs();
4818 }
4819
4820 // XXX Doesn't this leak inoutValue?
4821 if (aError.Failed()) {
4822 return;
4823 }
4824
4825 nsString outValue;
4826 outValue.Adopt(inoutValue);
4827 if (ok && inoutValue) {
4828 aReturn = std::move(outValue);
4829 }
4830}
4831
4832void nsGlobalWindowOuter::FocusOuter(CallerType aCallerType,
4833 bool aFromOtherProcess,
4834 uint64_t aActionId) {
4835 RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
4836 if (MOZ_UNLIKELY(!fm)(__builtin_expect(!!(!fm), 0))) {
4837 return;
4838 }
4839
4840 auto [canFocus, isActive] = GetBrowsingContext()->CanFocusCheck(aCallerType);
4841 if (aFromOtherProcess) {
4842 // We trust that the check passed in a process that's, in principle,
4843 // untrusted, because we don't have the required caller context available
4844 // here. Also, the worst that the other process can do in this case is to
4845 // raise a window it's not supposed to be allowed to raise.
4846 // https://bugzilla.mozilla.org/show_bug.cgi?id=1677899
4847 MOZ_ASSERT(XRE_IsContentProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()"
" (" "Parent should not trust other processes." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4848); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "Parent should not trust other processes." ")"); do { *
((volatile int*)__null) = 4848; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
4848 "Parent should not trust other processes.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()"
" (" "Parent should not trust other processes." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4848); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "Parent should not trust other processes." ")"); do { *
((volatile int*)__null) = 4848; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4849 canFocus = true;
4850 }
4851
4852 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4853 if (treeOwnerAsWin && (canFocus || isActive)) {
4854 bool isEnabled = true;
4855 if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled))((bool)(__builtin_expect(!!(!NS_FAILED_impl(treeOwnerAsWin->
GetEnabled(&isEnabled))), 1)))
&& !isEnabled) {
4856 NS_WARNING("Should not try to set the focus on a disabled window")NS_DebugBreak(NS_DEBUG_WARNING, "Should not try to set the focus on a disabled window"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4856)
;
4857 return;
4858 }
4859 }
4860
4861 if (!mDocShell) {
4862 return;
4863 }
4864
4865 // If the window has a child frame focused, clear the focus. This
4866 // ensures that focus will be in this frame and not in a child.
4867 if (nsIContent* content = GetFocusedElement()) {
4868 if (HTMLIFrameElement::FromNode(content)) {
4869 fm->ClearFocus(this);
4870 }
4871 }
4872
4873 RefPtr<BrowsingContext> parent;
4874 BrowsingContext* bc = GetBrowsingContext();
4875 if (bc) {
4876 parent = bc->GetParent();
4877 if (!parent && XRE_IsParentProcess()) {
4878 parent = bc->Canonical()->GetParentCrossChromeBoundary();
4879 }
4880 }
4881 if (parent) {
4882 if (!parent->IsInProcess()) {
4883 if (isActive) {
4884 OwningNonNull<nsGlobalWindowOuter> kungFuDeathGrip(*this);
4885 fm->WindowRaised(kungFuDeathGrip, aActionId);
4886 } else {
4887 ContentChild* contentChild = ContentChild::GetSingleton();
4888 MOZ_ASSERT(contentChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentChild))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentChild", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4888); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 4888; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4889 contentChild->SendFinalizeFocusOuter(bc, canFocus, aCallerType);
4890 }
4891 return;
4892 }
4893
4894 MOZ_ASSERT(mDoc, "Call chain should have ensured document creation.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDoc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(mDoc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mDoc" " (" "Call chain should have ensured document creation."
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4894); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc" ") ("
"Call chain should have ensured document creation." ")"); do
{ *((volatile int*)__null) = 4894; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4895 if (mDoc) {
4896 if (Element* frame = mDoc->GetEmbedderElement()) {
4897 nsContentUtils::RequestFrameFocus(*frame, canFocus, aCallerType);
4898 }
4899 }
4900 return;
4901 }
4902
4903 if (canFocus) {
4904 // if there is no parent, this must be a toplevel window, so raise the
4905 // window if canFocus is true. If this is a child process, the raise
4906 // window request will get forwarded to the parent by the puppet widget.
4907 OwningNonNull<nsGlobalWindowOuter> kungFuDeathGrip(*this);
4908 fm->RaiseWindow(kungFuDeathGrip, aCallerType, aActionId);
4909 }
4910}
4911
4912nsresult nsGlobalWindowOuter::Focus(CallerType aCallerType) {
4913 FORWARD_TO_INNER(Focus, (aCallerType), NS_ERROR_UNEXPECTED)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4913); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->Focus (aCallerType); } while (0)
;
4914}
4915
4916void nsGlobalWindowOuter::BlurOuter(CallerType aCallerType) {
4917 if (!GetBrowsingContext()->CanBlurCheck(aCallerType)) {
4918 return;
4919 }
4920
4921 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
4922 if (chrome) {
4923 chrome->Blur();
4924 }
4925}
4926
4927void nsGlobalWindowOuter::StopOuter(ErrorResult& aError) {
4928 // IsNavigationAllowed checks are usually done in nsDocShell directly,
4929 // however nsDocShell::Stop has a bunch of internal users that would fail
4930 // the IsNavigationAllowed check.
4931 if (!mDocShell || !nsDocShell::Cast(mDocShell)->IsNavigationAllowed()) {
4932 return;
4933 }
4934
4935 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4936 if (webNav) {
4937 aError = webNav->Stop(nsIWebNavigation::STOP_ALL);
4938 }
4939}
4940
4941void nsGlobalWindowOuter::PrintOuter(ErrorResult& aError) {
4942 if (!AreDialogsEnabled()) {
4943 // Per spec, silently return. https://github.com/whatwg/html/commit/21a1de1
4944 return;
4945 }
4946
4947 // Printing is disabled, silently return.
4948 if (!StaticPrefs::print_enabled()) {
4949 return;
4950 }
4951
4952 // If we're loading, queue the print for later. This is a special-case that
4953 // only applies to the window.print() call, for compat with other engines and
4954 // pre-existing behavior.
4955 if (mShouldDelayPrintUntilAfterLoad) {
4956 if (nsIDocShell* docShell = GetDocShell()) {
4957 if (docShell->GetBusyFlags() & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) {
4958 mDelayedPrintUntilAfterLoad = true;
4959 return;
4960 }
4961 }
4962 }
4963
4964#ifdef NS_PRINTING1
4965 RefPtr<BrowsingContext> top =
4966 mBrowsingContext ? mBrowsingContext->Top() : nullptr;
4967 if (NS_WARN_IF(top && top->GetIsPrinting())NS_warn_if_impl(top && top->GetIsPrinting(), "top && top->GetIsPrinting()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4967)
) {
4968 return;
4969 }
4970
4971 if (top) {
4972 Unused << top->SetIsPrinting(true);
4973 }
4974
4975 auto unset = MakeScopeExit([&] {
4976 if (top) {
4977 Unused << top->SetIsPrinting(false);
4978 }
4979 });
4980
4981 const bool forPreview =
4982 !StaticPrefs::print_always_print_silent() &&
4983 !Preferences::GetBool("print.prefer_system_dialog", false);
4984 Print(nullptr, nullptr, nullptr, nullptr, IsPreview(forPreview),
4985 IsForWindowDotPrint::Yes, nullptr, nullptr, aError);
4986#endif
4987}
4988
4989class MOZ_RAII AutoModalState {
4990 public:
4991 explicit AutoModalState(nsGlobalWindowOuter& aWin)
4992 : mModalStateWin(aWin.EnterModalState()) {}
4993
4994 ~AutoModalState() {
4995 if (mModalStateWin) {
4996 mModalStateWin->LeaveModalState();
4997 }
4998 }
4999
5000 RefPtr<nsGlobalWindowOuter> mModalStateWin;
5001};
5002
5003Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
5004 nsIPrintSettings* aPrintSettings, RemotePrintJobChild* aRemotePrintJob,
5005 nsIWebProgressListener* aListener, nsIDocShell* aDocShellToCloneInto,
5006 IsPreview aIsPreview, IsForWindowDotPrint aForWindowDotPrint,
5007 PrintPreviewResolver&& aPrintPreviewCallback,
5008 RefPtr<BrowsingContext>* aCachedBrowsingContext, ErrorResult& aError) {
5009#ifdef NS_PRINTING1
5010 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
5011 do_GetService("@mozilla.org/gfx/printsettings-service;1");
5012 if (!printSettingsService) {
5013 // we currently return here in headless mode - should we?
5014 aError.ThrowNotSupportedError("No print settings service");
5015 return nullptr;
5016 }
5017
5018 nsCOMPtr<nsIPrintSettings> ps = aPrintSettings;
5019 if (!ps) {
5020 // We shouldn't need this once bug 1776169 is fixed.
5021 printSettingsService->GetDefaultPrintSettingsForPrinting(
5022 getter_AddRefs(ps));
5023 }
5024
5025 RefPtr<Document> docToPrint = mDoc;
5026 if (NS_WARN_IF(!docToPrint)NS_warn_if_impl(!docToPrint, "!docToPrint", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5026)
) {
5027 aError.ThrowNotSupportedError("Document is gone");
5028 return nullptr;
5029 }
5030
5031 RefPtr<BrowsingContext> sourceBC = docToPrint->GetBrowsingContext();
5032 MOZ_DIAGNOSTIC_ASSERT(sourceBC)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sourceBC)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sourceBC))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("sourceBC", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5032); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "sourceBC"
")"); do { *((volatile int*)__null) = 5032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5033 if (!sourceBC) {
5034 aError.ThrowNotSupportedError("No browsing context for source document");
5035 return nullptr;
5036 }
5037
5038 nsAutoSyncOperation sync(docToPrint, SyncOperationBehavior::eAllowInput);
5039 AutoModalState modalState(*this);
5040
5041 nsCOMPtr<nsIDocumentViewer> viewer;
5042 RefPtr<BrowsingContext> bc;
5043 bool hasPrintCallbacks = false;
5044 bool wasStaticDocument = docToPrint->IsStaticDocument();
5045 bool usingCachedBrowsingContext = false;
5046 if (aCachedBrowsingContext && *aCachedBrowsingContext) {
5047 MOZ_ASSERT(!wasStaticDocument,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!wasStaticDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!wasStaticDocument))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!wasStaticDocument"
" (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5049); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5049; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
5048 "Why pass in non-empty aCachedBrowsingContext if original "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!wasStaticDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!wasStaticDocument))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!wasStaticDocument"
" (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5049); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5049; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
5049 "document is already static?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!wasStaticDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!wasStaticDocument))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!wasStaticDocument"
" (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5049); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5049; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
5050 if (!wasStaticDocument) {
5051 // The passed in document is not a static clone and the caller passed in a
5052 // static clone to reuse, so swap it in.
5053 docToPrint = (*aCachedBrowsingContext)->GetDocument();
5054 MOZ_ASSERT(docToPrint)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(docToPrint)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(docToPrint))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("docToPrint", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5054); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docToPrint"
")"); do { *((volatile int*)__null) = 5054; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5055 MOZ_ASSERT(docToPrint->IsStaticDocument())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(docToPrint->IsStaticDocument())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(docToPrint->IsStaticDocument
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("docToPrint->IsStaticDocument()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5055); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docToPrint->IsStaticDocument()"
")"); do { *((volatile int*)__null) = 5055; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5056 wasStaticDocument = true;
5057 usingCachedBrowsingContext = true;
5058 }
5059 }
5060 if (wasStaticDocument) {
5061 if (aForWindowDotPrint == IsForWindowDotPrint::Yes) {
5062 aError.ThrowNotSupportedError(
5063 "Calling print() from a print preview is unsupported, did you intend "
5064 "to call printPreview() instead?");
5065 return nullptr;
5066 }
5067 if (usingCachedBrowsingContext) {
5068 bc = docToPrint->GetBrowsingContext();
5069 } else {
5070 // We're already a print preview window, just reuse our browsing context /
5071 // content viewer.
5072 bc = sourceBC;
5073 }
5074 nsCOMPtr<nsIDocShell> docShell = bc->GetDocShell();
5075 if (!docShell) {
5076 aError.ThrowNotSupportedError("No docshell");
5077 return nullptr;
5078 }
5079 // We could handle this if needed.
5080 if (aDocShellToCloneInto && aDocShellToCloneInto != docShell) {
5081 aError.ThrowNotSupportedError(
5082 "We don't handle cloning a print preview doc into a different "
5083 "docshell");
5084 return nullptr;
5085 }
5086 docShell->GetDocViewer(getter_AddRefs(viewer));
5087 MOZ_DIAGNOSTIC_ASSERT(viewer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(viewer)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(viewer))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("viewer", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5087); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "viewer"
")"); do { *((volatile int*)__null) = 5087; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5088 } else {
5089 if (aDocShellToCloneInto) {
5090 // Ensure the content viewer is created if needed.
5091 Unused << aDocShellToCloneInto->GetDocument();
5092 bc = aDocShellToCloneInto->GetBrowsingContext();
5093 } else {
5094 AutoNoJSAPI nojsapi;
5095 auto printKind = aForWindowDotPrint == IsForWindowDotPrint::Yes
5096 ? PrintKind::WindowDotPrint
5097 : PrintKind::InternalPrint;
5098 // For PrintKind::WindowDotPrint, this call will not only make the parent
5099 // process create a CanonicalBrowsingContext for the returned `bc`, but
5100 // it will also make the parent process initiate the print/print preview.
5101 // See the handling of OPEN_PRINT_BROWSER in browser.js.
5102 aError = OpenInternal(""_ns, u""_ns, u""_ns,
5103 false, // aDialog
5104 true, // aCalledNoScript
5105 false, // aDoJSFixups
5106 true, // aNavigate
5107 nullptr, // No args
5108 nullptr, // aLoadState
5109 false, // aForceNoOpener
5110 printKind, getter_AddRefs(bc));
5111 if (NS_WARN_IF(aError.Failed())NS_warn_if_impl(aError.Failed(), "aError.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5111)
) {
5112 return nullptr;
5113 }
5114 if (aCachedBrowsingContext) {
5115 MOZ_ASSERT(!*aCachedBrowsingContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!*aCachedBrowsingContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!*aCachedBrowsingContext))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!*aCachedBrowsingContext"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5115); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!*aCachedBrowsingContext"
")"); do { *((volatile int*)__null) = 5115; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5116 *aCachedBrowsingContext = bc;
5117 }
5118 }
5119 if (!bc) {
5120 aError.ThrowNotAllowedError("No browsing context");
5121 return nullptr;
5122 }
5123
5124 Unused << bc->Top()->SetIsPrinting(true);
5125 nsCOMPtr<nsIDocShell> cloneDocShell = bc->GetDocShell();
5126 MOZ_DIAGNOSTIC_ASSERT(cloneDocShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cloneDocShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cloneDocShell))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("cloneDocShell",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5126); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "cloneDocShell"
")"); do { *((volatile int*)__null) = 5126; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5127 cloneDocShell->GetDocViewer(getter_AddRefs(viewer));
5128 MOZ_DIAGNOSTIC_ASSERT(viewer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(viewer)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(viewer))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("viewer", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5128); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "viewer"
")"); do { *((volatile int*)__null) = 5128; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5129 if (!viewer) {
5130 aError.ThrowNotSupportedError("Didn't end up with a content viewer");
5131 return nullptr;
5132 }
5133
5134 if (bc != sourceBC) {
5135 MOZ_ASSERT(bc->IsTopContent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc->IsTopContent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bc->IsTopContent()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("bc->IsTopContent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5135); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc->IsTopContent()"
")"); do { *((volatile int*)__null) = 5135; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5136 // If we are cloning from a document in a different BrowsingContext, we
5137 // need to make sure to copy over our opener policy information from that
5138 // BrowsingContext. In the case where the source is an iframe, this
5139 // information needs to be copied from the toplevel source
5140 // BrowsingContext, as we may be making a static clone of a single
5141 // subframe.
5142 MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy
()))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash
("" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5143); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")"); do { *((volatile int*)__null) = 5143; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5143 bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy
()))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash
("" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5143); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")"); do { *((volatile int*)__null) = 5143; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
5144 MOZ_DIAGNOSTIC_ASSERT(bc->Group() == sourceBC->Group())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc->Group() == sourceBC->Group())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(bc->Group() == sourceBC->Group()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("bc->Group() == sourceBC->Group()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5144); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "bc->Group() == sourceBC->Group()"
")"); do { *((volatile int*)__null) = 5144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5145 }
5146
5147 if (RefPtr<Document> doc = viewer->GetDocument()) {
5148 if (doc->IsShowing()) {
5149 // We're going to drop this document on the floor, in the SetDocument
5150 // call below. Make sure to run OnPageHide() to keep state consistent
5151 // and avoids assertions in the document destructor.
5152 doc->OnPageHide(false, nullptr);
5153 }
5154 }
5155
5156 AutoPrintEventDispatcher dispatcher(*docToPrint);
5157
5158 nsAutoScriptBlocker blockScripts;
5159 RefPtr<Document> clone = docToPrint->CreateStaticClone(
5160 cloneDocShell, viewer, ps, &hasPrintCallbacks);
5161 if (!clone) {
5162 aError.ThrowNotSupportedError("Clone operation for printing failed");
5163 return nullptr;
5164 }
5165 }
5166
5167 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint = do_QueryInterface(viewer);
5168 if (!webBrowserPrint) {
5169 aError.ThrowNotSupportedError(
5170 "Content viewer didn't implement nsIWebBrowserPrint");
5171 return nullptr;
5172 }
5173 bool closeWindowAfterPrint;
5174 if (wasStaticDocument) {
5175 // Here the document was a static clone to begin with that this code did not
5176 // create, so we should not clean it up.
5177 // The exception is if we're using the passed-in aCachedBrowsingContext, in
5178 // which case this is the second print with this static document clone that
5179 // we created the first time through, and we are responsible for cleaning it
5180 // up.
5181 closeWindowAfterPrint = usingCachedBrowsingContext;
5182 } else {
5183 // In this case the document was not a static clone, so we made a static
5184 // clone for printing purposes and must clean it up after the print is done.
5185 // The exception is if aCachedBrowsingContext is non-NULL, meaning the
5186 // caller is intending to print this document again, so we need to defer the
5187 // cleanup until after the second print.
5188 closeWindowAfterPrint = !aCachedBrowsingContext;
5189 }
5190 webBrowserPrint->SetCloseWindowAfterPrint(closeWindowAfterPrint);
5191
5192 // For window.print(), we postpone making these calls until the round-trip to
5193 // the parent process (triggered by the OpenInternal call above) calls us
5194 // again. Only a call from the parent can provide a valid nsPrintSettings
5195 // object and RemotePrintJobChild object.
5196 if (aForWindowDotPrint == IsForWindowDotPrint::No) {
5197 if (aIsPreview == IsPreview::Yes) {
5198 aError = webBrowserPrint->PrintPreview(ps, aListener,
5199 std::move(aPrintPreviewCallback));
5200 if (aError.Failed()) {
5201 return nullptr;
5202 }
5203 } else {
5204 // Historically we've eaten this error.
5205 webBrowserPrint->Print(ps, aRemotePrintJob, aListener);
5206 }
5207 }
5208
5209 // When using window.print() with the new UI, we usually want to block until
5210 // the print dialog is hidden. But we can't really do that if we have print
5211 // callbacks, because we are inside a sync operation, and we want to run
5212 // microtasks / etc that the print callbacks may create. It is really awkward
5213 // to have this subtle behavior difference...
5214 //
5215 // We also want to do this for fuzzing, so that they can test window.print().
5216 const bool shouldBlock = [&] {
5217 if (aForWindowDotPrint == IsForWindowDotPrint::No) {
5218 return false;
5219 }
5220 if (aIsPreview == IsPreview::Yes) {
5221 return !hasPrintCallbacks;
5222 }
5223 return StaticPrefs::dom_window_print_fuzzing_block_while_printing();
5224 }();
5225
5226 if (shouldBlock) {
5227 SpinEventLoopUntil("nsGlobalWindowOuter::Print"_ns,
5228 [&] { return bc->IsDiscarded(); });
5229 }
5230
5231 return WindowProxyHolder(std::move(bc));
5232#else
5233 return nullptr;
5234#endif // NS_PRINTING
5235}
5236
5237void nsGlobalWindowOuter::MoveToOuter(int32_t aXPos, int32_t aYPos,
5238 CallerType aCallerType,
5239 ErrorResult& aError) {
5240 /*
5241 * If caller is not chrome and the user has not explicitly exempted the site,
5242 * prevent window.moveTo() by exiting early
5243 */
5244
5245 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5246 return;
5247 }
5248
5249 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5250 if (!treeOwnerAsWin) {
5251 aError.Throw(NS_ERROR_FAILURE);
5252 return;
5253 }
5254
5255 // We need to do the same transformation GetScreenXY does.
5256 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
5257 if (!presContext) {
5258 return;
5259 }
5260
5261 CSSIntPoint cssPos(aXPos, aYPos);
5262 CheckSecurityLeftAndTop(&cssPos.x.value, &cssPos.y.value, aCallerType);
5263
5264 nsDeviceContext* context = presContext->DeviceContext();
5265
5266 auto devPos = LayoutDeviceIntPoint::FromAppUnitsRounded(
5267 CSSIntPoint::ToAppUnits(cssPos), context->AppUnitsPerDevPixel());
5268
5269 aError = treeOwnerAsWin->SetPosition(devPos.x, devPos.y);
5270 CheckForDPIChange();
5271}
5272
5273void nsGlobalWindowOuter::MoveByOuter(int32_t aXDif, int32_t aYDif,
5274 CallerType aCallerType,
5275 ErrorResult& aError) {
5276 /*
5277 * If caller is not chrome and the user has not explicitly exempted the site,
5278 * prevent window.moveBy() by exiting early
5279 */
5280
5281 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5282 return;
5283 }
5284
5285 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5286 if (!treeOwnerAsWin) {
5287 aError.Throw(NS_ERROR_FAILURE);
5288 return;
5289 }
5290
5291 // To do this correctly we have to convert what we get from GetPosition
5292 // into CSS pixels, add the arguments, do the security check, and
5293 // then convert back to device pixels for the call to SetPosition.
5294
5295 int32_t x, y;
5296 aError = treeOwnerAsWin->GetPosition(&x, &y);
5297 if (aError.Failed()) {
5298 return;
5299 }
5300
5301 auto cssScale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
5302 CSSIntPoint cssPos = RoundedToInt(treeOwnerAsWin->GetPosition() / cssScale);
5303
5304 cssPos.x += aXDif;
5305 cssPos.y += aYDif;
5306
5307 CheckSecurityLeftAndTop(&cssPos.x.value, &cssPos.y.value, aCallerType);
5308
5309 LayoutDeviceIntPoint newDevPos = RoundedToInt(cssPos * cssScale);
5310 aError = treeOwnerAsWin->SetPosition(newDevPos.x, newDevPos.y);
5311
5312 CheckForDPIChange();
5313}
5314
5315nsresult nsGlobalWindowOuter::MoveBy(int32_t aXDif, int32_t aYDif) {
5316 ErrorResult rv;
5317 MoveByOuter(aXDif, aYDif, CallerType::System, rv);
5318
5319 return rv.StealNSResult();
5320}
5321
5322void nsGlobalWindowOuter::ResizeToOuter(int32_t aWidth, int32_t aHeight,
5323 CallerType aCallerType,
5324 ErrorResult& aError) {
5325 /*
5326 * If caller is not chrome and the user has not explicitly exempted the site,
5327 * prevent window.resizeTo() by exiting early
5328 */
5329
5330 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5331 return;
5332 }
5333
5334 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5335 if (!treeOwnerAsWin) {
5336 aError.Throw(NS_ERROR_FAILURE);
5337 return;
5338 }
5339
5340 CSSIntSize cssSize(aWidth, aHeight);
5341 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5342
5343 LayoutDeviceIntSize devSize =
5344 RoundedToInt(cssSize * CSSToDevScaleForBaseWindow(treeOwnerAsWin));
5345 aError = treeOwnerAsWin->SetSize(devSize.width, devSize.height, true);
5346
5347 CheckForDPIChange();
5348}
5349
5350void nsGlobalWindowOuter::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif,
5351 CallerType aCallerType,
5352 ErrorResult& aError) {
5353 /*
5354 * If caller is not chrome and the user has not explicitly exempted the site,
5355 * prevent window.resizeBy() by exiting early
5356 */
5357
5358 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5359 return;
5360 }
5361
5362 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5363 if (!treeOwnerAsWin) {
5364 aError.Throw(NS_ERROR_FAILURE);
5365 return;
5366 }
5367
5368 LayoutDeviceIntSize size = treeOwnerAsWin->GetSize();
5369
5370 // To do this correctly we have to convert what we got from GetSize
5371 // into CSS pixels, add the arguments, do the security check, and
5372 // then convert back to device pixels for the call to SetSize.
5373
5374 auto scale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
5375 CSSIntSize cssSize = RoundedToInt(size / scale);
5376
5377 cssSize.width += aWidthDif;
5378 cssSize.height += aHeightDif;
5379
5380 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5381
5382 LayoutDeviceIntSize newDevSize = RoundedToInt(cssSize * scale);
5383
5384 aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true);
5385
5386 CheckForDPIChange();
5387}
5388
5389void nsGlobalWindowOuter::SizeToContentOuter(
5390 const SizeToContentConstraints& aConstraints, ErrorResult& aError) {
5391 if (!mDocShell) {
5392 return;
5393 }
5394
5395 if (mBrowsingContext->IsSubframe()) {
5396 return;
5397 }
5398
5399 // The content viewer does a check to make sure that it's a content
5400 // viewer for a toplevel docshell.
5401 nsCOMPtr<nsIDocumentViewer> viewer;
5402 mDocShell->GetDocViewer(getter_AddRefs(viewer));
5403 if (!viewer) {
5404 return aError.Throw(NS_ERROR_FAILURE);
5405 }
5406
5407 auto contentSize = viewer->GetContentSize(
5408 aConstraints.mMaxWidth, aConstraints.mMaxHeight, aConstraints.mPrefWidth);
5409 if (!contentSize) {
5410 return aError.Throw(NS_ERROR_FAILURE);
5411 }
5412
5413 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
5414 if (!treeOwner) {
5415 return aError.Throw(NS_ERROR_FAILURE);
5416 }
5417
5418 // Don't use DevToCSSIntPixelsForBaseWindow() nor
5419 // CSSToDevIntPixelsForBaseWindow() here because contentSize is comes from
5420 // nsIDocumentViewer::GetContentSize() and it's computed with nsPresContext so
5421 // that we need to work with nsPresContext here too.
5422 RefPtr<nsPresContext> presContext = viewer->GetPresContext();
5423 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(presContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(presContext))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("presContext" " ("
"Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5424 presContext,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(presContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(presContext))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("presContext" " ("
"Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5425 "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(presContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(presContext))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("presContext" " ("
"Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5426 CSSIntSize cssSize = *contentSize;
5427
5428 LayoutDeviceIntSize newDevSize(
5429 presContext->CSSPixelsToDevPixels(cssSize.width),
5430 presContext->CSSPixelsToDevPixels(cssSize.height));
5431
5432 nsCOMPtr<nsIDocShell> docShell = mDocShell;
5433 aError =
5434 treeOwner->SizeShellTo(docShell, newDevSize.width, newDevSize.height);
5435}
5436
5437already_AddRefed<nsPIWindowRoot> nsGlobalWindowOuter::GetTopWindowRoot() {
5438 nsPIDOMWindowOuter* piWin = GetPrivateRoot();
5439 if (!piWin) {
5440 return nullptr;
5441 }
5442
5443 nsCOMPtr<nsPIWindowRoot> window =
5444 do_QueryInterface(piWin->GetChromeEventHandler());
5445 return window.forget();
5446}
5447
5448void nsGlobalWindowOuter::FirePopupBlockedEvent(
5449 Document* aDoc, nsIURI* aPopupURI, const nsAString& aPopupWindowName,
5450 const nsAString& aPopupWindowFeatures) {
5451 MOZ_ASSERT(aDoc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDoc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aDoc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aDoc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5451); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDoc" ")");
do { *((volatile int*)__null) = 5451; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5452
5453 // Fire a "DOMPopupBlocked" event so that the UI can hear about
5454 // blocked popups.
5455 PopupBlockedEventInit init;
5456 init.mBubbles = true;
5457 init.mCancelable = true;
5458 // XXX: This is a different object, but webidl requires an inner window here
5459 // now.
5460 init.mRequestingWindow = GetCurrentInnerWindowInternal(this);
5461 init.mPopupWindowURI = aPopupURI;
5462 init.mPopupWindowName = aPopupWindowName;
5463 init.mPopupWindowFeatures = aPopupWindowFeatures;
5464
5465 RefPtr<PopupBlockedEvent> event =
5466 PopupBlockedEvent::Constructor(aDoc, u"DOMPopupBlocked"_ns, init);
5467
5468 event->SetTrusted(true);
5469
5470 aDoc->DispatchEvent(*event);
5471}
5472
5473// static
5474bool nsGlobalWindowOuter::CanSetProperty(const char* aPrefName) {
5475 // Chrome can set any property.
5476 if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
5477 return true;
5478 }
5479
5480 // If the pref is set to true, we can not set the property
5481 // and vice versa.
5482 return !Preferences::GetBool(aPrefName, true);
5483}
5484
5485/* If a window open is blocked, fire the appropriate DOM events. */
5486void nsGlobalWindowOuter::FireAbuseEvents(
5487 const nsACString& aPopupURL, const nsAString& aPopupWindowName,
5488 const nsAString& aPopupWindowFeatures) {
5489 // fetch the URI of the window requesting the opened window
5490 nsCOMPtr<Document> currentDoc = GetDoc();
5491 nsCOMPtr<nsIURI> popupURI;
5492
5493 // build the URI of the would-have-been popup window
5494 // (see nsWindowWatcher::URIfromURL)
5495
5496 // first, fetch the opener's base URI
5497
5498 nsIURI* baseURL = nullptr;
5499
5500 nsCOMPtr<Document> doc = GetEntryDocument();
5501 if (doc) baseURL = doc->GetDocBaseURI();
5502
5503 // use the base URI to build what would have been the popup's URI
5504 Unused << NS_NewURI(getter_AddRefs(popupURI), aPopupURL, nullptr, baseURL);
5505
5506 // fire an event block full of informative URIs
5507 FirePopupBlockedEvent(currentDoc, popupURI, aPopupWindowName,
5508 aPopupWindowFeatures);
5509}
5510
5511Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenOuter(
5512 const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
5513 ErrorResult& aError) {
5514 RefPtr<BrowsingContext> bc;
5515 NS_ConvertUTF16toUTF8 url(aUrl);
5516 nsresult rv = OpenJS(url, aName, aOptions, getter_AddRefs(bc));
5517 if (rv == NS_ERROR_MALFORMED_URI) {
5518 aError.ThrowSyntaxError("Unable to open a window with invalid URL '"_ns +
5519 url + "'."_ns);
5520 return nullptr;
5521 }
5522
5523 // XXX Is it possible that some internal errors are thrown here?
5524 aError = rv;
5525
5526 if (!bc) {
5527 return nullptr;
5528 }
5529 return WindowProxyHolder(std::move(bc));
5530}
5531
5532nsresult nsGlobalWindowOuter::Open(const nsACString& aUrl,
5533 const nsAString& aName,
5534 const nsAString& aOptions,
5535 nsDocShellLoadState* aLoadState,
5536 bool aForceNoOpener,
5537 BrowsingContext** _retval) {
5538 return OpenInternal(aUrl, aName, aOptions,
5539 false, // aDialog
5540 true, // aCalledNoScript
5541 false, // aDoJSFixups
5542 true, // aNavigate
5543 nullptr, // No args
5544 aLoadState, aForceNoOpener, PrintKind::None, _retval);
5545}
5546
5547nsresult nsGlobalWindowOuter::OpenJS(const nsACString& aUrl,
5548 const nsAString& aName,
5549 const nsAString& aOptions,
5550 BrowsingContext** _retval) {
5551 return OpenInternal(aUrl, aName, aOptions,
5552 false, // aDialog
5553 false, // aCalledNoScript
5554 true, // aDoJSFixups
5555 true, // aNavigate
5556 nullptr, // No args
5557 nullptr, // aLoadState
5558 false, // aForceNoOpener
5559 PrintKind::None, _retval);
5560}
5561
5562// like Open, but attaches to the new window any extra parameters past
5563// [features] as a JS property named "arguments"
5564nsresult nsGlobalWindowOuter::OpenDialog(const nsACString& aUrl,
5565 const nsAString& aName,
5566 const nsAString& aOptions,
5567 nsIArray* aArguments,
5568 BrowsingContext** _retval) {
5569 return OpenInternal(aUrl, aName, aOptions,
5570 true, // aDialog
5571 true, // aCalledNoScript
5572 false, // aDoJSFixups
5573 true, // aNavigate
5574 aArguments, // Arguments
5575 nullptr, // aLoadState
5576 false, // aForceNoOpener
5577 PrintKind::None, _retval);
5578}
5579
5580// Like Open, but passes aNavigate=false.
5581/* virtual */
5582nsresult nsGlobalWindowOuter::OpenNoNavigate(const nsACString& aUrl,
5583 const nsAString& aName,
5584 const nsAString& aOptions,
5585 BrowsingContext** _retval) {
5586 return OpenInternal(aUrl, aName, aOptions,
5587 false, // aDialog
5588 true, // aCalledNoScript
5589 false, // aDoJSFixups
5590 false, // aNavigate
5591 nullptr, // No args
5592 nullptr, // aLoadState
5593 false, // aForceNoOpener
5594 PrintKind::None, _retval);
5595}
5596
5597Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenDialogOuter(
5598 JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
5599 const nsAString& aOptions, const Sequence<JS::Value>& aExtraArgument,
5600 ErrorResult& aError) {
5601 nsCOMPtr<nsIJSArgArray> argvArray;
5602 aError =
5603 NS_CreateJSArgv(aCx, aExtraArgument.Length(), aExtraArgument.Elements(),
5604 getter_AddRefs(argvArray));
5605 if (aError.Failed()) {
5606 return nullptr;
5607 }
5608
5609 RefPtr<BrowsingContext> dialog;
5610 aError = OpenInternal(NS_ConvertUTF16toUTF8(aUrl), aName, aOptions,
5611 true, // aDialog
5612 false, // aCalledNoScript
5613 false, // aDoJSFixups
5614 true, // aNavigate
5615 argvArray, // Arguments
5616 nullptr, // aLoadState
5617 false, // aForceNoOpener
5618 PrintKind::None, getter_AddRefs(dialog));
5619 if (!dialog) {
5620 return nullptr;
5621 }
5622 return WindowProxyHolder(std::move(dialog));
5623}
5624
5625WindowProxyHolder nsGlobalWindowOuter::GetFramesOuter() {
5626 RefPtr<nsPIDOMWindowOuter> frames(this);
5627 FlushPendingNotifications(FlushType::ContentAndNotify);
5628 return WindowProxyHolder(mBrowsingContext);
5629}
5630
5631/* static */
5632bool nsGlobalWindowOuter::GatherPostMessageData(
5633 JSContext* aCx, const nsAString& aTargetOrigin, BrowsingContext** aSource,
5634 nsAString& aOrigin, nsIURI** aTargetOriginURI,
5635 nsIPrincipal** aCallerPrincipal, nsGlobalWindowInner** aCallerInnerWindow,
5636 nsIURI** aCallerURI, Maybe<nsID>* aCallerAgentClusterId,
5637 nsACString* aScriptLocation, ErrorResult& aError) {
5638 //
5639 // Window.postMessage is an intentional subversion of the same-origin policy.
5640 // As such, this code must be particularly careful in the information it
5641 // exposes to calling code.
5642 //
5643 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5644 //
5645
5646 // First, get the caller's window
5647 RefPtr<nsGlobalWindowInner> callerInnerWin =
5648 nsContentUtils::IncumbentInnerWindow();
5649 nsIPrincipal* callerPrin;
5650 if (callerInnerWin) {
5651 RefPtr<Document> doc = callerInnerWin->GetExtantDoc();
5652 if (!doc) {
5653 return false;
5654 }
5655 NS_IF_ADDREF(*aCallerURI = doc->GetDocumentURI())ns_if_addref(*aCallerURI = doc->GetDocumentURI());
5656
5657 // Compute the caller's origin either from its principal or, in the case the
5658 // principal doesn't carry a URI (e.g. the system principal), the caller's
5659 // document. We must get this now instead of when the event is created and
5660 // dispatched, because ultimately it is the identity of the calling window
5661 // *now* that determines who sent the message (and not an identity which
5662 // might have changed due to intervening navigations).
5663 callerPrin = callerInnerWin->GetPrincipal();
5664 } else {
5665 // In case the global is not a window, it can be a sandbox, and the
5666 // sandbox's principal can be used for the security check.
5667 nsIGlobalObject* global = GetIncumbentGlobal();
5668 NS_ASSERTION(global, "Why is there no global object?")do { if (!(global)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Why is there no global object?"
, "global", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5668); MOZ_PretendNoReturn(); } } while (0)
;
5669 callerPrin = global->PrincipalOrNull();
5670 if (callerPrin) {
5671 BasePrincipal::Cast(callerPrin)->GetScriptLocation(*aScriptLocation);
5672 }
5673 }
5674 if (!callerPrin) {
5675 return false;
5676 }
5677
5678 // if the principal has a URI, use that to generate the origin
5679 if (!callerPrin->IsSystemPrincipal()) {
5680 nsAutoCString webExposedOriginSerialization;
5681 callerPrin->GetWebExposedOriginSerialization(webExposedOriginSerialization);
5682 CopyUTF8toUTF16(webExposedOriginSerialization, aOrigin);
5683 } else if (callerInnerWin) {
5684 if (!*aCallerURI) {
5685 return false;
5686 }
5687 // otherwise use the URI of the document to generate origin
5688 nsContentUtils::GetWebExposedOriginSerialization(*aCallerURI, aOrigin);
5689 } else {
5690 // in case of a sandbox with a system principal origin can be empty
5691 if (!callerPrin->IsSystemPrincipal()) {
5692 return false;
5693 }
5694 }
5695 NS_IF_ADDREF(*aCallerPrincipal = callerPrin)ns_if_addref(*aCallerPrincipal = callerPrin);
5696
5697 // "/" indicates same origin as caller, "*" indicates no specific origin is
5698 // required.
5699 if (!aTargetOrigin.EqualsASCII("/") && !aTargetOrigin.EqualsASCII("*")) {
5700 nsCOMPtr<nsIURI> targetOriginURI;
5701 if (NS_FAILED(NS_NewURI(getter_AddRefs(targetOriginURI), aTargetOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(targetOriginURI), aTargetOrigin))), 0)))
) {
5702 aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
5703 return false;
5704 }
5705
5706 nsresult rv = NS_MutateURI(targetOriginURI)
5707 .SetUserPass(""_ns)
5708 .SetPathQueryRef(""_ns)
5709 .Finalize(aTargetOriginURI);
5710 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5711 return false;
5712 }
5713 }
5714
5715 if (!nsContentUtils::IsCallerChrome() && callerInnerWin &&
5716 callerInnerWin->GetOuterWindowInternal()) {
5717 NS_ADDREF(*aSource = callerInnerWin->GetOuterWindowInternal()(*aSource = callerInnerWin->GetOuterWindowInternal() ->
GetBrowsingContext())->AddRef()
5718 ->GetBrowsingContext())(*aSource = callerInnerWin->GetOuterWindowInternal() ->
GetBrowsingContext())->AddRef()
;
5719 } else {
5720 *aSource = nullptr;
5721 }
5722
5723 if (aCallerAgentClusterId && callerInnerWin &&
5724 callerInnerWin->GetDocGroup()) {
5725 *aCallerAgentClusterId =
5726 Some(callerInnerWin->GetDocGroup()->AgentClusterId());
5727 }
5728
5729 callerInnerWin.forget(aCallerInnerWindow);
5730
5731 return true;
5732}
5733
5734bool nsGlobalWindowOuter::GetPrincipalForPostMessage(
5735 const nsAString& aTargetOrigin, nsIURI* aTargetOriginURI,
5736 nsIPrincipal* aCallerPrincipal, nsIPrincipal& aSubjectPrincipal,
5737 nsIPrincipal** aProvidedPrincipal) {
5738 //
5739 // Window.postMessage is an intentional subversion of the same-origin policy.
5740 // As such, this code must be particularly careful in the information it
5741 // exposes to calling code.
5742 //
5743 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5744 //
5745
5746 // Convert the provided origin string into a URI for comparison purposes.
5747 nsCOMPtr<nsIPrincipal> providedPrincipal;
5748
5749 if (aTargetOrigin.EqualsASCII("/")) {
5750 providedPrincipal = aCallerPrincipal;
5751 }
5752 // "*" indicates no specific origin is required.
5753 else if (!aTargetOrigin.EqualsASCII("*")) {
5754 OriginAttributes attrs = aSubjectPrincipal.OriginAttributesRef();
5755 if (aSubjectPrincipal.IsSystemPrincipal()) {
5756 auto principal = BasePrincipal::Cast(GetPrincipal());
5757
5758 if (attrs != principal->OriginAttributesRef()) {
5759 nsAutoCString targetURL;
5760 nsAutoCString sourceOrigin;
5761 nsAutoCString targetOrigin;
5762
5763 if (NS_FAILED(principal->GetAsciiSpec(targetURL))((bool)(__builtin_expect(!!(NS_FAILED_impl(principal->GetAsciiSpec
(targetURL))), 0)))
||
5764 NS_FAILED(principal->GetOrigin(targetOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(principal->GetOrigin
(targetOrigin))), 0)))
||
5765 NS_FAILED(aSubjectPrincipal.GetOrigin(sourceOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(aSubjectPrincipal.
GetOrigin(sourceOrigin))), 0)))
) {
5766 NS_WARNING("Failed to get source and target origins")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to get source and target origins"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5766)
;
5767 return false;
5768 }
5769
5770 nsContentUtils::LogSimpleConsoleError(
5771 NS_ConvertUTF8toUTF16(nsPrintfCString(
5772 R"(Attempting to post a message to window with url "%s" and )"
5773 R"(origin "%s" from a system principal scope with mismatched )"
5774 R"(origin "%s".)",
5775 targetURL.get(), targetOrigin.get(), sourceOrigin.get())),
5776 "DOM"_ns, !!principal->PrivateBrowsingId(),
5777 principal->IsSystemPrincipal());
5778
5779 attrs = principal->OriginAttributesRef();
5780 }
5781 }
5782
5783 // Create a nsIPrincipal inheriting the app/browser attributes from the
5784 // caller.
5785 providedPrincipal =
5786 BasePrincipal::CreateContentPrincipal(aTargetOriginURI, attrs);
5787 if (NS_WARN_IF(!providedPrincipal)NS_warn_if_impl(!providedPrincipal, "!providedPrincipal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5787)
) {
5788 return false;
5789 }
5790 } else {
5791 // We still need to check the originAttributes if the target origin is '*'.
5792 // But we will ingore the FPD here since the FPDs are possible to be
5793 // different.
5794 auto principal = BasePrincipal::Cast(GetPrincipal());
5795 NS_ENSURE_TRUE(principal, false)do { if ((__builtin_expect(!!(!(principal)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "principal" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5795); return false; } } while (false)
;
5796
5797 OriginAttributes targetAttrs = principal->OriginAttributesRef();
5798 OriginAttributes sourceAttrs = aSubjectPrincipal.OriginAttributesRef();
5799 // We have to exempt the check of OA if the subject prioncipal is a system
5800 // principal since there are many tests try to post messages to content from
5801 // chrome with a mismatch OA. For example, using the ContentTask.spawn() to
5802 // post a message into a private browsing window. The injected code in
5803 // ContentTask.spawn() will be executed under the system principal and the
5804 // OA of the system principal mismatches with the OA of a private browsing
5805 // window.
5806 MOZ_DIAGNOSTIC_ASSERT(aSubjectPrincipal.IsSystemPrincipal() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs
.EqualsIgnoringFPD(targetAttrs))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSubjectPrincipal.IsSystemPrincipal
() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5807); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
")"); do { *((volatile int*)__null) = 5807; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5807 sourceAttrs.EqualsIgnoringFPD(targetAttrs))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs
.EqualsIgnoringFPD(targetAttrs))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSubjectPrincipal.IsSystemPrincipal
() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5807); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
")"); do { *((volatile int*)__null) = 5807; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5808
5809 // If 'privacy.firstparty.isolate.block_post_message' is true, we will block
5810 // postMessage across different first party domains.
5811 if (OriginAttributes::IsBlockPostMessageForFPI() &&
5812 !aSubjectPrincipal.IsSystemPrincipal() &&
5813 sourceAttrs.mFirstPartyDomain != targetAttrs.mFirstPartyDomain) {
5814 return false;
5815 }
5816 }
5817
5818 providedPrincipal.forget(aProvidedPrincipal);
5819 return true;
5820}
5821
5822void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
5823 JS::Handle<JS::Value> aMessage,
5824 const nsAString& aTargetOrigin,
5825 JS::Handle<JS::Value> aTransfer,
5826 nsIPrincipal& aSubjectPrincipal,
5827 ErrorResult& aError) {
5828 RefPtr<BrowsingContext> sourceBc;
5829 nsAutoString origin;
5830 nsCOMPtr<nsIURI> targetOriginURI;
5831 nsCOMPtr<nsIPrincipal> callerPrincipal;
5832 RefPtr<nsGlobalWindowInner> callerInnerWindow;
5833 nsCOMPtr<nsIURI> callerURI;
5834 Maybe<nsID> callerAgentClusterId = Nothing();
5835 nsAutoCString scriptLocation;
5836 if (!GatherPostMessageData(
5837 aCx, aTargetOrigin, getter_AddRefs(sourceBc), origin,
5838 getter_AddRefs(targetOriginURI), getter_AddRefs(callerPrincipal),
5839 getter_AddRefs(callerInnerWindow), getter_AddRefs(callerURI),
5840 &callerAgentClusterId, &scriptLocation, aError)) {
5841 return;
5842 }
5843
5844 nsCOMPtr<nsIPrincipal> providedPrincipal;
5845 if (!GetPrincipalForPostMessage(aTargetOrigin, targetOriginURI,
5846 callerPrincipal, aSubjectPrincipal,
5847 getter_AddRefs(providedPrincipal))) {
5848 return;
5849 }
5850
5851 // Create and asynchronously dispatch a runnable which will handle actual DOM
5852 // event creation and dispatch.
5853 RefPtr<PostMessageEvent> event = new PostMessageEvent(
5854 sourceBc, origin, this, providedPrincipal,
5855 callerInnerWindow ? callerInnerWindow->WindowID() : 0, callerURI,
5856 scriptLocation, callerAgentClusterId);
5857
5858 JS::CloneDataPolicy clonePolicy;
5859
5860 if (GetDocGroup() && callerAgentClusterId.isSome() &&
5861 GetDocGroup()->AgentClusterId().Equals(callerAgentClusterId.value())) {
5862 clonePolicy.allowIntraClusterClonableSharedObjects();
5863 }
5864
5865 if (callerInnerWindow && callerInnerWindow->IsSharedMemoryAllowed()) {
5866 clonePolicy.allowSharedMemoryObjects();
5867 }
5868
5869 event->Write(aCx, aMessage, aTransfer, clonePolicy, aError);
5870 if (NS_WARN_IF(aError.Failed())NS_warn_if_impl(aError.Failed(), "aError.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5870)
) {
5871 return;
5872 }
5873
5874 event->DispatchToTargetThread(aError);
5875}
5876
5877class nsCloseEvent : public Runnable {
5878 RefPtr<nsGlobalWindowOuter> mWindow;
5879 bool mIndirect;
5880
5881 nsCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect)
5882 : mozilla::Runnable("nsCloseEvent"),
5883 mWindow(aWindow),
5884 mIndirect(aIndirect) {}
5885
5886 public:
5887 static nsresult PostCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect) {
5888 nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
5889 return aWindow->Dispatch(ev.forget());
5890 }
5891
5892 NS_IMETHODvirtual nsresult Run() override {
5893 if (mWindow) {
5894 if (mIndirect) {
5895 return PostCloseEvent(mWindow, false);
5896 }
5897 mWindow->ReallyCloseWindow();
5898 }
5899 return NS_OK;
5900 }
5901};
5902
5903bool nsGlobalWindowOuter::CanClose() {
5904 if (mIsChrome) {
5905 nsCOMPtr<nsIBrowserDOMWindow> bwin = GetBrowserDOMWindow();
5906
5907 bool canClose = true;
5908 if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))((bool)(__builtin_expect(!!(!NS_FAILED_impl(bwin->CanClose
(&canClose))), 1)))
) {
5909 return canClose;
5910 }
5911 }
5912
5913 if (!mDocShell) {
5914 return true;
5915 }
5916
5917 nsCOMPtr<nsIDocumentViewer> viewer;
5918 mDocShell->GetDocViewer(getter_AddRefs(viewer));
5919 if (viewer) {
5920 bool canClose;
5921 nsresult rv = viewer->PermitUnload(&canClose);
5922 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !canClose) return false;
5923 }
5924
5925 // If we still have to print, we delay the closing until print has happened.
5926 if (mShouldDelayPrintUntilAfterLoad && mDelayedPrintUntilAfterLoad) {
5927 mDelayedCloseForPrinting = true;
5928 return false;
5929 }
5930
5931 return true;
5932}
5933
5934void nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller) {
5935 if (!mDocShell || IsInModalState() || mBrowsingContext->IsSubframe()) {
5936 // window.close() is called on a frame in a frameset, on a window
5937 // that's already closed, or on a window for which there's
5938 // currently a modal dialog open. Ignore such calls.
5939 return;
5940 }
5941
5942 if (mHavePendingClose) {
5943 // We're going to be closed anyway; do nothing since we don't want
5944 // to double-close
5945 return;
5946 }
5947
5948 if (mBlockScriptedClosingFlag) {
5949 // A script's popup has been blocked and we don't want
5950 // the window to be closed directly after this event,
5951 // so the user can see that there was a blocked popup.
5952 return;
5953 }
5954
5955 // Don't allow scripts from content to close non-neterror windows that
5956 // were not opened by script.
5957 if (mDoc) {
5958 nsAutoString url;
5959 nsresult rv = mDoc->GetURL(url);
5960 NS_ENSURE_SUCCESS_VOID(rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5960); return; } } while (false)
;
5961
5962 if (!StringBeginsWith(url, u"about:neterror"_ns) &&
5963 !mBrowsingContext->GetTopLevelCreatedByWebContent() &&
5964 !aTrustedCaller && !IsOnlyTopLevelDocumentInSHistory()) {
5965 bool allowClose =
5966 mAllowScriptsToClose ||
5967 Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
5968 if (!allowClose) {
5969 // We're blocking the close operation
5970 // report localized error msg in JS console
5971 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
5972 "DOM Window"_ns,
5973 mDoc, // Better name for the category?
5974 nsContentUtils::eDOM_PROPERTIES,
5975 "WindowCloseByScriptBlockedWarning");
5976
5977 return;
5978 }
5979 }
5980 }
5981
5982 if (!mInClose && !mIsClosed && !CanClose()) {
5983 return;
5984 }
5985
5986 // Fire a DOM event notifying listeners that this window is about to
5987 // be closed. The tab UI code may choose to cancel the default
5988 // action for this event, if so, we won't actually close the window
5989 // (since the tab UI code will close the tab in stead). Sure, this
5990 // could be abused by content code, but do we care? I don't think
5991 // so...
5992
5993 bool wasInClose = mInClose;
5994 mInClose = true;
5995
5996 if (!DispatchCustomEvent(u"DOMWindowClose"_ns, ChromeOnlyDispatch::eYes)) {
5997 // Someone chose to prevent the default action for this event, if
5998 // so, let's not close this window after all...
5999
6000 mInClose = wasInClose;
6001 return;
6002 }
6003
6004 FinalClose();
6005}
6006
6007bool nsGlobalWindowOuter::IsOnlyTopLevelDocumentInSHistory() {
6008 NS_ENSURE_TRUE(mDocShell && mBrowsingContext, false)do { if ((__builtin_expect(!!(!(mDocShell && mBrowsingContext
)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocShell && mBrowsingContext"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6008); return false; } } while (false)
;
6009 // Disabled since IsFrame() is buggy in Fission
6010 // MOZ_ASSERT(mBrowsingContext->IsTop());
6011
6012 if (mozilla::SessionHistoryInParent()) {
6013 return mBrowsingContext->GetIsSingleToplevelInHistory();
6014 }
6015
6016 RefPtr<ChildSHistory> csh = nsDocShell::Cast(mDocShell)->GetSessionHistory();
6017 if (csh && csh->LegacySHistory()) {
6018 return csh->LegacySHistory()->IsEmptyOrHasEntriesForSingleTopLevelPage();
6019 }
6020
6021 return false;
6022}
6023
6024nsresult nsGlobalWindowOuter::Close() {
6025 CloseOuter(/* aTrustedCaller = */ true);
6026 return NS_OK;
6027}
6028
6029void nsGlobalWindowOuter::ForceClose() {
6030 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_GetProcessType() == GeckoProcessType_Default)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(XRE_GetProcessType() == GeckoProcessType_Default))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_GetProcessType() == GeckoProcessType_Default"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6030); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_GetProcessType() == GeckoProcessType_Default"
")"); do { *((volatile int*)__null) = 6030; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6031
6032 if (mBrowsingContext->IsSubframe() || !mDocShell) {
6033 // This may be a frame in a frameset, or a window that's already closed.
6034 // Ignore such calls.
6035 return;
6036 }
6037
6038 if (mHavePendingClose) {
6039 // We're going to be closed anyway; do nothing since we don't want
6040 // to double-close
6041 return;
6042 }
6043
6044 mInClose = true;
6045
6046 DispatchCustomEvent(u"DOMWindowClose"_ns, ChromeOnlyDispatch::eYes);
6047
6048 FinalClose();
6049}
6050
6051void nsGlobalWindowOuter::FinalClose() {
6052 // Flag that we were closed.
6053 mIsClosed = true;
6054
6055 if (!mBrowsingContext->IsDiscarded()) {
6056 MOZ_ALWAYS_SUCCEEDS(mBrowsingContext->SetClosed(true))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(mBrowsingContext->SetClosed(true))), 1)))), 1))) { } else
{ do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(mBrowsingContext->SetClosed(true))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6056); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(mBrowsingContext->SetClosed(true))"
")"); do { *((volatile int*)__null) = 6056; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
6057 }
6058
6059 // If we get here from CloseOuter then it means that the parent process is
6060 // going to close our window for us. It's just important to set mIsClosed.
6061 if (XRE_GetProcessType() == GeckoProcessType_Content) {
6062 return;
6063 }
6064
6065 // This stuff is non-sensical but incredibly fragile. The reasons for the
6066 // behavior here don't make sense today and may not have ever made sense,
6067 // but various bits of frontend code break when you change them. If you need
6068 // to fix up this behavior, feel free to. It's a righteous task, but involves
6069 // wrestling with various download manager tests, frontend code, and possible
6070 // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
6071 // testing ground.
6072 //
6073 // In particular, if some inner of |win| is the entry global, we must
6074 // complete _two_ round-trips to the event loop before the call to
6075 // ReallyCloseWindow. This allows setTimeout handlers that are set after
6076 // FinalClose() is called to run before the window is torn down.
6077 nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6078 do_QueryInterface(GetEntryGlobal());
6079 bool indirect = entryWindow && entryWindow->GetOuterWindow() == this;
6080 if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsCloseEvent::PostCloseEvent
(this, indirect))), 0)))
) {
6081 ReallyCloseWindow();
6082 } else {
6083 mHavePendingClose = true;
6084 }
6085}
6086
6087void nsGlobalWindowOuter::ReallyCloseWindow() {
6088 // Make sure we never reenter this method.
6089 mHavePendingClose = true;
6090
6091 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6092 if (!treeOwnerAsWin) {
6093 return;
6094 }
6095
6096 treeOwnerAsWin->Destroy();
6097 CleanUp();
6098}
6099
6100void nsGlobalWindowOuter::SuppressEventHandling() {
6101 if (mSuppressEventHandlingDepth == 0) {
6102 if (BrowsingContext* bc = GetBrowsingContext()) {
6103 bc->PreOrderWalk([&](BrowsingContext* aBC) {
6104 if (nsCOMPtr<nsPIDOMWindowOuter> win = aBC->GetDOMWindow()) {
6105 if (RefPtr<Document> doc = win->GetExtantDoc()) {
6106 mSuspendedDocs.AppendElement(doc);
6107 // Note: Document::SuppressEventHandling will also automatically
6108 // suppress event handling for any in-process sub-documents.
6109 // However, since we need to deal with cases where remote
6110 // BrowsingContexts may be interleaved with in-process ones, we
6111 // still need to walk the entire tree ourselves. This may be
6112 // slightly redundant in some cases, but since event handling
6113 // suppressions maintain a count of current blockers, it does not
6114 // cause any problems.
6115 doc->SuppressEventHandling();
6116 }
6117 }
6118 });
6119 }
6120 }
6121 mSuppressEventHandlingDepth++;
6122}
6123
6124void nsGlobalWindowOuter::UnsuppressEventHandling() {
6125 MOZ_ASSERT(mSuppressEventHandlingDepth != 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSuppressEventHandlingDepth != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSuppressEventHandlingDepth !=
0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mSuppressEventHandlingDepth != 0", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6125); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSuppressEventHandlingDepth != 0"
")"); do { *((volatile int*)__null) = 6125; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6126 mSuppressEventHandlingDepth--;
6127
6128 if (mSuppressEventHandlingDepth == 0 && mSuspendedDocs.Length()) {
6129 RefPtr<Document> currentDoc = GetExtantDoc();
6130 bool fireEvent = currentDoc == mSuspendedDocs[0];
6131 nsTArray<RefPtr<Document>> suspendedDocs = std::move(mSuspendedDocs);
6132 for (const auto& doc : suspendedDocs) {
6133 doc->UnsuppressEventHandlingAndFireEvents(fireEvent);
6134 }
6135 }
6136}
6137
6138nsGlobalWindowOuter* nsGlobalWindowOuter::EnterModalState() {
6139 // GetInProcessScriptableTop, not GetInProcessTop, so that EnterModalState
6140 // works properly with <iframe mozbrowser>.
6141 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6142
6143 if (!topWin) {
6144 NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Uh, EnterModalState() called w/o a reachable top window?"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6144); MOZ_PretendNoReturn(); } while (0)
;
6145 return nullptr;
6146 }
6147
6148 // If there is an active ESM in this window, clear it. Otherwise, this can
6149 // cause a problem if a modal state is entered during a mouseup event.
6150 EventStateManager* activeESM = static_cast<EventStateManager*>(
6151 EventStateManager::GetActiveEventStateManager());
6152 if (activeESM && activeESM->GetPresContext()) {
6153 PresShell* activePresShell = activeESM->GetPresContext()->GetPresShell();
6154 if (activePresShell && (nsContentUtils::ContentIsCrossDocDescendantOf(
6155 activePresShell->GetDocument(), mDoc) ||
6156 nsContentUtils::ContentIsCrossDocDescendantOf(
6157 mDoc, activePresShell->GetDocument()))) {
6158 EventStateManager::ClearGlobalActiveContent(activeESM);
6159
6160 PresShell::ReleaseCapturingContent();
6161
6162 if (activePresShell) {
6163 RefPtr<nsFrameSelection> frameSelection =
6164 activePresShell->FrameSelection();
6165 frameSelection->SetDragState(false);
6166 }
6167 }
6168 }
6169
6170 // If there are any drag and drop operations in flight, try to end them.
6171 nsCOMPtr<nsIDragService> ds =
6172 do_GetService("@mozilla.org/widget/dragservice;1");
6173 if (ds && topWin->GetDocShell()) {
6174 if (PresShell* presShell = topWin->GetDocShell()->GetPresShell()) {
6175 if (nsViewManager* vm = presShell->GetViewManager()) {
6176 RefPtr<nsIWidget> widget = vm->GetRootWidget();
6177 if (nsCOMPtr<nsIDragSession> session = ds->GetCurrentSession(widget)) {
6178 session->EndDragSession(true, 0);
6179 }
6180 }
6181 }
6182 }
6183
6184 // Clear the capturing content if it is under topDoc.
6185 // Usually the activeESM check above does that, but there are cases when
6186 // we don't have activeESM, or it is for different document.
6187 Document* topDoc = topWin->GetExtantDoc();
6188 nsIContent* capturingContent = PresShell::GetCapturingContent();
6189 if (capturingContent && topDoc &&
6190 nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
6191 PresShell::ReleaseCapturingContent();
6192 }
6193
6194 if (topWin->mModalStateDepth == 0) {
6195 topWin->SuppressEventHandling();
6196
6197 if (nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(topWin)) {
6198 inner->Suspend();
6199 }
6200 }
6201 topWin->mModalStateDepth++;
6202 return topWin;
6203}
6204
6205void nsGlobalWindowOuter::LeaveModalState() {
6206 {
6207 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6208 if (!topWin) {
6209 NS_WARNING("Uh, LeaveModalState() called w/o a reachable top window?")NS_DebugBreak(NS_DEBUG_WARNING, "Uh, LeaveModalState() called w/o a reachable top window?"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6209)
;
6210 return;
6211 }
6212
6213 if (topWin != this) {
6214 MOZ_ASSERT(IsSuspended())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsSuspended())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsSuspended()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("IsSuspended()",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSuspended()"
")"); do { *((volatile int*)__null) = 6214; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6215 return topWin->LeaveModalState();
6216 }
6217 }
6218
6219 MOZ_ASSERT(mModalStateDepth != 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mModalStateDepth != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mModalStateDepth != 0))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("mModalStateDepth != 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mModalStateDepth != 0"
")"); do { *((volatile int*)__null) = 6219; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6220 MOZ_ASSERT(IsSuspended())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsSuspended())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsSuspended()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("IsSuspended()",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSuspended()"
")"); do { *((volatile int*)__null) = 6220; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6221 mModalStateDepth--;
6222
6223 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6224 if (mModalStateDepth == 0) {
6225 if (inner) {
6226 inner->Resume();
6227 }
6228
6229 UnsuppressEventHandling();
6230 }
6231
6232 // Remember the time of the last dialog quit.
6233 if (auto* bcg = GetBrowsingContextGroup()) {
6234 bcg->SetLastDialogQuitTime(TimeStamp::Now());
6235 }
6236
6237 if (mModalStateDepth == 0) {
6238 RefPtr<Event> event = NS_NewDOMEvent(inner, nullptr, nullptr);
6239 event->InitEvent(u"endmodalstate"_ns, true, false);
6240 event->SetTrusted(true);
6241 event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
6242 DispatchEvent(*event);
6243 }
6244}
6245
6246bool nsGlobalWindowOuter::IsInModalState() {
6247 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6248
6249 if (!topWin) {
6250 // IsInModalState() getting called w/o a reachable top window is a bit
6251 // iffy, but valid enough not to make noise about it. See bug 404828
6252 return false;
6253 }
6254
6255 return topWin->mModalStateDepth != 0;
6256}
6257
6258void nsGlobalWindowOuter::NotifyWindowIDDestroyed(const char* aTopic) {
6259 nsCOMPtr<nsIRunnable> runnable =
6260 new WindowDestroyedEvent(this, mWindowID, aTopic);
6261 Dispatch(runnable.forget());
6262}
6263
6264Element* nsGlobalWindowOuter::GetFrameElement(nsIPrincipal& aSubjectPrincipal) {
6265 // Per HTML5, the frameElement getter returns null in cross-origin situations.
6266 Element* element = GetFrameElement();
6267 if (!element) {
6268 return nullptr;
6269 }
6270
6271 if (!aSubjectPrincipal.SubsumesConsideringDomain(element->NodePrincipal())) {
6272 return nullptr;
6273 }
6274
6275 return element;
6276}
6277
6278Element* nsGlobalWindowOuter::GetFrameElement() {
6279 if (!mBrowsingContext || mBrowsingContext->IsTop()) {
6280 return nullptr;
6281 }
6282 return mBrowsingContext->GetEmbedderElement();
6283}
6284
6285namespace {
6286class ChildCommandDispatcher : public Runnable {
6287 public:
6288 ChildCommandDispatcher(nsPIWindowRoot* aRoot, nsIBrowserChild* aBrowserChild,
6289 nsPIDOMWindowOuter* aWindow, const nsAString& aAction)
6290 : mozilla::Runnable("ChildCommandDispatcher"),
6291 mRoot(aRoot),
6292 mBrowserChild(aBrowserChild),
6293 mWindow(aWindow),
6294 mAction(aAction) {}
6295
6296 NS_IMETHODvirtual nsresult Run() override {
6297 AutoTArray<nsCString, 70> enabledCommands, disabledCommands;
6298 mRoot->GetEnabledDisabledCommands(enabledCommands, disabledCommands);
6299 if (enabledCommands.Length() || disabledCommands.Length()) {
6300 BrowserChild* bc = static_cast<BrowserChild*>(mBrowserChild.get());
6301 bc->SendEnableDisableCommands(mWindow->GetBrowsingContext(), mAction,
6302 enabledCommands, disabledCommands);
6303 }
6304
6305 return NS_OK;
6306 }
6307
6308 private:
6309 nsCOMPtr<nsPIWindowRoot> mRoot;
6310 nsCOMPtr<nsIBrowserChild> mBrowserChild;
6311 nsCOMPtr<nsPIDOMWindowOuter> mWindow;
6312 nsString mAction;
6313};
6314
6315class CommandDispatcher : public Runnable {
6316 public:
6317 CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
6318 const nsAString& aAction)
6319 : mozilla::Runnable("CommandDispatcher"),
6320 mDispatcher(aDispatcher),
6321 mAction(aAction) {}
6322
6323 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230, bug 1535398)
6324 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODvirtual nsresult Run() override {
6325 return mDispatcher->UpdateCommands(mAction);
6326 }
6327
6328 const nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
6329 nsString mAction;
6330};
6331} // anonymous namespace
6332
6333void nsGlobalWindowOuter::UpdateCommands(const nsAString& anAction) {
6334 // If this is a child process, redirect to the parent process.
6335 if (nsIDocShell* docShell = GetDocShell()) {
6336 if (nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild()) {
6337 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
6338 if (root) {
6339 nsContentUtils::AddScriptRunner(
6340 new ChildCommandDispatcher(root, child, this, anAction));
6341 }
6342 return;
6343 }
6344 }
6345
6346 nsPIDOMWindowOuter* rootWindow = GetPrivateRoot();
6347 if (!rootWindow) {
6348 return;
6349 }
6350
6351 Document* doc = rootWindow->GetExtantDoc();
6352
6353 if (!doc) {
6354 return;
6355 }
6356
6357 // Retrieve the command dispatcher and call updateCommands on it.
6358 nsIDOMXULCommandDispatcher* xulCommandDispatcher =
6359 doc->GetCommandDispatcher();
6360 if (xulCommandDispatcher) {
6361 nsContentUtils::AddScriptRunner(
6362 new CommandDispatcher(xulCommandDispatcher, anAction));
6363 }
6364}
6365
6366Selection* nsGlobalWindowOuter::GetSelectionOuter() {
6367 if (!mDocShell) {
6368 return nullptr;
6369 }
6370
6371 PresShell* presShell = mDocShell->GetPresShell();
6372 if (!presShell) {
6373 return nullptr;
6374 }
6375 return presShell->GetCurrentSelection(SelectionType::eNormal);
6376}
6377
6378already_AddRefed<Selection> nsGlobalWindowOuter::GetSelection() {
6379 RefPtr<Selection> selection = GetSelectionOuter();
6380 return selection.forget();
6381}
6382
6383bool nsGlobalWindowOuter::FindOuter(const nsAString& aString,
6384 bool aCaseSensitive, bool aBackwards,
6385 bool aWrapAround, bool aWholeWord,
6386 bool aSearchInFrames, bool aShowDialog,
6387 ErrorResult& aError) {
6388 Unused << aShowDialog;
6389
6390 nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
6391 if (!finder) {
6392 aError.Throw(NS_ERROR_NOT_AVAILABLE);
6393 return false;
6394 }
6395
6396 // Set the options of the search
6397 aError = finder->SetSearchString(aString);
6398 if (aError.Failed()) {
6399 return false;
6400 }
6401 finder->SetMatchCase(aCaseSensitive);
6402 finder->SetFindBackwards(aBackwards);
6403 finder->SetWrapFind(aWrapAround);
6404 finder->SetEntireWord(aWholeWord);
6405 finder->SetSearchFrames(aSearchInFrames);
6406
6407 // the nsIWebBrowserFind is initialized to use this window
6408 // as the search root, but uses focus to set the current search
6409 // frame. If we're being called from JS (as here), this window
6410 // should be the current search frame.
6411 nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
6412 if (framesFinder) {
6413 framesFinder->SetRootSearchFrame(this); // paranoia
6414 framesFinder->SetCurrentSearchFrame(this);
6415 }
6416
6417 if (aString.IsEmpty()) {
6418 return false;
6419 }
6420
6421 // Launch the search with the passed in search string
6422 bool didFind = false;
6423 aError = finder->FindNext(&didFind);
6424 return didFind;
6425}
6426
6427//*****************************************************************************
6428// EventTarget
6429//*****************************************************************************
6430
6431nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOwnerGlobalForBindingsInternal() {
6432 return this;
6433}
6434
6435nsIGlobalObject* nsGlobalWindowOuter::GetOwnerGlobal() const {
6436 return GetCurrentInnerWindowInternal(this);
6437}
6438
6439bool nsGlobalWindowOuter::DispatchEvent(Event& aEvent, CallerType aCallerType,
6440 ErrorResult& aRv) {
6441 FORWARD_TO_INNER(DispatchEvent, (aEvent, aCallerType, aRv), false)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6441); return false; } return GetCurrentInnerWindowInternal
(this)->DispatchEvent (aEvent, aCallerType, aRv); } while (
0)
;
6442}
6443
6444bool nsGlobalWindowOuter::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
6445 // It's OK that we just return false here on failure to create an
6446 // inner. GetOrCreateListenerManager() will likewise fail, and then
6447 // we won't be adding any listeners anyway.
6448 FORWARD_TO_INNER_CREATE(ComputeDefaultWantsUntrusted, (aRv), false)do { if (!mInnerWindow) { if (mIsClosed) { return false; } nsCOMPtr
<Document> kungFuDeathGrip = GetDoc(); ::mozilla::Unused
<< kungFuDeathGrip; if (!mInnerWindow) { return false;
} } return GetCurrentInnerWindowInternal(this)->ComputeDefaultWantsUntrusted
(aRv); } while (0)
;
6449}
6450
6451EventListenerManager* nsGlobalWindowOuter::GetOrCreateListenerManager() {
6452 FORWARD_TO_INNER_CREATE(GetOrCreateListenerManager, (), nullptr)do { if (!mInnerWindow) { if (mIsClosed) { return nullptr; } nsCOMPtr
<Document> kungFuDeathGrip = GetDoc(); ::mozilla::Unused
<< kungFuDeathGrip; if (!mInnerWindow) { return nullptr
; } } return GetCurrentInnerWindowInternal(this)->GetOrCreateListenerManager
(); } while (0)
;
6453}
6454
6455EventListenerManager* nsGlobalWindowOuter::GetExistingListenerManager() const {
6456 FORWARD_TO_INNER(GetExistingListenerManager, (), nullptr)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6456); return nullptr; } return GetCurrentInnerWindowInternal
(this)->GetExistingListenerManager (); } while (0)
;
6457}
6458
6459//*****************************************************************************
6460// nsGlobalWindowOuter::nsPIDOMWindow
6461//*****************************************************************************
6462
6463nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateParent() {
6464 nsCOMPtr<nsPIDOMWindowOuter> parent = GetInProcessParent();
6465
6466 if (this == parent) {
6467 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6468 if (!chromeElement)
6469 return nullptr; // This is ok, just means a null parent.
6470
6471 Document* doc = chromeElement->GetComposedDoc();
6472 if (!doc) return nullptr; // This is ok, just means a null parent.
6473
6474 return doc->GetWindow();
6475 }
6476
6477 return parent;
6478}
6479
6480nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateRoot() {
6481 nsCOMPtr<nsPIDOMWindowOuter> top = GetInProcessTop();
6482
6483 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6484 if (chromeElement) {
6485 Document* doc = chromeElement->GetComposedDoc();
6486 if (doc) {
6487 nsCOMPtr<nsPIDOMWindowOuter> parent = doc->GetWindow();
6488 if (parent) {
6489 top = parent->GetInProcessTop();
6490 }
6491 }
6492 }
6493
6494 return top;
6495}
6496
6497// This has a caller in Windows-only code (nsNativeAppSupportWin).
6498Location* nsGlobalWindowOuter::GetLocation() {
6499 // This method can be called on the outer window as well.
6500 FORWARD_TO_INNER(Location, (), nullptr)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6500); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Location (); } while (0)
;
6501}
6502
6503void nsGlobalWindowOuter::SetIsBackground(bool aIsBackground) {
6504 bool changed = aIsBackground != IsBackground();
6505 SetIsBackgroundInternal(aIsBackground);
6506
6507 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6508
6509 if (inner && changed) {
6510 inner->UpdateBackgroundState();
6511 }
6512
6513 if (aIsBackground) {
6514 // Notify gamepadManager we are at the background window,
6515 // we need to stop vibrate.
6516 // Stop the vr telemery time spent when it switches to
6517 // the background window.
6518 if (inner && changed) {
6519 inner->StopGamepadHaptics();
6520 inner->StopVRActivity();
6521 // true is for asking to set the delta time to
6522 // the telemetry.
6523 inner->ResetVRTelemetry(true);
6524 }
6525 return;
6526 }
6527
6528 if (inner) {
6529 // When switching to be as a top tab, restart the telemetry.
6530 // false is for only resetting the timestamp.
6531 inner->ResetVRTelemetry(false);
6532 inner->SyncGamepadState();
6533 inner->StartVRActivity();
6534 }
6535}
6536
6537void nsGlobalWindowOuter::SetIsBackgroundInternal(bool aIsBackground) {
6538 mIsBackground = aIsBackground;
6539}
6540
6541void nsGlobalWindowOuter::SetChromeEventHandler(
6542 EventTarget* aChromeEventHandler) {
6543 SetChromeEventHandlerInternal(aChromeEventHandler);
6544 // update the chrome event handler on all our inner windows
6545 RefPtr<nsGlobalWindowInner> inner;
6546 for (PRCList* node = PR_LIST_HEAD(this)(this)->next; node != this;
6547 node = PR_NEXT_LINK(inner)((inner)->next)) {
6548 // This cast is only safe if `node != this`, as nsGlobalWindowOuter is also
6549 // in the list.
6550 inner = static_cast<nsGlobalWindowInner*>(node);
6551 NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,do { if (!(!inner->mOuterWindow || inner->mOuterWindow ==
this)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad outer window pointer"
, "!inner->mOuterWindow || inner->mOuterWindow == this"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6552); MOZ_PretendNoReturn(); } } while (0)
6552 "bad outer window pointer")do { if (!(!inner->mOuterWindow || inner->mOuterWindow ==
this)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad outer window pointer"
, "!inner->mOuterWindow || inner->mOuterWindow == this"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6552); MOZ_PretendNoReturn(); } } while (0)
;
6553 inner->SetChromeEventHandlerInternal(aChromeEventHandler);
6554 }
6555}
6556
6557void nsGlobalWindowOuter::SetFocusedElement(Element* aElement,
6558 uint32_t aFocusMethod,
6559 bool aNeedsFocus) {
6560 FORWARD_TO_INNER_VOID(SetFocusedElement,do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6561); return; } GetCurrentInnerWindowInternal(this)->SetFocusedElement
(aElement, aFocusMethod, aNeedsFocus); return; } while (0)
6561 (aElement, aFocusMethod, aNeedsFocus))do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6561); return; } GetCurrentInnerWindowInternal(this)->SetFocusedElement
(aElement, aFocusMethod, aNeedsFocus); return; } while (0)
;
6562}
6563
6564uint32_t nsGlobalWindowOuter::GetFocusMethod() {
6565 FORWARD_TO_INNER(GetFocusMethod, (), 0)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6565); return 0; } return GetCurrentInnerWindowInternal(this
)->GetFocusMethod (); } while (0)
;
6566}
6567
6568bool nsGlobalWindowOuter::ShouldShowFocusRing() {
6569 FORWARD_TO_INNER(ShouldShowFocusRing, (), false)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6569); return false; } return GetCurrentInnerWindowInternal
(this)->ShouldShowFocusRing (); } while (0)
;
6570}
6571
6572bool nsGlobalWindowOuter::TakeFocus(bool aFocus, uint32_t aFocusMethod) {
6573 FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), false)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6573); return false; } return GetCurrentInnerWindowInternal
(this)->TakeFocus (aFocus, aFocusMethod); } while (0)
;
6574}
6575
6576void nsGlobalWindowOuter::SetReadyForFocus() {
6577 FORWARD_TO_INNER_VOID(SetReadyForFocus, ())do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6577); return; } GetCurrentInnerWindowInternal(this)->SetReadyForFocus
(); return; } while (0)
;
6578}
6579
6580void nsGlobalWindowOuter::PageHidden(bool aIsEnteringBFCacheInParent) {
6581 FORWARD_TO_INNER_VOID(PageHidden, (aIsEnteringBFCacheInParent))do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6581); return; } GetCurrentInnerWindowInternal(this)->PageHidden
(aIsEnteringBFCacheInParent); return; } while (0)
;
6582}
6583
6584already_AddRefed<nsICSSDeclaration>
6585nsGlobalWindowOuter::GetComputedStyleHelperOuter(Element& aElt,
6586 const nsAString& aPseudoElt,
6587 bool aDefaultStylesOnly,
6588 ErrorResult& aRv) {
6589 if (!mDoc) {
6590 return nullptr;
6591 }
6592
6593 RefPtr<nsICSSDeclaration> compStyle = NS_NewComputedDOMStyle(
6594 &aElt, aPseudoElt, mDoc,
6595 aDefaultStylesOnly ? nsComputedDOMStyle::StyleType::DefaultOnly
6596 : nsComputedDOMStyle::StyleType::All,
6597 aRv);
6598
6599 return compStyle.forget();
6600}
6601
6602//*****************************************************************************
6603// nsGlobalWindowOuter::nsIInterfaceRequestor
6604//*****************************************************************************
6605
6606nsresult nsGlobalWindowOuter::GetInterfaceInternal(const nsIID& aIID,
6607 void** aSink) {
6608 NS_ENSURE_ARG_POINTER(aSink)do { if ((__builtin_expect(!!(!(aSink)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aSink" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6608); return NS_ERROR_INVALID_POINTER; } } while (false)
;
6609 *aSink = nullptr;
6610
6611 if (aIID.Equals(NS_GET_IID(nsIWebNavigation)(nsIWebNavigation::COMTypeInfo<nsIWebNavigation, void>::
kIID)
)) {
6612 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
6613 webNav.forget(aSink);
6614 } else if (aIID.Equals(NS_GET_IID(nsIDocShell)(nsIDocShell::COMTypeInfo<nsIDocShell, void>::kIID))) {
6615 nsCOMPtr<nsIDocShell> docShell = mDocShell;
6616 docShell.forget(aSink);
6617 }
6618#ifdef NS_PRINTING1
6619 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint)(nsIWebBrowserPrint::COMTypeInfo<nsIWebBrowserPrint, void>
::kIID)
)) {
6620 if (mDocShell) {
6621 nsCOMPtr<nsIDocumentViewer> viewer;
6622 mDocShell->GetDocViewer(getter_AddRefs(viewer));
6623 if (viewer) {
6624 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
6625 webBrowserPrint.forget(aSink);
6626 }
6627 }
6628 }
6629#endif
6630 else if (aIID.Equals(NS_GET_IID(nsILoadContext)(nsILoadContext::COMTypeInfo<nsILoadContext, void>::kIID
)
)) {
6631 nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(mDocShell));
6632 loadContext.forget(aSink);
6633 }
6634
6635 return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
6636}
6637
6638NS_IMETHODIMPnsresult
6639nsGlobalWindowOuter::GetInterface(const nsIID& aIID, void** aSink) {
6640 nsresult rv = GetInterfaceInternal(aIID, aSink);
6641 if (rv == NS_ERROR_NO_INTERFACE) {
6642 return QueryInterface(aIID, aSink);
6643 }
6644 return rv;
6645}
6646
6647bool nsGlobalWindowOuter::IsSuspended() const {
6648 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6648); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6648; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6649 // No inner means we are effectively suspended
6650 if (!mInnerWindow) {
6651 return true;
6652 }
6653 return mInnerWindow->IsSuspended();
6654}
6655
6656bool nsGlobalWindowOuter::IsFrozen() const {
6657 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6657; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6658 // No inner means we are effectively frozen
6659 if (!mInnerWindow) {
6660 return true;
6661 }
6662 return mInnerWindow->IsFrozen();
6663}
6664
6665nsresult nsGlobalWindowOuter::FireDelayedDOMEvents(bool aIncludeSubWindows) {
6666 FORWARD_TO_INNER(FireDelayedDOMEvents, (aIncludeSubWindows),do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6667); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->FireDelayedDOMEvents (aIncludeSubWindows); } while
(0)
6667 NS_ERROR_UNEXPECTED)do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6667); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->FireDelayedDOMEvents (aIncludeSubWindows); } while
(0)
;
6668}
6669
6670//*****************************************************************************
6671// nsGlobalWindowOuter: Window Control Functions
6672//*****************************************************************************
6673
6674nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessParentInternal() {
6675 nsCOMPtr<nsPIDOMWindowOuter> parent = GetInProcessParent();
6676
6677 if (parent && parent != this) {
6678 return parent;
6679 }
6680
6681 return nullptr;
6682}
6683
6684void nsGlobalWindowOuter::UnblockScriptedClosing() {
6685 mBlockScriptedClosingFlag = false;
6686}
6687
6688class AutoUnblockScriptClosing {
6689 private:
6690 RefPtr<nsGlobalWindowOuter> mWin;
6691
6692 public:
6693 explicit AutoUnblockScriptClosing(nsGlobalWindowOuter* aWin) : mWin(aWin) {
6694 MOZ_ASSERT(mWin)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWin)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(mWin))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mWin", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6694); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWin" ")");
do { *((volatile int*)__null) = 6694; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6695 }
6696 ~AutoUnblockScriptClosing() {
6697 void (nsGlobalWindowOuter::*run)() =
6698 &nsGlobalWindowOuter::UnblockScriptedClosing;
6699 nsCOMPtr<nsIRunnable> caller = NewRunnableMethod(
23
Calling 'NewRunnableMethod<RefPtr<nsGlobalWindowOuter> &, void (nsGlobalWindowOuter::*)()>'
6700 "AutoUnblockScriptClosing::~AutoUnblockScriptClosing", mWin, run);
6701 mWin->Dispatch(caller.forget());
6702 }
6703};
6704
6705nsresult nsGlobalWindowOuter::OpenInternal(
6706 const nsACString& aUrl, const nsAString& aName, const nsAString& aOptions,
6707 bool aDialog, bool aCalledNoScript, bool aDoJSFixups, bool aNavigate,
6708 nsIArray* aArguments, nsDocShellLoadState* aLoadState, bool aForceNoOpener,
6709 PrintKind aPrintKind, BrowsingContext** aReturn) {
6710 mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
1
Calling defaulted default constructor for 'Maybe<AutoUnblockScriptClosing>'
12
Returning from default constructor for 'Maybe<AutoUnblockScriptClosing>'
6711
6712 // Calls to window.open from script should navigate.
6713 MOZ_ASSERT(aCalledNoScript || aNavigate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aCalledNoScript || aNavigate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aCalledNoScript || aNavigate
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aCalledNoScript || aNavigate", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCalledNoScript || aNavigate"
")"); do { *((volatile int*)__null) = 6713; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
13
Assuming 'aCalledNoScript' is true
14
Taking false branch
15
Loop condition is false. Exiting loop
6714
6715 *aReturn = nullptr;
6716
6717 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
6718 if (!chrome) {
16
Taking true branch
6719 // No chrome means we don't want to go through with this open call
6720 // -- see nsIWindowWatcher.idl
6721 return NS_ERROR_NOT_AVAILABLE;
17
Calling implicit destructor for 'Maybe<AutoUnblockScriptClosing>'
18
Calling '~MaybeStorage'
6722 }
6723
6724 NS_ASSERTION(mDocShell, "Must have docshell here")do { if (!(mDocShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Must have docshell here"
, "mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6724); MOZ_PretendNoReturn(); } } while (0)
;
6725
6726 NS_ConvertUTF16toUTF8 optionsUtf8(aOptions);
6727
6728 WindowFeatures features;
6729 if (!features.Tokenize(optionsUtf8)) {
6730 return NS_ERROR_FAILURE;
6731 }
6732
6733 bool forceNoOpener = aForceNoOpener;
6734 if (features.Exists("noopener")) {
6735 forceNoOpener = features.GetBool("noopener");
6736 features.Remove("noopener");
6737 }
6738
6739 bool forceNoReferrer = false;
6740 if (features.Exists("noreferrer")) {
6741 forceNoReferrer = features.GetBool("noreferrer");
6742 if (forceNoReferrer) {
6743 // noreferrer implies noopener
6744 forceNoOpener = true;
6745 }
6746 features.Remove("noreferrer");
6747 }
6748
6749 nsAutoCString options;
6750 features.Stringify(options);
6751
6752 // If noopener is force-enabled for the current document, then set noopener to
6753 // true, and clear the name to "_blank".
6754 nsAutoString windowName(aName);
6755 if (nsDocShell::Cast(GetDocShell())->NoopenerForceEnabled() &&
6756 aPrintKind == PrintKind::None) {
6757 MOZ_DIAGNOSTIC_ASSERT(aNavigate,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNavigate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNavigate))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNavigate" " (" "cannot OpenNoNavigate if noopener is force-enabled"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6758); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNavigate"
") (" "cannot OpenNoNavigate if noopener is force-enabled" ")"
); do { *((volatile int*)__null) = 6758; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6758 "cannot OpenNoNavigate if noopener is force-enabled")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNavigate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNavigate))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aNavigate" " (" "cannot OpenNoNavigate if noopener is force-enabled"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6758); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNavigate"
") (" "cannot OpenNoNavigate if noopener is force-enabled" ")"
); do { *((volatile int*)__null) = 6758; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6759
6760 forceNoOpener = true;
6761 windowName = u"_blank"_ns;
6762 }
6763
6764 bool windowExists = WindowExists(windowName, forceNoOpener, !aCalledNoScript);
6765
6766 // XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()
6767 // (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.
6768 // But note that if you change this to GetEntryGlobal(), say, then
6769 // OnLinkClickEvent::Run will need a full-blown AutoEntryScript. (Bug 1930445)
6770 const bool checkForPopup = [&]() {
6771 if (aDialog) {
6772 return false;
6773 }
6774 if (windowExists) {
6775 return false;
6776 }
6777 if (aLoadState && aLoadState->IsFormSubmission()) {
6778 return true;
6779 }
6780 return !nsContentUtils::LegacyIsCallerChromeOrNativeCode();
6781 }();
6782
6783 nsCOMPtr<nsIURI> uri;
6784
6785 // It's important to do this security check before determining whether this
6786 // window opening should be blocked, to ensure that we don't FireAbuseEvents
6787 // for a window opening that wouldn't have succeeded in the first place.
6788 if (!aUrl.IsEmpty()) {
6789 // It's safe to skip the security check below if we're a dialog because
6790 // window.openDialog is not callable from content script. See bug 56851.
6791 //
6792 // If we're not navigating, we assume that whoever *does* navigate the
6793 // window will do a security check of their own.
6794 auto result =
6795 URIfromURLAndMaybeDoSecurityCheck(aUrl, !aDialog && aNavigate);
6796 if (result.isErr()) {
6797 return result.unwrapErr();
6798 }
6799
6800 uri = result.unwrap();
6801 } else if (mDoc) {
6802 mDoc->SetUseCounter(eUseCounter_custom_WindowOpenEmptyUrl);
6803 }
6804
6805 UserActivation::Modifiers modifiers;
6806 mBrowsingContext->GetUserActivationModifiersForPopup(&modifiers);
6807
6808 // Need to create loadState before the user activation is consumed in
6809 // BrowsingContext::RevisePopupAbuseLevel() below.
6810 RefPtr<nsDocShellLoadState> loadState = aLoadState;
6811 if (!loadState && aNavigate && uri) {
6812 loadState = nsWindowWatcher::CreateLoadState(uri, this);
6813 }
6814
6815 PopupBlocker::PopupControlState abuseLevel =
6816 PopupBlocker::GetPopupControlState();
6817 if (checkForPopup) {
6818 abuseLevel = mBrowsingContext->RevisePopupAbuseLevel(abuseLevel);
6819 if (abuseLevel >= PopupBlocker::openBlocked) {
6820 if (!aCalledNoScript) {
6821 // If script in some other window is doing a window.open on us and
6822 // it's being blocked, then it's OK to close us afterwards, probably.
6823 // But if we're doing a window.open on ourselves and block the popup,
6824 // prevent this window from closing until after this script terminates
6825 // so that whatever popup blocker UI the app has will be visible.
6826 nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6827 do_QueryInterface(GetEntryGlobal());
6828 // Note that entryWindow can be null here if some JS component was the
6829 // place where script was entered for this JS execution.
6830 if (entryWindow && entryWindow->GetOuterWindow() == this) {
6831 mBlockScriptedClosingFlag = true;
6832 closeUnblocker.emplace(this);
6833 }
6834 }
6835
6836 FireAbuseEvents(aUrl, windowName, aOptions);
6837 return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
6838 }
6839 }
6840
6841 // Per https://github.com/whatwg/html/pull/10547, we should always consume
6842 // user activation when opening a new window, even if the popup blocker is
6843 // disabled or the website has popup permission.
6844 if (!windowExists && mDoc) {
6845 mDoc->ConsumeTransientUserGestureActivation();
6846 }
6847
6848 RefPtr<BrowsingContext> domReturn;
6849
6850 nsresult rv = NS_OK;
6851 nsCOMPtr<nsIWindowWatcher> wwatch =
6852 do_GetService(NS_WINDOWWATCHER_CONTRACTID"@mozilla.org/embedcomp/window-watcher;1", &rv);
6853 NS_ENSURE_TRUE(wwatch, rv)do { if ((__builtin_expect(!!(!(wwatch)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "wwatch" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6853); return rv; } } while (false)
;
6854
6855 NS_ConvertUTF16toUTF8 name(windowName);
6856
6857 nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
6858 NS_ENSURE_STATE(pwwatch)do { if ((__builtin_expect(!!(!(pwwatch)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "pwwatch" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6858); return NS_ERROR_UNEXPECTED; } } while (false)
;
6859
6860 MOZ_ASSERT_IF(checkForPopup, abuseLevel < PopupBlocker::openBlocked)do { if (checkForPopup) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(abuseLevel < PopupBlocker
::openBlocked)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(abuseLevel < PopupBlocker::openBlocked
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"abuseLevel < PopupBlocker::openBlocked", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "abuseLevel < PopupBlocker::openBlocked"
")"); do { *((volatile int*)__null) = 6860; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6861 // At this point we should know for a fact that if checkForPopup then
6862 // abuseLevel < PopupBlocker::openBlocked, so we could just check for
6863 // abuseLevel == PopupBlocker::openControlled. But let's be defensive just in
6864 // case and treat anything that fails the above assert as a spam popup too, if
6865 // it ever happens.
6866 bool isPopupSpamWindow =
6867 checkForPopup && (abuseLevel >= PopupBlocker::openControlled);
6868
6869 const auto wwPrintKind = [&] {
6870 switch (aPrintKind) {
6871 case PrintKind::None:
6872 return nsPIWindowWatcher::PRINT_NONE;
6873 case PrintKind::InternalPrint:
6874 return nsPIWindowWatcher::PRINT_INTERNAL;
6875 case PrintKind::WindowDotPrint:
6876 return nsPIWindowWatcher::PRINT_WINDOW_DOT_PRINT;
6877 }
6878 MOZ_ASSERT_UNREACHABLE("Wat")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Wat" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Wat" ")"); do { *((volatile int*
)__null) = 6878; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6879 return nsPIWindowWatcher::PRINT_NONE;
6880 }();
6881
6882 {
6883 // Reset popup state while opening a window to prevent the
6884 // current state from being active the whole time a modal
6885 // dialog is open.
6886 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
6887
6888 if (!aCalledNoScript) {
6889 // We asserted at the top of this function that aNavigate is true for
6890 // !aCalledNoScript.
6891 rv = pwwatch->OpenWindow2(this, uri, name, options, modifiers,
6892 /* aCalledFromScript = */ true, aDialog,
6893 aNavigate, aArguments, isPopupSpamWindow,
6894 forceNoOpener, forceNoReferrer, wwPrintKind,
6895 loadState, getter_AddRefs(domReturn));
6896 } else {
6897 // Force a system caller here so that the window watcher won't screw us
6898 // up. We do NOT want this case looking at the JS context on the stack
6899 // when searching. Compare comments on
6900 // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
6901
6902 // Note: Because nsWindowWatcher is so broken, it's actually important
6903 // that we don't force a system caller here, because that screws it up
6904 // when it tries to compute the caller principal to associate with dialog
6905 // arguments. That whole setup just really needs to be rewritten. :-(
6906 AutoNoJSAPI nojsapi;
6907 rv = pwwatch->OpenWindow2(this, uri, name, options, modifiers,
6908 /* aCalledFromScript = */ false, aDialog,
6909 aNavigate, aArguments, isPopupSpamWindow,
6910 forceNoOpener, forceNoReferrer, wwPrintKind,
6911 loadState, getter_AddRefs(domReturn));
6912 }
6913 }
6914
6915 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6915); return rv; } } while (false)
;
6916
6917 // success!
6918
6919 if (!aCalledNoScript && !windowExists && uri && !forceNoOpener) {
6920 MaybeAllowStorageForOpenedWindow(uri);
6921 }
6922
6923 if (domReturn && aDoJSFixups) {
6924 nsPIDOMWindowOuter* outer = domReturn->GetDOMWindow();
6925 if (outer && !nsGlobalWindowOuter::Cast(outer)->IsChromeWindow()) {
6926 // A new non-chrome window was created from a call to
6927 // window.open() from JavaScript, make sure there's a document in
6928 // the new window. We do this by simply asking the new window for
6929 // its document, this will synchronously create an empty document
6930 // if there is no document in the window.
6931 // XXXbz should this just use EnsureInnerWindow()?
6932
6933 // Force document creation.
6934 nsCOMPtr<Document> doc = outer->GetDoc();
6935 Unused << doc;
6936 }
6937 }
6938
6939 domReturn.forget(aReturn);
6940 return NS_OK;
6941}
6942
6943void nsGlobalWindowOuter::MaybeAllowStorageForOpenedWindow(nsIURI* aURI) {
6944 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6945 if (NS_WARN_IF(!inner)NS_warn_if_impl(!inner, "!inner", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6945)
) {
6946 return;
6947 }
6948
6949 // No 3rd party URL/window.
6950 if (!AntiTrackingUtils::IsThirdPartyWindow(inner, aURI)) {
6951 return;
6952 }
6953
6954 Document* doc = inner->GetDoc();
6955 if (!doc) {
6956 return;
6957 }
6958 nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateContentPrincipal(
6959 aURI, doc->NodePrincipal()->OriginAttributesRef());
6960
6961 // We don't care when the asynchronous work finishes here.
6962 // Without e10s or fission enabled this is run in the parent process.
6963 if (XRE_IsParentProcess()) {
6964 Unused << StorageAccessAPIHelper::AllowAccessForOnParentProcess(
6965 principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
6966 } else {
6967 Unused << StorageAccessAPIHelper::AllowAccessForOnChildProcess(
6968 principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
6969 }
6970}
6971
6972//*****************************************************************************
6973// nsGlobalWindowOuter: Helper Functions
6974//*****************************************************************************
6975
6976already_AddRefed<nsIDocShellTreeOwner> nsPIDOMWindowOuter::GetTreeOwner() {
6977 // If there's no docShellAsItem, this window must have been closed,
6978 // in that case there is no tree owner.
6979
6980 if (!mDocShell) {
6981 return nullptr;
6982 }
6983
6984 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
6985 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
6986 return treeOwner.forget();
6987}
6988
6989already_AddRefed<nsIBaseWindow> nsPIDOMWindowOuter::GetTreeOwnerWindow() {
6990 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
6991
6992 // If there's no mDocShell, this window must have been closed,
6993 // in that case there is no tree owner.
6994
6995 if (mDocShell) {
6996 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
6997 }
6998
6999 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
7000 return baseWindow.forget();
7001}
7002
7003already_AddRefed<nsIWebBrowserChrome>
7004nsPIDOMWindowOuter::GetWebBrowserChrome() {
7005 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
7006
7007 nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
7008 return browserChrome.forget();
7009}
7010
7011ScrollContainerFrame* nsGlobalWindowOuter::GetScrollContainerFrame() {
7012 if (!mDocShell) {
7013 return nullptr;
7014 }
7015
7016 PresShell* presShell = mDocShell->GetPresShell();
7017 if (presShell) {
7018 return presShell->GetRootScrollContainerFrame();
7019 }
7020 return nullptr;
7021}
7022
7023Result<already_AddRefed<nsIURI>, nsresult>
7024nsGlobalWindowOuter::URIfromURLAndMaybeDoSecurityCheck(const nsACString& aURL,
7025 bool aSecurityCheck) {
7026 nsCOMPtr<nsPIDOMWindowInner> sourceWindow =
7027 do_QueryInterface(GetEntryGlobal());
7028 if (!sourceWindow) {
7029 sourceWindow = GetCurrentInnerWindow();
7030 }
7031
7032 // Resolve the baseURI, which could be relative to the calling window.
7033 //
7034 // Note the algorithm to get the base URI should match the one
7035 // used to actually kick off the load in nsWindowWatcher.cpp.
7036 nsCOMPtr<Document> doc = sourceWindow->GetDoc();
7037 nsIURI* baseURI = nullptr;
7038 auto encoding = UTF_8_ENCODING; // default to utf-8
7039 if (doc) {
7040 baseURI = doc->GetDocBaseURI();
7041 encoding = doc->GetDocumentCharacterSet();
7042 }
7043 nsCOMPtr<nsIURI> uri;
7044 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, encoding, baseURI);
7045 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7045)
) {
7046 return Err(NS_ERROR_DOM_SYNTAX_ERR);
7047 }
7048
7049 if (aSecurityCheck) {
7050 AutoJSContext cx;
7051 nsGlobalWindowInner* sourceWin = nsGlobalWindowInner::Cast(sourceWindow);
7052 JSAutoRealm ar(cx, sourceWin->GetGlobalJSObject());
7053
7054 if (NS_FAILED(nsContentUtils::GetSecurityManager()->CheckLoadURIFromScript(((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckLoadURIFromScript( cx, uri))), 0)))
7055 cx, uri))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckLoadURIFromScript( cx, uri))), 0)))
) {
7056 return Err(NS_ERROR_FAILURE);
7057 }
7058 }
7059
7060 return uri.forget();
7061}
7062
7063void nsGlobalWindowOuter::FlushPendingNotifications(FlushType aType) {
7064 if (mDoc) {
7065 mDoc->FlushPendingNotifications(aType);
7066 }
7067}
7068
7069void nsGlobalWindowOuter::EnsureSizeAndPositionUpToDate() {
7070 // If we're a subframe, make sure our size is up to date. Make sure to go
7071 // through the document chain rather than the window chain to not flush on
7072 // detached iframes, see bug 1545516.
7073 if (mDoc && mDoc->StyleOrLayoutObservablyDependsOnParentDocumentLayout()) {
7074 RefPtr<Document> parent = mDoc->GetInProcessParentDocument();
7075 parent->FlushPendingNotifications(FlushType::Layout);
7076 }
7077}
7078
7079already_AddRefed<nsISupports> nsGlobalWindowOuter::SaveWindowState() {
7080 MOZ_ASSERT(!mozilla::SessionHistoryInParent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mozilla::SessionHistoryInParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mozilla::SessionHistoryInParent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mozilla::SessionHistoryInParent()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mozilla::SessionHistoryInParent()"
")"); do { *((volatile int*)__null) = 7080; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7081
7082 if (!mContext || !GetWrapperPreserveColor()) {
7083 // The window may be getting torn down; don't bother saving state.
7084 return nullptr;
7085 }
7086
7087 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
7088 NS_ASSERTION(inner, "No inner window to save")do { if (!(inner)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "No inner window to save"
, "inner", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7088); MOZ_PretendNoReturn(); } } while (0)
;
7089
7090 if (WindowContext* wc = inner->GetWindowContext()) {
7091 MOZ_ASSERT(!wc->GetWindowStateSaved())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!wc->GetWindowStateSaved())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!wc->GetWindowStateSaved(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!wc->GetWindowStateSaved()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wc->GetWindowStateSaved()"
")"); do { *((volatile int*)__null) = 7091; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7092 Unused << wc->SetWindowStateSaved(true);
7093 }
7094
7095 // Don't do anything else to this inner window! After this point, all
7096 // calls to SetTimeoutOrInterval will create entries in the timeout
7097 // list that will only run after this window has come out of the bfcache.
7098 // Also, while we're frozen, we won't dispatch online/offline events
7099 // to the page.
7100 inner->Freeze();
7101
7102 nsCOMPtr<nsISupports> state = new WindowStateHolder(inner);
7103
7104 MOZ_LOG(gPageCacheLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gPageCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "saving window state, state = %p", (void*)
state); } } while (0)
7105 ("saving window state, state = %p", (void*)state))do { const ::mozilla::LogModule* moz_real_module = gPageCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "saving window state, state = %p", (void*)
state); } } while (0)
;
7106
7107 return state.forget();
7108}
7109
7110nsresult nsGlobalWindowOuter::RestoreWindowState(nsISupports* aState) {
7111 MOZ_ASSERT(!mozilla::SessionHistoryInParent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mozilla::SessionHistoryInParent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mozilla::SessionHistoryInParent
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mozilla::SessionHistoryInParent()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7111); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mozilla::SessionHistoryInParent()"
")"); do { *((volatile int*)__null) = 7111; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7112
7113 if (!mContext || !GetWrapperPreserveColor()) {
7114 // The window may be getting torn down; don't bother restoring state.
7115 return NS_OK;
7116 }
7117
7118 nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
7119 NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(holder)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "holder" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7119); return NS_ERROR_FAILURE; } } while (false)
;
7120
7121 MOZ_LOG(gPageCacheLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gPageCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "restoring window state, state = %p", (void
*)holder); } } while (0)
7122 ("restoring window state, state = %p", (void*)holder))do { const ::mozilla::LogModule* moz_real_module = gPageCacheLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "restoring window state, state = %p", (void
*)holder); } } while (0)
;
7123
7124 // And we're ready to go!
7125 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
7126
7127 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
7128 // it easy to tell which link was last clicked when going back a page.
7129 RefPtr<Element> focusedElement = inner->GetFocusedElement();
7130 if (nsContentUtils::ContentIsLink(focusedElement)) {
7131 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
7132 fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
7133 nsIFocusManager::FLAG_SHOWRING);
7134 }
7135 }
7136
7137 if (WindowContext* wc = inner->GetWindowContext()) {
7138 MOZ_ASSERT(wc->GetWindowStateSaved())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wc->GetWindowStateSaved())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(wc->GetWindowStateSaved()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"wc->GetWindowStateSaved()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7138); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wc->GetWindowStateSaved()"
")"); do { *((volatile int*)__null) = 7138; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7139 Unused << wc->SetWindowStateSaved(false);
7140 }
7141
7142 inner->Thaw();
7143
7144 holder->DidRestoreWindow();
7145
7146 return NS_OK;
7147}
7148
7149void nsGlobalWindowOuter::AddSizeOfIncludingThis(
7150 nsWindowSizes& aWindowSizes) const {
7151 aWindowSizes.mDOMSizes.mDOMOtherSize +=
7152 aWindowSizes.mState.mMallocSizeOf(this);
7153}
7154
7155uint32_t nsGlobalWindowOuter::GetAutoActivateVRDisplayID() {
7156 uint32_t retVal = mAutoActivateVRDisplayID;
7157 mAutoActivateVRDisplayID = 0;
7158 return retVal;
7159}
7160
7161void nsGlobalWindowOuter::SetAutoActivateVRDisplayID(
7162 uint32_t aAutoActivateVRDisplayID) {
7163 mAutoActivateVRDisplayID = aAutoActivateVRDisplayID;
7164}
7165
7166already_AddRefed<nsWindowRoot> nsGlobalWindowOuter::GetWindowRootOuter() {
7167 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
7168 return root.forget().downcast<nsWindowRoot>();
7169}
7170
7171nsIDOMWindowUtils* nsGlobalWindowOuter::WindowUtils() {
7172 if (!mWindowUtils) {
7173 mWindowUtils = new nsDOMWindowUtils(this);
7174 }
7175 return mWindowUtils;
7176}
7177
7178bool nsGlobalWindowOuter::IsInSyncOperation() {
7179 return GetExtantDoc() && GetExtantDoc()->IsInSyncOperation();
7180}
7181
7182// Note: This call will lock the cursor, it will not change as it moves.
7183// To unlock, the cursor must be set back to Auto.
7184void nsGlobalWindowOuter::SetCursorOuter(const nsACString& aCursor,
7185 ErrorResult& aError) {
7186 auto cursor = StyleCursorKind::Auto;
7187 if (!Servo_CursorKind_Parse(&aCursor, &cursor)) {
7188 // FIXME: It's a bit weird that this doesn't throw but stuff below does, but
7189 // matches previous behavior so...
7190 return;
7191 }
7192
7193 RefPtr<nsPresContext> presContext;
7194 if (mDocShell) {
7195 presContext = mDocShell->GetPresContext();
7196 }
7197
7198 if (presContext) {
7199 // Need root widget.
7200 PresShell* presShell = mDocShell->GetPresShell();
7201 if (!presShell) {
7202 aError.Throw(NS_ERROR_FAILURE);
7203 return;
7204 }
7205
7206 nsViewManager* vm = presShell->GetViewManager();
7207 if (!vm) {
7208 aError.Throw(NS_ERROR_FAILURE);
7209 return;
7210 }
7211
7212 nsView* rootView = vm->GetRootView();
7213 if (!rootView) {
7214 aError.Throw(NS_ERROR_FAILURE);
7215 return;
7216 }
7217
7218 nsIWidget* widget = rootView->GetNearestWidget(nullptr);
7219 if (!widget) {
7220 aError.Throw(NS_ERROR_FAILURE);
7221 return;
7222 }
7223
7224 // Call esm and set cursor.
7225 aError = presContext->EventStateManager()->SetCursor(
7226 cursor, nullptr, {}, Nothing(), widget, true);
7227 }
7228}
7229
7230nsIBrowserDOMWindow* nsGlobalWindowOuter::GetBrowserDOMWindow() {
7231 MOZ_RELEASE_ASSERT(IsChromeWindow())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsChromeWindow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsChromeWindow()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsChromeWindow()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7231); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "IsChromeWindow()"
")"); do { *((volatile int*)__null) = 7231; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7232 return mChromeFields.mBrowserDOMWindow;
7233}
7234
7235void nsGlobalWindowOuter::SetBrowserDOMWindowOuter(
7236 nsIBrowserDOMWindow* aBrowserWindow) {
7237 MOZ_ASSERT(IsChromeWindow())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsChromeWindow())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsChromeWindow()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsChromeWindow()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsChromeWindow()"
")"); do { *((volatile int*)__null) = 7237; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7238 mChromeFields.mBrowserDOMWindow = aBrowserWindow;
7239}
7240
7241ChromeMessageBroadcaster* nsGlobalWindowOuter::GetMessageManager() {
7242 if (!mInnerWindow) {
7243 NS_WARNING("No inner window available!")NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7243)
;
7244 return nullptr;
7245 }
7246 return GetCurrentInnerWindowInternal(this)->MessageManager();
7247}
7248
7249ChromeMessageBroadcaster* nsGlobalWindowOuter::GetGroupMessageManager(
7250 const nsAString& aGroup) {
7251 if (!mInnerWindow) {
7252 NS_WARNING("No inner window available!")NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7252)
;
7253 return nullptr;
7254 }
7255 return GetCurrentInnerWindowInternal(this)->GetGroupMessageManager(aGroup);
7256}
7257
7258void nsGlobalWindowOuter::InitWasOffline() { mWasOffline = NS_IsOffline(); }
7259
7260#if defined(_WINDOWS_) && !defined(MOZ_WRAPPED_WINDOWS_H)
7261# pragma message( \
7262 "wrapper failure reason: " MOZ_WINDOWS_WRAPPER_DISABLED_REASON)
7263# error "Never include unwrapped windows.h in this file!"
7264#endif
7265
7266// Helper called by methods that move/resize the window,
7267// to ensure the presContext (if any) is aware of resolution
7268// change that may happen in multi-monitor configuration.
7269void nsGlobalWindowOuter::CheckForDPIChange() {
7270 if (mDocShell) {
7271 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
7272 if (presContext) {
7273 if (presContext->DeviceContext()->CheckDPIChange()) {
7274 presContext->UIResolutionChanged();
7275 }
7276 }
7277 }
7278}
7279
7280nsresult nsGlobalWindowOuter::Dispatch(
7281 already_AddRefed<nsIRunnable>&& aRunnable) const {
7282 MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7282); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 7282; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7283 return NS_DispatchToCurrentThread(std::move(aRunnable));
7284}
7285
7286nsISerialEventTarget* nsGlobalWindowOuter::SerialEventTarget() const {
7287 MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7287); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 7287; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7288 return GetMainThreadSerialEventTarget();
7289}
7290
7291void nsGlobalWindowOuter::MaybeResetWindowName(Document* aNewDocument) {
7292 MOZ_ASSERT(aNewDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewDocument))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aNewDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewDocument"
")"); do { *((volatile int*)__null) = 7292; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7293
7294 if (!StaticPrefs::privacy_window_name_update_enabled()) {
7295 return;
7296 }
7297
7298 const LoadingSessionHistoryInfo* info =
7299 nsDocShell::Cast(mDocShell)->GetLoadingSessionHistoryInfo();
7300 if (!info || info->mForceMaybeResetName.isNothing()) {
7301 // We only reset the window name for the top-level content as well as
7302 // storing in session entries.
7303 if (!GetBrowsingContext()->IsTopContent()) {
7304 return;
7305 }
7306
7307 // Following implements https://html.spec.whatwg.org/#history-traversal:
7308 // Step 4.2. Check if the loading document has a different origin than the
7309 // previous document.
7310
7311 // We don't need to do anything if we haven't loaded a non-initial document.
7312 if (!GetBrowsingContext()->GetHasLoadedNonInitialDocument()) {
7313 return;
7314 }
7315
7316 // If we have an existing document, directly check the document prinicpals
7317 // with the new document to know if it is cross-origin.
7318 //
7319 // Note that there will be an issue of initial document handling in Fission
7320 // when running the WPT unset_context_name-1.html. In the test, the first
7321 // about:blank page would be loaded with the principal of the testing domain
7322 // in Fission and the window.name will be set there. Then, The window.name
7323 // won't be reset after navigating to the testing page because the principal
7324 // is the same. But, it won't be the case for non-Fission mode that the
7325 // first about:blank will be loaded with a null principal and the
7326 // window.name will be reset when loading the test page.
7327 if (mDoc && mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal())) {
7328 return;
7329 }
7330
7331 // If we don't have an existing document, and if it's not the initial
7332 // about:blank, we could be loading a document because of the
7333 // process-switching. In this case, this should be a cross-origin
7334 // navigation.
7335 } else if (!info->mForceMaybeResetName.ref()) {
7336 return;
7337 }
7338
7339 // Step 4.2.2 Store the window.name into all session history entries that have
7340 // the same origin as the previous document.
7341 nsDocShell::Cast(mDocShell)->StoreWindowNameToSHEntries();
7342
7343 // Step 4.2.3 Clear the window.name if the browsing context is the top-level
7344 // content and doesn't have an opener.
7345
7346 // We need to reset the window name in case of a cross-origin navigation,
7347 // without an opener.
7348 RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext();
7349 if (opener) {
7350 return;
7351 }
7352
7353 Unused << mBrowsingContext->SetName(EmptyString());
7354}
7355
7356nsGlobalWindowOuter::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
7357 BrowsingContext* aBC) {
7358 BrowsingContextGroup* group = aBC->Group();
7359 if (!group) {
7360 NS_ERROR(do { NS_DebugBreak(NS_DEBUG_ASSERTION, "nsGlobalWindowOuter::TemporarilyDisableDialogs called without a "
"browsing context group?", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7362); MOZ_PretendNoReturn(); } while (0)
7361 "nsGlobalWindowOuter::TemporarilyDisableDialogs called without a "do { NS_DebugBreak(NS_DEBUG_ASSERTION, "nsGlobalWindowOuter::TemporarilyDisableDialogs called without a "
"browsing context group?", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7362); MOZ_PretendNoReturn(); } while (0)
7362 "browsing context group?")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "nsGlobalWindowOuter::TemporarilyDisableDialogs called without a "
"browsing context group?", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7362); MOZ_PretendNoReturn(); } while (0)
;
7363 return;
7364 }
7365
7366 if (group) {
7367 mGroup = group;
7368 mSavedDialogsEnabled = group->GetAreDialogsEnabled();
7369 group->SetAreDialogsEnabled(false);
7370 }
7371}
7372
7373nsGlobalWindowOuter::TemporarilyDisableDialogs::~TemporarilyDisableDialogs() {
7374 if (mGroup) {
7375 mGroup->SetAreDialogsEnabled(mSavedDialogsEnabled);
7376 }
7377}
7378
7379/* static */
7380already_AddRefed<nsGlobalWindowOuter> nsGlobalWindowOuter::Create(
7381 nsDocShell* aDocShell, bool aIsChrome) {
7382 uint64_t outerWindowID = aDocShell->GetOuterWindowID();
7383 RefPtr<nsGlobalWindowOuter> window = new nsGlobalWindowOuter(outerWindowID);
7384 if (aIsChrome) {
7385 window->mIsChrome = true;
7386 }
7387 window->SetDocShell(aDocShell);
7388
7389 window->InitWasOffline();
7390 return window.forget();
7391}
7392
7393nsIURI* nsPIDOMWindowOuter::GetDocumentURI() const {
7394 return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
7395}
7396
7397void nsPIDOMWindowOuter::MaybeCreateDoc() {
7398 MOZ_ASSERT(!mDoc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDoc)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(!mDoc))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("!mDoc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 7398); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDoc" ")")
; do { *((volatile int*)__null) = 7398; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7399 if (nsIDocShell* docShell = GetDocShell()) {
7400 // Note that |document| here is the same thing as our mDoc, but we
7401 // don't have to explicitly set the member variable because the docshell
7402 // has already called SetNewDocument().
7403 nsCOMPtr<Document> document = docShell->GetDocument();
7404 Unused << document;
7405 }
7406}
7407
7408void nsPIDOMWindowOuter::SetChromeEventHandlerInternal(
7409 EventTarget* aChromeEventHandler) {
7410 // Out-of-line so we don't need to include ContentFrameMessageManager.h in
7411 // nsPIDOMWindow.h.
7412 mChromeEventHandler = aChromeEventHandler;
7413
7414 // mParentTarget and mMessageManager will be set when the next event is
7415 // dispatched or someone asks for our message manager.
7416 mParentTarget = nullptr;
7417 mMessageManager = nullptr;
7418}
7419
7420mozilla::dom::DocGroup* nsPIDOMWindowOuter::GetDocGroup() const {
7421 Document* doc = GetExtantDoc();
7422 if (doc) {
7423 return doc->GetDocGroup();
7424 }
7425 return nullptr;
7426}
7427
7428nsPIDOMWindowOuter::nsPIDOMWindowOuter(uint64_t aWindowID)
7429 : mFrameElement(nullptr),
7430 mModalStateDepth(0),
7431 mSuppressEventHandlingDepth(0),
7432 mIsBackground(false),
7433 mIsRootOuterWindow(false),
7434 mInnerWindow(nullptr),
7435 mWindowID(aWindowID),
7436 mMarkedCCGeneration(0) {}
7437
7438nsPIDOMWindowOuter::~nsPIDOMWindowOuter() = default;

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h

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/. */
6
7/* A class for optional values and in-place lazy construction. */
8
9#ifndef mozilla_Maybe_h
10#define mozilla_Maybe_h
11
12#include <functional>
13#include <new> // for placement new
14#include <ostream>
15#include <type_traits>
16#include <utility>
17
18#include "mozilla/Alignment.h"
19#include "mozilla/Assertions.h"
20#include "mozilla/Attributes.h"
21#include "mozilla/MaybeStorageBase.h"
22#include "mozilla/MemoryChecking.h"
23#include "mozilla/OperatorNewExtensions.h"
24#include "mozilla/Poison.h"
25#include "mozilla/ThreadSafety.h"
26
27class nsCycleCollectionTraversalCallback;
28
29template <typename T>
30inline void CycleCollectionNoteChild(
31 nsCycleCollectionTraversalCallback& aCallback, T* aChild, const char* aName,
32 uint32_t aFlags);
33
34namespace mozilla {
35
36struct Nothing {};
37
38inline constexpr bool operator==(const Nothing&, const Nothing&) {
39 return true;
40}
41
42template <class T>
43class Maybe;
44
45namespace detail {
46
47// You would think that poisoning Maybe instances could just be a call
48// to mozWritePoison. Unfortunately, using a simple call to
49// mozWritePoison generates poor code on MSVC for small structures. The
50// generated code contains (always not-taken) branches and does a bunch
51// of setup for `rep stos{l,q}`, even though we know at compile time
52// exactly how many words we're poisoning. Instead, we're going to
53// force MSVC to generate the code we want via recursive templates.
54
55// Write the given poisonValue into p at offset*sizeof(uintptr_t).
56template <size_t offset>
57inline void WritePoisonAtOffset(void* p, const uintptr_t poisonValue) {
58 memcpy(static_cast<char*>(p) + offset * sizeof(poisonValue), &poisonValue,
59 sizeof(poisonValue));
60}
61
62template <size_t Offset, size_t NOffsets>
63struct InlinePoisoner {
64 static void poison(void* p, const uintptr_t poisonValue) {
65 WritePoisonAtOffset<Offset>(p, poisonValue);
66 InlinePoisoner<Offset + 1, NOffsets>::poison(p, poisonValue);
67 }
68};
69
70template <size_t N>
71struct InlinePoisoner<N, N> {
72 static void poison(void*, const uintptr_t) {
73 // All done!
74 }
75};
76
77// We can't generate inline code for large structures, though, because we'll
78// blow out recursive template instantiation limits, and the code would be
79// bloated to boot. So provide a fallback to the out-of-line poisoner.
80template <size_t ObjectSize>
81struct OutOfLinePoisoner {
82 static MOZ_NEVER_INLINE__attribute__((noinline)) void poison(void* p, const uintptr_t) {
83 mozWritePoison(p, ObjectSize);
84 }
85};
86
87template <typename T>
88inline void PoisonObject(T* p) {
89 const uintptr_t POISON = mozPoisonValue();
90 std::conditional_t<(sizeof(T) <= 8 * sizeof(POISON)),
91 InlinePoisoner<0, sizeof(T) / sizeof(POISON)>,
92 OutOfLinePoisoner<sizeof(T)>>::poison(p, POISON);
93}
94
95template <typename T>
96struct MaybePoisoner {
97 static const size_t N = sizeof(T);
98
99 static void poison(void* aPtr) {
100#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED1
101 if (N >= sizeof(uintptr_t)) {
102 PoisonObject(static_cast<std::remove_cv_t<T>*>(aPtr));
103 }
104#endif
105 MOZ_MAKE_MEM_UNDEFINED(aPtr, N)do { } while (0);
106 }
107};
108
109template <typename T,
110 bool TriviallyDestructibleAndCopyable =
111 IsTriviallyDestructibleAndCopyable<T>,
112 bool Copyable = std::is_copy_constructible_v<T>,
113 bool Movable = std::is_move_constructible_v<T>>
114class Maybe_CopyMove_Enabler;
115
116#define MOZ_MAYBE_COPY_OPS() \
117 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler& aOther) { \
118 if (downcast(aOther).isSome()) { \
119 downcast(*this).emplace(*downcast(aOther)); \
120 } \
121 } \
122 \
123 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler& aOther) { \
124 return downcast(*this).template operator= <T>(downcast(aOther)); \
125 }
126
127#define MOZ_MAYBE_MOVE_OPS() \
128 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) { \
129 if (downcast(aOther).isSome()) { \
130 downcast(*this).emplace(std::move(*downcast(aOther))); \
131 downcast(aOther).reset(); \
132 } \
133 } \
134 \
135 constexpr Maybe_CopyMove_Enabler& operator=( \
136 Maybe_CopyMove_Enabler&& aOther) { \
137 downcast(*this).template operator= <T>(std::move(downcast(aOther))); \
138 \
139 return *this; \
140 }
141
142#define MOZ_MAYBE_DOWNCAST() \
143 static constexpr Maybe<T>& downcast(Maybe_CopyMove_Enabler& aObj) { \
144 return static_cast<Maybe<T>&>(aObj); \
145 } \
146 static constexpr const Maybe<T>& downcast( \
147 const Maybe_CopyMove_Enabler& aObj) { \
148 return static_cast<const Maybe<T>&>(aObj); \
149 }
150
151template <typename T>
152class Maybe_CopyMove_Enabler<T, true, true, true> {
153 public:
154 Maybe_CopyMove_Enabler() = default;
155
156 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = default;
157 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = default;
158 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
159 downcast(aOther).reset();
160 }
161 constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
162 downcast(aOther).reset();
163 return *this;
164 }
165
166 private:
167 MOZ_MAYBE_DOWNCAST()
168};
169
170template <typename T>
171class Maybe_CopyMove_Enabler<T, true, false, true> {
172 public:
173 Maybe_CopyMove_Enabler() = default;
174
175 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
176 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
177 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
178 downcast(aOther).reset();
179 }
180 constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
181 downcast(aOther).reset();
182 return *this;
183 }
184
185 private:
186 MOZ_MAYBE_DOWNCAST()
187};
188
189template <typename T>
190class Maybe_CopyMove_Enabler<T, false, true, true> {
191 public:
192 Maybe_CopyMove_Enabler() = default;
193
194 MOZ_MAYBE_COPY_OPS()
195 MOZ_MAYBE_MOVE_OPS()
196
197 private:
198 MOZ_MAYBE_DOWNCAST()
199};
200
201template <typename T>
202class Maybe_CopyMove_Enabler<T, false, false, true> {
203 public:
204 Maybe_CopyMove_Enabler() = default;
205
206 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
207 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
208 MOZ_MAYBE_MOVE_OPS()
209
210 private:
211 MOZ_MAYBE_DOWNCAST()
212};
213
214template <typename T>
215class Maybe_CopyMove_Enabler<T, false, true, false> {
216 public:
217 Maybe_CopyMove_Enabler() = default;
218
219 MOZ_MAYBE_COPY_OPS()
220 Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete;
221 Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete;
222
223 private:
224 MOZ_MAYBE_DOWNCAST()
225};
226
227template <typename T, bool TriviallyDestructibleAndCopyable>
228class Maybe_CopyMove_Enabler<T, TriviallyDestructibleAndCopyable, false,
229 false> {
230 public:
231 Maybe_CopyMove_Enabler() = default;
232
233 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
234 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
235 Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete;
236 Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete;
237};
238
239#undef MOZ_MAYBE_COPY_OPS
240#undef MOZ_MAYBE_MOVE_OPS
241#undef MOZ_MAYBE_DOWNCAST
242
243template <typename T, bool TriviallyDestructibleAndCopyable =
244 IsTriviallyDestructibleAndCopyable<T>>
245struct MaybeStorage;
246
247template <typename T>
248struct MaybeStorage<T, false> : MaybeStorageBase<T> {
249 protected:
250 char mIsSome = false; // not bool -- guarantees minimal space consumption
251
252 constexpr MaybeStorage() = default;
3
Calling defaulted default constructor for 'MaybeStorageBase<AutoUnblockScriptClosing, false>'
8
Returning from default constructor for 'MaybeStorageBase<AutoUnblockScriptClosing, false>'
9
Returning without writing to 'this->mStorage.val.mWin.mRawPtr'
253 explicit MaybeStorage(const T& aVal)
254 : MaybeStorageBase<T>{aVal}, mIsSome{true} {}
255 explicit MaybeStorage(T&& aVal)
256 : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {}
257
258 template <typename... Args>
259 explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
260 : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...},
261 mIsSome{true} {}
262
263 public:
264 // Copy and move operations are no-ops, since copying is moving is implemented
265 // by Maybe_CopyMove_Enabler.
266
267 MaybeStorage(const MaybeStorage&) : MaybeStorageBase<T>{} {}
268 MaybeStorage& operator=(const MaybeStorage&) { return *this; }
269 MaybeStorage(MaybeStorage&&) : MaybeStorageBase<T>{} {}
270 MaybeStorage& operator=(MaybeStorage&&) { return *this; }
271
272 ~MaybeStorage() {
273 if (mIsSome
18.1
Field 'mIsSome' is 0
18.1
Field 'mIsSome' is 0
18.1
Field 'mIsSome' is 0
18.1
Field 'mIsSome' is 0
18.1
Field 'mIsSome' is 0
18.1
Field 'mIsSome' is 0
) {
19
Taking false branch
274 this->addr()->T::~T();
275 }
276 }
20
Calling implicit destructor for 'MaybeStorageBase<AutoUnblockScriptClosing, false>'
21
Calling '~Union'
277};
278
279template <typename T>
280struct MaybeStorage<T, true> : MaybeStorageBase<T> {
281 protected:
282 char mIsSome = false; // not bool -- guarantees minimal space consumption
283
284 constexpr MaybeStorage() = default;
285 constexpr explicit MaybeStorage(const T& aVal)
286 : MaybeStorageBase<T>{aVal}, mIsSome{true} {}
287 constexpr explicit MaybeStorage(T&& aVal)
288 : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {}
289
290 template <typename... Args>
291 constexpr explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
292 : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...},
293 mIsSome{true} {}
294};
295
296template <typename T>
297struct IsMaybeImpl : std::false_type {};
298
299template <typename T>
300struct IsMaybeImpl<Maybe<T>> : std::true_type {};
301
302template <typename T>
303using IsMaybe = IsMaybeImpl<std::decay_t<T>>;
304
305} // namespace detail
306
307template <typename T, typename U = typename std::remove_cv<
308 typename std::remove_reference<T>::type>::type>
309constexpr Maybe<U> Some(T&& aValue);
310
311/*
312 * Maybe is a container class which contains either zero or one elements. It
313 * serves two roles. It can represent values which are *semantically* optional,
314 * augmenting a type with an explicit 'Nothing' value. In this role, it provides
315 * methods that make it easy to work with values that may be missing, along with
316 * equality and comparison operators so that Maybe values can be stored in
317 * containers. Maybe values can be constructed conveniently in expressions using
318 * type inference, as follows:
319 *
320 * void doSomething(Maybe<Foo> aFoo) {
321 * if (aFoo) // Make sure that aFoo contains a value...
322 * aFoo->takeAction(); // and then use |aFoo->| to access it.
323 * } // |*aFoo| also works!
324 *
325 * doSomething(Nothing()); // Passes a Maybe<Foo> containing no value.
326 * doSomething(Some(Foo(100))); // Passes a Maybe<Foo> containing |Foo(100)|.
327 *
328 * You'll note that it's important to check whether a Maybe contains a value
329 * before using it, using conversion to bool, |isSome()|, or |isNothing()|. You
330 * can avoid these checks, and sometimes write more readable code, using
331 * |valueOr()|, |ptrOr()|, and |refOr()|, which allow you to retrieve the value
332 * in the Maybe and provide a default for the 'Nothing' case. You can also use
333 * |apply()| to call a function only if the Maybe holds a value, and |map()| to
334 * transform the value in the Maybe, returning another Maybe with a possibly
335 * different type.
336 *
337 * Maybe's other role is to support lazily constructing objects without using
338 * dynamic storage. A Maybe directly contains storage for a value, but it's
339 * empty by default. |emplace()|, as mentioned above, can be used to construct a
340 * value in Maybe's storage. The value a Maybe contains can be destroyed by
341 * calling |reset()|; this will happen automatically if a Maybe is destroyed
342 * while holding a value.
343 *
344 * It's a common idiom in C++ to use a pointer as a 'Maybe' type, with a null
345 * value meaning 'Nothing' and any other value meaning 'Some'. You can convert
346 * from such a pointer to a Maybe value using 'ToMaybe()'.
347 *
348 * Maybe is inspired by similar types in the standard library of many other
349 * languages (e.g. Haskell's Maybe and Rust's Option). In the C++ world it's
350 * very similar to std::optional, which was proposed for C++14 and originated in
351 * Boost. The most important differences between Maybe and std::optional are:
352 *
353 * - std::optional<T> may be compared with T. We deliberately forbid that.
354 * - std::optional has |valueOr()|, equivalent to Maybe's |valueOr()|, but
355 * lacks corresponding methods for |refOr()| and |ptrOr()|.
356 * - std::optional lacks |map()| and |apply()|, making it less suitable for
357 * functional-style code.
358 * - std::optional lacks many convenience functions that Maybe has. Most
359 * unfortunately, it lacks equivalents of the type-inferred constructor
360 * functions |Some()| and |Nothing()|.
361 */
362template <class T>
363class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
364 : private detail::MaybeStorage<T>,
365 public detail::Maybe_CopyMove_Enabler<T> {
366 template <typename, bool, bool, bool>
367 friend class detail::Maybe_CopyMove_Enabler;
368
369 template <typename U, typename V>
370 friend constexpr Maybe<V> Some(U&& aValue);
371
372 struct SomeGuard {};
373
374 template <typename U>
375 constexpr Maybe(U&& aValue, SomeGuard)
376 : detail::MaybeStorage<T>{std::forward<U>(aValue)} {}
377
378 using detail::MaybeStorage<T>::mIsSome;
379 using detail::MaybeStorage<T>::mStorage;
380
381 void poisonData() { detail::MaybePoisoner<T>::poison(&mStorage.val); }
382
383 public:
384 using ValueType = T;
385
386 MOZ_ALLOW_TEMPORARY constexpr Maybe() = default;
2
Calling defaulted default constructor for 'MaybeStorage<AutoUnblockScriptClosing, false>'
10
Returning from default constructor for 'MaybeStorage<AutoUnblockScriptClosing, false>'
11
Returning without writing to 'this->mStorage.val.mWin.mRawPtr'
387
388 MOZ_ALLOW_TEMPORARY MOZ_IMPLICIT constexpr Maybe(Nothing) : Maybe{} {}
389
390 template <typename... Args>
391 constexpr explicit Maybe(std::in_place_t, Args&&... aArgs)
392 : detail::MaybeStorage<T>{std::in_place, std::forward<Args>(aArgs)...} {}
393
394 /**
395 * Maybe<T> can be copy-constructed from a Maybe<U> if T is constructible from
396 * a const U&.
397 */
398 template <typename U,
399 std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true>
400 MOZ_IMPLICIT Maybe(const Maybe<U>& aOther) {
401 if (aOther.isSome()) {
402 emplace(*aOther);
403 }
404 }
405
406 template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>,
407 bool> = true>
408 explicit Maybe(const Maybe<U>& aOther) = delete;
409
410 /**
411 * Maybe<T> can be move-constructed from a Maybe<U> if T is constructible from
412 * a U&&.
413 */
414 template <typename U,
415 std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true>
416 MOZ_IMPLICIT Maybe(Maybe<U>&& aOther) {
417 if (aOther.isSome()) {
418 emplace(std::move(*aOther));
419 aOther.reset();
420 }
421 }
422 template <typename U,
423 std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true>
424 explicit Maybe(Maybe<U>&& aOther) = delete;
425
426 template <typename U,
427 std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true>
428 Maybe& operator=(const Maybe<U>& aOther) {
429 if (aOther.isSome()) {
430 if (mIsSome) {
431 ref() = aOther.ref();
432 } else {
433 emplace(*aOther);
434 }
435 } else {
436 reset();
437 }
438 return *this;
439 }
440
441 template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>,
442 bool> = true>
443 Maybe& operator=(const Maybe<U>& aOther) = delete;
444
445 template <typename U,
446 std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true>
447 Maybe& operator=(Maybe<U>&& aOther) {
448 if (aOther.isSome()) {
449 if (mIsSome) {
450 ref() = std::move(aOther.ref());
451 } else {
452 emplace(std::move(*aOther));
453 }
454 aOther.reset();
455 } else {
456 reset();
457 }
458
459 return *this;
460 }
461
462 template <typename U,
463 std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true>
464 Maybe& operator=(Maybe<U>&& aOther) = delete;
465
466 constexpr Maybe& operator=(Nothing) {
467 reset();
468 return *this;
469 }
470
471 /* Methods that check whether this Maybe contains a value */
472 constexpr explicit operator bool() const { return isSome(); }
473 constexpr bool isSome() const { return mIsSome; }
474 constexpr bool isNothing() const { return !mIsSome; }
475
476 /* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|.
477 */
478 constexpr T value() const&;
479 constexpr T value() &&;
480 constexpr T value() const&&;
481
482 /**
483 * Move the contents of this Maybe<T> out of internal storage and return it
484 * without calling the destructor. The internal storage is also reset to
485 * avoid multiple calls. Unsafe unless |isSome()|.
486 */
487 constexpr T extract() {
488 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 488); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 488; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
489 T v = std::move(mStorage.val);
490 reset();
491 return v;
492 }
493
494 /**
495 * Returns the value (possibly |Nothing()|) by moving it out of this Maybe<T>
496 * and leaving |Nothing()| in its place.
497 */
498 Maybe<T> take() { return std::exchange(*this, Nothing()); }
499
500 /*
501 * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
502 * the default value provided.
503 *
504 * Note: If the value passed to aDefault is not the result of a trivial
505 * expression, but expensive to evaluate, e.g. |valueOr(ExpensiveFunction())|,
506 * use |valueOrFrom| instead, e.g.
507 * |valueOrFrom([arg] { return ExpensiveFunction(arg); })|. This ensures
508 * that the expensive expression is only evaluated when its result will
509 * actually be used.
510 */
511 template <typename V>
512 constexpr T valueOr(V&& aDefault) const {
513 if (isSome()) {
514 return ref();
515 }
516 return std::forward<V>(aDefault);
517 }
518
519 /*
520 * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
521 * the value returned from the function or functor provided.
522 */
523 template <typename F>
524 constexpr T valueOrFrom(F&& aFunc) const {
525 if (isSome()) {
526 return ref();
527 }
528 return aFunc();
529 }
530
531 /* Returns the contents of this Maybe<T> by pointer. Unsafe unless |isSome()|.
532 */
533 T* ptr();
534 constexpr const T* ptr() const;
535
536 /*
537 * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
538 * returns the default value provided.
539 */
540 T* ptrOr(T* aDefault) {
541 if (isSome()) {
542 return ptr();
543 }
544 return aDefault;
545 }
546
547 constexpr const T* ptrOr(const T* aDefault) const {
548 if (isSome()) {
549 return ptr();
550 }
551 return aDefault;
552 }
553
554 /*
555 * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
556 * returns the value returned from the function or functor provided.
557 */
558 template <typename F>
559 T* ptrOrFrom(F&& aFunc) {
560 if (isSome()) {
561 return ptr();
562 }
563 return aFunc();
564 }
565
566 template <typename F>
567 const T* ptrOrFrom(F&& aFunc) const {
568 if (isSome()) {
569 return ptr();
570 }
571 return aFunc();
572 }
573
574 constexpr T* operator->();
575 constexpr const T* operator->() const;
576
577 /* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */
578 constexpr T& ref() &;
579 constexpr const T& ref() const&;
580 constexpr T&& ref() &&;
581 constexpr const T&& ref() const&&;
582
583 /*
584 * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns
585 * the default value provided.
586 */
587 constexpr T& refOr(T& aDefault) {
588 if (isSome()) {
589 return ref();
590 }
591 return aDefault;
592 }
593
594 constexpr const T& refOr(const T& aDefault) const {
595 if (isSome()) {
596 return ref();
597 }
598 return aDefault;
599 }
600
601 /*
602 * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns the
603 * value returned from the function or functor provided.
604 */
605 template <typename F>
606 constexpr T& refOrFrom(F&& aFunc) {
607 if (isSome()) {
608 return ref();
609 }
610 return aFunc();
611 }
612
613 template <typename F>
614 constexpr const T& refOrFrom(F&& aFunc) const {
615 if (isSome()) {
616 return ref();
617 }
618 return aFunc();
619 }
620
621 constexpr T& operator*() &;
622 constexpr const T& operator*() const&;
623 constexpr T&& operator*() &&;
624 constexpr const T&& operator*() const&&;
625
626 /* If |isSome()|, runs the provided function or functor on the contents of
627 * this Maybe. */
628 template <typename Func>
629 constexpr Maybe& apply(Func&& aFunc) & {
630 if (isSome()) {
631 std::forward<Func>(aFunc)(ref());
632 }
633 return *this;
634 }
635
636 template <typename Func>
637 constexpr const Maybe& apply(Func&& aFunc) const& {
638 if (isSome()) {
639 std::forward<Func>(aFunc)(ref());
640 }
641 return *this;
642 }
643
644 template <typename Func>
645 constexpr Maybe& apply(Func&& aFunc) && {
646 if (isSome()) {
647 std::forward<Func>(aFunc)(extract());
648 }
649 return *this;
650 }
651
652 template <typename Func>
653 constexpr Maybe& apply(Func&& aFunc) const&& {
654 if (isSome()) {
655 std::forward<Func>(aFunc)(extract());
656 }
657 return *this;
658 }
659
660 /*
661 * If |isSome()|, runs the provided function and returns the result wrapped
662 * in a Maybe. If |isNothing()|, returns an empty Maybe value with the same
663 * value type as what the provided function would have returned.
664 */
665 template <typename Func>
666 constexpr auto map(Func&& aFunc) & {
667 if (isSome()) {
668 return Some(std::forward<Func>(aFunc)(ref()));
669 }
670 return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
671 }
672
673 template <typename Func>
674 constexpr auto map(Func&& aFunc) const& {
675 if (isSome()) {
676 return Some(std::forward<Func>(aFunc)(ref()));
677 }
678 return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
679 }
680
681 template <typename Func>
682 constexpr auto map(Func&& aFunc) && {
683 if (isSome()) {
684 return Some(std::forward<Func>(aFunc)(extract()));
685 }
686 return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{};
687 }
688
689 template <typename Func>
690 constexpr auto map(Func&& aFunc) const&& {
691 if (isSome()) {
692 return Some(std::forward<Func>(aFunc)(extract()));
693 }
694 return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{};
695 }
696
697 /*
698 * If |isSome()|, runs the provided function or functor on the contents of
699 * this Maybe and returns the result. Note that the provided function or
700 * functor must return a Maybe<U> of any type U.
701 * If |isNothing()|, returns an empty Maybe value with the same type as what
702 * the provided function would have returned.
703 */
704 template <typename Func>
705 constexpr auto andThen(Func&& aFunc) & {
706 static_assert(std::is_invocable_v<Func, T&>);
707 using U = std::invoke_result_t<Func, T&>;
708 static_assert(detail::IsMaybe<U>::value);
709 if (isSome()) {
710 return std::invoke(std::forward<Func>(aFunc), ref());
711 }
712 return std::remove_cv_t<std::remove_reference_t<U>>{};
713 }
714
715 template <typename Func>
716 constexpr auto andThen(Func&& aFunc) const& {
717 static_assert(std::is_invocable_v<Func, const T&>);
718 using U = std::invoke_result_t<Func, const T&>;
719 static_assert(detail::IsMaybe<U>::value);
720 if (isSome()) {
721 return std::invoke(std::forward<Func>(aFunc), ref());
722 }
723 return std::remove_cv_t<std::remove_reference_t<U>>{};
724 }
725
726 template <typename Func>
727 constexpr auto andThen(Func&& aFunc) && {
728 static_assert(std::is_invocable_v<Func, T&&>);
729 using U = std::invoke_result_t<Func, T&&>;
730 static_assert(detail::IsMaybe<U>::value);
731 if (isSome()) {
732 return std::invoke(std::forward<Func>(aFunc), extract());
733 }
734 return std::remove_cv_t<std::remove_reference_t<U>>{};
735 }
736
737 template <typename Func>
738 constexpr auto andThen(Func&& aFunc) const&& {
739 static_assert(std::is_invocable_v<Func, const T&&>);
740 using U = std::invoke_result_t<Func, const T&&>;
741 static_assert(detail::IsMaybe<U>::value);
742 if (isSome()) {
743 return std::invoke(std::forward<Func>(aFunc), extract());
744 }
745 return std::remove_cv_t<std::remove_reference_t<U>>{};
746 }
747
748 /*
749 * If |isNothing()|, runs the provided function or functor and returns its
750 * result. If |isSome()|, returns the contained value wrapped in a Maybe.
751 */
752 template <typename Func>
753 constexpr Maybe orElse(Func&& aFunc) & {
754 static_assert(std::is_invocable_v<Func>);
755 using U = std::invoke_result_t<Func>;
756 static_assert(
757 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
758 if (isSome()) {
759 return *this;
760 }
761 return std::invoke(std::forward<Func>(aFunc));
762 }
763
764 template <typename Func>
765 constexpr Maybe orElse(Func&& aFunc) const& {
766 static_assert(std::is_invocable_v<Func>);
767 using U = std::invoke_result_t<Func>;
768 static_assert(
769 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
770 if (isSome()) {
771 return *this;
772 }
773 return std::invoke(std::forward<Func>(aFunc));
774 }
775
776 template <typename Func>
777 constexpr Maybe orElse(Func&& aFunc) && {
778 static_assert(std::is_invocable_v<Func>);
779 using U = std::invoke_result_t<Func>;
780 static_assert(
781 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
782 if (isSome()) {
783 return std::move(*this);
784 }
785 return std::invoke(std::forward<Func>(aFunc));
786 }
787
788 template <typename Func>
789 constexpr Maybe orElse(Func&& aFunc) const&& {
790 static_assert(std::is_invocable_v<Func>);
791 using U = std::invoke_result_t<Func>;
792 static_assert(
793 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
794 if (isSome()) {
795 return std::move(*this);
796 }
797 return std::invoke(std::forward<Func>(aFunc));
798 }
799
800 /* If |isSome()|, empties this Maybe and destroys its contents. */
801 constexpr void reset() {
802 if (isSome()) {
803 if constexpr (!std::is_trivially_destructible_v<T>) {
804 /*
805 * Static analyzer gets confused if we have Maybe<MutexAutoLock>,
806 * so we suppress thread-safety warnings here
807 */
808 MOZ_PUSH_IGNORE_THREAD_SAFETYGCC diagnostic push GCC diagnostic ignored "-Wthread-safety"
809 ref().T::~T();
810 MOZ_POP_THREAD_SAFETYGCC diagnostic pop
811 poisonData();
812 }
813 mIsSome = false;
814 }
815 }
816
817 /*
818 * Constructs a T value in-place in this empty Maybe<T>'s storage. The
819 * arguments to |emplace()| are the parameters to T's constructor.
820 */
821 template <typename... Args>
822 constexpr void emplace(Args&&... aArgs);
823
824 template <typename U>
825 constexpr std::enable_if_t<std::is_same_v<T, U> &&
826 std::is_copy_constructible_v<U> &&
827 !std::is_move_constructible_v<U>>
828 emplace(U&& aArgs) {
829 emplace(aArgs);
830 }
831
832 friend std::ostream& operator<<(std::ostream& aStream,
833 const Maybe<T>& aMaybe) {
834 if (aMaybe) {
835 aStream << aMaybe.ref();
836 } else {
837 aStream << "<Nothing>";
838 }
839 return aStream;
840 }
841};
842
843template <typename T>
844class Maybe<T&> {
845 public:
846 constexpr Maybe() = default;
847 constexpr MOZ_IMPLICIT Maybe(Nothing) {}
848
849 void emplace(T& aRef) { mValue = &aRef; }
850
851 /* Methods that check whether this Maybe contains a value */
852 constexpr explicit operator bool() const { return isSome(); }
853 constexpr bool isSome() const { return mValue; }
854 constexpr bool isNothing() const { return !mValue; }
855
856 T& ref() const {
857 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 857); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 857; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
858 return *mValue;
859 }
860
861 T* operator->() const { return &ref(); }
862 T& operator*() const { return ref(); }
863
864 // Deliberately not defining value and ptr accessors, as these may be
865 // confusing on a reference-typed Maybe.
866
867 // XXX Should we define refOr?
868
869 void reset() { mValue = nullptr; }
870
871 template <typename Func>
872 const Maybe& apply(Func&& aFunc) const {
873 if (isSome()) {
874 std::forward<Func>(aFunc)(ref());
875 }
876 return *this;
877 }
878
879 template <typename Func>
880 auto map(Func&& aFunc) const {
881 Maybe<decltype(std::forward<Func>(aFunc)(ref()))> val;
882 if (isSome()) {
883 val.emplace(std::forward<Func>(aFunc)(ref()));
884 }
885 return val;
886 }
887
888 template <typename Func>
889 constexpr auto andThen(Func&& aFunc) const {
890 static_assert(std::is_invocable_v<Func, T&>);
891 using U = std::invoke_result_t<Func, T&>;
892 static_assert(detail::IsMaybe<U>::value);
893 if (isSome()) {
894 return std::invoke(std::forward<Func>(aFunc), ref());
895 }
896 return std::remove_cv_t<std::remove_reference_t<U>>{};
897 }
898
899 template <typename Func>
900 constexpr Maybe orElse(Func&& aFunc) const {
901 static_assert(std::is_invocable_v<Func>);
902 using U = std::invoke_result_t<Func>;
903 static_assert(
904 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
905 if (isSome()) {
906 return *this;
907 }
908 return std::invoke(std::forward<Func>(aFunc));
909 }
910
911 bool refEquals(const Maybe<T&>& aOther) const {
912 return mValue == aOther.mValue;
913 }
914
915 bool refEquals(const T& aOther) const { return mValue == &aOther; }
916
917 private:
918 T* mValue = nullptr;
919};
920
921template <typename T>
922constexpr T Maybe<T>::value() const& {
923 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 923); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 923; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
924 return ref();
925}
926
927template <typename T>
928constexpr T Maybe<T>::value() && {
929 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 929); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 929; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
930 return std::move(ref());
931}
932
933template <typename T>
934constexpr T Maybe<T>::value() const&& {
935 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 935); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 935; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
936 return std::move(ref());
937}
938
939template <typename T>
940T* Maybe<T>::ptr() {
941 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 941); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 941; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
942 return &ref();
943}
944
945template <typename T>
946constexpr const T* Maybe<T>::ptr() const {
947 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 947); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 947; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
948 return &ref();
949}
950
951template <typename T>
952constexpr T* Maybe<T>::operator->() {
953 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 953); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 953; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
954 return ptr();
955}
956
957template <typename T>
958constexpr const T* Maybe<T>::operator->() const {
959 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 959); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
960 return ptr();
961}
962
963template <typename T>
964constexpr T& Maybe<T>::ref() & {
965 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 965); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 965; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
966 return mStorage.val;
967}
968
969template <typename T>
970constexpr const T& Maybe<T>::ref() const& {
971 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 971); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 971; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
972 return mStorage.val;
973}
974
975template <typename T>
976constexpr T&& Maybe<T>::ref() && {
977 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 977); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 977; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
978 return std::move(mStorage.val);
979}
980
981template <typename T>
982constexpr const T&& Maybe<T>::ref() const&& {
983 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 983); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 983; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
984 return std::move(mStorage.val);
985}
986
987template <typename T>
988constexpr T& Maybe<T>::operator*() & {
989 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 989); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 989; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
990 return ref();
991}
992
993template <typename T>
994constexpr const T& Maybe<T>::operator*() const& {
995 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 995); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 995; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
996 return ref();
997}
998
999template <typename T>
1000constexpr T&& Maybe<T>::operator*() && {
1001 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1001); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 1001; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1002 return std::move(ref());
1003}
1004
1005template <typename T>
1006constexpr const T&& Maybe<T>::operator*() const&& {
1007 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1007); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 1007; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1008 return std::move(ref());
1009}
1010
1011template <typename T>
1012template <typename... Args>
1013constexpr void Maybe<T>::emplace(Args&&... aArgs) {
1014 MOZ_RELEASE_ASSERT(!isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1014); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!isSome()"
")"); do { *((volatile int*)__null) = 1014; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1015 ::new (KnownNotNull, &mStorage.val) T(std::forward<Args>(aArgs)...);
1016 mIsSome = true;
1017}
1018
1019/*
1020 * Some() creates a Maybe<T> value containing the provided T value. If T has a
1021 * move constructor, it's used to make this as efficient as possible.
1022 *
1023 * Some() selects the type of Maybe it returns by removing any const, volatile,
1024 * or reference qualifiers from the type of the value you pass to it. This gives
1025 * it more intuitive behavior when used in expressions, but it also means that
1026 * if you need to construct a Maybe value that holds a const, volatile, or
1027 * reference value, you need to use emplace() instead.
1028 */
1029template <typename T, typename U>
1030constexpr Maybe<U> Some(T&& aValue) {
1031 return {std::forward<T>(aValue), typename Maybe<U>::SomeGuard{}};
1032}
1033
1034template <typename T>
1035constexpr Maybe<T&> SomeRef(T& aValue) {
1036 Maybe<T&> value;
1037 value.emplace(aValue);
1038 return value;
1039}
1040
1041template <typename T>
1042constexpr Maybe<T&> ToMaybeRef(T* const aPtr) {
1043 return aPtr ? SomeRef(*aPtr) : Nothing{};
1044}
1045
1046template <typename T>
1047Maybe<std::remove_cv_t<std::remove_reference_t<T>>> ToMaybe(T* aPtr) {
1048 if (aPtr) {
1049 return Some(*aPtr);
1050 }
1051 return Nothing();
1052}
1053
1054/*
1055 * Two Maybe<T> values are equal if
1056 * - both are Nothing, or
1057 * - both are Some, and the values they contain are equal.
1058 */
1059template <typename T>
1060constexpr bool operator==(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1061 static_assert(!std::is_reference_v<T>,
1062 "operator== is not defined for Maybe<T&>, compare values or "
1063 "addresses explicitly instead");
1064 if (aLHS.isNothing() != aRHS.isNothing()) {
1065 return false;
1066 }
1067 return aLHS.isNothing() || *aLHS == *aRHS;
1068}
1069
1070template <typename T>
1071constexpr bool operator!=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1072 return !(aLHS == aRHS);
1073}
1074
1075/*
1076 * We support comparison to Nothing to allow reasonable expressions like:
1077 * if (maybeValue == Nothing()) { ... }
1078 */
1079template <typename T>
1080constexpr bool operator==(const Maybe<T>& aLHS, const Nothing& aRHS) {
1081 return aLHS.isNothing();
1082}
1083
1084template <typename T>
1085constexpr bool operator!=(const Maybe<T>& aLHS, const Nothing& aRHS) {
1086 return !(aLHS == aRHS);
1087}
1088
1089template <typename T>
1090constexpr bool operator==(const Nothing& aLHS, const Maybe<T>& aRHS) {
1091 return aRHS.isNothing();
1092}
1093
1094template <typename T>
1095constexpr bool operator!=(const Nothing& aLHS, const Maybe<T>& aRHS) {
1096 return !(aLHS == aRHS);
1097}
1098
1099/*
1100 * Maybe<T> values are ordered in the same way T values are ordered, except that
1101 * Nothing comes before anything else.
1102 */
1103template <typename T>
1104constexpr bool operator<(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1105 if (aLHS.isNothing()) {
1106 return aRHS.isSome();
1107 }
1108 if (aRHS.isNothing()) {
1109 return false;
1110 }
1111 return *aLHS < *aRHS;
1112}
1113
1114template <typename T>
1115constexpr bool operator>(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1116 return !(aLHS < aRHS || aLHS == aRHS);
1117}
1118
1119template <typename T>
1120constexpr bool operator<=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1121 return aLHS < aRHS || aLHS == aRHS;
1122}
1123
1124template <typename T>
1125constexpr bool operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1126 return !(aLHS < aRHS);
1127}
1128
1129template <typename T>
1130inline void ImplCycleCollectionTraverse(
1131 nsCycleCollectionTraversalCallback& aCallback, mozilla::Maybe<T>& aField,
1132 const char* aName, uint32_t aFlags = 0) {
1133 if (aField) {
1134 ImplCycleCollectionTraverse(aCallback, aField.ref(), aName, aFlags);
1135 }
1136}
1137
1138template <typename T>
1139inline void ImplCycleCollectionUnlink(mozilla::Maybe<T>& aField) {
1140 if (aField) {
1141 ImplCycleCollectionUnlink(aField.ref());
1142 }
1143}
1144
1145} // namespace mozilla
1146
1147#endif /* mozilla_Maybe_h */

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MaybeStorageBase.h

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/. */
6
7/* Internal storage class used e.g. by Maybe and Result. This file doesn't
8 * contain any public declarations. */
9
10#ifndef mfbt_MaybeStorageBase_h
11#define mfbt_MaybeStorageBase_h
12
13#include <type_traits>
14#include <utility>
15
16namespace mozilla::detail {
17
18template <typename T>
19constexpr bool IsTriviallyDestructibleAndCopyable =
20 std::is_trivially_destructible_v<T> &&
21 (std::is_trivially_copy_constructible_v<T> ||
22 !std::is_copy_constructible_v<T>);
23
24template <typename T, bool TriviallyDestructibleAndCopyable =
25 IsTriviallyDestructibleAndCopyable<T>>
26struct MaybeStorageBase;
27
28template <typename T>
29struct MaybeStorageBase<T, false> {
30 protected:
31 using NonConstT = std::remove_const_t<T>;
32
33 union Union {
34 Union() {}
5
Returning without writing to 'this->val.mWin.mRawPtr'
35 explicit Union(const T& aVal) : val{aVal} {}
36 template <typename U,
37 typename = std::enable_if_t<std::is_move_constructible_v<U>>>
38 explicit Union(U&& aVal) : val{std::forward<U>(aVal)} {}
39 template <typename... Args>
40 explicit Union(std::in_place_t, Args&&... aArgs)
41 : val{std::forward<Args>(aArgs)...} {}
42
43 ~Union() {}
22
Calling '~AutoUnblockScriptClosing'
44
45 NonConstT val;
46 } mStorage;
47
48 public:
49 constexpr MaybeStorageBase() = default;
4
Calling default constructor for 'Union'
6
Returning from default constructor for 'Union'
7
Returning without writing to 'this->mStorage.val.mWin.mRawPtr'
50 explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {}
51 explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {}
52 template <typename... Args>
53 explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs)
54 : mStorage{std::in_place, std::forward<Args>(aArgs)...} {}
55
56 const T* addr() const { return &mStorage.val; }
57 T* addr() { return &mStorage.val; }
58};
59
60template <typename T>
61struct MaybeStorageBase<T, true> {
62 protected:
63 using NonConstT = std::remove_const_t<T>;
64
65 union Union {
66 constexpr Union() : empty() {}
67 constexpr explicit Union(const T& aVal) : val{aVal} {}
68 constexpr explicit Union(T&& aVal) : val{std::move(aVal)} {}
69 template <typename... Args>
70 constexpr explicit Union(std::in_place_t, Args&&... aArgs)
71 : val{std::forward<Args>(aArgs)...} {}
72
73 NonConstT val;
74 char empty;
75 } mStorage;
76
77 public:
78 constexpr MaybeStorageBase() = default;
79 constexpr explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {}
80 constexpr explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {}
81
82 template <typename... Args>
83 constexpr explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs)
84 : mStorage{std::in_place, std::forward<Args>(aArgs)...} {}
85
86 constexpr const T* addr() const { return &mStorage.val; }
87 constexpr T* addr() { return &mStorage.val; }
88};
89
90} // namespace mozilla::detail
91
92#endif

/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsJSEnvironment.h

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#ifndef nsJSEnvironment_h
7#define nsJSEnvironment_h
8
9#include "nsIScriptContext.h"
10#include "nsIScriptGlobalObject.h"
11#include "nsCOMPtr.h"
12#include "prtime.h"
13#include "nsCycleCollectionParticipant.h"
14#include "nsIArray.h"
15#include "mozilla/Attributes.h"
16#include "mozilla/TimeStamp.h"
17#include "nsThreadUtils.h"
18#include "xpcpublic.h"
19
20class nsICycleCollectorListener;
21class nsIDocShell;
22
23namespace mozilla {
24
25template <class>
26class Maybe;
27struct CycleCollectorResults;
28
29static const uint32_t kMajorForgetSkippableCalls = 5;
30
31} // namespace mozilla
32
33class nsJSContext : public nsIScriptContext {
34 public:
35 nsJSContext(bool aGCOnDestruction, nsIScriptGlobalObject* aGlobalObject);
36
37 NS_DECL_CYCLE_COLLECTING_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsCycleCollectingAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public: virtual void DeleteCycleCollectable(
void); public:
38 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSContext,class cycleCollection : public nsXPCOMCycleCollectionParticipant
{ public: constexpr explicit cycleCollection(Flags aFlags = 0
) : nsXPCOMCycleCollectionParticipant(aFlags) {} private: public
: virtual nsresult TraverseNative(void* p, nsCycleCollectionTraversalCallback
& cb) override; virtual const char* ClassName() override {
return "nsJSContext"; }; virtual void DeleteCycleCollectable
(void* p) override { DowncastCCParticipant<nsJSContext>
(p)->DeleteCycleCollectable(); } static nsJSContext* Downcast
(nsISupports* s) { return static_cast<nsJSContext*>(static_cast
<nsIScriptContext*>(s)); } static nsISupports* Upcast(nsJSContext
* p) { return static_cast<nsISupports*>(static_cast<
nsIScriptContext*>(p)); } template <typename T> friend
nsISupports* ToSupports(T* p, cycleCollection* dummy); virtual
void Unlink(void* p) override; virtual void Trace(void* p, const
TraceCallbacks& cb, void* closure) override; static constexpr
nsXPCOMCycleCollectionParticipant* GetParticipant() { return
&nsJSContext::_cycleCollectorGlobal; } }; virtual void CheckForRightParticipant
() { nsXPCOMCycleCollectionParticipant* p; CallQueryInterface
(this, &p); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(p == &_cycleCollectorGlobal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(p == &_cycleCollectorGlobal
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"p == &_cycleCollectorGlobal" " (" "nsJSContext" " should QI to its own CC participant"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsJSEnvironment.h"
, 39); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == &_cycleCollectorGlobal"
") (" "nsJSContext" " should QI to its own CC participant" ")"
); do { *((volatile int*)__null) = 39; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } static cycleCollection
_cycleCollectorGlobal; virtual void BaseCycleCollectable() final
{}
39 nsIScriptContext)class cycleCollection : public nsXPCOMCycleCollectionParticipant
{ public: constexpr explicit cycleCollection(Flags aFlags = 0
) : nsXPCOMCycleCollectionParticipant(aFlags) {} private: public
: virtual nsresult TraverseNative(void* p, nsCycleCollectionTraversalCallback
& cb) override; virtual const char* ClassName() override {
return "nsJSContext"; }; virtual void DeleteCycleCollectable
(void* p) override { DowncastCCParticipant<nsJSContext>
(p)->DeleteCycleCollectable(); } static nsJSContext* Downcast
(nsISupports* s) { return static_cast<nsJSContext*>(static_cast
<nsIScriptContext*>(s)); } static nsISupports* Upcast(nsJSContext
* p) { return static_cast<nsISupports*>(static_cast<
nsIScriptContext*>(p)); } template <typename T> friend
nsISupports* ToSupports(T* p, cycleCollection* dummy); virtual
void Unlink(void* p) override; virtual void Trace(void* p, const
TraceCallbacks& cb, void* closure) override; static constexpr
nsXPCOMCycleCollectionParticipant* GetParticipant() { return
&nsJSContext::_cycleCollectorGlobal; } }; virtual void CheckForRightParticipant
() { nsXPCOMCycleCollectionParticipant* p; CallQueryInterface
(this, &p); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(p == &_cycleCollectorGlobal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(p == &_cycleCollectorGlobal
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"p == &_cycleCollectorGlobal" " (" "nsJSContext" " should QI to its own CC participant"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsJSEnvironment.h"
, 39); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == &_cycleCollectorGlobal"
") (" "nsJSContext" " should QI to its own CC participant" ")"
); do { *((volatile int*)__null) = 39; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } static cycleCollection
_cycleCollectorGlobal; virtual void BaseCycleCollectable() final
{}
40
41 virtual nsIScriptGlobalObject* GetGlobalObject() override;
42 inline nsIScriptGlobalObject* GetGlobalObjectRef() {
43 return mGlobalObjectRef;
44 }
45
46 virtual nsresult SetProperty(JS::Handle<JSObject*> aTarget,
47 const char* aPropName,
48 nsISupports* aVal) override;
49
50 virtual bool GetProcessingScriptTag() override;
51 virtual void SetProcessingScriptTag(bool aResult) override;
52
53 virtual nsresult InitClasses(JS::Handle<JSObject*> aGlobalObj) override;
54
55 virtual void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) override;
56 virtual JSObject* GetWindowProxy() override;
57
58 enum IsShrinking { ShrinkingGC, NonShrinkingGC };
59
60 // Setup all the statics etc - safe to call multiple times after Startup().
61 static void EnsureStatics();
62
63 static void SetLowMemoryState(bool aState);
64
65 static void GarbageCollectNow(JS::GCReason reason,
66 IsShrinking aShrinking = NonShrinkingGC);
67
68 static void RunIncrementalGCSlice(JS::GCReason aReason,
69 IsShrinking aShrinking,
70 JS::SliceBudget& aBudget);
71
72 static void CycleCollectNow(mozilla::CCReason aReason,
73 nsICycleCollectorListener* aListener = nullptr);
74
75 // Finish up any in-progress incremental GC.
76 static void PrepareForCycleCollectionSlice(mozilla::CCReason aReason,
77 mozilla::TimeStamp aDeadline);
78
79 // Run a cycle collector slice, using a heuristic to decide how long to run
80 // it.
81 static void RunCycleCollectorSlice(mozilla::CCReason aReason,
82 mozilla::TimeStamp aDeadline);
83
84 // Run a cycle collector slice, using the given work budget.
85 static void RunCycleCollectorWorkSlice(int64_t aWorkBudget);
86
87 static void BeginCycleCollectionCallback(mozilla::CCReason aReason);
88 static void EndCycleCollectionCallback(
89 const mozilla::CycleCollectorResults& aResults);
90
91 // Return the longest CC slice time since ClearMaxCCSliceTime() was last
92 // called.
93 static uint32_t GetMaxCCSliceTimeSinceClear();
94 static void ClearMaxCCSliceTime();
95
96 // If there is some pending CC or GC timer/runner, this will run it.
97 static void RunNextCollectorTimer(
98 JS::GCReason aReason,
99 mozilla::TimeStamp aDeadline = mozilla::TimeStamp());
100 // If user has been idle and aDocShell is for an iframe being loaded in an
101 // already loaded top level docshell, this will run a CC or GC
102 // timer/runner if there is such pending.
103 static void MaybeRunNextCollectorSlice(nsIDocShell* aDocShell,
104 JS::GCReason aReason);
105
106 // The GC should run soon, in the zone of aObj if given. If aObj is
107 // nullptr, collect all Zones.
108 static void PokeGC(JS::GCReason aReason, JSObject* aObj,
109 mozilla::TimeDuration aDelay = 0);
110
111 // If usage is nearing a threshold, request idle-only GC work. (This is called
112 // when a collection would be relatively convenient.)
113 static void MaybePokeGC();
114
115 // Immediately perform a non-incremental shrinking GC and CC.
116 static void DoLowMemoryGC();
117
118 // Perform a non-incremental shrinking GC and CC according to
119 // IdleScheduler.
120 static void LowMemoryGC();
121
122 static void MaybePokeCC();
123
124 // Calling LikelyShortLivingObjectCreated() makes a GC more likely.
125 static void LikelyShortLivingObjectCreated();
126
127 static bool HasHadCleanupSinceLastGC();
128
129 nsIScriptGlobalObject* GetCachedGlobalObject() {
130 // Verify that we have a global so that this
131 // does always return a null when GetGlobalObject() is null.
132 JSObject* global = GetWindowProxy();
133 return global ? mGlobalObjectRef.get() : nullptr;
134 }
135
136 protected:
137 virtual ~nsJSContext();
138
139 // Helper to convert xpcom datatypes to jsvals.
140 nsresult ConvertSupportsTojsvals(JSContext* aCx, nsISupports* aArgs,
141 JS::Handle<JSObject*> aScope,
142 JS::MutableHandleVector<JS::Value> aArgsOut);
143
144 nsresult AddSupportsPrimitiveTojsvals(JSContext* aCx, nsISupports* aArg,
145 JS::Value* aArgv);
146
147 private:
148 void Destroy();
149
150 JS::Heap<JSObject*> mWindowProxy;
151
152 bool mGCOnDestruction;
153 bool mProcessingScriptTag;
154
155 // mGlobalObjectRef ensures that the outer window stays alive as long as the
156 // context does. It is eventually collected by the cycle collector.
157 nsCOMPtr<nsIScriptGlobalObject> mGlobalObjectRef;
158
159 static bool DOMOperationCallback(JSContext* cx);
160};
161
162namespace mozilla::dom {
163
164class SerializedStackHolder;
165
166void StartupJSEnvironment();
167void ShutdownJSEnvironment();
168
169// Runnable that's used to do async error reporting
170class AsyncErrorReporter final : public mozilla::Runnable {
171 public:
172 explicit AsyncErrorReporter(xpc::ErrorReport* aReport);
173 // SerializeStack is suitable for main or worklet thread use.
174 // Stacks from worker threads are not supported.
175 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1578968
176 void SerializeStack(JSContext* aCx, JS::Handle<JSObject*> aStack);
177
178 // Set the exception value associated with this error report.
179 // Should only be called from the main thread.
180 void SetException(JSContext* aCx, JS::Handle<JS::Value> aException);
181
182 protected:
183 NS_IMETHODvirtual nsresult Run() override;
184
185 // This is only used on main thread!
186 JS::PersistentRooted<JS::Value> mException;
187 bool mHasException = false;
188
189 RefPtr<xpc::ErrorReport> mReport;
190 // This may be used to marshal a stack from an arbitrary thread/runtime into
191 // the main thread/runtime where the console service runs.
192 UniquePtr<SerializedStackHolder> mStackHolder;
193};
194
195} // namespace mozilla::dom
196
197// An interface for fast and native conversion to/from nsIArray. If an object
198// supports this interface, JS can reach directly in for the argv, and avoid
199// nsISupports conversion. If this interface is not supported, the object will
200// be queried for nsIArray, and everything converted via xpcom objects.
201#define NS_IJSARGARRAY_IID{ 0xb6acdac8, 0xf5c6, 0x432c, { 0xa8, 0x6e, 0x33, 0xee, 0xb1,
0xb0, 0xcd, 0xdc } }
\
202 { \
203 0xb6acdac8, 0xf5c6, 0x432c, { \
204 0xa8, 0x6e, 0x33, 0xee, 0xb1, 0xb0, 0xcd, 0xdc \
205 } \
206 }
207
208class nsIJSArgArray : public nsIArray {
209 public:
210 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSARGARRAY_IID)template <typename T, typename U> struct COMTypeInfo;
211 // Bug 312003 describes why this must be "void **", but after calling argv
212 // may be cast to JS::Value* and the args found at:
213 // ((JS::Value*)argv)[0], ..., ((JS::Value*)argv)[argc - 1]
214 virtual nsresult GetArgs(uint32_t* argc, void** argv) = 0;
215};
216
217NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSArgArray, NS_IJSARGARRAY_IID)template <typename T> struct nsIJSArgArray::COMTypeInfo
<nsIJSArgArray, T> { static const nsIID kIID __attribute__
((visibility("hidden"))); }; template <typename T> const
nsIID nsIJSArgArray::COMTypeInfo<nsIJSArgArray, T>::kIID
__attribute__((visibility("hidden"))) = { 0xb6acdac8, 0xf5c6
, 0x432c, { 0xa8, 0x6e, 0x33, 0xee, 0xb1, 0xb0, 0xcd, 0xdc } }
;
218
219#endif /* nsJSEnvironment_h */

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsThreadUtils.h

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#ifndef nsThreadUtils_h__
8#define nsThreadUtils_h__
9
10#include <type_traits>
11#include <tuple>
12#include <utility>
13
14#include "MainThreadUtils.h"
15#include "mozilla/EventQueue.h"
16#include "mozilla/AbstractThread.h"
17#include "mozilla/Atomics.h"
18#include "mozilla/Likely.h"
19#include "mozilla/Maybe.h"
20#include "mozilla/ThreadLocal.h"
21#include "mozilla/TimeStamp.h"
22
23#include "nsCOMPtr.h"
24#include "nsICancelableRunnable.h"
25#include "nsIDiscardableRunnable.h"
26#include "nsIIdlePeriod.h"
27#include "nsIIdleRunnable.h"
28#include "nsINamed.h"
29#include "nsIRunnable.h"
30#include "nsIThreadManager.h"
31#include "nsITimer.h"
32#include "nsString.h"
33#include "prinrval.h"
34#include "prthread.h"
35
36class MessageLoop;
37class nsIThread;
38
39//-----------------------------------------------------------------------------
40// These methods are alternatives to the methods on nsIThreadManager, provided
41// for convenience.
42
43/**
44 * Create a new thread, and optionally provide an initial event for the thread.
45 *
46 * @param aName
47 * The name of the thread.
48 * @param aResult
49 * The resulting nsIThread object.
50 * @param aInitialEvent
51 * The initial event to run on this thread. This parameter may be null.
52 * @param aOptions
53 * Options used to configure thread creation.
54 * Options are documented in nsIThreadManager.idl.
55 *
56 * @returns NS_ERROR_INVALID_ARG
57 * Indicates that the given name is not unique.
58 */
59
60extern nsresult NS_NewNamedThread(
61 const nsACString& aName, nsIThread** aResult,
62 nsIRunnable* aInitialEvent = nullptr,
63 nsIThreadManager::ThreadCreationOptions aOptions = {});
64
65extern nsresult NS_NewNamedThread(
66 const nsACString& aName, nsIThread** aResult,
67 already_AddRefed<nsIRunnable> aInitialEvent,
68 nsIThreadManager::ThreadCreationOptions aOptions = {});
69
70template <size_t LEN>
71inline nsresult NS_NewNamedThread(
72 const char (&aName)[LEN], nsIThread** aResult,
73 already_AddRefed<nsIRunnable> aInitialEvent,
74 nsIThreadManager::ThreadCreationOptions aOptions = {}) {
75 static_assert(LEN <= 16, "Thread name must be no more than 16 characters");
76 return NS_NewNamedThread(nsDependentCString(aName, LEN - 1), aResult,
77 std::move(aInitialEvent), aOptions);
78}
79
80template <size_t LEN>
81inline nsresult NS_NewNamedThread(
82 const char (&aName)[LEN], nsIThread** aResult,
83 nsIRunnable* aInitialEvent = nullptr,
84 nsIThreadManager::ThreadCreationOptions aOptions = {}) {
85 nsCOMPtr<nsIRunnable> event = aInitialEvent;
86 static_assert(LEN <= 16, "Thread name must be no more than 16 characters");
87 return NS_NewNamedThread(nsDependentCString(aName, LEN - 1), aResult,
88 event.forget(), aOptions);
89}
90
91/**
92 * Get a reference to the current thread, creating it if it does not exist yet.
93 *
94 * @param aResult
95 * The resulting nsIThread object.
96 */
97extern nsresult NS_GetCurrentThread(nsIThread** aResult);
98
99/**
100 * Dispatch the given event to the current thread.
101 *
102 * @param aEvent
103 * The event to dispatch.
104 *
105 * @returns NS_ERROR_INVALID_ARG
106 * If event is null.
107 */
108extern nsresult NS_DispatchToCurrentThread(nsIRunnable* aEvent);
109extern nsresult NS_DispatchToCurrentThread(
110 already_AddRefed<nsIRunnable>&& aEvent);
111
112/**
113 * Dispatch the given event to the main thread.
114 *
115 * @param aEvent
116 * The event to dispatch.
117 * @param aDispatchFlags
118 * The flags to pass to the main thread's dispatch method.
119 *
120 * @returns NS_ERROR_INVALID_ARG
121 * If event is null.
122 */
123extern nsresult NS_DispatchToMainThread(
124 nsIRunnable* aEvent, uint32_t aDispatchFlags = NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
125extern nsresult NS_DispatchToMainThread(
126 already_AddRefed<nsIRunnable>&& aEvent,
127 uint32_t aDispatchFlags = NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
128
129extern nsresult NS_DelayedDispatchToCurrentThread(
130 already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDelayMs);
131
132/**
133 * Dispatch the given event to the specified queue of the current thread.
134 *
135 * @param aEvent The event to dispatch.
136 * @param aQueue The event queue for the thread to use
137 *
138 * @returns NS_ERROR_INVALID_ARG
139 * If event is null.
140 * @returns NS_ERROR_UNEXPECTED
141 * If the thread is shutting down.
142 */
143extern nsresult NS_DispatchToCurrentThreadQueue(
144 already_AddRefed<nsIRunnable>&& aEvent, mozilla::EventQueuePriority aQueue);
145
146/**
147 * Dispatch the given event to the specified queue of the main thread.
148 *
149 * @param aEvent The event to dispatch.
150 * @param aQueue The event queue for the thread to use
151 *
152 * @returns NS_ERROR_INVALID_ARG
153 * If event is null.
154 * @returns NS_ERROR_UNEXPECTED
155 * If the thread is shutting down.
156 */
157extern nsresult NS_DispatchToMainThreadQueue(
158 already_AddRefed<nsIRunnable>&& aEvent, mozilla::EventQueuePriority aQueue);
159
160/**
161 * Dispatch the given event to an idle queue of the current thread.
162 *
163 * @param aEvent The event to dispatch. If the event implements
164 * nsIIdleRunnable, it will receive a call on
165 * nsIIdleRunnable::SetTimer when dispatched, with the value of
166 * aTimeout.
167 *
168 * @param aTimeout The time in milliseconds until the event should be
169 * moved from an idle queue to the regular queue, if it hasn't been
170 * executed. If aEvent is also an nsIIdleRunnable, it is expected
171 * that it should handle the timeout itself, after a call to
172 * nsIIdleRunnable::SetTimer.
173 *
174 * @param aQueue
175 * The event queue for the thread to use. Must be an idle queue
176 * (Idle or DeferredTimers)
177 *
178 * @returns NS_ERROR_INVALID_ARG
179 * If event is null.
180 * @returns NS_ERROR_UNEXPECTED
181 * If the thread is shutting down.
182 */
183extern nsresult NS_DispatchToCurrentThreadQueue(
184 already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout,
185 mozilla::EventQueuePriority aQueue);
186
187/**
188 * Dispatch the given event to a queue of a thread.
189 *
190 * @param aEvent The event to dispatch.
191 * @param aThread The target thread for the dispatch.
192 * @param aQueue The event queue for the thread to use.
193 *
194 * @returns NS_ERROR_INVALID_ARG
195 * If event is null.
196 * @returns NS_ERROR_UNEXPECTED
197 * If the thread is shutting down.
198 */
199extern nsresult NS_DispatchToThreadQueue(already_AddRefed<nsIRunnable>&& aEvent,
200 nsIThread* aThread,
201 mozilla::EventQueuePriority aQueue);
202
203/**
204 * Dispatch the given event to an idle queue of a thread.
205 *
206 * @param aEvent The event to dispatch. If the event implements
207 * nsIIdleRunnable, it will receive a call on
208 * nsIIdleRunnable::SetTimer when dispatched, with the value of
209 * aTimeout.
210 *
211 * @param aTimeout The time in milliseconds until the event should be
212 * moved from an idle queue to the regular queue, if it hasn't been
213 * executed. If aEvent is also an nsIIdleRunnable, it is expected
214 * that it should handle the timeout itself, after a call to
215 * nsIIdleRunnable::SetTimer.
216 *
217 * @param aThread The target thread for the dispatch.
218 *
219 * @param aQueue
220 * The event queue for the thread to use. Must be an idle queue
221 * (Idle or DeferredTimers)
222 *
223 * @returns NS_ERROR_INVALID_ARG
224 * If event is null.
225 * @returns NS_ERROR_UNEXPECTED
226 * If the thread is shutting down.
227 */
228extern nsresult NS_DispatchToThreadQueue(already_AddRefed<nsIRunnable>&& aEvent,
229 uint32_t aTimeout, nsIThread* aThread,
230 mozilla::EventQueuePriority aQueue);
231
232#ifndef XPCOM_GLUE_AVOID_NSPR
233/**
234 * Process all pending events for the given thread before returning. This
235 * method simply calls ProcessNextEvent on the thread while HasPendingEvents
236 * continues to return true and the time spent in NS_ProcessPendingEvents
237 * does not exceed the given timeout value.
238 *
239 * @param aThread
240 * The thread object for which to process pending events. If null, then
241 * events will be processed for the current thread.
242 * @param aTimeout
243 * The maximum number of milliseconds to spend processing pending events.
244 * Events are not pre-empted to honor this timeout. Rather, the timeout
245 * value is simply used to determine whether or not to process another event.
246 * Pass PR_INTERVAL_NO_TIMEOUT to specify no timeout.
247 */
248extern nsresult NS_ProcessPendingEvents(
249 nsIThread* aThread, PRIntervalTime aTimeout = PR_INTERVAL_NO_TIMEOUT0xffffffffUL);
250#endif
251
252/**
253 * Shortcut for nsIThread::HasPendingEvents.
254 *
255 * It is an error to call this function when the given thread is not the
256 * current thread. This function will return false if called from some
257 * other thread.
258 *
259 * @param aThread
260 * The current thread or null.
261 *
262 * @returns
263 * A boolean value that if "true" indicates that there are pending events
264 * in the current thread's event queue.
265 */
266extern bool NS_HasPendingEvents(nsIThread* aThread = nullptr);
267
268/**
269 * Shortcut for nsIThread::ProcessNextEvent.
270 *
271 * It is an error to call this function when the given thread is not the
272 * current thread. This function will simply return false if called
273 * from some other thread.
274 *
275 * @param aThread
276 * The current thread or null.
277 * @param aMayWait
278 * A boolean parameter that if "true" indicates that the method may block
279 * the calling thread to wait for a pending event.
280 *
281 * @returns
282 * A boolean value that if "true" indicates that an event from the current
283 * thread's event queue was processed.
284 */
285extern bool NS_ProcessNextEvent(nsIThread* aThread = nullptr,
286 bool aMayWait = true);
287
288/**
289 * Returns true if we're in the compositor thread.
290 *
291 * We declare this here because the headers required to invoke
292 * CompositorThreadHolder::IsInCompositorThread() also pull in a bunch of system
293 * headers that #define various tokens in a way that can break the build.
294 */
295extern bool NS_IsInCompositorThread();
296
297extern bool NS_IsInCanvasThreadOrWorker();
298
299extern bool NS_IsInVRThread();
300
301//-----------------------------------------------------------------------------
302// Helpers that work with nsCOMPtr:
303
304inline already_AddRefed<nsIThread> do_GetCurrentThread() {
305 nsIThread* thread = nullptr;
306 NS_GetCurrentThread(&thread);
307 return already_AddRefed<nsIThread>(thread);
308}
309
310inline already_AddRefed<nsIThread> do_GetMainThread() {
311 nsIThread* thread = nullptr;
312 NS_GetMainThread(&thread);
313 return already_AddRefed<nsIThread>(thread);
314}
315
316//-----------------------------------------------------------------------------
317
318// Fast access to the current thread. Will create an nsIThread if one does not
319// exist already! Do not release the returned pointer! If you want to use this
320// pointer from some other thread, then you will need to AddRef it. Otherwise,
321// you should only consider this pointer valid from code running on the current
322// thread.
323extern nsIThread* NS_GetCurrentThread();
324
325// Exactly the same as NS_GetCurrentThread, except it will not create an
326// nsThread if one does not exist yet. This is useful in cases where you have
327// code that runs on threads that may or may not not be driven by an nsThread
328// event loop, and wish to avoid inadvertently creating a superfluous nsThread.
329extern nsIThread* NS_GetCurrentThreadNoCreate();
330
331/**
332 * Set the name of the current thread. Prefer this function over
333 * PR_SetCurrentThreadName() if possible. The name will also be included in the
334 * crash report.
335 *
336 * @param aName
337 * Name of the thread. A C language null-terminated string.
338 */
339extern void NS_SetCurrentThreadName(const char* aName);
340
341//-----------------------------------------------------------------------------
342
343#ifndef XPCOM_GLUE_AVOID_NSPR
344
345namespace mozilla {
346
347// This class is designed to be subclassed.
348class IdlePeriod : public nsIIdlePeriod {
349 public:
350 NS_DECL_THREADSAFE_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::true_type; protected
: ::mozilla::ThreadSafeAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public:
351 NS_DECL_NSIIDLEPERIODvirtual nsresult GetIdlePeriodHint(mozilla::TimeStamp * _retval
) override;
352
353 IdlePeriod() = default;
354
355 protected:
356 virtual ~IdlePeriod() = default;
357
358 private:
359 IdlePeriod(const IdlePeriod&) = delete;
360 IdlePeriod& operator=(const IdlePeriod&) = delete;
361 IdlePeriod& operator=(const IdlePeriod&&) = delete;
362};
363
364// Cancelable runnable methods implement nsICancelableRunnable, and
365// Idle and IdleWithTimer also nsIIdleRunnable.
366enum class RunnableKind { Standard, Cancelable, Idle, IdleWithTimer };
367
368// Implementing nsINamed on Runnable bloats vtables for the hundreds of
369// Runnable subclasses that we have, so we want to avoid that overhead
370// when we're not using nsINamed for anything.
371# ifndef RELEASE_OR_BETA
372# define MOZ_COLLECTING_RUNNABLE_TELEMETRY
373# endif
374
375// This class is designed to be subclassed.
376class Runnable : public nsIRunnable
377# ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
378 ,
379 public nsINamed
380# endif
381{
382 public:
383 NS_DECL_THREADSAFE_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::true_type; protected
: ::mozilla::ThreadSafeAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public:
384 NS_DECL_NSIRUNNABLEvirtual nsresult Run(void) override;
385# ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
386 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
387# endif
388
389 Runnable() = delete;
390
391# ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
392 explicit Runnable(const char* aName) : mName(aName) {}
393# else
394 explicit Runnable(const char* aName) {}
395# endif
396
397 protected:
398 virtual ~Runnable() = default;
399
400# ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
401 const char* mName = nullptr;
402# endif
403
404 private:
405 Runnable(const Runnable&) = delete;
406 Runnable& operator=(const Runnable&) = delete;
407 Runnable& operator=(const Runnable&&) = delete;
408};
409
410// This is a base class for tasks that might not be run, such as those that may
411// be dispatched to workers.
412// The owner of an event target will call either Run() or OnDiscard()
413// exactly once.
414// Derived classes should override Run(). An OnDiscard() override may
415// provide cleanup when Run() will not be called.
416class DiscardableRunnable : public Runnable, public nsIDiscardableRunnable {
417 public:
418 NS_DECL_ISUPPORTS_INHERITEDpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override;
419 // nsIDiscardableRunnable
420 void OnDiscard() override {}
421
422 DiscardableRunnable() = delete;
423 explicit DiscardableRunnable(const char* aName) : Runnable(aName) {}
424
425 protected:
426 virtual ~DiscardableRunnable() = default;
427
428 private:
429 DiscardableRunnable(const DiscardableRunnable&) = delete;
430 DiscardableRunnable& operator=(const DiscardableRunnable&) = delete;
431 DiscardableRunnable& operator=(const DiscardableRunnable&&) = delete;
432};
433
434// This class is designed to be subclassed.
435// Derived classes should override Run() and Cancel() to provide that
436// calling Run() after Cancel() is a no-op.
437class CancelableRunnable : public DiscardableRunnable,
438 public nsICancelableRunnable {
439 public:
440 NS_DECL_ISUPPORTS_INHERITEDpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override;
441 // nsIDiscardableRunnable
442 void OnDiscard() override;
443 // nsICancelableRunnable
444 virtual nsresult Cancel() override = 0;
445
446 CancelableRunnable() = delete;
447 explicit CancelableRunnable(const char* aName) : DiscardableRunnable(aName) {}
448
449 protected:
450 virtual ~CancelableRunnable() = default;
451
452 private:
453 CancelableRunnable(const CancelableRunnable&) = delete;
454 CancelableRunnable& operator=(const CancelableRunnable&) = delete;
455 CancelableRunnable& operator=(const CancelableRunnable&&) = delete;
456};
457
458// This class is designed to be subclassed.
459class IdleRunnable : public DiscardableRunnable, public nsIIdleRunnable {
460 public:
461 NS_DECL_ISUPPORTS_INHERITEDpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override;
462
463 explicit IdleRunnable(const char* aName) : DiscardableRunnable(aName) {}
464
465 protected:
466 virtual ~IdleRunnable() = default;
467
468 private:
469 IdleRunnable(const IdleRunnable&) = delete;
470 IdleRunnable& operator=(const IdleRunnable&) = delete;
471 IdleRunnable& operator=(const IdleRunnable&&) = delete;
472};
473
474// This class is designed to be subclassed.
475class CancelableIdleRunnable : public CancelableRunnable,
476 public nsIIdleRunnable {
477 public:
478 NS_DECL_ISUPPORTS_INHERITEDpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override;
479
480 CancelableIdleRunnable() : CancelableRunnable("CancelableIdleRunnable") {}
481 explicit CancelableIdleRunnable(const char* aName)
482 : CancelableRunnable(aName) {}
483
484 protected:
485 virtual ~CancelableIdleRunnable() = default;
486
487 private:
488 CancelableIdleRunnable(const CancelableIdleRunnable&) = delete;
489 CancelableIdleRunnable& operator=(const CancelableIdleRunnable&) = delete;
490 CancelableIdleRunnable& operator=(const CancelableIdleRunnable&&) = delete;
491};
492
493// This class is designed to be a wrapper of a real runnable to support event
494// prioritizable.
495class PrioritizableRunnable : public Runnable, public nsIRunnablePriority {
496 public:
497 PrioritizableRunnable(already_AddRefed<nsIRunnable>&& aRunnable,
498 uint32_t aPriority);
499
500# ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
501 NS_IMETHODvirtual nsresult GetName(nsACString& aName) override;
502# endif
503
504 NS_DECL_ISUPPORTS_INHERITEDpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override;
505 NS_DECL_NSIRUNNABLEvirtual nsresult Run(void) override;
506 NS_DECL_NSIRUNNABLEPRIORITYvirtual nsresult GetPriority(uint32_t *aPriority) override;
507
508 protected:
509 virtual ~PrioritizableRunnable() = default;
510
511 nsCOMPtr<nsIRunnable> mRunnable;
512 uint32_t mPriority;
513};
514
515class PrioritizableCancelableRunnable : public CancelableRunnable,
516 public nsIRunnablePriority {
517 public:
518 PrioritizableCancelableRunnable(uint32_t aPriority, const char* aName)
519 : CancelableRunnable(aName), mPriority(aPriority) {}
520
521 NS_DECL_ISUPPORTS_INHERITEDpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override;
522 NS_DECL_NSIRUNNABLEPRIORITYvirtual nsresult GetPriority(uint32_t *aPriority) override;
523
524 protected:
525 virtual ~PrioritizableCancelableRunnable() = default;
526
527 const uint32_t mPriority;
528};
529
530extern already_AddRefed<nsIRunnable> CreateRenderBlockingRunnable(
531 already_AddRefed<nsIRunnable>&& aRunnable);
532
533namespace detail {
534
535// An event that can be used to call a C++11 functions or function objects,
536// including lambdas. The function must have no required arguments, and must
537// return void.
538template <typename StoredFunction>
539class RunnableFunction : public Runnable {
540 public:
541 template <typename F>
542 explicit RunnableFunction(const char* aName, F&& aFunction)
543 : Runnable(aName), mFunction(std::forward<F>(aFunction)) {}
544
545 NS_IMETHODvirtual nsresult Run() override {
546 static_assert(std::is_void_v<decltype(mFunction())>,
547 "The lambda must return void!");
548 mFunction();
549 return NS_OK;
550 }
551
552 private:
553 StoredFunction mFunction;
554};
555
556// Type alias for NS_NewRunnableFunction
557template <typename Function>
558using RunnableFunctionImpl =
559 // Make sure we store a non-reference in nsRunnableFunction.
560 typename detail::RunnableFunction<std::remove_reference_t<Function>>;
561} // namespace detail
562
563namespace detail {
564
565template <typename T>
566struct RemoveSmartPointerHelper {
567 using Type = T;
568};
569
570template <typename T>
571struct RemoveSmartPointerHelper<RefPtr<T>> {
572 using Type = T;
573};
574
575template <typename T>
576struct RemoveSmartPointerHelper<nsCOMPtr<T>> {
577 using Type = T;
578};
579
580template <typename T>
581struct RemoveRawOrSmartPointerHelper {
582 using Type = typename RemoveSmartPointerHelper<T>::Type;
583};
584
585template <typename T>
586struct RemoveRawOrSmartPointerHelper<T*> {
587 using Type = T;
588};
589
590} // namespace detail
591
592template <typename T>
593using RemoveSmartPointer =
594 typename detail::RemoveSmartPointerHelper<std::remove_cv_t<T>>::Type;
595
596template <typename T>
597using RemoveRawOrSmartPointer =
598 typename detail::RemoveRawOrSmartPointerHelper<std::remove_cv_t<T>>::Type;
599
600} // namespace mozilla
601
602inline nsISupports* ToSupports(mozilla::Runnable* p) {
603 return static_cast<nsIRunnable*>(p);
604}
605
606template <typename Function>
607already_AddRefed<mozilla::Runnable> NS_NewRunnableFunction(
608 const char* aName, Function&& aFunction) {
609 // We store a non-reference in RunnableFunction, but still forward aFunction
610 // to move if possible.
611 return do_AddRef(new mozilla::detail::RunnableFunctionImpl<Function>(
612 aName, std::forward<Function>(aFunction)));
613}
614
615// Creates a new object implementing nsIRunnable and nsICancelableRunnable,
616// which runs a given function on Run and clears the stored function object on a
617// call to `Cancel` (and thus destroys all objects it holds).
618template <typename Function>
619already_AddRefed<mozilla::CancelableRunnable> NS_NewCancelableRunnableFunction(
620 const char* aName, Function&& aFunc) {
621 class FuncCancelableRunnable final : public mozilla::CancelableRunnable {
622 public:
623 static_assert(
624 std::is_void_v<
625 decltype(std::declval<std::remove_reference_t<Function>>()())>);
626
627 NS_INLINE_DECL_REFCOUNTING_INHERITED(FuncCancelableRunnable,virtual MozExternalRefCountType AddRef() override { static_assert
(!std::is_destructible_v<FuncCancelableRunnable>, "Reference-counted class "
"FuncCancelableRunnable" " should not have a public destructor. "
"Make this class's destructor non-public"); nsrefcnt r = CancelableRunnable
::AddRef(); if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt
<FuncCancelableRunnable>) { NS_LogAddRef((this), (r), (
"FuncCancelableRunnable"), (uint32_t)(sizeof(*this))); } return
r; } virtual MozExternalRefCountType Release() override { nsrefcnt
r = CancelableRunnable::Release(); if constexpr (::mozilla::
detail::ShouldLogInheritedRefcnt<FuncCancelableRunnable>
) { NS_LogRelease((this), (r), ("FuncCancelableRunnable")); }
return r; }
628 CancelableRunnable)virtual MozExternalRefCountType AddRef() override { static_assert
(!std::is_destructible_v<FuncCancelableRunnable>, "Reference-counted class "
"FuncCancelableRunnable" " should not have a public destructor. "
"Make this class's destructor non-public"); nsrefcnt r = CancelableRunnable
::AddRef(); if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt
<FuncCancelableRunnable>) { NS_LogAddRef((this), (r), (
"FuncCancelableRunnable"), (uint32_t)(sizeof(*this))); } return
r; } virtual MozExternalRefCountType Release() override { nsrefcnt
r = CancelableRunnable::Release(); if constexpr (::mozilla::
detail::ShouldLogInheritedRefcnt<FuncCancelableRunnable>
) { NS_LogRelease((this), (r), ("FuncCancelableRunnable")); }
return r; }
629
630 explicit FuncCancelableRunnable(const char* aName, Function&& aFunc)
631 : CancelableRunnable{aName},
632 mFunc{mozilla::Some(std::forward<Function>(aFunc))} {}
633
634 NS_IMETHODvirtual nsresult Run() override {
635 if (mFunc) {
636 (*mFunc)();
637 }
638
639 return NS_OK;
640 }
641
642 nsresult Cancel() override {
643 mFunc.reset();
644 return NS_OK;
645 }
646
647 private:
648 ~FuncCancelableRunnable() = default;
649
650 mozilla::Maybe<std::remove_reference_t<Function>> mFunc;
651 };
652
653 return mozilla::MakeAndAddRef<FuncCancelableRunnable>(
654 aName, std::forward<Function>(aFunc));
655}
656
657namespace mozilla {
658namespace detail {
659
660template <RunnableKind Kind>
661class TimerBehaviour {
662 public:
663 nsITimer* GetTimer() { return nullptr; }
664 void CancelTimer() {}
665
666 protected:
667 ~TimerBehaviour() = default;
668};
669
670template <>
671class TimerBehaviour<RunnableKind::IdleWithTimer> {
672 public:
673 nsITimer* GetTimer() {
674 if (!mTimer) {
675 mTimer = NS_NewTimer();
676 }
677
678 return mTimer;
679 }
680
681 void CancelTimer() {
682 if (mTimer) {
683 mTimer->Cancel();
684 }
685 }
686
687 protected:
688 ~TimerBehaviour() { CancelTimer(); }
689
690 private:
691 nsCOMPtr<nsITimer> mTimer;
692};
693
694} // namespace detail
695} // namespace mozilla
696
697// An event that can be used to call a method on a class. The class type must
698// support reference counting. This event supports Revoke for use
699// with nsRevocableEventPtr.
700template <class ClassType, typename ReturnType = void, bool Owning = true,
701 mozilla::RunnableKind Kind = mozilla::RunnableKind::Standard>
702class nsRunnableMethod
703 : public std::conditional_t<
704 Kind == mozilla::RunnableKind::Standard, mozilla::Runnable,
705 std::conditional_t<Kind == mozilla::RunnableKind::Cancelable,
706 mozilla::CancelableRunnable,
707 mozilla::CancelableIdleRunnable>>,
708 protected mozilla::detail::TimerBehaviour<Kind> {
709 using BaseType = std::conditional_t<
710 Kind == mozilla::RunnableKind::Standard, mozilla::Runnable,
711 std::conditional_t<Kind == mozilla::RunnableKind::Cancelable,
712 mozilla::CancelableRunnable,
713 mozilla::CancelableIdleRunnable>>;
714
715 public:
716 nsRunnableMethod(const char* aName) : BaseType(aName) {}
717
718 virtual void Revoke() = 0;
719
720 // These ReturnTypeEnforcer classes disallow return types that
721 // we know are not safe. The default ReturnTypeEnforcer compiles just fine but
722 // already_AddRefed will not.
723 template <typename OtherReturnType>
724 class ReturnTypeEnforcer {
725 public:
726 typedef int ReturnTypeIsSafe;
727 };
728
729 template <class T>
730 class ReturnTypeEnforcer<already_AddRefed<T>> {
731 // No ReturnTypeIsSafe makes this illegal!
732 };
733
734 // Make sure this return type is safe.
735 typedef typename ReturnTypeEnforcer<ReturnType>::ReturnTypeIsSafe check;
736};
737
738template <class ClassType, bool Owning>
739struct nsRunnableMethodReceiver {
740 RefPtr<ClassType> mObj;
741 explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
742 explicit nsRunnableMethodReceiver(RefPtr<ClassType>&& aObj)
743 : mObj(std::move(aObj)) {}
744 ~nsRunnableMethodReceiver() { Revoke(); }
745 ClassType* Get() const { return mObj.get(); }
746 void Revoke() { mObj = nullptr; }
747};
748
749template <class ClassType>
750struct nsRunnableMethodReceiver<ClassType, false> {
751 ClassType* MOZ_NON_OWNING_REF mObj;
752 explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
753 ClassType* Get() const { return mObj; }
754 void Revoke() { mObj = nullptr; }
755};
756
757static inline constexpr bool IsIdle(mozilla::RunnableKind aKind) {
758 return aKind == mozilla::RunnableKind::Idle ||
759 aKind == mozilla::RunnableKind::IdleWithTimer;
760}
761
762template <typename PtrType, typename Method, bool Owning,
763 mozilla::RunnableKind Kind>
764struct nsRunnableMethodTraits;
765
766template <typename PtrType, class C, typename R, bool Owning,
767 mozilla::RunnableKind Kind, typename... As>
768struct nsRunnableMethodTraits<PtrType, R (C::*)(As...), Owning, Kind> {
769 using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>;
770 static_assert(std::is_base_of<C, class_type>::value,
771 "Stored class must inherit from method's class");
772 using return_type = R;
773 using base_type = nsRunnableMethod<C, R, Owning, Kind>;
774 static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
775};
776
777template <typename PtrType, class C, typename R, bool Owning,
778 mozilla::RunnableKind Kind, typename... As>
779struct nsRunnableMethodTraits<PtrType, R (C::*)(As...) const, Owning, Kind> {
780 using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>;
781 static_assert(std::is_base_of<C, class_type>::value,
782 "Stored class must inherit from method's class");
783 using return_type = R;
784 using base_type = nsRunnableMethod<C, R, Owning, Kind>;
785 static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
786};
787
788# ifdef NS_HAVE_STDCALL
789template <typename PtrType, class C, typename R, bool Owning,
790 mozilla::RunnableKind Kind, typename... As>
791struct nsRunnableMethodTraits<PtrType, R (__stdcall C::*)(As...), Owning,
792 Kind> {
793 using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>;
794 static_assert(std::is_base_of<C, class_type>::value,
795 "Stored class must inherit from method's class");
796 using return_type = R;
797 using base_type = nsRunnableMethod<C, R, Owning, Kind>;
798 static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
799};
800
801template <typename PtrType, class C, typename R, bool Owning,
802 mozilla::RunnableKind Kind>
803struct nsRunnableMethodTraits<PtrType, R (NS_STDCALL C::*)(), Owning, Kind> {
804 using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>;
805 static_assert(std::is_base_of<C, class_type>::value,
806 "Stored class must inherit from method's class");
807 using return_type = R;
808 using base_type = nsRunnableMethod<C, R, Owning, Kind>;
809 static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
810};
811
812template <typename PtrType, class C, typename R, bool Owning,
813 mozilla::RunnableKind Kind, typename... As>
814struct nsRunnableMethodTraits<PtrType, R (__stdcall C::*)(As...) const, Owning,
815 Kind> {
816 using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>;
817 static_assert(std::is_base_of<C, class_type>::value,
818 "Stored class must inherit from method's class");
819 using return_type = R;
820 using base_type = nsRunnableMethod<C, R, Owning, Kind>;
821 static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
822};
823
824template <typename PtrType, class C, typename R, bool Owning,
825 mozilla::RunnableKind Kind>
826struct nsRunnableMethodTraits<PtrType, R (NS_STDCALL C::*)() const, Owning,
827 Kind> {
828 using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>;
829 static_assert(std::is_base_of<C, class_type>::value,
830 "Stored class must inherit from method's class");
831 using return_type = R;
832 using base_type = nsRunnableMethod<C, R, Owning, Kind>;
833 static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
834};
835# endif
836
837// IsParameterStorageClass<T>::value is true if T is a parameter-storage class
838// that will be recognized by NS_New[NonOwning]RunnableMethodWithArg[s] to
839// force a specific storage&passing strategy (instead of inferring one,
840// see ParameterStorage).
841// When creating a new storage class, add a specialization for it to be
842// recognized.
843template <typename T>
844struct IsParameterStorageClass : public std::false_type {};
845
846// StoreXPassByY structs used to inform nsRunnableMethodArguments how to
847// store arguments, and how to pass them to the target method.
848
849template <typename T>
850struct StoreCopyPassByConstLRef {
851 using stored_type = std::decay_t<T>;
852 typedef const stored_type& passed_type;
853 stored_type m;
854 template <typename A>
855 MOZ_IMPLICIT StoreCopyPassByConstLRef(A&& a) : m(std::forward<A>(a)) {}
856 passed_type PassAsParameter() { return m; }
857};
858template <typename S>
859struct IsParameterStorageClass<StoreCopyPassByConstLRef<S>>
860 : public std::true_type {};
861
862template <typename T>
863struct StoreCopyPassByRRef {
864 using stored_type = std::decay_t<T>;
865 typedef stored_type&& passed_type;
866 stored_type m;
867 template <typename A>
868 MOZ_IMPLICIT StoreCopyPassByRRef(A&& a) : m(std::forward<A>(a)) {}
869 passed_type PassAsParameter() { return std::move(m); }
870};
871template <typename S>
872struct IsParameterStorageClass<StoreCopyPassByRRef<S>> : public std::true_type {
873};
874
875template <typename T>
876struct StoreRefPassByLRef {
877 typedef T& stored_type;
878 typedef T& passed_type;
879 stored_type m;
880 template <typename A>
881 MOZ_IMPLICIT StoreRefPassByLRef(A& a) : m(a) {}
882 passed_type PassAsParameter() { return m; }
883};
884template <typename S>
885struct IsParameterStorageClass<StoreRefPassByLRef<S>> : public std::true_type {
886};
887
888template <typename T>
889struct StoreConstRefPassByConstLRef {
890 typedef const T& stored_type;
891 typedef const T& passed_type;
892 stored_type m;
893 template <typename A>
894 MOZ_IMPLICIT StoreConstRefPassByConstLRef(const A& a) : m(a) {}
895 passed_type PassAsParameter() { return m; }
896};
897template <typename S>
898struct IsParameterStorageClass<StoreConstRefPassByConstLRef<S>>
899 : public std::true_type {};
900
901template <typename T>
902struct StoreRefPtrPassByPtr {
903 typedef RefPtr<T> stored_type;
904 typedef T* passed_type;
905 stored_type m;
906 template <typename A>
907 MOZ_IMPLICIT StoreRefPtrPassByPtr(A&& a) : m(std::forward<A>(a)) {}
908 passed_type PassAsParameter() { return m.get(); }
909};
910template <typename S>
911struct IsParameterStorageClass<StoreRefPtrPassByPtr<S>>
912 : public std::true_type {};
913
914template <typename T>
915struct StorePtrPassByPtr {
916 typedef T* stored_type;
917 typedef T* passed_type;
918 stored_type m;
919 template <typename A>
920 MOZ_IMPLICIT StorePtrPassByPtr(A a) : m(a) {}
921 passed_type PassAsParameter() { return m; }
922};
923template <typename S>
924struct IsParameterStorageClass<StorePtrPassByPtr<S>> : public std::true_type {};
925
926template <typename T>
927struct StoreConstPtrPassByConstPtr {
928 typedef const T* stored_type;
929 typedef const T* passed_type;
930 stored_type m;
931 template <typename A>
932 MOZ_IMPLICIT StoreConstPtrPassByConstPtr(A a) : m(a) {}
933 passed_type PassAsParameter() { return m; }
934};
935template <typename S>
936struct IsParameterStorageClass<StoreConstPtrPassByConstPtr<S>>
937 : public std::true_type {};
938
939namespace detail {
940
941template <typename>
942struct SFINAE1True : std::true_type {};
943
944template <class T>
945static auto HasRefCountMethodsTest(int)
946 -> SFINAE1True<decltype(std::declval<T>().AddRef(),
947 std::declval<T>().Release())>;
948template <class>
949static auto HasRefCountMethodsTest(long) -> std::false_type;
950
951template <class T>
952constexpr static bool HasRefCountMethods =
953 decltype(HasRefCountMethodsTest<T>(0))::value;
954
955// Choose storage&passing strategy based on preferred storage type:
956// - If IsParameterStorageClass<T>::value is true, use as-is.
957// - RC* -> StoreRefPtrPassByPtr<RC> :Store RefPtr<RC>, pass RC*
958// ^^ RC quacks like a ref-counted type (i.e., has AddRef and Release methods)
959// - const T* -> StoreConstPtrPassByConstPtr<T> :Store const T*, pass const T*
960// - T* -> StorePtrPassByPtr<T> :Store T*, pass T*.
961// - const T& -> StoreConstRefPassByConstLRef<T>:Store const T&, pass const T&.
962// - T& -> StoreRefPassByLRef<T> :Store T&, pass T&.
963// - T&& -> StoreCopyPassByRRef<T> :Store T, pass std::move(T).
964// - RefPtr<T>, nsCOMPtr<T>
965// -> StoreRefPtrPassByPtr<T> :Store RefPtr<T>, pass T*
966// - Other T -> StoreCopyPassByConstLRef<T> :Store T, pass const T&.
967//
968// For anything less common, please use a lambda function rather than devising
969// new parameter-storage classes. (In fact, consider doing that anyway.)
970
971template <typename T>
972struct OtherParameterStorage;
973
974// The `IsParameterStorageClass` and `RC*` cases must be handled separately (see
975// `ParameterStorageHelper`, below) until we can use C++20 concepts.
976
977template <typename T>
978struct OtherParameterStorage<const T*> {
979 using Type = StoreConstPtrPassByConstPtr<T>;
980};
981
982template <typename T>
983struct OtherParameterStorage<T*> {
984 using Type = StorePtrPassByPtr<T>;
985};
986
987template <typename T>
988struct OtherParameterStorage<const T&> {
989 using Type = StoreConstRefPassByConstLRef<T>;
990};
991
992template <typename T>
993struct OtherParameterStorage<T&> {
994 using Type = StoreRefPassByLRef<T>;
995};
996
997template <typename T>
998struct OtherParameterStorage<RefPtr<T>> {
999 using Type = StoreRefPtrPassByPtr<T>;
1000};
1001
1002template <typename T>
1003struct OtherParameterStorage<nsCOMPtr<T>> {
1004 using Type = StoreRefPtrPassByPtr<T>;
1005};
1006
1007template <typename T>
1008struct OtherParameterStorage<T&&> {
1009 using Type = StoreCopyPassByRRef<T>;
1010};
1011
1012template <typename T>
1013struct OtherParameterStorage<const T&&> {
1014 // This is good advice regardless of the types you're handling.
1015 static_assert(!SFINAE1True<T>::value, "please use a lambda function");
1016};
1017
1018// default impl.
1019template <typename T>
1020struct OtherParameterStorage {
1021 using Type = StoreCopyPassByConstLRef<T>;
1022};
1023
1024template <typename T, bool A = IsParameterStorageClass<T>::value,
1025 bool B = std::is_pointer_v<T> &&
1026 HasRefCountMethods<std::remove_pointer_t<T>>>
1027struct ParameterStorageHelper;
1028
1029template <typename T, bool B>
1030struct ParameterStorageHelper<T, true, B> {
1031 using Type = T;
1032};
1033
1034template <typename T>
1035struct ParameterStorageHelper<T, false, true> {
1036 using Type = StoreRefPtrPassByPtr<std::remove_pointer_t<T>>;
1037};
1038
1039template <typename T>
1040struct ParameterStorageHelper<T, false, false> {
1041 using Type = typename OtherParameterStorage<std::remove_cv_t<T>>::Type;
1042};
1043
1044template <typename T>
1045struct ParameterStorage {
1046 using Type = typename ParameterStorageHelper<T>::Type;
1047};
1048
1049template <class T>
1050static auto HasSetDeadlineTest(int)
1051 -> SFINAE1True<decltype(std::declval<T>().SetDeadline(
1052 std::declval<mozilla::TimeStamp>()))>;
1053
1054template <class T>
1055static auto HasSetDeadlineTest(long) -> std::false_type;
1056
1057template <class T>
1058struct HasSetDeadline : decltype(HasSetDeadlineTest<T>(0)) {};
1059
1060template <class T>
1061std::enable_if_t<::detail::HasSetDeadline<T>::value> SetDeadlineImpl(
1062 T* aObj, mozilla::TimeStamp aTimeStamp) {
1063 aObj->SetDeadline(aTimeStamp);
1064}
1065
1066template <class T>
1067std::enable_if_t<!::detail::HasSetDeadline<T>::value> SetDeadlineImpl(
1068 T* aObj, mozilla::TimeStamp aTimeStamp) {}
1069} /* namespace detail */
1070
1071namespace mozilla {
1072namespace detail {
1073
1074// struct used to store arguments and later apply them to a method.
1075template <typename... Ts>
1076struct RunnableMethodArguments final {
1077 std::tuple<typename ::detail::ParameterStorage<Ts>::Type...> mArguments;
1078 template <typename... As>
1079 explicit RunnableMethodArguments(As&&... aArguments)
1080 : mArguments(std::forward<As>(aArguments)...) {}
1081 template <class C, typename M>
1082 decltype(auto) apply(C* o, M m) {
1083 return std::apply(
1084 [&o, m](auto&&... args) {
1085 return ((*o).*m)(args.PassAsParameter()...);
1086 },
1087 mArguments);
1088 }
1089};
1090
1091template <typename PtrType, typename Method, bool Owning, RunnableKind Kind,
1092 typename... Storages>
1093class RunnableMethodImpl final
1094 : public ::nsRunnableMethodTraits<PtrType, Method, Owning,
1095 Kind>::base_type {
1096 typedef typename ::nsRunnableMethodTraits<PtrType, Method, Owning, Kind>
1097 Traits;
1098
1099 typedef typename Traits::class_type ClassType;
1100 typedef typename Traits::base_type BaseType;
1101 ::nsRunnableMethodReceiver<ClassType, Owning> mReceiver;
1102 Method mMethod;
1103 RunnableMethodArguments<Storages...> mArgs;
1104 using BaseType::CancelTimer;
1105 using BaseType::GetTimer;
1106
1107 private:
1108 virtual ~RunnableMethodImpl() { Revoke(); };
1109 static void TimedOut(nsITimer* aTimer, void* aClosure) {
1110 static_assert(IsIdle(Kind), "Don't use me!");
1111 RefPtr<CancelableIdleRunnable> r =
1112 static_cast<CancelableIdleRunnable*>(aClosure);
1113 r->SetDeadline(TimeStamp());
1114 r->Run();
1115 r->Cancel();
1116 }
1117
1118 public:
1119 template <typename ForwardedPtrType, typename... Args>
1120 explicit RunnableMethodImpl(const char* aName, ForwardedPtrType&& aObj,
1121 Method aMethod, Args&&... aArgs)
1122 : BaseType(aName),
1123 mReceiver(std::forward<ForwardedPtrType>(aObj)),
25
Calling 'RefPtr::operator nsGlobalWindowOuter *'
1124 mMethod(aMethod),
1125 mArgs(std::forward<Args>(aArgs)...) {
1126 static_assert(sizeof...(Storages) == sizeof...(Args),
1127 "Storages and Args should have equal sizes");
1128 }
1129
1130 NS_IMETHODvirtual nsresult Run() {
1131 CancelTimer();
1132
1133 if (MOZ_LIKELY(mReceiver.Get())(__builtin_expect(!!(mReceiver.Get()), 1))) {
1134 mArgs.apply(mReceiver.Get(), mMethod);
1135 }
1136
1137 return NS_OK;
1138 }
1139
1140 nsresult Cancel() {
1141 static_assert(Kind >= RunnableKind::Cancelable, "Don't use me!");
1142 Revoke();
1143 return NS_OK;
1144 }
1145
1146 void Revoke() {
1147 CancelTimer();
1148 mReceiver.Revoke();
1149 }
1150
1151 void SetDeadline(TimeStamp aDeadline) {
1152 if (MOZ_LIKELY(mReceiver.Get())(__builtin_expect(!!(mReceiver.Get()), 1))) {
1153 ::detail::SetDeadlineImpl(mReceiver.Get(), aDeadline);
1154 }
1155 }
1156
1157 void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) {
1158 MOZ_ASSERT(aTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTarget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aTarget", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsThreadUtils.h"
, 1158); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTarget" ")"
); do { *((volatile int*)__null) = 1158; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1159
1160 if (nsCOMPtr<nsITimer> timer = GetTimer()) {
1161 timer->Cancel();
1162 timer->SetTarget(aTarget);
1163 timer->InitWithNamedFuncCallback(TimedOut, this, aDelay,
1164 nsITimer::TYPE_ONE_SHOT,
1165 "detail::RunnableMethodImpl::SetTimer");
1166 }
1167 }
1168};
1169
1170// Type aliases for NewRunnableMethod.
1171template <typename PtrType, typename Method>
1172using OwningRunnableMethod =
1173 typename ::nsRunnableMethodTraits<std::remove_reference_t<PtrType>, Method,
1174 true, RunnableKind::Standard>::base_type;
1175template <typename PtrType, typename Method, typename... Storages>
1176using OwningRunnableMethodImpl =
1177 RunnableMethodImpl<std::remove_reference_t<PtrType>, Method, true,
1178 RunnableKind::Standard, Storages...>;
1179
1180// Type aliases for NewCancelableRunnableMethod.
1181template <typename PtrType, typename Method>
1182using CancelableRunnableMethod =
1183 typename ::nsRunnableMethodTraits<std::remove_reference_t<PtrType>, Method,
1184 true,
1185 RunnableKind::Cancelable>::base_type;
1186template <typename PtrType, typename Method, typename... Storages>
1187using CancelableRunnableMethodImpl =
1188 RunnableMethodImpl<std::remove_reference_t<PtrType>, Method, true,
1189 RunnableKind::Cancelable, Storages...>;
1190
1191// Type aliases for NewIdleRunnableMethod.
1192template <typename PtrType, typename Method>
1193using IdleRunnableMethod =
1194 typename ::nsRunnableMethodTraits<std::remove_reference_t<PtrType>, Method,
1195 true, RunnableKind::Idle>::base_type;
1196template <typename PtrType, typename Method, typename... Storages>
1197using IdleRunnableMethodImpl =
1198 RunnableMethodImpl<std::remove_reference_t<PtrType>, Method, true,
1199 RunnableKind::Idle, Storages...>;
1200
1201// Type aliases for NewIdleRunnableMethodWithTimer.
1202template <typename PtrType, typename Method>
1203using IdleRunnableMethodWithTimer =
1204 typename ::nsRunnableMethodTraits<std::remove_reference_t<PtrType>, Method,
1205 true,
1206 RunnableKind::IdleWithTimer>::base_type;
1207template <typename PtrType, typename Method, typename... Storages>
1208using IdleRunnableMethodWithTimerImpl =
1209 RunnableMethodImpl<std::remove_reference_t<PtrType>, Method, true,
1210 RunnableKind::IdleWithTimer, Storages...>;
1211
1212// Type aliases for NewNonOwningRunnableMethod.
1213template <typename PtrType, typename Method>
1214using NonOwningRunnableMethod =
1215 typename ::nsRunnableMethodTraits<std::remove_reference_t<PtrType>, Method,
1216 false, RunnableKind::Standard>::base_type;
1217template <typename PtrType, typename Method, typename... Storages>
1218using NonOwningRunnableMethodImpl =
1219 RunnableMethodImpl<std::remove_reference_t<PtrType>, Method, false,
1220 RunnableKind::Standard, Storages...>;
1221
1222// Type aliases for NonOwningCancelableRunnableMethod
1223template <typename PtrType, typename Method>
1224using NonOwningCancelableRunnableMethod =
1225 typename ::nsRunnableMethodTraits<std::remove_reference_t<PtrType>, Method,
1226 false,
1227 RunnableKind::Cancelable>::base_type;
1228template <typename PtrType, typename Method, typename... Storages>
1229using NonOwningCancelableRunnableMethodImpl =
1230 RunnableMethodImpl<std::remove_reference_t<PtrType>, Method, false,
1231 RunnableKind::Cancelable, Storages...>;
1232
1233// Type aliases for NonOwningIdleRunnableMethod
1234template <typename PtrType, typename Method>
1235using NonOwningIdleRunnableMethod =
1236 typename ::nsRunnableMethodTraits<std::remove_reference_t<PtrType>, Method,
1237 false, RunnableKind::Idle>::base_type;
1238template <typename PtrType, typename Method, typename... Storages>
1239using NonOwningIdleRunnableMethodImpl =
1240 RunnableMethodImpl<std::remove_reference_t<PtrType>, Method, false,
1241 RunnableKind::Idle, Storages...>;
1242
1243// Type aliases for NewIdleRunnableMethodWithTimer.
1244template <typename PtrType, typename Method>
1245using NonOwningIdleRunnableMethodWithTimer =
1246 typename ::nsRunnableMethodTraits<std::remove_reference_t<PtrType>, Method,
1247 false,
1248 RunnableKind::IdleWithTimer>::base_type;
1249template <typename PtrType, typename Method, typename... Storages>
1250using NonOwningIdleRunnableMethodWithTimerImpl =
1251 RunnableMethodImpl<std::remove_reference_t<PtrType>, Method, false,
1252 RunnableKind::IdleWithTimer, Storages...>;
1253
1254} // namespace detail
1255
1256// NewRunnableMethod and friends
1257//
1258// Very often in Gecko, you'll find yourself in a situation where you want
1259// to invoke a method (with or without arguments) asynchronously. You
1260// could write a small helper class inheriting from nsRunnable to handle
1261// all these details, or you could let NewRunnableMethod take care of all
1262// those details for you.
1263//
1264// The simplest use of NewRunnableMethod looks like:
1265//
1266// nsCOMPtr<nsIRunnable> event =
1267// mozilla::NewRunnableMethod("description", myObject,
1268// &MyClass::HandleEvent);
1269// NS_DispatchToCurrentThread(event);
1270//
1271// Statically enforced constraints:
1272// - myObject must be of (or implicitly convertible to) type MyClass
1273// - MyClass must define AddRef and Release methods
1274//
1275// The "description" string should specify a human-readable name for the
1276// runnable; the provided string is used by various introspection tools
1277// in the browser.
1278//
1279// The created runnable will take a strong reference to `myObject`. For
1280// non-refcounted objects, or refcounted objects with unusual refcounting
1281// requirements, and if and only if you are 110% certain that `myObject`
1282// will live long enough, you can use NewNonOwningRunnableMethod instead,
1283// which will, as its name implies, take a non-owning reference. If you
1284// find yourself having to use this function, you should accompany your use
1285// with a proof comment describing why the runnable will not lead to
1286// use-after-frees.
1287//
1288// (If you find yourself writing contorted code to Release() an object
1289// asynchronously on a different thread, you should use the
1290// NS_ProxyRelease function.)
1291//
1292// Invoking a method with arguments takes a little more care. The
1293// natural extension of the above:
1294//
1295// nsCOMPtr<nsIRunnable> event =
1296// mozilla::NewRunnableMethod("description", myObject,
1297// &MyClass::HandleEvent,
1298// arg1, arg2, ...);
1299//
1300// can lead to security hazards (e.g. passing in raw pointers to refcounted
1301// objects and storing those raw pointers in the runnable). We therefore
1302// require you to specify the storage types used by the runnable, just as
1303// you would if you were writing out the class by hand:
1304//
1305// nsCOMPtr<nsIRunnable> event =
1306// mozilla::NewRunnableMethod<RefPtr<T>, nsTArray<U>>
1307// ("description", myObject, &MyClass::HandleEvent, arg1, arg2);
1308//
1309// Please note that you do not have to pass the same argument type as you
1310// specify in the template arguments. For example, if you want to transfer
1311// ownership to a runnable, you can write:
1312//
1313// RefPtr<T> ptr = ...;
1314// nsTArray<U> array = ...;
1315// nsCOMPtr<nsIRunnable> event =
1316// mozilla::NewRunnableMethod<RefPtr<T>, nsTArray<U>>
1317// ("description", myObject, &MyClass::DoSomething,
1318// std::move(ptr), std::move(array));
1319//
1320// and there will be no extra AddRef/Release traffic, or copying of the array.
1321//
1322// Each type that you specify as a template argument to NewRunnableMethod
1323// comes with its own style of storage in the runnable and its own style
1324// of argument passing to the invoked method. See the comment for
1325// ParameterStorage above for more details.
1326//
1327// If you need to customize the storage type and/or argument passing type,
1328// you can write your own class to use as a template argument to
1329// NewRunnableMethod. If you find yourself having to do that frequently,
1330// please file a bug in Core::XPCOM about adding the custom type to the
1331// core code in this file, and/or for custom rules for ParameterStorage
1332// to select that strategy.
1333//
1334// For places that require you to use cancelable runnables, such as
1335// workers, there's also NewCancelableRunnableMethod and its non-owning
1336// counterpart. The runnables returned by these methods additionally
1337// implement nsICancelableRunnable.
1338//
1339// Finally, all of the functions discussed above have additional overloads
1340// that do not take a `const char*` as their first parameter; you may see
1341// these in older code. The `const char*` overload is preferred and
1342// should be used in new code exclusively.
1343
1344template <typename PtrType, typename Method>
1345already_AddRefed<detail::OwningRunnableMethod<PtrType, Method>>
1346NewRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod) {
1347 return do_AddRef(new detail::OwningRunnableMethodImpl<PtrType, Method>(
24
Calling constructor for 'RunnableMethodImpl<RefPtr<nsGlobalWindowOuter>, void (nsGlobalWindowOuter::*)(), true, mozilla::RunnableKind::Standard, >'
1348 aName, std::forward<PtrType>(aPtr), aMethod));
1349}
1350
1351template <typename PtrType, typename Method>
1352already_AddRefed<detail::CancelableRunnableMethod<PtrType, Method>>
1353NewCancelableRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod) {
1354 return do_AddRef(new detail::CancelableRunnableMethodImpl<PtrType, Method>(
1355 aName, std::forward<PtrType>(aPtr), aMethod));
1356}
1357
1358template <typename PtrType, typename Method>
1359already_AddRefed<detail::IdleRunnableMethod<PtrType, Method>>
1360NewIdleRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod) {
1361 return do_AddRef(new detail::IdleRunnableMethodImpl<PtrType, Method>(
1362 aName, std::forward<PtrType>(aPtr), aMethod));
1363}
1364
1365template <typename PtrType, typename Method>
1366already_AddRefed<detail::IdleRunnableMethodWithTimer<PtrType, Method>>
1367NewIdleRunnableMethodWithTimer(const char* aName, PtrType&& aPtr,
1368 Method aMethod) {
1369 return do_AddRef(new detail::IdleRunnableMethodWithTimerImpl<PtrType, Method>(
1370 aName, std::forward<PtrType>(aPtr), aMethod));
1371}
1372
1373template <typename PtrType, typename Method>
1374already_AddRefed<detail::NonOwningRunnableMethod<PtrType, Method>>
1375NewNonOwningRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod) {
1376 return do_AddRef(new detail::NonOwningRunnableMethodImpl<PtrType, Method>(
1377 aName, std::forward<PtrType>(aPtr), aMethod));
1378}
1379
1380template <typename PtrType, typename Method>
1381already_AddRefed<detail::NonOwningCancelableRunnableMethod<PtrType, Method>>
1382NewNonOwningCancelableRunnableMethod(const char* aName, PtrType&& aPtr,
1383 Method aMethod) {
1384 return do_AddRef(
1385 new detail::NonOwningCancelableRunnableMethodImpl<PtrType, Method>(
1386 aName, std::forward<PtrType>(aPtr), aMethod));
1387}
1388
1389template <typename PtrType, typename Method>
1390already_AddRefed<detail::NonOwningIdleRunnableMethod<PtrType, Method>>
1391NewNonOwningIdleRunnableMethod(const char* aName, PtrType&& aPtr,
1392 Method aMethod) {
1393 return do_AddRef(new detail::NonOwningIdleRunnableMethodImpl<PtrType, Method>(
1394 aName, std::forward<PtrType>(aPtr), aMethod));
1395}
1396
1397template <typename PtrType, typename Method>
1398already_AddRefed<detail::NonOwningIdleRunnableMethodWithTimer<PtrType, Method>>
1399NewNonOwningIdleRunnableMethodWithTimer(const char* aName, PtrType&& aPtr,
1400 Method aMethod) {
1401 return do_AddRef(
1402 new detail::NonOwningIdleRunnableMethodWithTimerImpl<PtrType, Method>(
1403 aName, std::forward<PtrType>(aPtr), aMethod));
1404}
1405
1406// Similar to NewRunnableMethod. Call like so:
1407// nsCOMPtr<nsIRunnable> event =
1408// NewRunnableMethod<Types,...>(myObject, &MyClass::HandleEvent, myArg1,...);
1409// 'Types' are the stored type for each argument, see ParameterStorage for
1410// details.
1411template <typename... Storages, typename PtrType, typename Method,
1412 typename... Args>
1413already_AddRefed<detail::OwningRunnableMethod<PtrType, Method>>
1414NewRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod,
1415 Args&&... aArgs) {
1416 static_assert(sizeof...(Storages) == sizeof...(Args),
1417 "<Storages...> size should be equal to number of arguments");
1418 return do_AddRef(
1419 new detail::OwningRunnableMethodImpl<PtrType, Method, Storages...>(
1420 aName, std::forward<PtrType>(aPtr), aMethod,
1421 std::forward<Args>(aArgs)...));
1422}
1423
1424template <typename... Storages, typename PtrType, typename Method,
1425 typename... Args>
1426already_AddRefed<detail::NonOwningRunnableMethod<PtrType, Method>>
1427NewNonOwningRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod,
1428 Args&&... aArgs) {
1429 static_assert(sizeof...(Storages) == sizeof...(Args),
1430 "<Storages...> size should be equal to number of arguments");
1431 return do_AddRef(
1432 new detail::NonOwningRunnableMethodImpl<PtrType, Method, Storages...>(
1433 aName, std::forward<PtrType>(aPtr), aMethod,
1434 std::forward<Args>(aArgs)...));
1435}
1436
1437template <typename... Storages, typename PtrType, typename Method,
1438 typename... Args>
1439already_AddRefed<detail::CancelableRunnableMethod<PtrType, Method>>
1440NewCancelableRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod,
1441 Args&&... aArgs) {
1442 static_assert(sizeof...(Storages) == sizeof...(Args),
1443 "<Storages...> size should be equal to number of arguments");
1444 return do_AddRef(
1445 new detail::CancelableRunnableMethodImpl<PtrType, Method, Storages...>(
1446 aName, std::forward<PtrType>(aPtr), aMethod,
1447 std::forward<Args>(aArgs)...));
1448}
1449
1450template <typename... Storages, typename PtrType, typename Method,
1451 typename... Args>
1452already_AddRefed<detail::NonOwningCancelableRunnableMethod<PtrType, Method>>
1453NewNonOwningCancelableRunnableMethod(const char* aName, PtrType&& aPtr,
1454 Method aMethod, Args&&... aArgs) {
1455 static_assert(sizeof...(Storages) == sizeof...(Args),
1456 "<Storages...> size should be equal to number of arguments");
1457 return do_AddRef(
1458 new detail::NonOwningCancelableRunnableMethodImpl<PtrType, Method,
1459 Storages...>(
1460 aName, std::forward<PtrType>(aPtr), aMethod,
1461 std::forward<Args>(aArgs)...));
1462}
1463
1464template <typename... Storages, typename PtrType, typename Method,
1465 typename... Args>
1466already_AddRefed<detail::IdleRunnableMethod<PtrType, Method>>
1467NewIdleRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod,
1468 Args&&... aArgs) {
1469 static_assert(sizeof...(Storages) == sizeof...(Args),
1470 "<Storages...> size should be equal to number of arguments");
1471 return do_AddRef(
1472 new detail::IdleRunnableMethodImpl<PtrType, Method, Storages...>(
1473 aName, std::forward<PtrType>(aPtr), aMethod,
1474 std::forward<Args>(aArgs)...));
1475}
1476
1477template <typename... Storages, typename PtrType, typename Method,
1478 typename... Args>
1479already_AddRefed<detail::NonOwningIdleRunnableMethod<PtrType, Method>>
1480NewNonOwningIdleRunnableMethod(const char* aName, PtrType&& aPtr,
1481 Method aMethod, Args&&... aArgs) {
1482 static_assert(sizeof...(Storages) == sizeof...(Args),
1483 "<Storages...> size should be equal to number of arguments");
1484 return do_AddRef(
1485 new detail::NonOwningIdleRunnableMethodImpl<PtrType, Method, Storages...>(
1486 aName, std::forward<PtrType>(aPtr), aMethod,
1487 std::forward<Args>(aArgs)...));
1488}
1489
1490} // namespace mozilla
1491
1492#endif // XPCOM_GLUE_AVOID_NSPR
1493
1494// This class is designed to be used when you have an event class E that has a
1495// pointer back to resource class R. If R goes away while E is still pending,
1496// then it is important to "revoke" E so that it does not try use R after R has
1497// been destroyed. nsRevocableEventPtr makes it easy for R to manage such
1498// situations:
1499//
1500// class R;
1501//
1502// class E : public mozilla::Runnable {
1503// public:
1504// void Revoke() {
1505// mResource = nullptr;
1506// }
1507// private:
1508// R *mResource;
1509// };
1510//
1511// class R {
1512// public:
1513// void EventHandled() {
1514// mEvent.Forget();
1515// }
1516// private:
1517// nsRevocableEventPtr<E> mEvent;
1518// };
1519//
1520// void R::PostEvent() {
1521// // Make sure any pending event is revoked.
1522// mEvent->Revoke();
1523//
1524// nsCOMPtr<nsIRunnable> event = new E();
1525// if (NS_SUCCEEDED(NS_DispatchToCurrentThread(event))) {
1526// // Keep pointer to event so we can revoke it.
1527// mEvent = event;
1528// }
1529// }
1530//
1531// NS_IMETHODIMP E::Run() {
1532// if (!mResource)
1533// return NS_OK;
1534// ...
1535// mResource->EventHandled();
1536// return NS_OK;
1537// }
1538//
1539template <class T>
1540class nsRevocableEventPtr {
1541 public:
1542 nsRevocableEventPtr() : mEvent(nullptr) {}
1543 ~nsRevocableEventPtr() { Revoke(); }
1544
1545 const nsRevocableEventPtr& operator=(RefPtr<T>&& aEvent) {
1546 if (mEvent != aEvent) {
1547 Revoke();
1548 mEvent = std::move(aEvent);
1549 }
1550 return *this;
1551 }
1552
1553 void Revoke() {
1554 if (mEvent) {
1555 mEvent->Revoke();
1556 mEvent = nullptr;
1557 }
1558 }
1559
1560 void Forget() { mEvent = nullptr; }
1561 bool IsPending() { return mEvent != nullptr; }
1562 T* get() { return mEvent; }
1563
1564 private:
1565 // Not implemented
1566 nsRevocableEventPtr(const nsRevocableEventPtr&);
1567 nsRevocableEventPtr& operator=(const nsRevocableEventPtr&);
1568
1569 RefPtr<T> mEvent;
1570};
1571
1572template <class T>
1573inline already_AddRefed<T> do_AddRef(nsRevocableEventPtr<T>& aObj) {
1574 return do_AddRef(aObj.get());
1575}
1576
1577/**
1578 * A simple helper to suffix thread pool name
1579 * with incremental numbers.
1580 */
1581class nsThreadPoolNaming {
1582 public:
1583 nsThreadPoolNaming() = default;
1584
1585 /**
1586 * Returns a thread name as "<aPoolName> #<n>" and increments the counter.
1587 */
1588 nsCString GetNextThreadName(const nsACString& aPoolName);
1589
1590 template <size_t LEN>
1591 nsCString GetNextThreadName(const char (&aPoolName)[LEN]) {
1592 return GetNextThreadName(nsDependentCString(aPoolName, LEN - 1));
1593 }
1594
1595 private:
1596 mozilla::Atomic<uint32_t> mCounter{0};
1597
1598 nsThreadPoolNaming(const nsThreadPoolNaming&) = delete;
1599 void operator=(const nsThreadPoolNaming&) = delete;
1600};
1601
1602/**
1603 * Thread priority in most operating systems affect scheduling, not IO. This
1604 * helper is used to set the current thread to low IO priority for the lifetime
1605 * of the created object. You can only use this low priority IO setting within
1606 * the context of the current thread.
1607 */
1608class MOZ_STACK_CLASS nsAutoLowPriorityIO {
1609 public:
1610 nsAutoLowPriorityIO();
1611 ~nsAutoLowPriorityIO();
1612
1613 private:
1614 bool lowIOPrioritySet;
1615#if defined(XP_MACOSX)
1616 int oldPriority;
1617#endif
1618};
1619
1620void NS_SetMainThread();
1621
1622// Used only on cooperatively scheduled "main" threads. Causes the thread to be
1623// considered a main thread and also causes GetCurrentVirtualThread to return
1624// aVirtualThread.
1625void NS_SetMainThread(PRThread* aVirtualThread);
1626
1627// Used only on cooperatively scheduled "main" threads. Causes the thread to no
1628// longer be considered a main thread. Also causes GetCurrentVirtualThread() to
1629// return a unique value.
1630void NS_UnsetMainThread();
1631
1632/**
1633 * Return the expiration time of the next timer to run on the current
1634 * thread. If that expiration time is greater than aDefault, then
1635 * return aDefault. aSearchBound specifies a maximum number of timers
1636 * to examine to find a timer on the current thread. If no timer that
1637 * will run on the current thread is found after examining
1638 * aSearchBound timers, return the highest seen expiration time as a
1639 * best effort guess.
1640 *
1641 * Timers with either the type nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY or
1642 * nsITIMER::TYPE_REPEATING_SLACK_LOW_PRIORITY will be skipped when
1643 * searching for the next expiration time. This enables timers to
1644 * have lower priority than callbacks dispatched from
1645 * nsIThread::IdleDispatch.
1646 */
1647extern mozilla::TimeStamp NS_GetTimerDeadlineHintOnCurrentThread(
1648 mozilla::TimeStamp aDefault, uint32_t aSearchBound);
1649
1650/**
1651 * Dispatches the given event to a background thread. The primary benefit of
1652 * this API is that you do not have to manage the lifetime of your own thread
1653 * for running your own events; the thread manager will take care of the
1654 * background thread's lifetime. Not having to manage your own thread also
1655 * means less resource usage, as the underlying implementation here can manage
1656 * spinning up and shutting down threads appropriately.
1657 *
1658 * NOTE: there is no guarantee that events dispatched via these APIs are run
1659 * serially, in dispatch order; several dispatched events may run in parallel.
1660 * If you depend on serial execution of dispatched events, you should use
1661 * NS_CreateBackgroundTaskQueue instead, and dispatch events to the returned
1662 * event target.
1663 */
1664extern nsresult NS_DispatchBackgroundTask(
1665 already_AddRefed<nsIRunnable> aEvent,
1666 uint32_t aDispatchFlags = NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1667extern "C" nsresult NS_DispatchBackgroundTask(
1668 nsIRunnable* aEvent, uint32_t aDispatchFlags = NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1669
1670/**
1671 * Obtain a new serial event target that dispatches runnables to a background
1672 * thread. In many cases, this is a straight replacement for creating your
1673 * own, private thread, and is generally preferred to creating your own,
1674 * private thread.
1675 */
1676extern "C" nsresult NS_CreateBackgroundTaskQueue(
1677 const char* aName, nsISerialEventTarget** aTarget);
1678
1679/**
1680 * Dispatch the given runnable to the given event target, spinning the current
1681 * thread's event loop until the runnable has finished executing.
1682 *
1683 * This is roughly equivalent to the previously-supported `NS_DISPATCH_SYNC`
1684 * flag.
1685 */
1686extern nsresult NS_DispatchAndSpinEventLoopUntilComplete(
1687 const nsACString& aVeryGoodReasonToDoThis, nsIEventTarget* aEventTarget,
1688 already_AddRefed<nsIRunnable> aEvent);
1689
1690// Predeclaration for logging function below
1691namespace IPC {
1692class Message;
1693class MessageReader;
1694class MessageWriter;
1695} // namespace IPC
1696
1697class nsTimerImpl;
1698
1699namespace mozilla {
1700
1701// RAII class that will set the TLS entry to return the currently running
1702// nsISerialEventTarget.
1703// It should be used from inner event loop implementation.
1704class SerialEventTargetGuard {
1705 public:
1706 explicit SerialEventTargetGuard(nsISerialEventTarget* aThread)
1707 : mLastCurrentThread(sCurrentThreadTLS.get()) {
1708 Set(aThread);
1709 }
1710
1711 ~SerialEventTargetGuard() { sCurrentThreadTLS.set(mLastCurrentThread); }
1712
1713 static void InitTLS();
1714 static nsISerialEventTarget* GetCurrentSerialEventTarget() {
1715 return sCurrentThreadTLS.get();
1716 }
1717
1718 protected:
1719 friend class ::MessageLoop;
1720 static void Set(nsISerialEventTarget* aThread) {
1721 MOZ_ASSERT(aThread->IsOnCurrentThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aThread->IsOnCurrentThread()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsThreadUtils.h"
, 1721); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aThread->IsOnCurrentThread()"
")"); do { *((volatile int*)__null) = 1721; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1722 sCurrentThreadTLS.set(aThread);
1723 }
1724
1725 private:
1726 static MOZ_THREAD_LOCAL(nsISerialEventTarget*)__thread ::mozilla::detail::ThreadLocal< nsISerialEventTarget
*, ::mozilla::detail::ThreadLocalNativeStorage>
sCurrentThreadTLS;
1727 nsISerialEventTarget* mLastCurrentThread;
1728};
1729
1730// Get the serial event target corresponding to the currently executing task
1731// queue or thread. This method will assert if called on a thread pool without
1732// an active task queue.
1733//
1734// This function should generally be preferred over NS_GetCurrentThread since it
1735// will return a more useful answer when called from a task queue running on a
1736// thread pool or on a non-xpcom thread which accepts runnable dispatches.
1737//
1738// NOTE: The returned nsISerialEventTarget may not accept runnable dispatches
1739// (e.g. if it corresponds to a non-xpcom thread), however it may still be used
1740// to check if you're on the given thread/queue using IsOnCurrentThread().
1741
1742nsISerialEventTarget* GetCurrentSerialEventTarget();
1743
1744// Get a weak reference to a serial event target which can be used to dispatch
1745// runnables to the main thread.
1746//
1747// NOTE: While this is currently a weak pointer to the nsIThread* returned from
1748// NS_GetMainThread(), this may change in the future.
1749
1750nsISerialEventTarget* GetMainThreadSerialEventTarget();
1751
1752// Returns the number of CPUs, like PR_GetNumberOfProcessors, except
1753// that it can return a cached value on platforms where sandboxing
1754// would prevent reading the current value (currently Linux). CPU
1755// hotplugging is uncommon, so this is unlikely to make a difference
1756// in practice.
1757size_t GetNumberOfProcessors();
1758
1759/**
1760 * A helper class to log tasks dispatch and run with "MOZ_LOG=events:1". The
1761 * output is more machine readable and creates a link between dispatch and run.
1762 *
1763 * Usage example for the concrete template type nsIRunnable.
1764 * To log a dispatch, which means putting an event to a queue:
1765 * LogRunnable::LogDispatch(event);
1766 * theQueue.putEvent(event);
1767 *
1768 * To log execution (running) of the event:
1769 * nsCOMPtr<nsIRunnable> event = theQueue.popEvent();
1770 * {
1771 * LogRunnable::Run log(event);
1772 * event->Run();
1773 * event = null; // to include the destructor code in the span
1774 * }
1775 *
1776 * The class is a template so that we can support various specific super-types
1777 * of tasks in the future. We can't use void* because it may cast differently
1778 * and tracking the pointer in logs would then be impossible.
1779 */
1780template <typename T>
1781class LogTaskBase {
1782 public:
1783 LogTaskBase() = delete;
1784
1785 // Adds a simple log about dispatch of this runnable.
1786 static void LogDispatch(T* aEvent);
1787 // The `aContext` pointer adds another uniqe identifier, nothing more
1788 static void LogDispatch(T* aEvent, void* aContext);
1789
1790 // Logs dispatch of the message and along that also the PID of the target
1791 // proccess, purposed for uniquely identifying IPC messages.
1792 static void LogDispatchWithPid(T* aEvent, int32_t aPid);
1793
1794 // This is designed to surround a call to `Run()` or any code representing
1795 // execution of the task body.
1796 // The constructor adds a simple log about start of the runnable execution and
1797 // the destructor adds a log about ending the execution.
1798 class MOZ_RAII Run {
1799 public:
1800 Run() = delete;
1801 explicit Run(T* aEvent, bool aWillRunAgain = false);
1802 explicit Run(T* aEvent, void* aContext, bool aWillRunAgain = false);
1803 ~Run();
1804
1805 // When this is called, the log in this RAII dtor will only say
1806 // "interrupted" expecting that the event will run again.
1807 void WillRunAgain() { mWillRunAgain = true; }
1808
1809 private:
1810 bool mWillRunAgain = false;
1811 };
1812};
1813
1814class MicroTaskRunnable;
1815class Task; // TaskController
1816class PresShell;
1817namespace dom {
1818class FrameRequestCallback;
1819class VideoFrameRequestCallback;
1820} // namespace dom
1821
1822// Specialized methods must be explicitly predeclared.
1823template <>
1824LogTaskBase<nsIRunnable>::Run::Run(nsIRunnable* aEvent, bool aWillRunAgain);
1825template <>
1826LogTaskBase<Task>::Run::Run(Task* aTask, bool aWillRunAgain);
1827template <>
1828void LogTaskBase<IPC::Message>::LogDispatchWithPid(IPC::Message* aEvent,
1829 int32_t aPid);
1830template <>
1831LogTaskBase<IPC::Message>::Run::Run(IPC::Message* aMessage, bool aWillRunAgain);
1832template <>
1833LogTaskBase<nsTimerImpl>::Run::Run(nsTimerImpl* aEvent, bool aWillRunAgain);
1834
1835typedef LogTaskBase<nsIRunnable> LogRunnable;
1836typedef LogTaskBase<MicroTaskRunnable> LogMicroTaskRunnable;
1837typedef LogTaskBase<IPC::Message> LogIPCMessage;
1838typedef LogTaskBase<nsTimerImpl> LogTimerEvent;
1839typedef LogTaskBase<Task> LogTask;
1840typedef LogTaskBase<PresShell> LogPresShellObserver;
1841typedef LogTaskBase<dom::FrameRequestCallback> LogFrameRequestCallback;
1842typedef LogTaskBase<dom::VideoFrameRequestCallback>
1843 LogVideoFrameRequestCallback;
1844// If you add new types don't forget to add:
1845// `template class LogTaskBase<YourType>;` to nsThreadUtils.cpp
1846
1847} // namespace mozilla
1848
1849#endif // nsThreadUtils_h__

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/RefPtr.h

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#ifndef mozilla_RefPtr_h
8#define mozilla_RefPtr_h
9
10#include "mozilla/AlreadyAddRefed.h"
11#include "mozilla/Assertions.h"
12#include "mozilla/Attributes.h"
13#include "mozilla/DbgMacro.h"
14
15#include <type_traits>
16
17/*****************************************************************************/
18
19// template <class T> class RefPtrGetterAddRefs;
20
21class nsQueryReferent;
22class nsCOMPtr_helper;
23class nsISupports;
24
25namespace mozilla {
26template <class T>
27class MovingNotNull;
28template <class T>
29class NotNull;
30template <class T>
31class OwningNonNull;
32template <class T>
33class StaticLocalRefPtr;
34template <class T>
35class StaticRefPtr;
36
37// Traditionally, RefPtr supports automatic refcounting of any pointer type
38// with AddRef() and Release() methods that follow the traditional semantics.
39//
40// This traits class can be specialized to operate on other pointer types. For
41// example, we specialize this trait for opaque FFI types that represent
42// refcounted objects in Rust.
43//
44// Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
45// qualified type.
46template <class U>
47struct RefPtrTraits {
48 static void AddRef(U* aPtr) { aPtr->AddRef(); }
49 static void Release(U* aPtr) { aPtr->Release(); }
50};
51
52} // namespace mozilla
53
54template <class T>
55class MOZ_IS_REFPTR RefPtr {
56 private:
57 void assign_with_AddRef(T* aRawPtr) {
58 if (aRawPtr) {
59 ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
60 }
61 assign_assuming_AddRef(aRawPtr);
62 }
63
64 void assign_assuming_AddRef(T* aNewPtr) {
65 T* oldPtr = mRawPtr;
66 mRawPtr = aNewPtr;
67 if (oldPtr) {
68 ConstRemovingRefPtrTraits<T>::Release(oldPtr);
69 }
70 }
71
72 private:
73 T* MOZ_OWNING_REF mRawPtr;
74
75 public:
76 typedef T element_type;
77
78 ~RefPtr() {
79 if (mRawPtr) {
80 ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
81 }
82 }
83
84 // Constructors
85
86 RefPtr()
87 : mRawPtr(nullptr)
88 // default constructor
89 {}
90
91 RefPtr(const RefPtr<T>& aSmartPtr)
92 : mRawPtr(aSmartPtr.mRawPtr)
93 // copy-constructor
94 {
95 if (mRawPtr) {
96 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
97 }
98 }
99
100 RefPtr(RefPtr<T>&& aRefPtr) noexcept : mRawPtr(aRefPtr.mRawPtr) {
101 aRefPtr.mRawPtr = nullptr;
102 }
103
104 // construct from a raw pointer (of the right type)
105
106 MOZ_IMPLICIT RefPtr(T* aRawPtr) : mRawPtr(aRawPtr) {
107 if (mRawPtr) {
108 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
109 }
110 }
111
112 MOZ_IMPLICIT RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {}
113
114 template <typename I,
115 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
116 MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr)
117 : mRawPtr(aSmartPtr.take())
118 // construct from |already_AddRefed|
119 {}
120
121 template <typename I,
122 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
123 MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr)
124 : mRawPtr(aSmartPtr.take())
125 // construct from |otherRefPtr.forget()|
126 {}
127
128 template <typename I,
129 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
130 MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr)
131 : mRawPtr(aSmartPtr.get())
132 // copy-construct from a smart pointer with a related pointer type
133 {
134 if (mRawPtr) {
135 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
136 }
137 }
138
139 template <typename I,
140 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
141 MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr)
142 : mRawPtr(aSmartPtr.forget().take())
143 // construct from |Move(RefPtr<SomeSubclassOfT>)|.
144 {}
145
146 template <typename I,
147 typename = std::enable_if_t<!std::is_same_v<I, RefPtr<T>> &&
148 std::is_convertible_v<I, RefPtr<T>>>>
149 MOZ_IMPLICIT RefPtr(const mozilla::NotNull<I>& aSmartPtr)
150 : mRawPtr(RefPtr<T>(aSmartPtr.get()).forget().take())
151 // construct from |mozilla::NotNull|.
152 {}
153
154 template <typename I,
155 typename = std::enable_if_t<!std::is_same_v<I, RefPtr<T>> &&
156 std::is_convertible_v<I, RefPtr<T>>>>
157 MOZ_IMPLICIT RefPtr(mozilla::MovingNotNull<I>&& aSmartPtr)
158 : mRawPtr(RefPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take())
159 // construct from |mozilla::MovingNotNull|.
160 {}
161
162 MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper);
163 MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper);
164
165 // Defined in OwningNonNull.h
166 template <class U>
167 MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
168
169 // Defined in StaticLocalPtr.h
170 template <class U>
171 MOZ_IMPLICIT RefPtr(const mozilla::StaticLocalRefPtr<U>& aOther);
172
173 // Defined in StaticPtr.h
174 template <class U>
175 MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
176
177 // Assignment operators
178
179 RefPtr<T>& operator=(decltype(nullptr)) {
180 assign_assuming_AddRef(nullptr);
181 return *this;
182 }
183
184 RefPtr<T>& operator=(const RefPtr<T>& aRhs)
185 // copy assignment operator
186 {
187 assign_with_AddRef(aRhs.mRawPtr);
188 return *this;
189 }
190
191 template <typename I>
192 RefPtr<T>& operator=(const RefPtr<I>& aRhs)
193 // assign from an RefPtr of a related pointer type
194 {
195 assign_with_AddRef(aRhs.get());
196 return *this;
197 }
198
199 RefPtr<T>& operator=(T* aRhs)
200 // assign from a raw pointer (of the right type)
201 {
202 assign_with_AddRef(aRhs);
203 return *this;
204 }
205
206 template <typename I>
207 RefPtr<T>& operator=(already_AddRefed<I>& aRhs)
208 // assign from |already_AddRefed|
209 {
210 assign_assuming_AddRef(aRhs.take());
211 return *this;
212 }
213
214 template <typename I>
215 RefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
216 // assign from |otherRefPtr.forget()|
217 {
218 assign_assuming_AddRef(aRhs.take());
219 return *this;
220 }
221
222 RefPtr<T>& operator=(const nsQueryReferent& aQueryReferent);
223 RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
224
225 template <typename I,
226 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
227 RefPtr<T>& operator=(RefPtr<I>&& aRefPtr) noexcept {
228 assign_assuming_AddRef(aRefPtr.forget().take());
229 return *this;
230 }
231
232 template <typename I,
233 typename = std::enable_if_t<std::is_convertible_v<I, RefPtr<T>>>>
234 RefPtr<T>& operator=(const mozilla::NotNull<I>& aSmartPtr)
235 // assign from |mozilla::NotNull|.
236 {
237 assign_assuming_AddRef(RefPtr<T>(aSmartPtr.get()).forget().take());
238 return *this;
239 }
240
241 template <typename I,
242 typename = std::enable_if_t<std::is_convertible_v<I, RefPtr<T>>>>
243 RefPtr<T>& operator=(mozilla::MovingNotNull<I>&& aSmartPtr)
244 // assign from |mozilla::MovingNotNull|.
245 {
246 assign_assuming_AddRef(
247 RefPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take());
248 return *this;
249 }
250
251 // Defined in OwningNonNull.h
252 template <class U>
253 RefPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
254
255 // Defined in StaticLocalPtr.h
256 template <class U>
257 RefPtr<T>& operator=(const mozilla::StaticLocalRefPtr<U>& aOther);
258
259 // Defined in StaticPtr.h
260 template <class U>
261 RefPtr<T>& operator=(const mozilla::StaticRefPtr<U>& aOther);
262
263 // Other pointer operators
264
265 void swap(RefPtr<T>& aRhs)
266 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
267 {
268 T* temp = aRhs.mRawPtr;
269 aRhs.mRawPtr = mRawPtr;
270 mRawPtr = temp;
271 }
272
273 void swap(T*& aRhs)
274 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
275 {
276 T* temp = aRhs;
277 aRhs = mRawPtr;
278 mRawPtr = temp;
279 }
280
281 already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget()
282 // return the value of mRawPtr and null out mRawPtr. Useful for
283 // already_AddRefed return values.
284 {
285 T* temp = nullptr;
286 swap(temp);
287 return already_AddRefed<T>(temp);
288 }
289
290 template <typename I>
291 void forget(I** aRhs)
292 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
293 // Useful to avoid unnecessary AddRef/Release pairs with "out"
294 // parameters where aRhs bay be a T** or an I** where I is a base class
295 // of T.
296 {
297 MOZ_ASSERT(aRhs, "Null pointer passed to forget!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRhs)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aRhs))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aRhs" " (" "Null pointer passed to forget!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/RefPtr.h"
, 297); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRhs" ") (" "Null pointer passed to forget!"
")"); do { *((volatile int*)__null) = 297; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
298 *aRhs = mRawPtr;
299 mRawPtr = nullptr;
300 }
301
302 void forget(nsISupports** aRhs) {
303 MOZ_ASSERT(aRhs, "Null pointer passed to forget!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRhs)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aRhs))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aRhs" " (" "Null pointer passed to forget!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/RefPtr.h"
, 303); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRhs" ") (" "Null pointer passed to forget!"
")"); do { *((volatile int*)__null) = 303; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
304 *aRhs = ToSupports(mRawPtr);
305 mRawPtr = nullptr;
306 }
307
308 T* get() const
309 /*
310 Prefer the implicit conversion provided automatically by |operator T*()
311 const|. Use |get()| to resolve ambiguity or to get a castable pointer.
312 */
313 {
314 return const_cast<T*>(mRawPtr);
27
Undefined or garbage value returned to caller
315 }
316
317 operator T*() const&
318 /*
319 ...makes an |RefPtr| act like its underlying raw pointer type whenever it
320 is used in a context where a raw pointer is expected. It is this operator
321 that makes an |RefPtr| substitutable for a raw pointer.
322
323 Prefer the implicit use of this operator to calling |get()|, except where
324 necessary to resolve ambiguity.
325 */
326 {
327 return get();
26
Calling 'RefPtr::get'
328 }
329
330 // Don't allow implicit conversion of temporary RefPtr to raw pointer,
331 // because the refcount might be one and the pointer will immediately become
332 // invalid.
333 operator T*() const&& = delete;
334
335 // These are needed to avoid the deleted operator above. XXX Why is operator!
336 // needed separately? Shouldn't the compiler prefer using the non-deleted
337 // operator bool instead of the deleted operator T*?
338 explicit operator bool() const { return !!mRawPtr; }
339 bool operator!() const { return !mRawPtr; }
340
341 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
342 MOZ_ASSERT(mRawPtr != nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRawPtr != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRawPtr != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRawPtr != nullptr"
" (" "You can't dereference a NULL RefPtr with operator->()."
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/RefPtr.h"
, 343); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRawPtr != nullptr"
") (" "You can't dereference a NULL RefPtr with operator->()."
")"); do { *((volatile int*)__null) = 343; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
343 "You can't dereference a NULL RefPtr with operator->().")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRawPtr != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRawPtr != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRawPtr != nullptr"
" (" "You can't dereference a NULL RefPtr with operator->()."
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/RefPtr.h"
, 343); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRawPtr != nullptr"
") (" "You can't dereference a NULL RefPtr with operator->()."
")"); do { *((volatile int*)__null) = 343; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
344 return get();
345 }
346
347 template <typename R, typename... Args>
348 class Proxy {
349 typedef R (T::*member_function)(Args...);
350 T* mRawPtr;
351 member_function mFunction;
352
353 public:
354 Proxy(T* aRawPtr, member_function aFunction)
355 : mRawPtr(aRawPtr), mFunction(aFunction) {}
356 template <typename... ActualArgs>
357 R operator()(ActualArgs&&... aArgs) {
358 return ((*mRawPtr).*mFunction)(std::forward<ActualArgs>(aArgs)...);
359 }
360 };
361
362 template <typename R, typename... Args>
363 Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const {
364 MOZ_ASSERT(mRawPtr != nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRawPtr != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRawPtr != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRawPtr != nullptr"
" (" "You can't dereference a NULL RefPtr with operator->*()."
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/RefPtr.h"
, 365); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRawPtr != nullptr"
") (" "You can't dereference a NULL RefPtr with operator->*()."
")"); do { *((volatile int*)__null) = 365; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
365 "You can't dereference a NULL RefPtr with operator->*().")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRawPtr != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRawPtr != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRawPtr != nullptr"
" (" "You can't dereference a NULL RefPtr with operator->*()."
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/RefPtr.h"
, 365); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRawPtr != nullptr"
") (" "You can't dereference a NULL RefPtr with operator->*()."
")"); do { *((volatile int*)__null) = 365; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
366 return Proxy<R, Args...>(get(), aFptr);
367 }
368
369 RefPtr<T>* get_address()
370 // This is not intended to be used by clients. See |address_of|
371 // below.
372 {
373 return this;
374 }
375
376 const RefPtr<T>* get_address() const
377 // This is not intended to be used by clients. See |address_of|
378 // below.
379 {
380 return this;
381 }
382
383 public:
384 T& operator*() const {
385 MOZ_ASSERT(mRawPtr != nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRawPtr != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRawPtr != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRawPtr != nullptr"
" (" "You can't dereference a NULL RefPtr with operator*()."
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/RefPtr.h"
, 386); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRawPtr != nullptr"
") (" "You can't dereference a NULL RefPtr with operator*()."
")"); do { *((volatile int*)__null) = 386; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
386 "You can't dereference a NULL RefPtr with operator*().")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRawPtr != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRawPtr != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRawPtr != nullptr"
" (" "You can't dereference a NULL RefPtr with operator*()."
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/RefPtr.h"
, 386); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRawPtr != nullptr"
") (" "You can't dereference a NULL RefPtr with operator*()."
")"); do { *((volatile int*)__null) = 386; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
387 return *get();
388 }
389
390 T** StartAssignment() {
391 assign_assuming_AddRef(nullptr);
392 return reinterpret_cast<T**>(&mRawPtr);
393 }
394
395 private:
396 // This helper class makes |RefPtr<const T>| possible by casting away
397 // the constness from the pointer when calling AddRef() and Release().
398 //
399 // This is necessary because AddRef() and Release() implementations can't
400 // generally expected to be const themselves (without heavy use of |mutable|
401 // and |const_cast| in their own implementations).
402 //
403 // This should be sound because while |RefPtr<const T>| provides a
404 // const view of an object, the object itself should not be const (it
405 // would have to be allocated as |new const T| or similar to be const).
406 template <class U>
407 struct ConstRemovingRefPtrTraits {
408 static void AddRef(U* aPtr) { mozilla::RefPtrTraits<U>::AddRef(aPtr); }
409 static void Release(U* aPtr) { mozilla::RefPtrTraits<U>::Release(aPtr); }
410 };
411 template <class U>
412 struct ConstRemovingRefPtrTraits<const U> {
413 static void AddRef(const U* aPtr) {
414 mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr));
415 }
416 static void Release(const U* aPtr) {
417 mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr));
418 }
419 };
420};
421
422class nsCycleCollectionTraversalCallback;
423template <typename T>
424void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback,
425 T* aChild, const char* aName, uint32_t aFlags);
426
427template <typename T>
428inline void ImplCycleCollectionUnlink(RefPtr<T>& aField) {
429 aField = nullptr;
430}
431
432template <typename T>
433inline void ImplCycleCollectionTraverse(
434 nsCycleCollectionTraversalCallback& aCallback, const RefPtr<T>& aField,
435 const char* aName, uint32_t aFlags = 0) {
436 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
437}
438
439template <class T>
440inline RefPtr<T>* address_of(RefPtr<T>& aPtr) {
441 return aPtr.get_address();
442}
443
444template <class T>
445inline const RefPtr<T>* address_of(const RefPtr<T>& aPtr) {
446 return aPtr.get_address();
447}
448
449template <class T>
450class RefPtrGetterAddRefs
451/*
452 ...
453
454 This class is designed to be used for anonymous temporary objects in the
455 argument list of calls that return COM interface pointers, e.g.,
456
457 RefPtr<IFoo> fooP;
458 ...->GetAddRefedPointer(getter_AddRefs(fooP))
459
460 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
461
462 When initialized with a |RefPtr|, as in the example above, it returns
463 a |void**|, a |T**|, or an |nsISupports**| as needed, that the
464 outer call (|GetAddRefedPointer| in this case) can fill in.
465
466 This type should be a nested class inside |RefPtr<T>|.
467*/
468{
469 public:
470 explicit RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr)
471 : mTargetSmartPtr(aSmartPtr) {
472 // nothing else to do
473 }
474
475 operator void**() {
476 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
477 }
478
479 operator T**() { return mTargetSmartPtr.StartAssignment(); }
480
481 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
482
483 private:
484 RefPtr<T>& mTargetSmartPtr;
485};
486
487template <class T>
488inline RefPtrGetterAddRefs<T> getter_AddRefs(RefPtr<T>& aSmartPtr)
489/*
490 Used around a |RefPtr| when
491 ...makes the class |RefPtrGetterAddRefs<T>| invisible.
492*/
493{
494 return RefPtrGetterAddRefs<T>(aSmartPtr);
495}
496
497// Comparing two |RefPtr|s
498
499template <class T, class U>
500inline bool operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
501 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
502}
503
504template <class T, class U>
505inline bool operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
506 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
507}
508
509// Comparing an |RefPtr| to a raw pointer
510
511template <class T, class U>
512inline bool operator==(const RefPtr<T>& aLhs, const U* aRhs) {
513 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs);
514}
515
516template <class T, class U>
517inline bool operator==(const U* aLhs, const RefPtr<T>& aRhs) {
518 return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
519}
520
521template <class T, class U>
522inline bool operator!=(const RefPtr<T>& aLhs, const U* aRhs) {
523 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs);
524}
525
526template <class T, class U>
527inline bool operator!=(const U* aLhs, const RefPtr<T>& aRhs) {
528 return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
529}
530
531template <class T, class U>
532inline bool operator==(const RefPtr<T>& aLhs, U* aRhs) {
533 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
534}
535
536template <class T, class U>
537inline bool operator==(U* aLhs, const RefPtr<T>& aRhs) {
538 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
539}
540
541template <class T, class U>
542inline bool operator!=(const RefPtr<T>& aLhs, U* aRhs) {
543 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
544}
545
546template <class T, class U>
547inline bool operator!=(U* aLhs, const RefPtr<T>& aRhs) {
548 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
549}
550
551// Comparing an |RefPtr| to |nullptr|
552
553template <class T>
554inline bool operator==(const RefPtr<T>& aLhs, decltype(nullptr)) {
555 return aLhs.get() == nullptr;
556}
557
558template <class T>
559inline bool operator==(decltype(nullptr), const RefPtr<T>& aRhs) {
560 return nullptr == aRhs.get();
561}
562
563template <class T>
564inline bool operator!=(const RefPtr<T>& aLhs, decltype(nullptr)) {
565 return aLhs.get() != nullptr;
566}
567
568template <class T>
569inline bool operator!=(decltype(nullptr), const RefPtr<T>& aRhs) {
570 return nullptr != aRhs.get();
571}
572
573// MOZ_DBG support
574
575template <class T>
576std::ostream& operator<<(std::ostream& aOut, const RefPtr<T>& aObj) {
577 return mozilla::DebugValue(aOut, aObj.get());
578}
579
580/*****************************************************************************/
581
582template <class T>
583inline already_AddRefed<T> do_AddRef(T* aObj) {
584 RefPtr<T> ref(aObj);
585 return ref.forget();
586}
587
588template <class T>
589inline already_AddRefed<T> do_AddRef(const RefPtr<T>& aObj) {
590 RefPtr<T> ref(aObj);
591 return ref.forget();
592}
593
594namespace mozilla {
595
596template <typename T>
597class AlignmentFinder;
598
599// Provide a specialization of AlignmentFinder to allow MOZ_ALIGNOF(RefPtr<T>)
600// with an incomplete T.
601template <typename T>
602class AlignmentFinder<RefPtr<T>> {
603 public:
604 static const size_t alignment = alignof(T*);
605};
606
607/**
608 * Helper function to be able to conveniently write things like:
609 *
610 * already_AddRefed<T>
611 * f(...)
612 * {
613 * return MakeAndAddRef<T>(...);
614 * }
615 */
616template <typename T, typename... Args>
617already_AddRefed<T> MakeAndAddRef(Args&&... aArgs) {
618 RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
619 return p.forget();
620}
621
622/**
623 * Helper function to be able to conveniently write things like:
624 *
625 * auto runnable =
626 * MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
627 * mOnSuccess, mOnFailure, *error, mWindowID);
628 */
629template <typename T, typename... Args>
630RefPtr<T> MakeRefPtr(Args&&... aArgs) {
631 RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
632 return p;
633}
634
635} // namespace mozilla
636
637/**
638 * Deduction guide to allow simple `RefPtr` definitions from an
639 * already_AddRefed<T> without repeating the type, e.g.:
640 *
641 * RefPtr ptr = MakeAndAddRef<SomeType>(...);
642 */
643template <typename T>
644RefPtr(already_AddRefed<T>) -> RefPtr<T>;
645
646#endif /* mozilla_RefPtr_h */