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-19/lib/clang/19 -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 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-19/lib/clang/19/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-2024-09-22-115206-3586786-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((sizeof(table) / sizeof(table[0])) > 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 { static_assert( mozilla::detail
::AssertionConditionType<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2482); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "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
2842bool nsGlobalWindowOuter::ConfirmDialogIfNeeded() {
2843 NS_ENSURE_TRUE(mDocShell, false)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"
, 2843); return false; } } while (false)
;
2844 nsCOMPtr<nsIPromptService> promptSvc =
2845 do_GetService("@mozilla.org/prompter;1");
2846
2847 if (!promptSvc) {
2848 return true;
2849 }
2850
2851 // Reset popup state while opening a modal dialog, and firing events
2852 // about the dialog, to prevent the current state from being active
2853 // the whole time a modal dialog is open.
2854 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
2855
2856 bool disableDialog = false;
2857 nsAutoString label, title;
2858 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2859 "ScriptDialogLabel", label);
2860 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2861 "ScriptDialogPreventTitle", title);
2862 promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
2863 if (disableDialog) {
2864 DisableDialogs();
2865 return false;
2866 }
2867
2868 return true;
2869}
2870
2871void nsGlobalWindowOuter::DisableDialogs() {
2872 BrowsingContextGroup* group = mBrowsingContext->Group();
2873 if (!group) {
2874 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"
, 2874); MOZ_PretendNoReturn(); } while (0)
;
2875 return;
2876 }
2877
2878 if (group) {
2879 group->SetAreDialogsEnabled(false);
2880 }
2881}
2882
2883void nsGlobalWindowOuter::EnableDialogs() {
2884 BrowsingContextGroup* group = mBrowsingContext->Group();
2885 if (!group) {
2886 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"
, 2886); MOZ_PretendNoReturn(); } while (0)
;
2887 return;
2888 }
2889
2890 if (group) {
2891 group->SetAreDialogsEnabled(true);
2892 }
2893}
2894
2895nsresult nsGlobalWindowOuter::PostHandleEvent(EventChainPostVisitor& aVisitor) {
2896 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"
, 2896); AnnotateMozCrashReason("MOZ_CRASH(" "The outer window should not be part of an event path"
")"); do { *((volatile int*)__null) = 2896; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2897}
2898
2899void nsGlobalWindowOuter::PoisonOuterWindowProxy(JSObject* aObject) {
2900 if (aObject == GetWrapperMaybeDead()) {
2901 PoisonWrapper();
2902 }
2903}
2904
2905nsresult nsGlobalWindowOuter::SetArguments(nsIArray* aArguments) {
2906 nsresult rv;
2907
2908 // We've now mostly separated them, but the difference is still opaque to
2909 // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
2910 // embedding waltz we do here).
2911 //
2912 // So we need to demultiplex the two cases here.
2913 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(this);
2914
2915 mArguments = aArguments;
2916 rv = currentInner->DefineArgumentsProperty(aArguments);
2917 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"
, 2917); return rv; } } while (false)
;
2918
2919 return NS_OK;
2920}
2921
2922//*****************************************************************************
2923// nsGlobalWindowOuter::nsIScriptObjectPrincipal
2924//*****************************************************************************
2925
2926nsIPrincipal* nsGlobalWindowOuter::GetPrincipal() {
2927 if (mDoc) {
2928 // If we have a document, get the principal from the document
2929 return mDoc->NodePrincipal();
2930 }
2931
2932 if (mDocumentPrincipal) {
2933 return mDocumentPrincipal;
2934 }
2935
2936 // If we don't have a principal and we don't have a document we
2937 // ask the parent window for the principal. This can happen when
2938 // loading a frameset that has a <frame src="javascript:xxx">, in
2939 // that case the global window is used in JS before we've loaded
2940 // a document into the window.
2941
2942 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2943 do_QueryInterface(GetInProcessParentInternal());
2944
2945 if (objPrincipal) {
2946 return objPrincipal->GetPrincipal();
2947 }
2948
2949 return nullptr;
2950}
2951
2952nsIPrincipal* nsGlobalWindowOuter::GetEffectiveCookiePrincipal() {
2953 if (mDoc) {
2954 // If we have a document, get the principal from the document
2955 return mDoc->EffectiveCookiePrincipal();
2956 }
2957
2958 if (mDocumentCookiePrincipal) {
2959 return mDocumentCookiePrincipal;
2960 }
2961
2962 // If we don't have a cookie principal and we don't have a document we ask
2963 // the parent window for the cookie principal.
2964
2965 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2966 do_QueryInterface(GetInProcessParentInternal());
2967
2968 if (objPrincipal) {
2969 return objPrincipal->GetEffectiveCookiePrincipal();
2970 }
2971
2972 return nullptr;
2973}
2974
2975nsIPrincipal* nsGlobalWindowOuter::GetEffectiveStoragePrincipal() {
2976 if (mDoc) {
2977 // If we have a document, get the principal from the document
2978 return mDoc->EffectiveStoragePrincipal();
2979 }
2980
2981 if (mDocumentStoragePrincipal) {
2982 return mDocumentStoragePrincipal;
2983 }
2984
2985 // If we don't have a storage principal and we don't have a document we ask
2986 // the parent window for the storage principal.
2987
2988 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2989 do_QueryInterface(GetInProcessParentInternal());
2990
2991 if (objPrincipal) {
2992 return objPrincipal->GetEffectiveStoragePrincipal();
2993 }
2994
2995 return nullptr;
2996}
2997
2998nsIPrincipal* nsGlobalWindowOuter::PartitionedPrincipal() {
2999 if (mDoc) {
3000 // If we have a document, get the principal from the document
3001 return mDoc->PartitionedPrincipal();
3002 }
3003
3004 if (mDocumentPartitionedPrincipal) {
3005 return mDocumentPartitionedPrincipal;
3006 }
3007
3008 // If we don't have a partitioned principal and we don't have a document we
3009 // ask the parent window for the partitioned principal.
3010
3011 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
3012 do_QueryInterface(GetInProcessParentInternal());
3013
3014 if (objPrincipal) {
3015 return objPrincipal->PartitionedPrincipal();
3016 }
3017
3018 return nullptr;
3019}
3020
3021//*****************************************************************************
3022// nsGlobalWindowOuter::nsIDOMWindow
3023//*****************************************************************************
3024
3025Element* nsPIDOMWindowOuter::GetFrameElementInternal() const {
3026 return mFrameElement;
3027}
3028
3029void nsPIDOMWindowOuter::SetFrameElementInternal(Element* aFrameElement) {
3030 mFrameElement = aFrameElement;
3031}
3032
3033Navigator* nsGlobalWindowOuter::GetNavigator() {
3034 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"
, 3034); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Navigator (); } while (0)
;
3035}
3036
3037nsScreen* nsGlobalWindowOuter::GetScreen() {
3038 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"
, 3038); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Screen (); } while (0)
;
3039}
3040
3041void nsPIDOMWindowOuter::ActivateMediaComponents() {
3042 if (!ShouldDelayMediaFromStart()) {
3043 return;
3044 }
3045 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)
3046 ("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)
3047 "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)
3048 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)
;
3049 if (BrowsingContext* bc = GetBrowsingContext()) {
3050 Unused << bc->Top()->SetShouldDelayMediaFromStart(false);
3051 }
3052 NotifyResumingDelayedMedia();
3053}
3054
3055bool nsPIDOMWindowOuter::ShouldDelayMediaFromStart() const {
3056 BrowsingContext* bc = GetBrowsingContext();
3057 return bc && bc->Top()->GetShouldDelayMediaFromStart();
3058}
3059
3060void nsPIDOMWindowOuter::NotifyResumingDelayedMedia() {
3061 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
3062 if (service) {
3063 service->NotifyResumingDelayedMedia(this);
3064 }
3065}
3066
3067bool nsPIDOMWindowOuter::GetAudioMuted() const {
3068 BrowsingContext* bc = GetBrowsingContext();
3069 return bc && bc->Top()->GetMuted();
3070}
3071
3072void nsPIDOMWindowOuter::RefreshMediaElementsVolume() {
3073 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
3074 if (service) {
3075 // TODO: RefreshAgentsVolume can probably be simplified further.
3076 service->RefreshAgentsVolume(this, 1.0f, GetAudioMuted());
3077 }
3078}
3079
3080mozilla::dom::BrowsingContextGroup*
3081nsPIDOMWindowOuter::GetBrowsingContextGroup() const {
3082 return mBrowsingContext ? mBrowsingContext->Group() : nullptr;
3083}
3084
3085Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetParentOuter() {
3086 BrowsingContext* bc = GetBrowsingContext();
3087 return bc ? bc->GetParent(IgnoreErrors()) : nullptr;
3088}
3089
3090/**
3091 * GetInProcessScriptableParent used to be called when a script read
3092 * window.parent. Under Fission, that is now handled by
3093 * BrowsingContext::GetParent, and the result is a WindowProxyHolder rather than
3094 * an actual global window. This method still exists for legacy callers which
3095 * relied on the old logic, and require in-process windows. However, it only
3096 * works correctly when no out-of-process frames exist between this window and
3097 * the top-level window, so it should not be used in new code.
3098 *
3099 * In contrast to GetRealParent, GetInProcessScriptableParent respects <iframe
3100 * mozbrowser> boundaries, so if |this| is contained by an <iframe
3101 * mozbrowser>, we will return |this| as its own parent.
3102 */
3103nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableParent() {
3104 if (!mDocShell) {
3105 return nullptr;
3106 }
3107
3108 if (BrowsingContext* parentBC = GetBrowsingContext()->GetParent()) {
3109 if (nsCOMPtr<nsPIDOMWindowOuter> parent = parentBC->GetDOMWindow()) {
3110 return parent;
3111 }
3112 }
3113 return this;
3114}
3115
3116/**
3117 * Behavies identically to GetInProcessScriptableParent extept that it returns
3118 * null if GetInProcessScriptableParent would return this window.
3119 */
3120nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableParentOrNull() {
3121 nsPIDOMWindowOuter* parent = GetInProcessScriptableParent();
3122 return (nsGlobalWindowOuter::Cast(parent) == this) ? nullptr : parent;
3123}
3124
3125already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetInProcessParent() {
3126 if (!mDocShell) {
3127 return nullptr;
3128 }
3129
3130 if (auto* parentBC = GetBrowsingContext()->GetParent()) {
3131 if (auto* parent = parentBC->GetDOMWindow()) {
3132 return do_AddRef(parent);
3133 }
3134 }
3135 return do_AddRef(this);
3136}
3137
3138static nsresult GetTopImpl(nsGlobalWindowOuter* aWin, nsIURI* aURIBeingLoaded,
3139 nsPIDOMWindowOuter** aTop, bool aScriptable,
3140 bool aExcludingExtensionAccessibleContentFrames) {
3141 *aTop = nullptr;
3142
3143 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"
, 3143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aScriptable"
")"); do { *((volatile int*)__null) = 3143; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3144
3145 // Walk up the parent chain.
3146
3147 nsCOMPtr<nsPIDOMWindowOuter> prevParent = aWin;
3148 nsCOMPtr<nsPIDOMWindowOuter> parent = aWin;
3149 do {
3150 if (!parent) {
3151 break;
3152 }
3153
3154 prevParent = parent;
3155
3156 if (aScriptable) {
3157 parent = parent->GetInProcessScriptableParent();
3158 } else {
3159 parent = parent->GetInProcessParent();
3160 }
3161
3162 if (aExcludingExtensionAccessibleContentFrames) {
3163 if (auto* p = nsGlobalWindowOuter::Cast(parent)) {
3164 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(p);
3165 nsIURI* uri = prevParent->GetDocumentURI();
3166 if (!uri) {
3167 // If our parent doesn't have a URI yet, we have a document that is in
3168 // the process of being loaded. In that case, our caller is
3169 // responsible for passing in the URI for the document that is being
3170 // loaded, so we fall back to using that URI here.
3171 uri = aURIBeingLoaded;
3172 }
3173
3174 if (currentInner && uri) {
3175 // If we find an inner window, we better find the uri for the current
3176 // window we're looking at. If we can't find it directly, it is the
3177 // responsibility of our caller to provide it to us.
3178 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"
, 3178); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "uri"
")"); do { *((volatile int*)__null) = 3178; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3179
3180 // If the new parent has permission to load the current page, we're
3181 // at a moz-extension:// frame which has a host permission that allows
3182 // it to load the document that we've loaded. In that case, stop at
3183 // this frame and consider it the top-level frame.
3184 //
3185 // Note that it's possible for the set of URIs accepted by
3186 // AddonAllowsLoad() to change at runtime, but we don't need to cache
3187 // the result of this check, since the important consumer of this code
3188 // (which is nsIHttpChannelInternal.topWindowURI) already caches the
3189 // result after computing it the first time.
3190 if (BasePrincipal::Cast(p->GetPrincipal())
3191 ->AddonAllowsLoad(uri, true)) {
3192 parent = prevParent;
3193 break;
3194 }
3195 }
3196 }
3197 }
3198
3199 } while (parent != prevParent);
3200
3201 if (parent) {
3202 parent.swap(*aTop);
3203 }
3204
3205 return NS_OK;
3206}
3207
3208/**
3209 * GetInProcessScriptableTop used to be called when a script read window.top.
3210 * Under Fission, that is now handled by BrowsingContext::Top, and the result is
3211 * a WindowProxyHolder rather than an actual global window. This method still
3212 * exists for legacy callers which relied on the old logic, and require
3213 * in-process windows. However, it only works correctly when no out-of-process
3214 * frames exist between this window and the top-level window, so it should not
3215 * be used in new code.
3216 *
3217 * In contrast to GetRealTop, GetInProcessScriptableTop respects <iframe
3218 * mozbrowser> boundaries. If we encounter a window owned by an <iframe
3219 * mozbrowser> while walking up the window hierarchy, we'll stop and return that
3220 * window.
3221 */
3222nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableTop() {
3223 nsCOMPtr<nsPIDOMWindowOuter> window;
3224 GetTopImpl(this, /* aURIBeingLoaded = */ nullptr, getter_AddRefs(window),
3225 /* aScriptable = */ true,
3226 /* aExcludingExtensionAccessibleContentFrames = */ false);
3227 return window.get();
3228}
3229
3230already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetInProcessTop() {
3231 nsCOMPtr<nsPIDOMWindowOuter> window;
3232 GetTopImpl(this, /* aURIBeingLoaded = */ nullptr, getter_AddRefs(window),
3233 /* aScriptable = */ false,
3234 /* aExcludingExtensionAccessibleContentFrames = */ false);
3235 return window.forget();
3236}
3237
3238already_AddRefed<nsPIDOMWindowOuter>
3239nsGlobalWindowOuter::GetTopExcludingExtensionAccessibleContentFrames(
3240 nsIURI* aURIBeingLoaded) {
3241 // There is a parent-process equivalent of this in DocumentLoadListener.cpp
3242 // GetTopWindowExcludingExtensionAccessibleContentFrames
3243 nsCOMPtr<nsPIDOMWindowOuter> window;
3244 GetTopImpl(this, aURIBeingLoaded, getter_AddRefs(window),
3245 /* aScriptable = */ false,
3246 /* aExcludingExtensionAccessibleContentFrames = */ true);
3247 return window.forget();
3248}
3249
3250void nsGlobalWindowOuter::GetContentOuter(JSContext* aCx,
3251 JS::MutableHandle<JSObject*> aRetval,
3252 CallerType aCallerType,
3253 ErrorResult& aError) {
3254 RefPtr<BrowsingContext> content = GetContentInternal(aCallerType, aError);
3255 if (aError.Failed()) {
3256 return;
3257 }
3258
3259 if (!content) {
3260 aRetval.set(nullptr);
3261 return;
3262 }
3263
3264 JS::Rooted<JS::Value> val(aCx);
3265 if (!ToJSValue(aCx, WindowProxyHolder{content}, &val)) {
3266 aError.Throw(NS_ERROR_UNEXPECTED);
3267 return;
3268 }
3269
3270 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"
, 3270); AnnotateMozCrashReason("MOZ_ASSERT" "(" "val.isObjectOrNull()"
")"); do { *((volatile int*)__null) = 3270; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3271 aRetval.set(val.toObjectOrNull());
3272}
3273
3274already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetContentInternal(
3275 CallerType aCallerType, ErrorResult& aError) {
3276 // First check for a named frame named "content"
3277 if (RefPtr<BrowsingContext> named = GetChildWindow(u"content"_ns)) {
3278 return named.forget();
3279 }
3280
3281 // If we're in the parent process, and being called by system code, `content`
3282 // should return the current primary content frame (if it's in-process).
3283 //
3284 // We return `nullptr` if the current primary content frame is out-of-process,
3285 // rather than a remote window proxy, as that is the existing behaviour as of
3286 // bug 1597437.
3287 if (XRE_IsParentProcess() && aCallerType == CallerType::System) {
3288 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
3289 if (!treeOwner) {
3290 aError.Throw(NS_ERROR_FAILURE);
3291 return nullptr;
3292 }
3293
3294 nsCOMPtr<nsIDocShellTreeItem> primaryContent;
3295 treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
3296 if (!primaryContent) {
3297 return nullptr;
3298 }
3299
3300 return do_AddRef(primaryContent->GetBrowsingContext());
3301 }
3302
3303 // For legacy untrusted callers we always return the same value as
3304 // `window.top`
3305 if (mDoc && aCallerType != CallerType::System) {
3306 mDoc->WarnOnceAbout(DeprecatedOperations::eWindowContentUntrusted);
3307 }
3308
3309 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"
, 3309); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBrowsingContext->IsContent()"
")"); do { *((volatile int*)__null) = 3309; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3310 return do_AddRef(mBrowsingContext->Top());
3311}
3312
3313nsresult nsGlobalWindowOuter::GetPrompter(nsIPrompt** aPrompt) {
3314 if (!mDocShell) return NS_ERROR_FAILURE;
3315
3316 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
3317 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"
, 3317); return NS_ERROR_NO_INTERFACE; } } while (false)
;
3318
3319 prompter.forget(aPrompt);
3320 return NS_OK;
3321}
3322
3323bool nsGlobalWindowOuter::GetClosedOuter() {
3324 // If someone called close(), or if we don't have a docshell, we're closed.
3325 return mIsClosed || !mDocShell;
3326}
3327
3328bool nsGlobalWindowOuter::Closed() { return GetClosedOuter(); }
3329
3330Nullable<WindowProxyHolder> nsGlobalWindowOuter::IndexedGetterOuter(
3331 uint32_t aIndex) {
3332 BrowsingContext* bc = GetBrowsingContext();
3333 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"
, 3333); return nullptr; } } while (false)
;
3334
3335 Span<RefPtr<BrowsingContext>> children = bc->NonSyntheticChildren();
3336
3337 if (aIndex < children.Length()) {
3338 return WindowProxyHolder(children[aIndex]);
3339 }
3340 return nullptr;
3341}
3342
3343nsIControllers* nsGlobalWindowOuter::GetControllersOuter(ErrorResult& aError) {
3344 if (!mControllers) {
3345 mControllers = new nsXULControllers();
3346 if (!mControllers) {
3347 aError.Throw(NS_ERROR_FAILURE);
3348 return nullptr;
3349 }
3350
3351 // Add in the default controller
3352 RefPtr<nsBaseCommandController> commandController =
3353 nsBaseCommandController::CreateWindowController();
3354 if (!commandController) {
3355 aError.Throw(NS_ERROR_FAILURE);
3356 return nullptr;
3357 }
3358
3359 mControllers->InsertControllerAt(0, commandController);
3360 commandController->SetCommandContext(static_cast<nsIDOMWindow*>(this));
3361 }
3362
3363 return mControllers;
3364}
3365
3366nsresult nsGlobalWindowOuter::GetControllers(nsIControllers** aResult) {
3367 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"
, 3367); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetControllers (aResult); } while (0)
;
3368}
3369
3370already_AddRefed<BrowsingContext>
3371nsGlobalWindowOuter::GetOpenerBrowsingContext() {
3372 RefPtr<BrowsingContext> opener = GetBrowsingContext()->GetOpener();
3373 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"
, 3374); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!opener || opener->Group() == GetBrowsingContext()->Group()"
")"); do { *((volatile int*)__null) = 3374; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3374 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"
, 3374); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!opener || opener->Group() == GetBrowsingContext()->Group()"
")"); do { *((volatile int*)__null) = 3374; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3375 if (!opener || opener->Group() != GetBrowsingContext()->Group()) {
3376 return nullptr;
3377 }
3378
3379 // Catch the case where we're chrome but the opener is not...
3380 if (nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
3381 GetPrincipal() == nsContentUtils::GetSystemPrincipal()) {
3382 auto* openerWin = nsGlobalWindowOuter::Cast(opener->GetDOMWindow());
3383 if (!openerWin ||
3384 openerWin->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
3385 return nullptr;
3386 }
3387 }
3388
3389 return opener.forget();
3390}
3391
3392nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSameProcessOpener() {
3393 if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
3394 return opener->GetDOMWindow();
3395 }
3396 return nullptr;
3397}
3398
3399Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpenerWindowOuter() {
3400 if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
3401 return WindowProxyHolder(std::move(opener));
3402 }
3403 return nullptr;
3404}
3405
3406Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpener() {
3407 return GetOpenerWindowOuter();
3408}
3409
3410void nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus) {
3411 aStatus = mStatus;
3412}
3413
3414void nsGlobalWindowOuter::SetStatusOuter(const nsAString& aStatus) {
3415 mStatus = aStatus;
3416
3417 // We don't support displaying window.status in the UI, so there's nothing
3418 // left to do here.
3419}
3420
3421void nsGlobalWindowOuter::GetNameOuter(nsAString& aName) {
3422 if (mDocShell) {
3423 mDocShell->GetName(aName);
3424 }
3425}
3426
3427void nsGlobalWindowOuter::SetNameOuter(const nsAString& aName,
3428 mozilla::ErrorResult& aError) {
3429 if (mDocShell) {
3430 aError = mDocShell->SetName(aName);
3431 }
3432}
3433
3434// NOTE: The idea of this function is that it should return the same as
3435// nsPresContext::CSSToDeviceScale() if it was in aWindow synchronously. For
3436// that, we use the UnscaledDevicePixelsPerCSSPixel() (which contains the device
3437// scale and the OS zoom scale) and then account for the browsing context full
3438// zoom. See the declaration of this function for context about why this is
3439// needed.
3440CSSToLayoutDeviceScale nsGlobalWindowOuter::CSSToDevScaleForBaseWindow(
3441 nsIBaseWindow* aWindow) {
3442 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"
, 3442); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { *((volatile int*)__null) = 3442; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3443 auto scale = aWindow->UnscaledDevicePixelsPerCSSPixel();
3444 if (mBrowsingContext) {
3445 scale.scale *= mBrowsingContext->FullZoom();
3446 }
3447 return scale;
3448}
3449
3450nsresult nsGlobalWindowOuter::GetInnerSize(CSSSize& aSize) {
3451 EnsureSizeAndPositionUpToDate();
3452
3453 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"
, 3453); return NS_ERROR_UNEXPECTED; } } while (false)
;
3454
3455 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3456 PresShell* presShell = mDocShell->GetPresShell();
3457
3458 if (!presContext || !presShell) {
3459 aSize = {};
3460 return NS_OK;
3461 }
3462
3463 // Whether or not the css viewport has been overridden, we can get the
3464 // correct value by looking at the visible area of the presContext.
3465 if (RefPtr<nsViewManager> viewManager = presShell->GetViewManager()) {
3466 viewManager->FlushDelayedResize();
3467 }
3468
3469 // FIXME: Bug 1598487 - Return the layout viewport instead of the ICB.
3470 nsSize viewportSize = presContext->GetVisibleArea().Size();
3471 if (presContext->GetDynamicToolbarState() == DynamicToolbarState::Collapsed) {
3472 viewportSize =
3473 nsLayoutUtils::ExpandHeightForViewportUnits(presContext, viewportSize);
3474 }
3475
3476 aSize = CSSPixel::FromAppUnits(viewportSize);
3477
3478 switch (StaticPrefs::dom_innerSize_rounding()) {
3479 case 1:
3480 aSize.width = std::roundf(aSize.width);
3481 aSize.height = std::roundf(aSize.height);
3482 break;
3483 case 2:
3484 aSize.width = std::truncf(aSize.width);
3485 aSize.height = std::truncf(aSize.height);
3486 break;
3487 default:
3488 break;
3489 }
3490
3491 return NS_OK;
3492}
3493
3494double nsGlobalWindowOuter::GetInnerWidthOuter(ErrorResult& aError) {
3495 CSSSize size;
3496 aError = GetInnerSize(size);
3497 return size.width;
3498}
3499
3500nsresult nsGlobalWindowOuter::GetInnerWidth(double* aInnerWidth) {
3501 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"
, 3501); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetInnerWidth (aInnerWidth); } while (0)
;
3502}
3503
3504double nsGlobalWindowOuter::GetInnerHeightOuter(ErrorResult& aError) {
3505 CSSSize size;
3506 aError = GetInnerSize(size);
3507 return size.height;
3508}
3509
3510nsresult nsGlobalWindowOuter::GetInnerHeight(double* aInnerHeight) {
3511 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"
, 3511); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetInnerHeight (aInnerHeight); } while (0)
;
3512}
3513
3514CSSIntSize nsGlobalWindowOuter::GetOuterSize(CallerType aCallerType,
3515 ErrorResult& aError) {
3516 if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
3517 RFPTarget::WindowOuterSize)) {
3518 if (BrowsingContext* bc = GetBrowsingContext()) {
3519 return bc->Top()->GetTopInnerSizeForRFP();
3520 }
3521 return {};
3522 }
3523
3524 // Windows showing documents in RDM panes and any subframes within them
3525 // return the simulated device size.
3526 if (mDoc) {
3527 Maybe<CSSIntSize> deviceSize = GetRDMDeviceSize(*mDoc);
3528 if (deviceSize.isSome()) {
3529 return *deviceSize;
3530 }
3531 }
3532
3533 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3534 if (!treeOwnerAsWin) {
3535 aError.Throw(NS_ERROR_FAILURE);
3536 return {};
3537 }
3538
3539 return RoundedToInt(treeOwnerAsWin->GetSize() /
3540 CSSToDevScaleForBaseWindow(treeOwnerAsWin));
3541}
3542
3543int32_t nsGlobalWindowOuter::GetOuterWidthOuter(CallerType aCallerType,
3544 ErrorResult& aError) {
3545 return GetOuterSize(aCallerType, aError).width;
3546}
3547
3548int32_t nsGlobalWindowOuter::GetOuterHeightOuter(CallerType aCallerType,
3549 ErrorResult& aError) {
3550 return GetOuterSize(aCallerType, aError).height;
3551}
3552
3553CSSPoint nsGlobalWindowOuter::ScreenEdgeSlop() {
3554 if (NS_WARN_IF(!mDocShell)NS_warn_if_impl(!mDocShell, "!mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3554)
) {
3555 return {};
3556 }
3557 RefPtr<nsPresContext> pc = mDocShell->GetPresContext();
3558 if (NS_WARN_IF(!pc)NS_warn_if_impl(!pc, "!pc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3558)
) {
3559 return {};
3560 }
3561 nsCOMPtr<nsIWidget> widget = GetMainWidget();
3562 if (NS_WARN_IF(!widget)NS_warn_if_impl(!widget, "!widget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3562)
) {
3563 return {};
3564 }
3565 LayoutDeviceIntPoint pt = widget->GetScreenEdgeSlop();
3566 auto auPoint =
3567 LayoutDeviceIntPoint::ToAppUnits(pt, pc->AppUnitsPerDevPixel());
3568 return CSSPoint::FromAppUnits(auPoint);
3569}
3570
3571CSSIntPoint nsGlobalWindowOuter::GetScreenXY(CallerType aCallerType,
3572 ErrorResult& aError) {
3573 // When resisting fingerprinting, always return (0,0)
3574 if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
3575 RFPTarget::WindowScreenXY)) {
3576 return CSSIntPoint(0, 0);
3577 }
3578
3579 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3580 if (!treeOwnerAsWin) {
3581 aError.Throw(NS_ERROR_FAILURE);
3582 return CSSIntPoint(0, 0);
3583 }
3584
3585 LayoutDeviceIntPoint windowPos;
3586 aError = treeOwnerAsWin->GetPosition(&windowPos.x.value, &windowPos.y.value);
3587
3588 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3589 if (!presContext) {
3590 // XXX Fishy LayoutDevice to CSS conversion?
3591 return CSSIntPoint(windowPos.x, windowPos.y);
3592 }
3593
3594 nsDeviceContext* context = presContext->DeviceContext();
3595 auto windowPosAppUnits = LayoutDeviceIntPoint::ToAppUnits(
3596 windowPos, context->AppUnitsPerDevPixel());
3597 return CSSIntPoint::FromAppUnitsRounded(windowPosAppUnits);
3598}
3599
3600int32_t nsGlobalWindowOuter::GetScreenXOuter(CallerType aCallerType,
3601 ErrorResult& aError) {
3602 return GetScreenXY(aCallerType, aError).x;
3603}
3604
3605nsRect nsGlobalWindowOuter::GetInnerScreenRect() {
3606 if (!mDocShell) {
3607 return nsRect();
3608 }
3609
3610 EnsureSizeAndPositionUpToDate();
3611
3612 if (!mDocShell) {
3613 return nsRect();
3614 }
3615
3616 PresShell* presShell = mDocShell->GetPresShell();
3617 if (!presShell) {
3618 return nsRect();
3619 }
3620 nsIFrame* rootFrame = presShell->GetRootFrame();
3621 if (!rootFrame) {
3622 return nsRect();
3623 }
3624
3625 return rootFrame->GetScreenRectInAppUnits();
3626}
3627
3628Maybe<CSSIntSize> nsGlobalWindowOuter::GetRDMDeviceSize(
3629 const Document& aDocument) {
3630 // RDM device size should reflect the simulated device resolution, and
3631 // be independent of any full zoom or resolution zoom applied to the
3632 // content. To get this value, we get the "unscaled" browser child size,
3633 // and divide by the full zoom. "Unscaled" in this case means unscaled
3634 // from device to screen but it has been affected (multiplied) by the
3635 // full zoom and we need to compensate for that.
3636 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"
, 3636); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3636; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3637
3638 // Bug 1576256: This does not work for cross-process subframes.
3639 const Document* topInProcessContentDoc =
3640 aDocument.GetTopLevelContentDocumentIfSameProcess();
3641 BrowsingContext* bc = topInProcessContentDoc
3642 ? topInProcessContentDoc->GetBrowsingContext()
3643 : nullptr;
3644 if (bc && bc->InRDMPane()) {
3645 nsIDocShell* docShell = topInProcessContentDoc->GetDocShell();
3646 if (docShell) {
3647 nsPresContext* presContext = docShell->GetPresContext();
3648 if (presContext) {
3649 nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild();
3650 if (child) {
3651 // We intentionally use GetFullZoom here instead of
3652 // GetDeviceFullZoom, because the unscaledInnerSize is based
3653 // on the full zoom and not the device full zoom (which is
3654 // rounded to result in integer device pixels).
3655 float zoom = presContext->GetFullZoom();
3656 BrowserChild* bc = static_cast<BrowserChild*>(child.get());
3657 CSSSize unscaledSize = bc->GetUnscaledInnerSize();
3658 return Some(CSSIntSize(gfx::RoundedToInt(unscaledSize / zoom)));
3659 }
3660 }
3661 }
3662 }
3663 return Nothing();
3664}
3665
3666float nsGlobalWindowOuter::GetMozInnerScreenXOuter(CallerType aCallerType) {
3667 // When resisting fingerprinting, always return 0.
3668 if (nsIGlobalObject::ShouldResistFingerprinting(
3669 aCallerType, RFPTarget::WindowInnerScreenXY)) {
3670 return 0.0;
3671 }
3672
3673 nsRect r = GetInnerScreenRect();
3674 return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3675}
3676
3677float nsGlobalWindowOuter::GetMozInnerScreenYOuter(CallerType aCallerType) {
3678 // Return 0 to prevent fingerprinting.
3679 if (nsIGlobalObject::ShouldResistFingerprinting(
3680 aCallerType, RFPTarget::WindowInnerScreenXY)) {
3681 return 0.0;
3682 }
3683
3684 nsRect r = GetInnerScreenRect();
3685 return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3686}
3687
3688int32_t nsGlobalWindowOuter::GetScreenYOuter(CallerType aCallerType,
3689 ErrorResult& aError) {
3690 return GetScreenXY(aCallerType, aError).y;
3691}
3692
3693// NOTE: Arguments to this function should have values scaled to
3694// CSS pixels, not device pixels.
3695void nsGlobalWindowOuter::CheckSecurityWidthAndHeight(int32_t* aWidth,
3696 int32_t* aHeight,
3697 CallerType aCallerType) {
3698 if (aCallerType != CallerType::System) {
3699 // if attempting to resize the window, hide any open popups
3700 nsContentUtils::HidePopupsInDocument(mDoc);
3701 }
3702
3703 // This one is easy. Just ensure the variable is greater than 100;
3704 if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
3705 // Check security state for use in determing window dimensions
3706
3707 if (aCallerType != CallerType::System) {
3708 // sec check failed
3709 if (aWidth && *aWidth < 100) {
3710 *aWidth = 100;
3711 }
3712 if (aHeight && *aHeight < 100) {
3713 *aHeight = 100;
3714 }
3715 }
3716 }
3717}
3718
3719// NOTE: Arguments to this function should have values in app units
3720void nsGlobalWindowOuter::SetCSSViewportWidthAndHeight(nscoord aInnerWidth,
3721 nscoord aInnerHeight) {
3722 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3723
3724 nsRect shellArea = presContext->GetVisibleArea();
3725 shellArea.SetHeight(aInnerHeight);
3726 shellArea.SetWidth(aInnerWidth);
3727
3728 // FIXME(emilio): This doesn't seem to be ok, this doesn't reflow or
3729 // anything... Should go through PresShell::ResizeReflow.
3730 //
3731 // But I don't think this can be reached by content, as we don't allow to set
3732 // inner{Width,Height}.
3733 presContext->SetVisibleArea(shellArea);
3734}
3735
3736// NOTE: Arguments to this function should have values scaled to
3737// CSS pixels, not device pixels.
3738void nsGlobalWindowOuter::CheckSecurityLeftAndTop(int32_t* aLeft, int32_t* aTop,
3739 CallerType aCallerType) {
3740 // This one is harder. We have to get the screen size and window dimensions.
3741
3742 // Check security state for use in determing window dimensions
3743
3744 if (aCallerType != CallerType::System) {
3745 // if attempting to move the window, hide any open popups
3746 nsContentUtils::HidePopupsInDocument(mDoc);
3747
3748 if (nsGlobalWindowOuter* rootWindow =
3749 nsGlobalWindowOuter::Cast(GetPrivateRoot())) {
3750 rootWindow->FlushPendingNotifications(FlushType::Layout);
3751 }
3752
3753 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3754
3755 RefPtr<nsScreen> screen = GetScreen();
3756
3757 if (treeOwnerAsWin && screen) {
3758 CSSToLayoutDeviceScale scale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
3759 CSSIntRect winRect =
3760 CSSIntRect::Round(treeOwnerAsWin->GetPositionAndSize() / scale);
3761
3762 // Get the screen dimensions
3763 // XXX This should use nsIScreenManager once it's fully fleshed out.
3764 int32_t screenLeft = screen->AvailLeft();
3765 int32_t screenWidth = screen->AvailWidth();
3766 int32_t screenHeight = screen->AvailHeight();
3767#if defined(XP_MACOSX)
3768 /* The mac's coordinate system is different from the assumed Windows'
3769 system. It offsets by the height of the menubar so that a window
3770 placed at (0,0) will be entirely visible. Unfortunately that
3771 correction is made elsewhere (in Widget) and the meaning of
3772 the Avail... coordinates is overloaded. Here we allow a window
3773 to be placed at (0,0) because it does make sense to do so.
3774 */
3775 int32_t screenTop = screen->Top();
3776#else
3777 int32_t screenTop = screen->AvailTop();
3778#endif
3779
3780 if (aLeft) {
3781 if (screenLeft + screenWidth < *aLeft + winRect.width)
3782 *aLeft = screenLeft + screenWidth - winRect.width;
3783 if (screenLeft > *aLeft) *aLeft = screenLeft;
3784 }
3785 if (aTop) {
3786 if (screenTop + screenHeight < *aTop + winRect.height)
3787 *aTop = screenTop + screenHeight - winRect.height;
3788 if (screenTop > *aTop) *aTop = screenTop;
3789 }
3790 } else {
3791 if (aLeft) *aLeft = 0;
3792 if (aTop) *aTop = 0;
3793 }
3794 }
3795}
3796
3797int32_t nsGlobalWindowOuter::GetScrollBoundaryOuter(Side aSide) {
3798 FlushPendingNotifications(FlushType::Layout);
3799 if (ScrollContainerFrame* sf = GetScrollContainerFrame()) {
3800 return nsPresContext::AppUnitsToIntCSSPixels(
3801 sf->GetScrollRange().Edge(aSide));
3802 }
3803 return 0;
3804}
3805
3806CSSPoint nsGlobalWindowOuter::GetScrollXY(bool aDoFlush) {
3807 if (aDoFlush) {
3808 FlushPendingNotifications(FlushType::Layout);
3809 } else {
3810 EnsureSizeAndPositionUpToDate();
3811 }
3812
3813 ScrollContainerFrame* sf = GetScrollContainerFrame();
3814 if (!sf) {
3815 return CSSIntPoint(0, 0);
3816 }
3817
3818 nsPoint scrollPos = sf->GetScrollPosition();
3819 if (scrollPos != nsPoint(0, 0) && !aDoFlush) {
3820 // Oh, well. This is the expensive case -- the window is scrolled and we
3821 // didn't actually flush yet. Repeat, but with a flush, since the content
3822 // may get shorter and hence our scroll position may decrease.
3823 return GetScrollXY(true);
3824 }
3825
3826 return CSSPoint::FromAppUnits(scrollPos);
3827}
3828
3829double nsGlobalWindowOuter::GetScrollXOuter() { return GetScrollXY(false).x; }
3830
3831double nsGlobalWindowOuter::GetScrollYOuter() { return GetScrollXY(false).y; }
3832
3833uint32_t nsGlobalWindowOuter::Length() {
3834 BrowsingContext* bc = GetBrowsingContext();
3835 return bc ? bc->NonSyntheticChildren().Length() : 0;
3836}
3837
3838Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetTopOuter() {
3839 BrowsingContext* bc = GetBrowsingContext();
3840 return bc ? bc->GetTop(IgnoreErrors()) : nullptr;
3841}
3842
3843already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetChildWindow(
3844 const nsAString& aName) {
3845 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"
, 3845); return nullptr; } } while (false)
;
3846 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"
, 3846); return nullptr; } } while (false)
;
3847 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"
, 3847); return nullptr; } } while (false)
;
3848
3849 return do_AddRef(mBrowsingContext->FindChildWithName(
3850 aName, *mInnerWindow->GetWindowGlobalChild()));
3851}
3852
3853bool nsGlobalWindowOuter::DispatchCustomEvent(
3854 const nsAString& aEventName, ChromeOnlyDispatch aChromeOnlyDispatch) {
3855 bool defaultActionEnabled = true;
3856
3857 if (aChromeOnlyDispatch == ChromeOnlyDispatch::eYes) {
3858 nsContentUtils::DispatchEventOnlyToChrome(mDoc, this, aEventName,
3859 CanBubble::eYes, Cancelable::eYes,
3860 &defaultActionEnabled);
3861 } else {
3862 nsContentUtils::DispatchTrustedEvent(mDoc, this, aEventName,
3863 CanBubble::eYes, Cancelable::eYes,
3864 &defaultActionEnabled);
3865 }
3866
3867 return defaultActionEnabled;
3868}
3869
3870bool nsGlobalWindowOuter::DispatchResizeEvent(const CSSIntSize& aSize) {
3871 ErrorResult res;
3872 RefPtr<Event> domEvent =
3873 mDoc->CreateEvent(u"CustomEvent"_ns, CallerType::System, res);
3874 if (res.Failed()) {
3875 return false;
3876 }
3877
3878 // We don't init the AutoJSAPI with ourselves because we don't want it
3879 // reporting errors to our onerror handlers.
3880 AutoJSAPI jsapi;
3881 jsapi.Init();
3882 JSContext* cx = jsapi.cx();
3883 JSAutoRealm ar(cx, GetWrapperPreserveColor());
3884
3885 DOMWindowResizeEventDetail detail;
3886 detail.mWidth = aSize.width;
3887 detail.mHeight = aSize.height;
3888 JS::Rooted<JS::Value> detailValue(cx);
3889 if (!ToJSValue(cx, detail, &detailValue)) {
3890 return false;
3891 }
3892
3893 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
3894 customEvent->InitCustomEvent(cx, u"DOMWindowResize"_ns,
3895 /* aCanBubble = */ true,
3896 /* aCancelable = */ true, detailValue);
3897
3898 domEvent->SetTrusted(true);
3899 domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
3900
3901 nsCOMPtr<EventTarget> target = this;
3902 domEvent->SetTarget(target);
3903
3904 return target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
3905}
3906
3907bool nsGlobalWindowOuter::WindowExists(const nsAString& aName,
3908 bool aForceNoOpener,
3909 bool aLookForCallerOnJSStack) {
3910 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"
, 3910); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocShell" ") ("
"Must have docshell" ")"); do { *((volatile int*)__null) = 3910
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3911
3912 if (aForceNoOpener) {
3913 return aName.LowerCaseEqualsLiteral("_self") ||
3914 aName.LowerCaseEqualsLiteral("_top") ||
3915 aName.LowerCaseEqualsLiteral("_parent");
3916 }
3917
3918 if (WindowGlobalChild* wgc = mInnerWindow->GetWindowGlobalChild()) {
3919 return wgc->FindBrowsingContextWithName(aName, aLookForCallerOnJSStack);
3920 }
3921 return false;
3922}
3923
3924already_AddRefed<nsIWidget> nsGlobalWindowOuter::GetMainWidget() {
3925 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3926
3927 nsCOMPtr<nsIWidget> widget;
3928
3929 if (treeOwnerAsWin) {
3930 treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
3931 }
3932
3933 return widget.forget();
3934}
3935
3936nsIWidget* nsGlobalWindowOuter::GetNearestWidget() const {
3937 nsIDocShell* docShell = GetDocShell();
3938 if (!docShell) {
3939 return nullptr;
3940 }
3941 PresShell* presShell = docShell->GetPresShell();
3942 if (!presShell) {
3943 return nullptr;
3944 }
3945 nsIFrame* rootFrame = presShell->GetRootFrame();
3946 if (!rootFrame) {
3947 return nullptr;
3948 }
3949 return rootFrame->GetView()->GetNearestWidget(nullptr);
3950}
3951
3952void nsGlobalWindowOuter::SetFullscreenOuter(bool aFullscreen,
3953 mozilla::ErrorResult& aError) {
3954 aError =
3955 SetFullscreenInternal(FullscreenReason::ForFullscreenMode, aFullscreen);
3956}
3957
3958nsresult nsGlobalWindowOuter::SetFullScreen(bool aFullscreen) {
3959 return SetFullscreenInternal(FullscreenReason::ForFullscreenMode,
3960 aFullscreen);
3961}
3962
3963static void FinishDOMFullscreenChange(Document* aDoc, bool aInDOMFullscreen) {
3964 if (aInDOMFullscreen) {
3965 // Ask the document to handle any pending DOM fullscreen change.
3966 if (!Document::HandlePendingFullscreenRequests(aDoc)) {
3967 // If we don't end up having anything in fullscreen,
3968 // async request exiting fullscreen.
3969 Document::AsyncExitFullscreen(aDoc);
3970 }
3971 } else {
3972 // If the window is leaving fullscreen state, also ask the document
3973 // to exit from DOM Fullscreen.
3974 Document::ExitFullscreenInDocTree(aDoc);
3975 }
3976}
3977
3978struct FullscreenTransitionDuration {
3979 // The unit of the durations is millisecond
3980 uint16_t mFadeIn = 0;
3981 uint16_t mFadeOut = 0;
3982 bool IsSuppressed() const { return mFadeIn == 0 && mFadeOut == 0; }
3983};
3984
3985static void GetFullscreenTransitionDuration(
3986 bool aEnterFullscreen, FullscreenTransitionDuration* aDuration) {
3987 const char* pref = aEnterFullscreen
3988 ? "full-screen-api.transition-duration.enter"
3989 : "full-screen-api.transition-duration.leave";
3990 nsAutoCString prefValue;
3991 Preferences::GetCString(pref, prefValue);
3992 if (!prefValue.IsEmpty()) {
3993 sscanf(prefValue.get(), "%hu%hu", &aDuration->mFadeIn,
3994 &aDuration->mFadeOut);
3995 }
3996}
3997
3998class FullscreenTransitionTask : public Runnable {
3999 public:
4000 FullscreenTransitionTask(const FullscreenTransitionDuration& aDuration,
4001 nsGlobalWindowOuter* aWindow, bool aFullscreen,
4002 nsIWidget* aWidget, nsISupports* aTransitionData)
4003 : mozilla::Runnable("FullscreenTransitionTask"),
4004 mWindow(aWindow),
4005 mWidget(aWidget),
4006 mTransitionData(aTransitionData),
4007 mDuration(aDuration),
4008 mStage(eBeforeToggle),
4009 mFullscreen(aFullscreen) {}
4010
4011 NS_IMETHODvirtual nsresult Run() override;
4012
4013 private:
4014 ~FullscreenTransitionTask() override = default;
4015
4016 /**
4017 * The flow of fullscreen transition:
4018 *
4019 * parent process | child process
4020 * ----------------------------------------------------------------
4021 *
4022 * | request/exit fullscreen
4023 * <-----|
4024 * BeforeToggle stage |
4025 * |
4026 * ToggleFullscreen stage *1 |----->
4027 * | HandleFullscreenRequests
4028 * |
4029 * <-----| MozAfterPaint event
4030 * AfterToggle stage *2 |
4031 * |
4032 * End stage |
4033 *
4034 * Note we also start a timer at *1 so that if we don't get MozAfterPaint
4035 * from the child process in time, we continue going to *2.
4036 */
4037 enum Stage {
4038 // BeforeToggle stage happens before we enter or leave fullscreen
4039 // state. In this stage, the task triggers the pre-toggle fullscreen
4040 // transition on the widget.
4041 eBeforeToggle,
4042 // ToggleFullscreen stage actually executes the fullscreen toggle,
4043 // and wait for the next paint on the content to continue.
4044 eToggleFullscreen,
4045 // AfterToggle stage happens after we toggle the fullscreen state.
4046 // In this stage, the task triggers the post-toggle fullscreen
4047 // transition on the widget.
4048 eAfterToggle,
4049 // End stage is triggered after the final transition finishes.
4050 eEnd
4051 };
4052
4053 class Observer final : public nsIObserver, public nsINamed {
4054 public:
4055 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:
4056 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
4057 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
4058
4059 explicit Observer(FullscreenTransitionTask* aTask) : mTask(aTask) {}
4060
4061 private:
4062 ~Observer() = default;
4063
4064 RefPtr<FullscreenTransitionTask> mTask;
4065 };
4066
4067 static const char* const kPaintedTopic;
4068
4069 RefPtr<nsGlobalWindowOuter> mWindow;
4070 nsCOMPtr<nsIWidget> mWidget;
4071 nsCOMPtr<nsITimer> mTimer;
4072 nsCOMPtr<nsISupports> mTransitionData;
4073
4074 TimeStamp mFullscreenChangeStartTime;
4075 FullscreenTransitionDuration mDuration;
4076 Stage mStage;
4077 bool mFullscreen;
4078};
4079
4080const char* const FullscreenTransitionTask::kPaintedTopic =
4081 "fullscreen-painted";
4082
4083NS_IMETHODIMPnsresult
4084FullscreenTransitionTask::Run() {
4085 Stage stage = mStage;
4086 mStage = Stage(mStage + 1);
4087 if (MOZ_UNLIKELY(mWidget->Destroyed())(__builtin_expect(!!(mWidget->Destroyed()), 0))) {
4088 // If the widget has been destroyed before we get here, don't try to
4089 // do anything more. Just let it go and release ourselves.
4090 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"
, 4090)
;
4091 mWindow->mIsInFullScreenTransition = false;
4092 return NS_OK;
4093 }
4094 if (stage == eBeforeToggle) {
4095 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)
;
4096
4097 mWindow->mIsInFullScreenTransition = true;
4098
4099 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4100 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"
, 4100); return NS_ERROR_FAILURE; } } while (false)
;
4101 obs->NotifyObservers(nullptr, "fullscreen-transition-start", nullptr);
4102
4103 mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,
4104 mDuration.mFadeIn, mTransitionData,
4105 this);
4106 } else if (stage == eToggleFullscreen) {
4107 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)
;
4108 mFullscreenChangeStartTime = TimeStamp::Now();
4109 // Toggle the fullscreen state on the widget
4110 if (!mWindow->SetWidgetFullscreen(FullscreenReason::ForFullscreenAPI,
4111 mFullscreen, mWidget)) {
4112 // Fail to setup the widget, call FinishFullscreenChange to
4113 // complete fullscreen change directly.
4114 mWindow->FinishFullscreenChange(mFullscreen);
4115 }
4116 // Set observer for the next content paint.
4117 nsCOMPtr<nsIObserver> observer = new Observer(this);
4118 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4119 obs->AddObserver(observer, kPaintedTopic, false);
4120 // There are several edge cases where we may never get the paint
4121 // notification, including:
4122 // 1. the window/tab is closed before the next paint;
4123 // 2. the user has switched to another tab before we get here.
4124 // Completely fixing those cases seems to be tricky, and since they
4125 // should rarely happen, it probably isn't worth to fix. Hence we
4126 // simply add a timeout here to ensure we never hang forever.
4127 // In addition, if the page is complicated or the machine is less
4128 // powerful, layout could take a long time, in which case, staying
4129 // in black screen for that long could hurt user experience even
4130 // more than exposing an intermediate state.
4131 uint32_t timeout =
4132 Preferences::GetUint("full-screen-api.transition.timeout", 1000);
4133 NS_NewTimerWithObserver(getter_AddRefs(mTimer), observer, timeout,
4134 nsITimer::TYPE_ONE_SHOT);
4135 } else if (stage == eAfterToggle) {
4136 Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,
4137 mFullscreenChangeStartTime);
4138 mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
4139 mDuration.mFadeOut, mTransitionData,
4140 this);
4141 } else if (stage == eEnd) {
4142 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)
;
4143
4144 mWindow->mIsInFullScreenTransition = false;
4145
4146 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4147 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"
, 4147); return NS_ERROR_FAILURE; } } while (false)
;
4148 obs->NotifyObservers(nullptr, "fullscreen-transition-end", nullptr);
4149
4150 mWidget->CleanupFullscreenTransition();
4151 }
4152 return NS_OK;
4153}
4154
4155NS_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"
, 4155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
4155; __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"
, 4155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionTask::Observer\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 4155; __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"
, 4155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 4155
; __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"
, 4155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionTask::Observer\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 4155; __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"
, 4155); 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((sizeof
(table) / sizeof(table[0])) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
4156
4157NS_IMETHODIMPnsresult
4158FullscreenTransitionTask::Observer::Observe(nsISupports* aSubject,
4159 const char* aTopic,
4160 const char16_t* aData) {
4161 bool shouldContinue = false;
4162 if (strcmp(aTopic, FullscreenTransitionTask::kPaintedTopic) == 0) {
4163 nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aSubject));
4164 nsCOMPtr<nsIWidget> widget =
4165 win ? nsGlobalWindowInner::Cast(win)->GetMainWidget() : nullptr;
4166 if (widget == mTask->mWidget) {
4167 // The paint notification arrives first. Cancel the timer.
4168 mTask->mTimer->Cancel();
4169 shouldContinue = true;
4170 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)
;
4171 }
4172 } else {
4173#ifdef DEBUG1
4174 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"
, 4175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"timer-callback\") == 0"
") (" "Should only get fullscreen-painted or timer-callback"
")"); do { *((volatile int*)__null) = 4175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4175 "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"
, 4175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"timer-callback\") == 0"
") (" "Should only get fullscreen-painted or timer-callback"
")"); do { *((volatile int*)__null) = 4175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4176 nsCOMPtr<nsITimer> timer(do_QueryInterface(aSubject));
4177 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"
, 4178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "timer && timer == mTask->mTimer"
") (" "Should only trigger this with the timer the task created"
")"); do { *((volatile int*)__null) = 4178; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4178 "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"
, 4178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "timer && timer == mTask->mTimer"
") (" "Should only trigger this with the timer the task created"
")"); do { *((volatile int*)__null) = 4178; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4179#endif
4180 shouldContinue = true;
4181 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)
;
4182 }
4183 if (shouldContinue) {
4184 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4185 obs->RemoveObserver(this, kPaintedTopic);
4186 mTask->mTimer = nullptr;
4187 mTask->Run();
4188 }
4189 return NS_OK;
4190}
4191
4192NS_IMETHODIMPnsresult
4193FullscreenTransitionTask::Observer::GetName(nsACString& aName) {
4194 aName.AssignLiteral("FullscreenTransitionTask");
4195 return NS_OK;
4196}
4197
4198static bool MakeWidgetFullscreen(nsGlobalWindowOuter* aWindow,
4199 FullscreenReason aReason, bool aFullscreen) {
4200 nsCOMPtr<nsIWidget> widget = aWindow->GetMainWidget();
4201 if (!widget) {
4202 return false;
4203 }
4204
4205 FullscreenTransitionDuration duration;
4206 bool performTransition = false;
4207 nsCOMPtr<nsISupports> transitionData;
4208 if (aReason == FullscreenReason::ForFullscreenAPI) {
4209 GetFullscreenTransitionDuration(aFullscreen, &duration);
4210 if (!duration.IsSuppressed()) {
4211 performTransition = widget->PrepareForFullscreenTransition(
4212 getter_AddRefs(transitionData));
4213 }
4214 }
4215
4216 if (!performTransition) {
4217 return aWindow->SetWidgetFullscreen(aReason, aFullscreen, widget);
4218 }
4219
4220 nsCOMPtr<nsIRunnable> task = new FullscreenTransitionTask(
4221 duration, aWindow, aFullscreen, widget, transitionData);
4222 task->Run();
4223 return true;
4224}
4225
4226nsresult nsGlobalWindowOuter::ProcessWidgetFullscreenRequest(
4227 FullscreenReason aReason, bool aFullscreen) {
4228 mInProcessFullscreenRequest.emplace(aReason, aFullscreen);
4229
4230 // Prevent chrome documents which are still loading from resizing
4231 // the window after we set fullscreen mode.
4232 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4233 nsCOMPtr<nsIAppWindow> appWin(do_GetInterface(treeOwnerAsWin));
4234 if (aFullscreen && appWin) {
4235 appWin->SetIntrinsicallySized(false);
4236 }
4237
4238 // Sometimes we don't want the top-level widget to actually go fullscreen:
4239 // - in the B2G desktop client, we don't want the emulated screen dimensions
4240 // to appear to increase when entering fullscreen mode; we just want the
4241 // content to fill the entire client area of the emulator window.
4242 // - in FxR Desktop, we don't want fullscreen to take over the monitor, but
4243 // instead we want fullscreen to fill the FxR window in the the headset.
4244 if (!StaticPrefs::full_screen_api_ignore_widgets() &&
4245 !mForceFullScreenInWidget) {
4246 if (MakeWidgetFullscreen(this, aReason, aFullscreen)) {
4247 // The rest of code for switching fullscreen is in nsGlobalWindowOuter::
4248 // FinishFullscreenChange() which will be called after sizemodechange
4249 // event is dispatched.
4250 return NS_OK;
4251 }
4252 }
4253
4254#if defined(NIGHTLY_BUILD1) && defined(XP_WIN)
4255 if (FxRWindowManager::GetInstance()->IsFxRWindow(mWindowID)) {
4256 mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/);
4257 shmem.SendFullscreenState(mWindowID, aFullscreen);
4258 }
4259#endif // NIGHTLY_BUILD && XP_WIN
4260 FinishFullscreenChange(aFullscreen);
4261 return NS_OK;
4262}
4263
4264nsresult nsGlobalWindowOuter::SetFullscreenInternal(FullscreenReason aReason,
4265 bool aFullscreen) {
4266 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"
, 4268); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4268; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4267 "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"
, 4268); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4268; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4268 "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"
, 4268); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4268; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4269
4270 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"
, 4270); return NS_ERROR_FAILURE; } } while (false)
;
4271
4272 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"
, 4275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4273 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"
, 4275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4274 "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"
, 4275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4275 "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"
, 4275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4276
4277 // Only chrome can change our fullscreen mode. Otherwise, the state
4278 // can only be changed for DOM fullscreen.
4279 if (aReason == FullscreenReason::ForFullscreenMode &&
4280 !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
4281 return NS_OK;
4282 }
4283
4284 // SetFullscreen needs to be called on the root window, so get that
4285 // via the DocShell tree, and if we are not already the root,
4286 // call SetFullscreen on that window instead.
4287 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4288 mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
4289 nsCOMPtr<nsPIDOMWindowOuter> window =
4290 rootItem ? rootItem->GetWindow() : nullptr;
4291 if (!window) return NS_ERROR_FAILURE;
4292 if (rootItem != mDocShell)
4293 return window->SetFullscreenInternal(aReason, aFullscreen);
4294
4295 // make sure we don't try to set full screen on a non-chrome window,
4296 // which might happen in embedding world
4297 if (mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome)
4298 return NS_ERROR_FAILURE;
4299
4300 // FullscreenReason::ForForceExitFullscreen can only be used with exiting
4301 // fullscreen
4302 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"
, 4304); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4304; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4303 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"
, 4304); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4304; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4304 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"
, 4304); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4304; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4305
4306 // If we are already in full screen mode, just return, we don't care about the
4307 // reason here, because,
4308 // - If we are in fullscreen mode due to browser fullscreen mode, requesting
4309 // DOM fullscreen does not change anything.
4310 // - If we are in fullscreen mode due to DOM fullscreen, requesting browser
4311 // fullscreen should not change anything, either. Note that we should not
4312 // update reason to ForFullscreenMode, otherwise the subsequent DOM
4313 // fullscreen exit will be ignored and user will be confused. And ideally
4314 // this should never happen as `window.fullscreen` returns `true` for DOM
4315 // fullscreen as well.
4316 if (mFullscreen.isSome() == aFullscreen) {
4317 // How come we get browser fullscreen request while we are already in DOM
4318 // fullscreen?
4319 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"
, 4320); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForFullscreenAPI"
")"); do { *((volatile int*)__null) = 4320; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4320 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"
, 4320); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForFullscreenAPI"
")"); do { *((volatile int*)__null) = 4320; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4321 return NS_OK;
4322 }
4323
4324 // Note that although entering DOM fullscreen could also cause
4325 // consequential calls to this method, those calls will be skipped
4326 // at the condition above.
4327 if (aReason == FullscreenReason::ForFullscreenMode) {
4328 if (!aFullscreen && mFullscreen &&
4329 mFullscreen.value() == FullscreenReason::ForFullscreenAPI) {
4330 // If we are exiting fullscreen mode, but we actually didn't
4331 // entered browser fullscreen mode, the fullscreen state was only for
4332 // the Fullscreen API. Change the reason here so that we can
4333 // perform transition for it.
4334 aReason = FullscreenReason::ForFullscreenAPI;
4335 }
4336 } else {
4337 // If we are exiting from DOM fullscreen while we initially make
4338 // the window fullscreen because of browser fullscreen mode, don't restore
4339 // the window. But we still need to exit the DOM fullscreen state.
4340 if (!aFullscreen && mFullscreen &&
4341 mFullscreen.value() == FullscreenReason::ForFullscreenMode) {
4342 // If there is a in-process fullscreen request, FinishDOMFullscreenChange
4343 // will be called when the request is finished.
4344 if (!mInProcessFullscreenRequest.isSome()) {
4345 FinishDOMFullscreenChange(mDoc, false);
4346 }
4347 return NS_OK;
4348 }
4349 }
4350
4351 // Set this before so if widget sends an event indicating its
4352 // gone full screen, the state trap above works.
4353 if (aFullscreen) {
4354 mFullscreen.emplace(aReason);
4355 } else {
4356 mFullscreen.reset();
4357 }
4358
4359 // If we are in process of fullscreen request, only keep the latest fullscreen
4360 // state, we will sync up later while the processing request is finished.
4361 if (mInProcessFullscreenRequest.isSome()) {
4362 mFullscreenHasChangedDuringProcessing = true;
4363 return NS_OK;
4364 }
4365
4366 return ProcessWidgetFullscreenRequest(aReason, aFullscreen);
4367}
4368
4369// Support a per-window, dynamic equivalent of enabling
4370// full-screen-api.ignore-widgets
4371void nsGlobalWindowOuter::ForceFullScreenInWidget() {
4372 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"
, 4372); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4372; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4373
4374 mForceFullScreenInWidget = true;
4375}
4376
4377bool nsGlobalWindowOuter::SetWidgetFullscreen(FullscreenReason aReason,
4378 bool aIsFullscreen,
4379 nsIWidget* aWidget) {
4380 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"
, 4381); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this == GetInProcessTopInternal()"
") (" "Only topmost window should call this" ")"); do { *((volatile
int*)__null) = 4381; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
4381 "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"
, 4381); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this == GetInProcessTopInternal()"
") (" "Only topmost window should call this" ")"); do { *((volatile
int*)__null) = 4381; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4382 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"
, 4382); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetFrameElementInternal()"
") (" "Content window should not call this" ")"); do { *((volatile
int*)__null) = 4382; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4383 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"
, 4383); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_GetProcessType() == GeckoProcessType_Default"
")"); do { *((volatile int*)__null) = 4383; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4384
4385 if (!NS_WARN_IF(!IsChromeWindow())NS_warn_if_impl(!IsChromeWindow(), "!IsChromeWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4385)
) {
4386 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"
, 4386)
) {
4387 if (PresShell* presShell = mDocShell->GetPresShell()) {
4388 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
4389 mChromeFields.mFullscreenPresShell = do_GetWeakReference(presShell);
4390 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"
, 4390); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChromeFields.mFullscreenPresShell"
")"); do { *((volatile int*)__null) = 4390; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4391 rd->SetIsResizeSuppressed();
4392 rd->Freeze();
4393 }
4394 }
4395 }
4396 }
4397 nsresult rv = aReason == FullscreenReason::ForFullscreenMode
4398 ?
4399 // If we enter fullscreen for fullscreen mode, we want
4400 // the native system behavior.
4401 aWidget->MakeFullScreenWithNativeTransition(aIsFullscreen)
4402 : aWidget->MakeFullScreen(aIsFullscreen);
4403 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
4404}
4405
4406/* virtual */
4407void nsGlobalWindowOuter::FullscreenWillChange(bool aIsFullscreen) {
4408 if (!mInProcessFullscreenRequest.isSome()) {
4409 // If there is no in-process fullscreen request, the fullscreen state change
4410 // is triggered from the OS directly, e.g. user use built-in window button
4411 // to enter/exit fullscreen on macOS.
4412 mInProcessFullscreenRequest.emplace(FullscreenReason::ForFullscreenMode,
4413 aIsFullscreen);
4414 if (mFullscreen.isSome() != aIsFullscreen) {
4415 if (aIsFullscreen) {
4416 mFullscreen.emplace(FullscreenReason::ForFullscreenMode);
4417 } else {
4418 mFullscreen.reset();
4419 }
4420 } else {
4421 // It is possible that FullscreenWillChange is notified with current
4422 // fullscreen state, e.g. browser goes into fullscreen when widget
4423 // fullscreen is prevented, and then user triggers fullscreen from the OS
4424 // directly again.
4425 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"
, 4427); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4427; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4426 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"
, 4427); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4427; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4427 "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"
, 4427); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4427; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4428 }
4429 }
4430 if (aIsFullscreen) {
4431 DispatchCustomEvent(u"willenterfullscreen"_ns, ChromeOnlyDispatch::eYes);
4432 } else {
4433 DispatchCustomEvent(u"willexitfullscreen"_ns, ChromeOnlyDispatch::eYes);
4434 }
4435}
4436
4437/* virtual */
4438void nsGlobalWindowOuter::FinishFullscreenChange(bool aIsFullscreen) {
4439 mozilla::Maybe<FullscreenRequest> currentInProcessRequest =
4440 std::move(mInProcessFullscreenRequest);
4441 if (!mFullscreenHasChangedDuringProcessing &&
4442 aIsFullscreen != mFullscreen.isSome()) {
4443 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"
, 4443)
;
4444 // We failed to make the widget enter fullscreen.
4445 // Stop further changes and restore the state.
4446 if (!aIsFullscreen) {
4447 mFullscreen.reset();
4448 } else {
4449#ifndef XP_MACOSX
4450 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"
, 4450); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Failed to exit fullscreen?" ")")
; do { *((volatile int*)__null) = 4450; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4451#endif
4452 // Restore fullscreen state with FullscreenReason::ForFullscreenAPI reason
4453 // in order to make subsequent DOM fullscreen exit request can exit
4454 // browser fullscreen mode.
4455 mFullscreen.emplace(FullscreenReason::ForFullscreenAPI);
4456 }
4457 return;
4458 }
4459
4460 // Note that we must call this to toggle the DOM fullscreen state
4461 // of the document before dispatching the "fullscreen" event, so
4462 // that the chrome can distinguish between browser fullscreen mode
4463 // and DOM fullscreen.
4464 FinishDOMFullscreenChange(mDoc, aIsFullscreen);
4465
4466 // dispatch a "fullscreen" DOM event so that XUL apps can
4467 // respond visually if we are kicked into full screen mode
4468 DispatchCustomEvent(u"fullscreen"_ns, ChromeOnlyDispatch::eYes);
4469
4470 if (!NS_WARN_IF(!IsChromeWindow())NS_warn_if_impl(!IsChromeWindow(), "!IsChromeWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4470)
) {
4471 if (RefPtr<PresShell> presShell =
4472 do_QueryReferent(mChromeFields.mFullscreenPresShell)) {
4473 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
4474 rd->Thaw();
4475 }
4476 mChromeFields.mFullscreenPresShell = nullptr;
4477 }
4478 }
4479
4480 // If fullscreen state has changed during processing fullscreen request, we
4481 // need to ensure widget matches our latest fullscreen state here.
4482 if (mFullscreenHasChangedDuringProcessing) {
4483 mFullscreenHasChangedDuringProcessing = false;
4484 // Widget doesn't care about the reason that makes it entering/exiting
4485 // fullscreen, so here we just need to ensure the fullscreen state is
4486 // matched.
4487 if (aIsFullscreen != mFullscreen.isSome()) {
4488 // If we end up need to exit fullscreen, use the same reason that brings
4489 // us into fullscreen mode, so that we will perform the same fullscreen
4490 // transistion effect for exiting.
4491 ProcessWidgetFullscreenRequest(
4492 mFullscreen.isSome() ? mFullscreen.value()
4493 : currentInProcessRequest.value().mReason,
4494 mFullscreen.isSome());
4495 }
4496 }
4497}
4498
4499/* virtual */
4500void nsGlobalWindowOuter::MacFullscreenMenubarOverlapChanged(
4501 mozilla::DesktopCoord aOverlapAmount) {
4502 ErrorResult res;
4503 RefPtr<Event> domEvent =
4504 mDoc->CreateEvent(u"CustomEvent"_ns, CallerType::System, res);
4505 if (res.Failed()) {
4506 return;
4507 }
4508
4509 AutoJSAPI jsapi;
4510 jsapi.Init();
4511 JSContext* cx = jsapi.cx();
4512 JSAutoRealm ar(cx, GetWrapperPreserveColor());
4513
4514 JS::Rooted<JS::Value> detailValue(cx);
4515 if (!ToJSValue(cx, aOverlapAmount, &detailValue)) {
4516 return;
4517 }
4518
4519 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
4520 customEvent->InitCustomEvent(cx, u"MacFullscreenMenubarRevealUpdate"_ns,
4521 /* aCanBubble = */ true,
4522 /* aCancelable = */ true, detailValue);
4523 domEvent->SetTrusted(true);
4524 domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
4525
4526 nsCOMPtr<EventTarget> target = this;
4527 domEvent->SetTarget(target);
4528
4529 target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
4530}
4531
4532bool nsGlobalWindowOuter::Fullscreen() const {
4533 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"
, 4533); return mFullscreen.isSome(); } } while (false)
;
4534
4535 // Get the fullscreen value of the root window, to always have the value
4536 // accurate, even when called from content.
4537 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4538 mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
4539 if (rootItem == mDocShell) {
4540 if (!XRE_IsContentProcess()) {
4541 // We are the root window. Return our internal value.
4542 return mFullscreen.isSome();
4543 }
4544 if (nsCOMPtr<nsIWidget> widget = GetNearestWidget()) {
4545 // We are in content process, figure out the value from
4546 // the sizemode of the puppet widget.
4547 return widget->SizeMode() == nsSizeMode_Fullscreen;
4548 }
4549 return false;
4550 }
4551
4552 nsCOMPtr<nsPIDOMWindowOuter> window = rootItem->GetWindow();
4553 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"
, 4553); return mFullscreen.isSome(); } } while (false)
;
4554
4555 return nsGlobalWindowOuter::Cast(window)->Fullscreen();
4556}
4557
4558bool nsGlobalWindowOuter::GetFullscreenOuter() { return Fullscreen(); }
4559
4560bool nsGlobalWindowOuter::GetFullScreen() {
4561 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"
, 4561); return false; } return GetCurrentInnerWindowInternal
(this)->GetFullScreen (); } while (0)
;
4562}
4563
4564void nsGlobalWindowOuter::EnsureReflowFlushAndPaint() {
4565 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"
, 4567); MOZ_PretendNoReturn(); } } while (0)
4566 "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"
, 4567); MOZ_PretendNoReturn(); } } while (0)
4567 "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"
, 4567); MOZ_PretendNoReturn(); } } while (0)
;
4568
4569 if (!mDocShell) return;
4570
4571 RefPtr<PresShell> presShell = mDocShell->GetPresShell();
4572 if (!presShell) {
4573 return;
4574 }
4575
4576 // Flush pending reflows.
4577 if (mDoc) {
4578 mDoc->FlushPendingNotifications(FlushType::Layout);
4579 }
4580
4581 // Unsuppress painting.
4582 presShell->UnsuppressPainting();
4583}
4584
4585// static
4586void nsGlobalWindowOuter::MakeMessageWithPrincipal(
4587 nsAString& aOutMessage, nsIPrincipal* aSubjectPrincipal, bool aUseHostPort,
4588 const char* aNullMessage, const char* aContentMessage,
4589 const char* aFallbackMessage) {
4590 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"
, 4590); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubjectPrincipal"
")"); do { *((volatile int*)__null) = 4590; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4591
4592 aOutMessage.Truncate();
4593
4594 // Try to get a host from the running principal -- this will do the
4595 // right thing for javascript: and data: documents.
4596
4597 nsAutoCString contentDesc;
4598
4599 if (aSubjectPrincipal->GetIsNullPrincipal()) {
4600 nsContentUtils::GetLocalizedString(
4601 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, aNullMessage, aOutMessage);
4602 } else {
4603 auto* addonPolicy = BasePrincipal::Cast(aSubjectPrincipal)->AddonPolicy();
4604 if (addonPolicy) {
4605 nsContentUtils::FormatLocalizedString(
4606 aOutMessage, nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4607 aContentMessage, addonPolicy->Name());
4608 } else {
4609 nsresult rv = NS_ERROR_FAILURE;
4610 if (aUseHostPort) {
4611 nsCOMPtr<nsIURI> uri = aSubjectPrincipal->GetURI();
4612 if (uri) {
4613 rv = uri->GetDisplayHostPort(contentDesc);
4614 }
4615 }
4616 if (!aUseHostPort || NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4617 rv = aSubjectPrincipal->GetExposablePrePath(contentDesc);
4618 }
4619 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !contentDesc.IsEmpty()) {
4620 NS_ConvertUTF8toUTF16 ucsPrePath(contentDesc);
4621 nsContentUtils::FormatLocalizedString(
4622 aOutMessage, nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4623 aContentMessage, ucsPrePath);
4624 }
4625 }
4626 }
4627
4628 if (aOutMessage.IsEmpty()) {
4629 // We didn't find a host so use the generic heading
4630 nsContentUtils::GetLocalizedString(
4631 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, aFallbackMessage,
4632 aOutMessage);
4633 }
4634
4635 // Just in case
4636 if (aOutMessage.IsEmpty()) {
4637 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"
, 4638)
4638 "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"
, 4638)
;
4639 aOutMessage.AssignLiteral("[Script]");
4640 }
4641}
4642
4643bool nsGlobalWindowOuter::CanMoveResizeWindows(CallerType aCallerType) {
4644 // When called from chrome, we can avoid the following checks.
4645 if (aCallerType != CallerType::System) {
4646 // Don't allow scripts to move or resize windows that were not opened by a
4647 // script.
4648 if (!mBrowsingContext->GetTopLevelCreatedByWebContent()) {
4649 return false;
4650 }
4651
4652 if (!CanSetProperty("dom.disable_window_move_resize")) {
4653 return false;
4654 }
4655
4656 // Ignore the request if we have more than one tab in the window.
4657 if (mBrowsingContext->Top()->HasSiblings()) {
4658 return false;
4659 }
4660 }
4661
4662 if (mDocShell) {
4663 bool allow;
4664 nsresult rv = mDocShell->GetAllowWindowControl(&allow);
4665 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !allow) return false;
4666 }
4667
4668 if (nsGlobalWindowInner::sMouseDown &&
4669 !nsGlobalWindowInner::sDragServiceDisabled) {
4670 nsCOMPtr<nsIDragService> ds =
4671 do_GetService("@mozilla.org/widget/dragservice;1");
4672 if (ds) {
4673 nsGlobalWindowInner::sDragServiceDisabled = true;
4674 ds->Suppress();
4675 }
4676 }
4677 return true;
4678}
4679
4680bool nsGlobalWindowOuter::AlertOrConfirm(bool aAlert, const nsAString& aMessage,
4681 nsIPrincipal& aSubjectPrincipal,
4682 ErrorResult& aError) {
4683 // XXX This method is very similar to nsGlobalWindowOuter::Prompt, make
4684 // sure any modifications here don't need to happen over there!
4685 if (!AreDialogsEnabled()) {
4686 // Just silently return. In the case of alert(), the return value is
4687 // ignored. In the case of confirm(), returning false is the same thing as
4688 // would happen if the user cancels.
4689 return false;
4690 }
4691
4692 // Reset popup state while opening a modal dialog, and firing events
4693 // about the dialog, to prevent the current state from being active
4694 // the whole time a modal dialog is open.
4695 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
4696
4697 // Before bringing up the window, unsuppress painting and flush
4698 // pending reflows.
4699 EnsureReflowFlushAndPaint();
4700
4701 nsAutoString title;
4702 MakeMessageWithPrincipal(title, &aSubjectPrincipal, false,
4703 "ScriptDlgNullPrincipalHeading", "ScriptDlgHeading",
4704 "ScriptDlgGenericHeading");
4705
4706 // Remove non-terminating null characters from the
4707 // string. See bug #310037.
4708 nsAutoString final;
4709 nsContentUtils::StripNullChars(aMessage, final);
4710 nsContentUtils::PlatformToDOMLineBreaks(final);
4711
4712 nsresult rv;
4713 nsCOMPtr<nsIPromptFactory> promptFac =
4714 do_GetService("@mozilla.org/prompter;1", &rv);
4715 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4716 aError.Throw(rv);
4717 return false;
4718 }
4719
4720 nsCOMPtr<nsIPrompt> prompt;
4721 aError =
4722 promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt)(nsIPrompt::COMTypeInfo<nsIPrompt, void>::kIID), getter_AddRefs(prompt));
4723 if (aError.Failed()) {
4724 return false;
4725 }
4726
4727 // Always allow content modal prompts for alert and confirm.
4728 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4729 promptBag->SetPropertyAsUint32(u"modalType"_ns,
4730 nsIPrompt::MODAL_TYPE_CONTENT);
4731 }
4732
4733 bool result = false;
4734 nsAutoSyncOperation sync(mDoc, SyncOperationBehavior::eSuspendInput);
4735 if (ShouldPromptToBlockDialogs()) {
4736 bool disallowDialog = false;
4737 nsAutoString label;
4738 MakeMessageWithPrincipal(
4739 label, &aSubjectPrincipal, true, "ScriptDialogLabelNullPrincipal",
4740 "ScriptDialogLabelContentPrincipal", "ScriptDialogLabelNullPrincipal");
4741
4742 aError = aAlert
4743 ? prompt->AlertCheck(title.get(), final.get(), label.get(),
4744 &disallowDialog)
4745 : prompt->ConfirmCheck(title.get(), final.get(), label.get(),
4746 &disallowDialog, &result);
4747
4748 if (disallowDialog) {
4749 DisableDialogs();
4750 }
4751 } else {
4752 aError = aAlert ? prompt->Alert(title.get(), final.get())
4753 : prompt->Confirm(title.get(), final.get(), &result);
4754 }
4755
4756 return result;
4757}
4758
4759void nsGlobalWindowOuter::AlertOuter(const nsAString& aMessage,
4760 nsIPrincipal& aSubjectPrincipal,
4761 ErrorResult& aError) {
4762 AlertOrConfirm(/* aAlert = */ true, aMessage, aSubjectPrincipal, aError);
4763}
4764
4765bool nsGlobalWindowOuter::ConfirmOuter(const nsAString& aMessage,
4766 nsIPrincipal& aSubjectPrincipal,
4767 ErrorResult& aError) {
4768 return AlertOrConfirm(/* aAlert = */ false, aMessage, aSubjectPrincipal,
4769 aError);
4770}
4771
4772void nsGlobalWindowOuter::PromptOuter(const nsAString& aMessage,
4773 const nsAString& aInitial,
4774 nsAString& aReturn,
4775 nsIPrincipal& aSubjectPrincipal,
4776 ErrorResult& aError) {
4777 // XXX This method is very similar to nsGlobalWindowOuter::AlertOrConfirm,
4778 // make sure any modifications here don't need to happen over there!
4779 SetDOMStringToNull(aReturn);
4780
4781 if (!AreDialogsEnabled()) {
4782 // Return null, as if the user just canceled the prompt.
4783 return;
4784 }
4785
4786 // Reset popup state while opening a modal dialog, and firing events
4787 // about the dialog, to prevent the current state from being active
4788 // the whole time a modal dialog is open.
4789 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
4790
4791 // Before bringing up the window, unsuppress painting and flush
4792 // pending reflows.
4793 EnsureReflowFlushAndPaint();
4794
4795 nsAutoString title;
4796 MakeMessageWithPrincipal(title, &aSubjectPrincipal, false,
4797 "ScriptDlgNullPrincipalHeading", "ScriptDlgHeading",
4798 "ScriptDlgGenericHeading");
4799
4800 // Remove non-terminating null characters from the
4801 // string. See bug #310037.
4802 nsAutoString fixedMessage, fixedInitial;
4803 nsContentUtils::StripNullChars(aMessage, fixedMessage);
4804 nsContentUtils::PlatformToDOMLineBreaks(fixedMessage);
4805 nsContentUtils::StripNullChars(aInitial, fixedInitial);
4806
4807 nsresult rv;
4808 nsCOMPtr<nsIPromptFactory> promptFac =
4809 do_GetService("@mozilla.org/prompter;1", &rv);
4810 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4811 aError.Throw(rv);
4812 return;
4813 }
4814
4815 nsCOMPtr<nsIPrompt> prompt;
4816 aError =
4817 promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt)(nsIPrompt::COMTypeInfo<nsIPrompt, void>::kIID), getter_AddRefs(prompt));
4818 if (aError.Failed()) {
4819 return;
4820 }
4821
4822 // Always allow content modal prompts for prompt.
4823 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4824 promptBag->SetPropertyAsUint32(u"modalType"_ns,
4825 nsIPrompt::MODAL_TYPE_CONTENT);
4826 }
4827
4828 // Pass in the default value, if any.
4829 char16_t* inoutValue = ToNewUnicode(fixedInitial);
4830 bool disallowDialog = false;
4831
4832 nsAutoString label;
4833 label.SetIsVoid(true);
4834 if (ShouldPromptToBlockDialogs()) {
4835 nsContentUtils::GetLocalizedString(
4836 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, "ScriptDialogLabel", label);
4837 }
4838
4839 nsAutoSyncOperation sync(mDoc, SyncOperationBehavior::eSuspendInput);
4840 bool ok;
4841 aError = prompt->Prompt(title.get(), fixedMessage.get(), &inoutValue,
4842 label.IsVoid() ? nullptr : label.get(),
4843 &disallowDialog, &ok);
4844
4845 if (disallowDialog) {
4846 DisableDialogs();
4847 }
4848
4849 // XXX Doesn't this leak inoutValue?
4850 if (aError.Failed()) {
4851 return;
4852 }
4853
4854 nsString outValue;
4855 outValue.Adopt(inoutValue);
4856 if (ok && inoutValue) {
4857 aReturn = std::move(outValue);
4858 }
4859}
4860
4861void nsGlobalWindowOuter::FocusOuter(CallerType aCallerType,
4862 bool aFromOtherProcess,
4863 uint64_t aActionId) {
4864 RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
4865 if (MOZ_UNLIKELY(!fm)(__builtin_expect(!!(!fm), 0))) {
4866 return;
4867 }
4868
4869 auto [canFocus, isActive] = GetBrowsingContext()->CanFocusCheck(aCallerType);
4870 if (aFromOtherProcess) {
4871 // We trust that the check passed in a process that's, in principle,
4872 // untrusted, because we don't have the required caller context available
4873 // here. Also, the worst that the other process can do in this case is to
4874 // raise a window it's not supposed to be allowed to raise.
4875 // https://bugzilla.mozilla.org/show_bug.cgi?id=1677899
4876 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"
, 4877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "Parent should not trust other processes." ")"); do { *
((volatile int*)__null) = 4877; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
4877 "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"
, 4877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "Parent should not trust other processes." ")"); do { *
((volatile int*)__null) = 4877; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4878 canFocus = true;
4879 }
4880
4881 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4882 if (treeOwnerAsWin && (canFocus || isActive)) {
4883 bool isEnabled = true;
4884 if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled))((bool)(__builtin_expect(!!(!NS_FAILED_impl(treeOwnerAsWin->
GetEnabled(&isEnabled))), 1)))
&& !isEnabled) {
4885 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"
, 4885)
;
4886 return;
4887 }
4888 }
4889
4890 if (!mDocShell) {
4891 return;
4892 }
4893
4894 // If the window has a child frame focused, clear the focus. This
4895 // ensures that focus will be in this frame and not in a child.
4896 if (nsIContent* content = GetFocusedElement()) {
4897 if (HTMLIFrameElement::FromNode(content)) {
4898 fm->ClearFocus(this);
4899 }
4900 }
4901
4902 RefPtr<BrowsingContext> parent;
4903 BrowsingContext* bc = GetBrowsingContext();
4904 if (bc) {
4905 parent = bc->GetParent();
4906 if (!parent && XRE_IsParentProcess()) {
4907 parent = bc->Canonical()->GetParentCrossChromeBoundary();
4908 }
4909 }
4910 if (parent) {
4911 if (!parent->IsInProcess()) {
4912 if (isActive) {
4913 OwningNonNull<nsGlobalWindowOuter> kungFuDeathGrip(*this);
4914 fm->WindowRaised(kungFuDeathGrip, aActionId);
4915 } else {
4916 ContentChild* contentChild = ContentChild::GetSingleton();
4917 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"
, 4917); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 4917; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4918 contentChild->SendFinalizeFocusOuter(bc, canFocus, aCallerType);
4919 }
4920 return;
4921 }
4922
4923 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"
, 4923); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc" ") ("
"Call chain should have ensured document creation." ")"); do
{ *((volatile int*)__null) = 4923; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4924 if (mDoc) {
4925 if (Element* frame = mDoc->GetEmbedderElement()) {
4926 nsContentUtils::RequestFrameFocus(*frame, canFocus, aCallerType);
4927 }
4928 }
4929 return;
4930 }
4931
4932 if (canFocus) {
4933 // if there is no parent, this must be a toplevel window, so raise the
4934 // window if canFocus is true. If this is a child process, the raise
4935 // window request will get forwarded to the parent by the puppet widget.
4936 OwningNonNull<nsGlobalWindowOuter> kungFuDeathGrip(*this);
4937 fm->RaiseWindow(kungFuDeathGrip, aCallerType, aActionId);
4938 }
4939}
4940
4941nsresult nsGlobalWindowOuter::Focus(CallerType aCallerType) {
4942 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"
, 4942); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->Focus (aCallerType); } while (0)
;
4943}
4944
4945void nsGlobalWindowOuter::BlurOuter(CallerType aCallerType) {
4946 if (!GetBrowsingContext()->CanBlurCheck(aCallerType)) {
4947 return;
4948 }
4949
4950 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
4951 if (chrome) {
4952 chrome->Blur();
4953 }
4954}
4955
4956void nsGlobalWindowOuter::StopOuter(ErrorResult& aError) {
4957 // IsNavigationAllowed checks are usually done in nsDocShell directly,
4958 // however nsDocShell::Stop has a bunch of internal users that would fail
4959 // the IsNavigationAllowed check.
4960 if (!mDocShell || !nsDocShell::Cast(mDocShell)->IsNavigationAllowed()) {
4961 return;
4962 }
4963
4964 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4965 if (webNav) {
4966 aError = webNav->Stop(nsIWebNavigation::STOP_ALL);
4967 }
4968}
4969
4970void nsGlobalWindowOuter::PrintOuter(ErrorResult& aError) {
4971 if (!AreDialogsEnabled()) {
4972 // Per spec, silently return. https://github.com/whatwg/html/commit/21a1de1
4973 return;
4974 }
4975
4976 // Printing is disabled, silently return.
4977 if (!StaticPrefs::print_enabled()) {
4978 return;
4979 }
4980
4981 // If we're loading, queue the print for later. This is a special-case that
4982 // only applies to the window.print() call, for compat with other engines and
4983 // pre-existing behavior.
4984 if (mShouldDelayPrintUntilAfterLoad) {
4985 if (nsIDocShell* docShell = GetDocShell()) {
4986 if (docShell->GetBusyFlags() & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) {
4987 mDelayedPrintUntilAfterLoad = true;
4988 return;
4989 }
4990 }
4991 }
4992
4993#ifdef NS_PRINTING1
4994 RefPtr<BrowsingContext> top =
4995 mBrowsingContext ? mBrowsingContext->Top() : nullptr;
4996 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"
, 4996)
) {
4997 return;
4998 }
4999
5000 if (top) {
5001 Unused << top->SetIsPrinting(true);
5002 }
5003
5004 auto unset = MakeScopeExit([&] {
5005 if (top) {
5006 Unused << top->SetIsPrinting(false);
5007 }
5008 });
5009
5010 const bool forPreview = !StaticPrefs::print_always_print_silent();
5011 Print(nullptr, nullptr, nullptr, nullptr, IsPreview(forPreview),
5012 IsForWindowDotPrint::Yes, nullptr, nullptr, aError);
5013#endif
5014}
5015
5016class MOZ_RAII AutoModalState {
5017 public:
5018 explicit AutoModalState(nsGlobalWindowOuter& aWin)
5019 : mModalStateWin(aWin.EnterModalState()) {}
5020
5021 ~AutoModalState() {
5022 if (mModalStateWin) {
5023 mModalStateWin->LeaveModalState();
5024 }
5025 }
5026
5027 RefPtr<nsGlobalWindowOuter> mModalStateWin;
5028};
5029
5030Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
5031 nsIPrintSettings* aPrintSettings, RemotePrintJobChild* aRemotePrintJob,
5032 nsIWebProgressListener* aListener, nsIDocShell* aDocShellToCloneInto,
5033 IsPreview aIsPreview, IsForWindowDotPrint aForWindowDotPrint,
5034 PrintPreviewResolver&& aPrintPreviewCallback,
5035 RefPtr<BrowsingContext>* aCachedBrowsingContext, ErrorResult& aError) {
5036#ifdef NS_PRINTING1
5037 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
5038 do_GetService("@mozilla.org/gfx/printsettings-service;1");
5039 if (!printSettingsService) {
5040 // we currently return here in headless mode - should we?
5041 aError.ThrowNotSupportedError("No print settings service");
5042 return nullptr;
5043 }
5044
5045 nsCOMPtr<nsIPrintSettings> ps = aPrintSettings;
5046 if (!ps) {
5047 // We shouldn't need this once bug 1776169 is fixed.
5048 printSettingsService->GetDefaultPrintSettingsForPrinting(
5049 getter_AddRefs(ps));
5050 }
5051
5052 RefPtr<Document> docToPrint = mDoc;
5053 if (NS_WARN_IF(!docToPrint)NS_warn_if_impl(!docToPrint, "!docToPrint", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5053)
) {
5054 aError.ThrowNotSupportedError("Document is gone");
5055 return nullptr;
5056 }
5057
5058 RefPtr<BrowsingContext> sourceBC = docToPrint->GetBrowsingContext();
5059 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"
, 5059); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "sourceBC"
")"); do { *((volatile int*)__null) = 5059; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5060 if (!sourceBC) {
5061 aError.ThrowNotSupportedError("No browsing context for source document");
5062 return nullptr;
5063 }
5064
5065 nsAutoSyncOperation sync(docToPrint, SyncOperationBehavior::eAllowInput);
5066 AutoModalState modalState(*this);
5067
5068 nsCOMPtr<nsIDocumentViewer> viewer;
5069 RefPtr<BrowsingContext> bc;
5070 bool hasPrintCallbacks = false;
5071 bool wasStaticDocument = docToPrint->IsStaticDocument();
5072 bool usingCachedBrowsingContext = false;
5073 if (aCachedBrowsingContext && *aCachedBrowsingContext) {
5074 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"
, 5076); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5076; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
5075 "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"
, 5076); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5076; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
5076 "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"
, 5076); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5076; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
5077 if (!wasStaticDocument) {
5078 // The passed in document is not a static clone and the caller passed in a
5079 // static clone to reuse, so swap it in.
5080 docToPrint = (*aCachedBrowsingContext)->GetDocument();
5081 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"
, 5081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docToPrint"
")"); do { *((volatile int*)__null) = 5081; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5082 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"
, 5082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docToPrint->IsStaticDocument()"
")"); do { *((volatile int*)__null) = 5082; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5083 wasStaticDocument = true;
5084 usingCachedBrowsingContext = true;
5085 }
5086 }
5087 if (wasStaticDocument) {
5088 if (aForWindowDotPrint == IsForWindowDotPrint::Yes) {
5089 aError.ThrowNotSupportedError(
5090 "Calling print() from a print preview is unsupported, did you intend "
5091 "to call printPreview() instead?");
5092 return nullptr;
5093 }
5094 if (usingCachedBrowsingContext) {
5095 bc = docToPrint->GetBrowsingContext();
5096 } else {
5097 // We're already a print preview window, just reuse our browsing context /
5098 // content viewer.
5099 bc = sourceBC;
5100 }
5101 nsCOMPtr<nsIDocShell> docShell = bc->GetDocShell();
5102 if (!docShell) {
5103 aError.ThrowNotSupportedError("No docshell");
5104 return nullptr;
5105 }
5106 // We could handle this if needed.
5107 if (aDocShellToCloneInto && aDocShellToCloneInto != docShell) {
5108 aError.ThrowNotSupportedError(
5109 "We don't handle cloning a print preview doc into a different "
5110 "docshell");
5111 return nullptr;
5112 }
5113 docShell->GetDocViewer(getter_AddRefs(viewer));
5114 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"
, 5114); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "viewer"
")"); do { *((volatile int*)__null) = 5114; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5115 } else {
5116 if (aDocShellToCloneInto) {
5117 // Ensure the content viewer is created if needed.
5118 Unused << aDocShellToCloneInto->GetDocument();
5119 bc = aDocShellToCloneInto->GetBrowsingContext();
5120 } else {
5121 AutoNoJSAPI nojsapi;
5122 auto printKind = aForWindowDotPrint == IsForWindowDotPrint::Yes
5123 ? PrintKind::WindowDotPrint
5124 : PrintKind::InternalPrint;
5125 // For PrintKind::WindowDotPrint, this call will not only make the parent
5126 // process create a CanonicalBrowsingContext for the returned `bc`, but
5127 // it will also make the parent process initiate the print/print preview.
5128 // See the handling of OPEN_PRINT_BROWSER in browser.js.
5129 aError = OpenInternal(""_ns, u""_ns, u""_ns,
5130 false, // aDialog
5131 true, // aCalledNoScript
5132 false, // aDoJSFixups
5133 true, // aNavigate
5134 nullptr, // No args
5135 nullptr, // aLoadState
5136 false, // aForceNoOpener
5137 printKind, getter_AddRefs(bc));
5138 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"
, 5138)
) {
5139 return nullptr;
5140 }
5141 if (aCachedBrowsingContext) {
5142 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"
, 5142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!*aCachedBrowsingContext"
")"); do { *((volatile int*)__null) = 5142; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5143 *aCachedBrowsingContext = bc;
5144 }
5145 }
5146 if (!bc) {
5147 aError.ThrowNotAllowedError("No browsing context");
5148 return nullptr;
5149 }
5150
5151 Unused << bc->Top()->SetIsPrinting(true);
5152 nsCOMPtr<nsIDocShell> cloneDocShell = bc->GetDocShell();
5153 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"
, 5153); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "cloneDocShell"
")"); do { *((volatile int*)__null) = 5153; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5154 cloneDocShell->GetDocViewer(getter_AddRefs(viewer));
5155 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"
, 5155); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "viewer"
")"); do { *((volatile int*)__null) = 5155; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5156 if (!viewer) {
5157 aError.ThrowNotSupportedError("Didn't end up with a content viewer");
5158 return nullptr;
5159 }
5160
5161 if (bc != sourceBC) {
5162 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"
, 5162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc->IsTopContent()"
")"); do { *((volatile int*)__null) = 5162; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5163 // If we are cloning from a document in a different BrowsingContext, we
5164 // need to make sure to copy over our opener policy information from that
5165 // BrowsingContext. In the case where the source is an iframe, this
5166 // information needs to be copied from the toplevel source
5167 // BrowsingContext, as we may be making a static clone of a single
5168 // subframe.
5169 MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy
()))), 1)))), 1))) { } else { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5170); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")"); do { *((volatile int*)__null) = 5170; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5170 bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy
()))), 1)))), 1))) { } else { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5170); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")"); do { *((volatile int*)__null) = 5170; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
5171 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"
, 5171); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "bc->Group() == sourceBC->Group()"
")"); do { *((volatile int*)__null) = 5171; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5172 }
5173
5174 if (RefPtr<Document> doc = viewer->GetDocument()) {
5175 if (doc->IsShowing()) {
5176 // We're going to drop this document on the floor, in the SetDocument
5177 // call below. Make sure to run OnPageHide() to keep state consistent
5178 // and avoids assertions in the document destructor.
5179 doc->OnPageHide(false, nullptr);
5180 }
5181 }
5182
5183 AutoPrintEventDispatcher dispatcher(*docToPrint);
5184
5185 nsAutoScriptBlocker blockScripts;
5186 RefPtr<Document> clone = docToPrint->CreateStaticClone(
5187 cloneDocShell, viewer, ps, &hasPrintCallbacks);
5188 if (!clone) {
5189 aError.ThrowNotSupportedError("Clone operation for printing failed");
5190 return nullptr;
5191 }
5192 }
5193
5194 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint = do_QueryInterface(viewer);
5195 if (!webBrowserPrint) {
5196 aError.ThrowNotSupportedError(
5197 "Content viewer didn't implement nsIWebBrowserPrint");
5198 return nullptr;
5199 }
5200 bool closeWindowAfterPrint;
5201 if (wasStaticDocument) {
5202 // Here the document was a static clone to begin with that this code did not
5203 // create, so we should not clean it up.
5204 // The exception is if we're using the passed-in aCachedBrowsingContext, in
5205 // which case this is the second print with this static document clone that
5206 // we created the first time through, and we are responsible for cleaning it
5207 // up.
5208 closeWindowAfterPrint = usingCachedBrowsingContext;
5209 } else {
5210 // In this case the document was not a static clone, so we made a static
5211 // clone for printing purposes and must clean it up after the print is done.
5212 // The exception is if aCachedBrowsingContext is non-NULL, meaning the
5213 // caller is intending to print this document again, so we need to defer the
5214 // cleanup until after the second print.
5215 closeWindowAfterPrint = !aCachedBrowsingContext;
5216 }
5217 webBrowserPrint->SetCloseWindowAfterPrint(closeWindowAfterPrint);
5218
5219 // For window.print(), we postpone making these calls until the round-trip to
5220 // the parent process (triggered by the OpenInternal call above) calls us
5221 // again. Only a call from the parent can provide a valid nsPrintSettings
5222 // object and RemotePrintJobChild object.
5223 if (aForWindowDotPrint == IsForWindowDotPrint::No) {
5224 if (aIsPreview == IsPreview::Yes) {
5225 aError = webBrowserPrint->PrintPreview(ps, aListener,
5226 std::move(aPrintPreviewCallback));
5227 if (aError.Failed()) {
5228 return nullptr;
5229 }
5230 } else {
5231 // Historically we've eaten this error.
5232 webBrowserPrint->Print(ps, aRemotePrintJob, aListener);
5233 }
5234 }
5235
5236 // When using window.print() with the new UI, we usually want to block until
5237 // the print dialog is hidden. But we can't really do that if we have print
5238 // callbacks, because we are inside a sync operation, and we want to run
5239 // microtasks / etc that the print callbacks may create. It is really awkward
5240 // to have this subtle behavior difference...
5241 //
5242 // We also want to do this for fuzzing, so that they can test window.print().
5243 const bool shouldBlock = [&] {
5244 if (aForWindowDotPrint == IsForWindowDotPrint::No) {
5245 return false;
5246 }
5247 if (aIsPreview == IsPreview::Yes) {
5248 return !hasPrintCallbacks;
5249 }
5250 return StaticPrefs::dom_window_print_fuzzing_block_while_printing();
5251 }();
5252
5253 if (shouldBlock) {
5254 SpinEventLoopUntil("nsGlobalWindowOuter::Print"_ns,
5255 [&] { return bc->IsDiscarded(); });
5256 }
5257
5258 return WindowProxyHolder(std::move(bc));
5259#else
5260 return nullptr;
5261#endif // NS_PRINTING
5262}
5263
5264void nsGlobalWindowOuter::MoveToOuter(int32_t aXPos, int32_t aYPos,
5265 CallerType aCallerType,
5266 ErrorResult& aError) {
5267 /*
5268 * If caller is not chrome and the user has not explicitly exempted the site,
5269 * prevent window.moveTo() by exiting early
5270 */
5271
5272 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5273 return;
5274 }
5275
5276 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5277 if (!treeOwnerAsWin) {
5278 aError.Throw(NS_ERROR_FAILURE);
5279 return;
5280 }
5281
5282 // We need to do the same transformation GetScreenXY does.
5283 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
5284 if (!presContext) {
5285 return;
5286 }
5287
5288 CSSIntPoint cssPos(aXPos, aYPos);
5289 CheckSecurityLeftAndTop(&cssPos.x.value, &cssPos.y.value, aCallerType);
5290
5291 nsDeviceContext* context = presContext->DeviceContext();
5292
5293 auto devPos = LayoutDeviceIntPoint::FromAppUnitsRounded(
5294 CSSIntPoint::ToAppUnits(cssPos), context->AppUnitsPerDevPixel());
5295
5296 aError = treeOwnerAsWin->SetPosition(devPos.x, devPos.y);
5297 CheckForDPIChange();
5298}
5299
5300void nsGlobalWindowOuter::MoveByOuter(int32_t aXDif, int32_t aYDif,
5301 CallerType aCallerType,
5302 ErrorResult& aError) {
5303 /*
5304 * If caller is not chrome and the user has not explicitly exempted the site,
5305 * prevent window.moveBy() by exiting early
5306 */
5307
5308 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5309 return;
5310 }
5311
5312 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5313 if (!treeOwnerAsWin) {
5314 aError.Throw(NS_ERROR_FAILURE);
5315 return;
5316 }
5317
5318 // To do this correctly we have to convert what we get from GetPosition
5319 // into CSS pixels, add the arguments, do the security check, and
5320 // then convert back to device pixels for the call to SetPosition.
5321
5322 int32_t x, y;
5323 aError = treeOwnerAsWin->GetPosition(&x, &y);
5324 if (aError.Failed()) {
5325 return;
5326 }
5327
5328 auto cssScale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
5329 CSSIntPoint cssPos = RoundedToInt(treeOwnerAsWin->GetPosition() / cssScale);
5330
5331 cssPos.x += aXDif;
5332 cssPos.y += aYDif;
5333
5334 CheckSecurityLeftAndTop(&cssPos.x.value, &cssPos.y.value, aCallerType);
5335
5336 LayoutDeviceIntPoint newDevPos = RoundedToInt(cssPos * cssScale);
5337 aError = treeOwnerAsWin->SetPosition(newDevPos.x, newDevPos.y);
5338
5339 CheckForDPIChange();
5340}
5341
5342nsresult nsGlobalWindowOuter::MoveBy(int32_t aXDif, int32_t aYDif) {
5343 ErrorResult rv;
5344 MoveByOuter(aXDif, aYDif, CallerType::System, rv);
5345
5346 return rv.StealNSResult();
5347}
5348
5349void nsGlobalWindowOuter::ResizeToOuter(int32_t aWidth, int32_t aHeight,
5350 CallerType aCallerType,
5351 ErrorResult& aError) {
5352 /*
5353 * If caller is not chrome and the user has not explicitly exempted the site,
5354 * prevent window.resizeTo() by exiting early
5355 */
5356
5357 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5358 return;
5359 }
5360
5361 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5362 if (!treeOwnerAsWin) {
5363 aError.Throw(NS_ERROR_FAILURE);
5364 return;
5365 }
5366
5367 CSSIntSize cssSize(aWidth, aHeight);
5368 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5369
5370 LayoutDeviceIntSize devSize =
5371 RoundedToInt(cssSize * CSSToDevScaleForBaseWindow(treeOwnerAsWin));
5372 aError = treeOwnerAsWin->SetSize(devSize.width, devSize.height, true);
5373
5374 CheckForDPIChange();
5375}
5376
5377void nsGlobalWindowOuter::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif,
5378 CallerType aCallerType,
5379 ErrorResult& aError) {
5380 /*
5381 * If caller is not chrome and the user has not explicitly exempted the site,
5382 * prevent window.resizeBy() by exiting early
5383 */
5384
5385 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5386 return;
5387 }
5388
5389 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5390 if (!treeOwnerAsWin) {
5391 aError.Throw(NS_ERROR_FAILURE);
5392 return;
5393 }
5394
5395 LayoutDeviceIntSize size = treeOwnerAsWin->GetSize();
5396
5397 // To do this correctly we have to convert what we got from GetSize
5398 // into CSS pixels, add the arguments, do the security check, and
5399 // then convert back to device pixels for the call to SetSize.
5400
5401 auto scale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
5402 CSSIntSize cssSize = RoundedToInt(size / scale);
5403
5404 cssSize.width += aWidthDif;
5405 cssSize.height += aHeightDif;
5406
5407 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5408
5409 LayoutDeviceIntSize newDevSize = RoundedToInt(cssSize * scale);
5410
5411 aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true);
5412
5413 CheckForDPIChange();
5414}
5415
5416void nsGlobalWindowOuter::SizeToContentOuter(
5417 const SizeToContentConstraints& aConstraints, ErrorResult& aError) {
5418 if (!mDocShell) {
5419 return;
5420 }
5421
5422 if (mBrowsingContext->IsSubframe()) {
5423 return;
5424 }
5425
5426 // The content viewer does a check to make sure that it's a content
5427 // viewer for a toplevel docshell.
5428 nsCOMPtr<nsIDocumentViewer> viewer;
5429 mDocShell->GetDocViewer(getter_AddRefs(viewer));
5430 if (!viewer) {
5431 return aError.Throw(NS_ERROR_FAILURE);
5432 }
5433
5434 auto contentSize = viewer->GetContentSize(
5435 aConstraints.mMaxWidth, aConstraints.mMaxHeight, aConstraints.mPrefWidth);
5436 if (!contentSize) {
5437 return aError.Throw(NS_ERROR_FAILURE);
5438 }
5439
5440 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
5441 if (!treeOwner) {
5442 return aError.Throw(NS_ERROR_FAILURE);
5443 }
5444
5445 // Don't use DevToCSSIntPixelsForBaseWindow() nor
5446 // CSSToDevIntPixelsForBaseWindow() here because contentSize is comes from
5447 // nsIDocumentViewer::GetContentSize() and it's computed with nsPresContext so
5448 // that we need to work with nsPresContext here too.
5449 RefPtr<nsPresContext> presContext = viewer->GetPresContext();
5450 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"
, 5452); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5452; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5451 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"
, 5452); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5452; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5452 "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"
, 5452); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5452; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5453 CSSIntSize cssSize = *contentSize;
5454
5455 LayoutDeviceIntSize newDevSize(
5456 presContext->CSSPixelsToDevPixels(cssSize.width),
5457 presContext->CSSPixelsToDevPixels(cssSize.height));
5458
5459 nsCOMPtr<nsIDocShell> docShell = mDocShell;
5460 aError =
5461 treeOwner->SizeShellTo(docShell, newDevSize.width, newDevSize.height);
5462}
5463
5464already_AddRefed<nsPIWindowRoot> nsGlobalWindowOuter::GetTopWindowRoot() {
5465 nsPIDOMWindowOuter* piWin = GetPrivateRoot();
5466 if (!piWin) {
5467 return nullptr;
5468 }
5469
5470 nsCOMPtr<nsPIWindowRoot> window =
5471 do_QueryInterface(piWin->GetChromeEventHandler());
5472 return window.forget();
5473}
5474
5475void nsGlobalWindowOuter::FirePopupBlockedEvent(
5476 Document* aDoc, nsIURI* aPopupURI, const nsAString& aPopupWindowName,
5477 const nsAString& aPopupWindowFeatures) {
5478 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"
, 5478); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDoc" ")");
do { *((volatile int*)__null) = 5478; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5479
5480 // Fire a "DOMPopupBlocked" event so that the UI can hear about
5481 // blocked popups.
5482 PopupBlockedEventInit init;
5483 init.mBubbles = true;
5484 init.mCancelable = true;
5485 // XXX: This is a different object, but webidl requires an inner window here
5486 // now.
5487 init.mRequestingWindow = GetCurrentInnerWindowInternal(this);
5488 init.mPopupWindowURI = aPopupURI;
5489 init.mPopupWindowName = aPopupWindowName;
5490 init.mPopupWindowFeatures = aPopupWindowFeatures;
5491
5492 RefPtr<PopupBlockedEvent> event =
5493 PopupBlockedEvent::Constructor(aDoc, u"DOMPopupBlocked"_ns, init);
5494
5495 event->SetTrusted(true);
5496
5497 aDoc->DispatchEvent(*event);
5498}
5499
5500// static
5501bool nsGlobalWindowOuter::CanSetProperty(const char* aPrefName) {
5502 // Chrome can set any property.
5503 if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
5504 return true;
5505 }
5506
5507 // If the pref is set to true, we can not set the property
5508 // and vice versa.
5509 return !Preferences::GetBool(aPrefName, true);
5510}
5511
5512/* If a window open is blocked, fire the appropriate DOM events. */
5513void nsGlobalWindowOuter::FireAbuseEvents(
5514 const nsACString& aPopupURL, const nsAString& aPopupWindowName,
5515 const nsAString& aPopupWindowFeatures) {
5516 // fetch the URI of the window requesting the opened window
5517 nsCOMPtr<Document> currentDoc = GetDoc();
5518 nsCOMPtr<nsIURI> popupURI;
5519
5520 // build the URI of the would-have-been popup window
5521 // (see nsWindowWatcher::URIfromURL)
5522
5523 // first, fetch the opener's base URI
5524
5525 nsIURI* baseURL = nullptr;
5526
5527 nsCOMPtr<Document> doc = GetEntryDocument();
5528 if (doc) baseURL = doc->GetDocBaseURI();
5529
5530 // use the base URI to build what would have been the popup's URI
5531 Unused << NS_NewURI(getter_AddRefs(popupURI), aPopupURL, nullptr, baseURL);
5532
5533 // fire an event block full of informative URIs
5534 FirePopupBlockedEvent(currentDoc, popupURI, aPopupWindowName,
5535 aPopupWindowFeatures);
5536}
5537
5538Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenOuter(
5539 const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
5540 ErrorResult& aError) {
5541 RefPtr<BrowsingContext> bc;
5542 NS_ConvertUTF16toUTF8 url(aUrl);
5543 nsresult rv = OpenJS(url, aName, aOptions, getter_AddRefs(bc));
5544 if (rv == NS_ERROR_MALFORMED_URI) {
5545 aError.ThrowSyntaxError("Unable to open a window with invalid URL '"_ns +
5546 url + "'."_ns);
5547 return nullptr;
5548 }
5549
5550 // XXX Is it possible that some internal errors are thrown here?
5551 aError = rv;
5552
5553 if (!bc) {
5554 return nullptr;
5555 }
5556 return WindowProxyHolder(std::move(bc));
5557}
5558
5559nsresult nsGlobalWindowOuter::Open(const nsACString& aUrl,
5560 const nsAString& aName,
5561 const nsAString& aOptions,
5562 nsDocShellLoadState* aLoadState,
5563 bool aForceNoOpener,
5564 BrowsingContext** _retval) {
5565 return OpenInternal(aUrl, aName, aOptions,
5566 false, // aDialog
5567 true, // aCalledNoScript
5568 false, // aDoJSFixups
5569 true, // aNavigate
5570 nullptr, // No args
5571 aLoadState, aForceNoOpener, PrintKind::None, _retval);
5572}
5573
5574nsresult nsGlobalWindowOuter::OpenJS(const nsACString& aUrl,
5575 const nsAString& aName,
5576 const nsAString& aOptions,
5577 BrowsingContext** _retval) {
5578 return OpenInternal(aUrl, aName, aOptions,
5579 false, // aDialog
5580 false, // aCalledNoScript
5581 true, // aDoJSFixups
5582 true, // aNavigate
5583 nullptr, // No args
5584 nullptr, // aLoadState
5585 false, // aForceNoOpener
5586 PrintKind::None, _retval);
5587}
5588
5589// like Open, but attaches to the new window any extra parameters past
5590// [features] as a JS property named "arguments"
5591nsresult nsGlobalWindowOuter::OpenDialog(const nsACString& aUrl,
5592 const nsAString& aName,
5593 const nsAString& aOptions,
5594 nsIArray* aArguments,
5595 BrowsingContext** _retval) {
5596 return OpenInternal(aUrl, aName, aOptions,
5597 true, // aDialog
5598 true, // aCalledNoScript
5599 false, // aDoJSFixups
5600 true, // aNavigate
5601 aArguments, // Arguments
5602 nullptr, // aLoadState
5603 false, // aForceNoOpener
5604 PrintKind::None, _retval);
5605}
5606
5607// Like Open, but passes aNavigate=false.
5608/* virtual */
5609nsresult nsGlobalWindowOuter::OpenNoNavigate(const nsACString& aUrl,
5610 const nsAString& aName,
5611 const nsAString& aOptions,
5612 BrowsingContext** _retval) {
5613 return OpenInternal(aUrl, aName, aOptions,
5614 false, // aDialog
5615 true, // aCalledNoScript
5616 false, // aDoJSFixups
5617 false, // aNavigate
5618 nullptr, // No args
5619 nullptr, // aLoadState
5620 false, // aForceNoOpener
5621 PrintKind::None, _retval);
5622}
5623
5624Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenDialogOuter(
5625 JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
5626 const nsAString& aOptions, const Sequence<JS::Value>& aExtraArgument,
5627 ErrorResult& aError) {
5628 nsCOMPtr<nsIJSArgArray> argvArray;
5629 aError =
5630 NS_CreateJSArgv(aCx, aExtraArgument.Length(), aExtraArgument.Elements(),
5631 getter_AddRefs(argvArray));
5632 if (aError.Failed()) {
5633 return nullptr;
5634 }
5635
5636 RefPtr<BrowsingContext> dialog;
5637 aError = OpenInternal(NS_ConvertUTF16toUTF8(aUrl), aName, aOptions,
5638 true, // aDialog
5639 false, // aCalledNoScript
5640 false, // aDoJSFixups
5641 true, // aNavigate
5642 argvArray, // Arguments
5643 nullptr, // aLoadState
5644 false, // aForceNoOpener
5645 PrintKind::None, getter_AddRefs(dialog));
5646 if (!dialog) {
5647 return nullptr;
5648 }
5649 return WindowProxyHolder(std::move(dialog));
5650}
5651
5652WindowProxyHolder nsGlobalWindowOuter::GetFramesOuter() {
5653 RefPtr<nsPIDOMWindowOuter> frames(this);
5654 FlushPendingNotifications(FlushType::ContentAndNotify);
5655 return WindowProxyHolder(mBrowsingContext);
5656}
5657
5658/* static */
5659bool nsGlobalWindowOuter::GatherPostMessageData(
5660 JSContext* aCx, const nsAString& aTargetOrigin, BrowsingContext** aSource,
5661 nsAString& aOrigin, nsIURI** aTargetOriginURI,
5662 nsIPrincipal** aCallerPrincipal, nsGlobalWindowInner** aCallerInnerWindow,
5663 nsIURI** aCallerURI, Maybe<nsID>* aCallerAgentClusterId,
5664 nsACString* aScriptLocation, ErrorResult& aError) {
5665 //
5666 // Window.postMessage is an intentional subversion of the same-origin policy.
5667 // As such, this code must be particularly careful in the information it
5668 // exposes to calling code.
5669 //
5670 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5671 //
5672
5673 // First, get the caller's window
5674 RefPtr<nsGlobalWindowInner> callerInnerWin =
5675 nsContentUtils::IncumbentInnerWindow();
5676 nsIPrincipal* callerPrin;
5677 if (callerInnerWin) {
5678 RefPtr<Document> doc = callerInnerWin->GetExtantDoc();
5679 if (!doc) {
5680 return false;
5681 }
5682 NS_IF_ADDREF(*aCallerURI = doc->GetDocumentURI())ns_if_addref(*aCallerURI = doc->GetDocumentURI());
5683
5684 // Compute the caller's origin either from its principal or, in the case the
5685 // principal doesn't carry a URI (e.g. the system principal), the caller's
5686 // document. We must get this now instead of when the event is created and
5687 // dispatched, because ultimately it is the identity of the calling window
5688 // *now* that determines who sent the message (and not an identity which
5689 // might have changed due to intervening navigations).
5690 callerPrin = callerInnerWin->GetPrincipal();
5691 } else {
5692 // In case the global is not a window, it can be a sandbox, and the
5693 // sandbox's principal can be used for the security check.
5694 nsIGlobalObject* global = GetIncumbentGlobal();
5695 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"
, 5695); MOZ_PretendNoReturn(); } } while (0)
;
5696 callerPrin = global->PrincipalOrNull();
5697 if (callerPrin) {
5698 BasePrincipal::Cast(callerPrin)->GetScriptLocation(*aScriptLocation);
5699 }
5700 }
5701 if (!callerPrin) {
5702 return false;
5703 }
5704
5705 // if the principal has a URI, use that to generate the origin
5706 if (!callerPrin->IsSystemPrincipal()) {
5707 nsAutoCString webExposedOriginSerialization;
5708 callerPrin->GetWebExposedOriginSerialization(webExposedOriginSerialization);
5709 CopyUTF8toUTF16(webExposedOriginSerialization, aOrigin);
5710 } else if (callerInnerWin) {
5711 if (!*aCallerURI) {
5712 return false;
5713 }
5714 // otherwise use the URI of the document to generate origin
5715 nsContentUtils::GetWebExposedOriginSerialization(*aCallerURI, aOrigin);
5716 } else {
5717 // in case of a sandbox with a system principal origin can be empty
5718 if (!callerPrin->IsSystemPrincipal()) {
5719 return false;
5720 }
5721 }
5722 NS_IF_ADDREF(*aCallerPrincipal = callerPrin)ns_if_addref(*aCallerPrincipal = callerPrin);
5723
5724 // "/" indicates same origin as caller, "*" indicates no specific origin is
5725 // required.
5726 if (!aTargetOrigin.EqualsASCII("/") && !aTargetOrigin.EqualsASCII("*")) {
5727 nsCOMPtr<nsIURI> targetOriginURI;
5728 if (NS_FAILED(NS_NewURI(getter_AddRefs(targetOriginURI), aTargetOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(targetOriginURI), aTargetOrigin))), 0)))
) {
5729 aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
5730 return false;
5731 }
5732
5733 nsresult rv = NS_MutateURI(targetOriginURI)
5734 .SetUserPass(""_ns)
5735 .SetPathQueryRef(""_ns)
5736 .Finalize(aTargetOriginURI);
5737 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5738 return false;
5739 }
5740 }
5741
5742 if (!nsContentUtils::IsCallerChrome() && callerInnerWin &&
5743 callerInnerWin->GetOuterWindowInternal()) {
5744 NS_ADDREF(*aSource = callerInnerWin->GetOuterWindowInternal()(*aSource = callerInnerWin->GetOuterWindowInternal() ->
GetBrowsingContext())->AddRef()
5745 ->GetBrowsingContext())(*aSource = callerInnerWin->GetOuterWindowInternal() ->
GetBrowsingContext())->AddRef()
;
5746 } else {
5747 *aSource = nullptr;
5748 }
5749
5750 if (aCallerAgentClusterId && callerInnerWin &&
5751 callerInnerWin->GetDocGroup()) {
5752 *aCallerAgentClusterId =
5753 Some(callerInnerWin->GetDocGroup()->AgentClusterId());
5754 }
5755
5756 callerInnerWin.forget(aCallerInnerWindow);
5757
5758 return true;
5759}
5760
5761bool nsGlobalWindowOuter::GetPrincipalForPostMessage(
5762 const nsAString& aTargetOrigin, nsIURI* aTargetOriginURI,
5763 nsIPrincipal* aCallerPrincipal, nsIPrincipal& aSubjectPrincipal,
5764 nsIPrincipal** aProvidedPrincipal) {
5765 //
5766 // Window.postMessage is an intentional subversion of the same-origin policy.
5767 // As such, this code must be particularly careful in the information it
5768 // exposes to calling code.
5769 //
5770 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5771 //
5772
5773 // Convert the provided origin string into a URI for comparison purposes.
5774 nsCOMPtr<nsIPrincipal> providedPrincipal;
5775
5776 if (aTargetOrigin.EqualsASCII("/")) {
5777 providedPrincipal = aCallerPrincipal;
5778 }
5779 // "*" indicates no specific origin is required.
5780 else if (!aTargetOrigin.EqualsASCII("*")) {
5781 OriginAttributes attrs = aSubjectPrincipal.OriginAttributesRef();
5782 if (aSubjectPrincipal.IsSystemPrincipal()) {
5783 auto principal = BasePrincipal::Cast(GetPrincipal());
5784
5785 if (attrs != principal->OriginAttributesRef()) {
5786 nsAutoCString targetURL;
5787 nsAutoCString sourceOrigin;
5788 nsAutoCString targetOrigin;
5789
5790 if (NS_FAILED(principal->GetAsciiSpec(targetURL))((bool)(__builtin_expect(!!(NS_FAILED_impl(principal->GetAsciiSpec
(targetURL))), 0)))
||
5791 NS_FAILED(principal->GetOrigin(targetOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(principal->GetOrigin
(targetOrigin))), 0)))
||
5792 NS_FAILED(aSubjectPrincipal.GetOrigin(sourceOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(aSubjectPrincipal.
GetOrigin(sourceOrigin))), 0)))
) {
5793 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"
, 5793)
;
5794 return false;
5795 }
5796
5797 nsContentUtils::LogSimpleConsoleError(
5798 NS_ConvertUTF8toUTF16(nsPrintfCString(
5799 R"(Attempting to post a message to window with url "%s" and )"
5800 R"(origin "%s" from a system principal scope with mismatched )"
5801 R"(origin "%s".)",
5802 targetURL.get(), targetOrigin.get(), sourceOrigin.get())),
5803 "DOM"_ns, !!principal->PrivateBrowsingId(),
5804 principal->IsSystemPrincipal());
5805
5806 attrs = principal->OriginAttributesRef();
5807 }
5808 }
5809
5810 // Create a nsIPrincipal inheriting the app/browser attributes from the
5811 // caller.
5812 providedPrincipal =
5813 BasePrincipal::CreateContentPrincipal(aTargetOriginURI, attrs);
5814 if (NS_WARN_IF(!providedPrincipal)NS_warn_if_impl(!providedPrincipal, "!providedPrincipal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5814)
) {
5815 return false;
5816 }
5817 } else {
5818 // We still need to check the originAttributes if the target origin is '*'.
5819 // But we will ingore the FPD here since the FPDs are possible to be
5820 // different.
5821 auto principal = BasePrincipal::Cast(GetPrincipal());
5822 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"
, 5822); return false; } } while (false)
;
5823
5824 OriginAttributes targetAttrs = principal->OriginAttributesRef();
5825 OriginAttributes sourceAttrs = aSubjectPrincipal.OriginAttributesRef();
5826 // We have to exempt the check of OA if the subject prioncipal is a system
5827 // principal since there are many tests try to post messages to content from
5828 // chrome with a mismatch OA. For example, using the ContentTask.spawn() to
5829 // post a message into a private browsing window. The injected code in
5830 // ContentTask.spawn() will be executed under the system principal and the
5831 // OA of the system principal mismatches with the OA of a private browsing
5832 // window.
5833 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"
, 5834); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
")"); do { *((volatile int*)__null) = 5834; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5834 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"
, 5834); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
")"); do { *((volatile int*)__null) = 5834; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5835
5836 // If 'privacy.firstparty.isolate.block_post_message' is true, we will block
5837 // postMessage across different first party domains.
5838 if (OriginAttributes::IsBlockPostMessageForFPI() &&
5839 !aSubjectPrincipal.IsSystemPrincipal() &&
5840 sourceAttrs.mFirstPartyDomain != targetAttrs.mFirstPartyDomain) {
5841 return false;
5842 }
5843 }
5844
5845 providedPrincipal.forget(aProvidedPrincipal);
5846 return true;
5847}
5848
5849void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
5850 JS::Handle<JS::Value> aMessage,
5851 const nsAString& aTargetOrigin,
5852 JS::Handle<JS::Value> aTransfer,
5853 nsIPrincipal& aSubjectPrincipal,
5854 ErrorResult& aError) {
5855 RefPtr<BrowsingContext> sourceBc;
5856 nsAutoString origin;
5857 nsCOMPtr<nsIURI> targetOriginURI;
5858 nsCOMPtr<nsIPrincipal> callerPrincipal;
5859 RefPtr<nsGlobalWindowInner> callerInnerWindow;
5860 nsCOMPtr<nsIURI> callerURI;
5861 Maybe<nsID> callerAgentClusterId = Nothing();
5862 nsAutoCString scriptLocation;
5863 if (!GatherPostMessageData(
5864 aCx, aTargetOrigin, getter_AddRefs(sourceBc), origin,
5865 getter_AddRefs(targetOriginURI), getter_AddRefs(callerPrincipal),
5866 getter_AddRefs(callerInnerWindow), getter_AddRefs(callerURI),
5867 &callerAgentClusterId, &scriptLocation, aError)) {
5868 return;
5869 }
5870
5871 nsCOMPtr<nsIPrincipal> providedPrincipal;
5872 if (!GetPrincipalForPostMessage(aTargetOrigin, targetOriginURI,
5873 callerPrincipal, aSubjectPrincipal,
5874 getter_AddRefs(providedPrincipal))) {
5875 return;
5876 }
5877
5878 // Create and asynchronously dispatch a runnable which will handle actual DOM
5879 // event creation and dispatch.
5880 RefPtr<PostMessageEvent> event = new PostMessageEvent(
5881 sourceBc, origin, this, providedPrincipal,
5882 callerInnerWindow ? callerInnerWindow->WindowID() : 0, callerURI,
5883 scriptLocation, callerAgentClusterId);
5884
5885 JS::CloneDataPolicy clonePolicy;
5886
5887 if (GetDocGroup() && callerAgentClusterId.isSome() &&
5888 GetDocGroup()->AgentClusterId().Equals(callerAgentClusterId.value())) {
5889 clonePolicy.allowIntraClusterClonableSharedObjects();
5890 }
5891
5892 if (callerInnerWindow && callerInnerWindow->IsSharedMemoryAllowed()) {
5893 clonePolicy.allowSharedMemoryObjects();
5894 }
5895
5896 event->Write(aCx, aMessage, aTransfer, clonePolicy, aError);
5897 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"
, 5897)
) {
5898 return;
5899 }
5900
5901 event->DispatchToTargetThread(aError);
5902}
5903
5904class nsCloseEvent : public Runnable {
5905 RefPtr<nsGlobalWindowOuter> mWindow;
5906 bool mIndirect;
5907
5908 nsCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect)
5909 : mozilla::Runnable("nsCloseEvent"),
5910 mWindow(aWindow),
5911 mIndirect(aIndirect) {}
5912
5913 public:
5914 static nsresult PostCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect) {
5915 nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
5916 return aWindow->Dispatch(ev.forget());
5917 }
5918
5919 NS_IMETHODvirtual nsresult Run() override {
5920 if (mWindow) {
5921 if (mIndirect) {
5922 return PostCloseEvent(mWindow, false);
5923 }
5924 mWindow->ReallyCloseWindow();
5925 }
5926 return NS_OK;
5927 }
5928};
5929
5930bool nsGlobalWindowOuter::CanClose() {
5931 if (mIsChrome) {
5932 nsCOMPtr<nsIBrowserDOMWindow> bwin = GetBrowserDOMWindow();
5933
5934 bool canClose = true;
5935 if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))((bool)(__builtin_expect(!!(!NS_FAILED_impl(bwin->CanClose
(&canClose))), 1)))
) {
5936 return canClose;
5937 }
5938 }
5939
5940 if (!mDocShell) {
5941 return true;
5942 }
5943
5944 nsCOMPtr<nsIDocumentViewer> viewer;
5945 mDocShell->GetDocViewer(getter_AddRefs(viewer));
5946 if (viewer) {
5947 bool canClose;
5948 nsresult rv = viewer->PermitUnload(&canClose);
5949 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !canClose) return false;
5950 }
5951
5952 // If we still have to print, we delay the closing until print has happened.
5953 if (mShouldDelayPrintUntilAfterLoad && mDelayedPrintUntilAfterLoad) {
5954 mDelayedCloseForPrinting = true;
5955 return false;
5956 }
5957
5958 return true;
5959}
5960
5961void nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller) {
5962 if (!mDocShell || IsInModalState() || mBrowsingContext->IsSubframe()) {
5963 // window.close() is called on a frame in a frameset, on a window
5964 // that's already closed, or on a window for which there's
5965 // currently a modal dialog open. Ignore such calls.
5966 return;
5967 }
5968
5969 if (mHavePendingClose) {
5970 // We're going to be closed anyway; do nothing since we don't want
5971 // to double-close
5972 return;
5973 }
5974
5975 if (mBlockScriptedClosingFlag) {
5976 // A script's popup has been blocked and we don't want
5977 // the window to be closed directly after this event,
5978 // so the user can see that there was a blocked popup.
5979 return;
5980 }
5981
5982 // Don't allow scripts from content to close non-neterror windows that
5983 // were not opened by script.
5984 if (mDoc) {
5985 nsAutoString url;
5986 nsresult rv = mDoc->GetURL(url);
5987 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"
, 5987); return; } } while (false)
;
5988
5989 if (!StringBeginsWith(url, u"about:neterror"_ns) &&
5990 !mBrowsingContext->GetTopLevelCreatedByWebContent() &&
5991 !aTrustedCaller && !IsOnlyTopLevelDocumentInSHistory()) {
5992 bool allowClose =
5993 mAllowScriptsToClose ||
5994 Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
5995 if (!allowClose) {
5996 // We're blocking the close operation
5997 // report localized error msg in JS console
5998 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
5999 "DOM Window"_ns,
6000 mDoc, // Better name for the category?
6001 nsContentUtils::eDOM_PROPERTIES,
6002 "WindowCloseByScriptBlockedWarning");
6003
6004 return;
6005 }
6006 }
6007 }
6008
6009 if (!mInClose && !mIsClosed && !CanClose()) {
6010 return;
6011 }
6012
6013 // Fire a DOM event notifying listeners that this window is about to
6014 // be closed. The tab UI code may choose to cancel the default
6015 // action for this event, if so, we won't actually close the window
6016 // (since the tab UI code will close the tab in stead). Sure, this
6017 // could be abused by content code, but do we care? I don't think
6018 // so...
6019
6020 bool wasInClose = mInClose;
6021 mInClose = true;
6022
6023 if (!DispatchCustomEvent(u"DOMWindowClose"_ns, ChromeOnlyDispatch::eYes)) {
6024 // Someone chose to prevent the default action for this event, if
6025 // so, let's not close this window after all...
6026
6027 mInClose = wasInClose;
6028 return;
6029 }
6030
6031 FinalClose();
6032}
6033
6034bool nsGlobalWindowOuter::IsOnlyTopLevelDocumentInSHistory() {
6035 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"
, 6035); return false; } } while (false)
;
6036 // Disabled since IsFrame() is buggy in Fission
6037 // MOZ_ASSERT(mBrowsingContext->IsTop());
6038
6039 if (mozilla::SessionHistoryInParent()) {
6040 return mBrowsingContext->GetIsSingleToplevelInHistory();
6041 }
6042
6043 RefPtr<ChildSHistory> csh = nsDocShell::Cast(mDocShell)->GetSessionHistory();
6044 if (csh && csh->LegacySHistory()) {
6045 return csh->LegacySHistory()->IsEmptyOrHasEntriesForSingleTopLevelPage();
6046 }
6047
6048 return false;
6049}
6050
6051nsresult nsGlobalWindowOuter::Close() {
6052 CloseOuter(/* aTrustedCaller = */ true);
6053 return NS_OK;
6054}
6055
6056void nsGlobalWindowOuter::ForceClose() {
6057 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"
, 6057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_GetProcessType() == GeckoProcessType_Default"
")"); do { *((volatile int*)__null) = 6057; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6058
6059 if (mBrowsingContext->IsSubframe() || !mDocShell) {
6060 // This may be a frame in a frameset, or a window that's already closed.
6061 // Ignore such calls.
6062 return;
6063 }
6064
6065 if (mHavePendingClose) {
6066 // We're going to be closed anyway; do nothing since we don't want
6067 // to double-close
6068 return;
6069 }
6070
6071 mInClose = true;
6072
6073 DispatchCustomEvent(u"DOMWindowClose"_ns, ChromeOnlyDispatch::eYes);
6074
6075 FinalClose();
6076}
6077
6078void nsGlobalWindowOuter::FinalClose() {
6079 // Flag that we were closed.
6080 mIsClosed = true;
6081
6082 if (!mBrowsingContext->IsDiscarded()) {
6083 MOZ_ALWAYS_SUCCEEDS(mBrowsingContext->SetClosed(true))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(mBrowsingContext->SetClosed(true))), 1)))), 1))) { } else
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(mBrowsingContext->SetClosed(true))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6083); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(mBrowsingContext->SetClosed(true))" ")"
); do { *((volatile int*)__null) = 6083; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6084 }
6085
6086 // If we get here from CloseOuter then it means that the parent process is
6087 // going to close our window for us. It's just important to set mIsClosed.
6088 if (XRE_GetProcessType() == GeckoProcessType_Content) {
6089 return;
6090 }
6091
6092 // This stuff is non-sensical but incredibly fragile. The reasons for the
6093 // behavior here don't make sense today and may not have ever made sense,
6094 // but various bits of frontend code break when you change them. If you need
6095 // to fix up this behavior, feel free to. It's a righteous task, but involves
6096 // wrestling with various download manager tests, frontend code, and possible
6097 // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
6098 // testing ground.
6099 //
6100 // In particular, if some inner of |win| is the entry global, we must
6101 // complete _two_ round-trips to the event loop before the call to
6102 // ReallyCloseWindow. This allows setTimeout handlers that are set after
6103 // FinalClose() is called to run before the window is torn down.
6104 nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6105 do_QueryInterface(GetEntryGlobal());
6106 bool indirect = entryWindow && entryWindow->GetOuterWindow() == this;
6107 if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsCloseEvent::PostCloseEvent
(this, indirect))), 0)))
) {
6108 ReallyCloseWindow();
6109 } else {
6110 mHavePendingClose = true;
6111 }
6112}
6113
6114void nsGlobalWindowOuter::ReallyCloseWindow() {
6115 // Make sure we never reenter this method.
6116 mHavePendingClose = true;
6117
6118 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6119 if (!treeOwnerAsWin) {
6120 return;
6121 }
6122
6123 treeOwnerAsWin->Destroy();
6124 CleanUp();
6125}
6126
6127void nsGlobalWindowOuter::SuppressEventHandling() {
6128 if (mSuppressEventHandlingDepth == 0) {
6129 if (BrowsingContext* bc = GetBrowsingContext()) {
6130 bc->PreOrderWalk([&](BrowsingContext* aBC) {
6131 if (nsCOMPtr<nsPIDOMWindowOuter> win = aBC->GetDOMWindow()) {
6132 if (RefPtr<Document> doc = win->GetExtantDoc()) {
6133 mSuspendedDocs.AppendElement(doc);
6134 // Note: Document::SuppressEventHandling will also automatically
6135 // suppress event handling for any in-process sub-documents.
6136 // However, since we need to deal with cases where remote
6137 // BrowsingContexts may be interleaved with in-process ones, we
6138 // still need to walk the entire tree ourselves. This may be
6139 // slightly redundant in some cases, but since event handling
6140 // suppressions maintain a count of current blockers, it does not
6141 // cause any problems.
6142 doc->SuppressEventHandling();
6143 }
6144 }
6145 });
6146 }
6147 }
6148 mSuppressEventHandlingDepth++;
6149}
6150
6151void nsGlobalWindowOuter::UnsuppressEventHandling() {
6152 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"
, 6152); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSuppressEventHandlingDepth != 0"
")"); do { *((volatile int*)__null) = 6152; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6153 mSuppressEventHandlingDepth--;
6154
6155 if (mSuppressEventHandlingDepth == 0 && mSuspendedDocs.Length()) {
6156 RefPtr<Document> currentDoc = GetExtantDoc();
6157 bool fireEvent = currentDoc == mSuspendedDocs[0];
6158 nsTArray<RefPtr<Document>> suspendedDocs = std::move(mSuspendedDocs);
6159 for (const auto& doc : suspendedDocs) {
6160 doc->UnsuppressEventHandlingAndFireEvents(fireEvent);
6161 }
6162 }
6163}
6164
6165nsGlobalWindowOuter* nsGlobalWindowOuter::EnterModalState() {
6166 // GetInProcessScriptableTop, not GetInProcessTop, so that EnterModalState
6167 // works properly with <iframe mozbrowser>.
6168 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6169
6170 if (!topWin) {
6171 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"
, 6171); MOZ_PretendNoReturn(); } while (0)
;
6172 return nullptr;
6173 }
6174
6175 // If there is an active ESM in this window, clear it. Otherwise, this can
6176 // cause a problem if a modal state is entered during a mouseup event.
6177 EventStateManager* activeESM = static_cast<EventStateManager*>(
6178 EventStateManager::GetActiveEventStateManager());
6179 if (activeESM && activeESM->GetPresContext()) {
6180 PresShell* activePresShell = activeESM->GetPresContext()->GetPresShell();
6181 if (activePresShell && (nsContentUtils::ContentIsCrossDocDescendantOf(
6182 activePresShell->GetDocument(), mDoc) ||
6183 nsContentUtils::ContentIsCrossDocDescendantOf(
6184 mDoc, activePresShell->GetDocument()))) {
6185 EventStateManager::ClearGlobalActiveContent(activeESM);
6186
6187 PresShell::ReleaseCapturingContent();
6188
6189 if (activePresShell) {
6190 RefPtr<nsFrameSelection> frameSelection =
6191 activePresShell->FrameSelection();
6192 frameSelection->SetDragState(false);
6193 }
6194 }
6195 }
6196
6197 // If there are any drag and drop operations in flight, try to end them.
6198 nsCOMPtr<nsIDragService> ds =
6199 do_GetService("@mozilla.org/widget/dragservice;1");
6200 if (ds && topWin->GetDocShell()) {
6201 if (PresShell* presShell = topWin->GetDocShell()->GetPresShell()) {
6202 if (nsViewManager* vm = presShell->GetViewManager()) {
6203 RefPtr<nsIWidget> widget = vm->GetRootWidget();
6204 if (nsCOMPtr<nsIDragSession> session = ds->GetCurrentSession(widget)) {
6205 session->EndDragSession(true, 0);
6206 }
6207 }
6208 }
6209 }
6210
6211 // Clear the capturing content if it is under topDoc.
6212 // Usually the activeESM check above does that, but there are cases when
6213 // we don't have activeESM, or it is for different document.
6214 Document* topDoc = topWin->GetExtantDoc();
6215 nsIContent* capturingContent = PresShell::GetCapturingContent();
6216 if (capturingContent && topDoc &&
6217 nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
6218 PresShell::ReleaseCapturingContent();
6219 }
6220
6221 if (topWin->mModalStateDepth == 0) {
6222 topWin->SuppressEventHandling();
6223
6224 if (nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(topWin)) {
6225 inner->Suspend();
6226 }
6227 }
6228 topWin->mModalStateDepth++;
6229 return topWin;
6230}
6231
6232void nsGlobalWindowOuter::LeaveModalState() {
6233 {
6234 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6235 if (!topWin) {
6236 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"
, 6236)
;
6237 return;
6238 }
6239
6240 if (topWin != this) {
6241 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"
, 6241); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSuspended()"
")"); do { *((volatile int*)__null) = 6241; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6242 return topWin->LeaveModalState();
6243 }
6244 }
6245
6246 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"
, 6246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mModalStateDepth != 0"
")"); do { *((volatile int*)__null) = 6246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6247 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"
, 6247); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSuspended()"
")"); do { *((volatile int*)__null) = 6247; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6248 mModalStateDepth--;
6249
6250 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6251 if (mModalStateDepth == 0) {
6252 if (inner) {
6253 inner->Resume();
6254 }
6255
6256 UnsuppressEventHandling();
6257 }
6258
6259 // Remember the time of the last dialog quit.
6260 if (auto* bcg = GetBrowsingContextGroup()) {
6261 bcg->SetLastDialogQuitTime(TimeStamp::Now());
6262 }
6263
6264 if (mModalStateDepth == 0) {
6265 RefPtr<Event> event = NS_NewDOMEvent(inner, nullptr, nullptr);
6266 event->InitEvent(u"endmodalstate"_ns, true, false);
6267 event->SetTrusted(true);
6268 event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
6269 DispatchEvent(*event);
6270 }
6271}
6272
6273bool nsGlobalWindowOuter::IsInModalState() {
6274 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6275
6276 if (!topWin) {
6277 // IsInModalState() getting called w/o a reachable top window is a bit
6278 // iffy, but valid enough not to make noise about it. See bug 404828
6279 return false;
6280 }
6281
6282 return topWin->mModalStateDepth != 0;
6283}
6284
6285void nsGlobalWindowOuter::NotifyWindowIDDestroyed(const char* aTopic) {
6286 nsCOMPtr<nsIRunnable> runnable =
6287 new WindowDestroyedEvent(this, mWindowID, aTopic);
6288 Dispatch(runnable.forget());
6289}
6290
6291Element* nsGlobalWindowOuter::GetFrameElement(nsIPrincipal& aSubjectPrincipal) {
6292 // Per HTML5, the frameElement getter returns null in cross-origin situations.
6293 Element* element = GetFrameElement();
6294 if (!element) {
6295 return nullptr;
6296 }
6297
6298 if (!aSubjectPrincipal.SubsumesConsideringDomain(element->NodePrincipal())) {
6299 return nullptr;
6300 }
6301
6302 return element;
6303}
6304
6305Element* nsGlobalWindowOuter::GetFrameElement() {
6306 if (!mBrowsingContext || mBrowsingContext->IsTop()) {
6307 return nullptr;
6308 }
6309 return mBrowsingContext->GetEmbedderElement();
6310}
6311
6312namespace {
6313class ChildCommandDispatcher : public Runnable {
6314 public:
6315 ChildCommandDispatcher(nsPIWindowRoot* aRoot, nsIBrowserChild* aBrowserChild,
6316 nsPIDOMWindowOuter* aWindow, const nsAString& aAction)
6317 : mozilla::Runnable("ChildCommandDispatcher"),
6318 mRoot(aRoot),
6319 mBrowserChild(aBrowserChild),
6320 mWindow(aWindow),
6321 mAction(aAction) {}
6322
6323 NS_IMETHODvirtual nsresult Run() override {
6324 AutoTArray<nsCString, 70> enabledCommands, disabledCommands;
6325 mRoot->GetEnabledDisabledCommands(enabledCommands, disabledCommands);
6326 if (enabledCommands.Length() || disabledCommands.Length()) {
6327 BrowserChild* bc = static_cast<BrowserChild*>(mBrowserChild.get());
6328 bc->SendEnableDisableCommands(mWindow->GetBrowsingContext(), mAction,
6329 enabledCommands, disabledCommands);
6330 }
6331
6332 return NS_OK;
6333 }
6334
6335 private:
6336 nsCOMPtr<nsPIWindowRoot> mRoot;
6337 nsCOMPtr<nsIBrowserChild> mBrowserChild;
6338 nsCOMPtr<nsPIDOMWindowOuter> mWindow;
6339 nsString mAction;
6340};
6341
6342class CommandDispatcher : public Runnable {
6343 public:
6344 CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
6345 const nsAString& aAction)
6346 : mozilla::Runnable("CommandDispatcher"),
6347 mDispatcher(aDispatcher),
6348 mAction(aAction) {}
6349
6350 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230, bug 1535398)
6351 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODvirtual nsresult Run() override {
6352 return mDispatcher->UpdateCommands(mAction);
6353 }
6354
6355 const nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
6356 nsString mAction;
6357};
6358} // anonymous namespace
6359
6360void nsGlobalWindowOuter::UpdateCommands(const nsAString& anAction) {
6361 // If this is a child process, redirect to the parent process.
6362 if (nsIDocShell* docShell = GetDocShell()) {
6363 if (nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild()) {
6364 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
6365 if (root) {
6366 nsContentUtils::AddScriptRunner(
6367 new ChildCommandDispatcher(root, child, this, anAction));
6368 }
6369 return;
6370 }
6371 }
6372
6373 nsPIDOMWindowOuter* rootWindow = GetPrivateRoot();
6374 if (!rootWindow) {
6375 return;
6376 }
6377
6378 Document* doc = rootWindow->GetExtantDoc();
6379
6380 if (!doc) {
6381 return;
6382 }
6383
6384 // Retrieve the command dispatcher and call updateCommands on it.
6385 nsIDOMXULCommandDispatcher* xulCommandDispatcher =
6386 doc->GetCommandDispatcher();
6387 if (xulCommandDispatcher) {
6388 nsContentUtils::AddScriptRunner(
6389 new CommandDispatcher(xulCommandDispatcher, anAction));
6390 }
6391}
6392
6393Selection* nsGlobalWindowOuter::GetSelectionOuter() {
6394 if (!mDocShell) {
6395 return nullptr;
6396 }
6397
6398 PresShell* presShell = mDocShell->GetPresShell();
6399 if (!presShell) {
6400 return nullptr;
6401 }
6402 return presShell->GetCurrentSelection(SelectionType::eNormal);
6403}
6404
6405already_AddRefed<Selection> nsGlobalWindowOuter::GetSelection() {
6406 RefPtr<Selection> selection = GetSelectionOuter();
6407 return selection.forget();
6408}
6409
6410bool nsGlobalWindowOuter::FindOuter(const nsAString& aString,
6411 bool aCaseSensitive, bool aBackwards,
6412 bool aWrapAround, bool aWholeWord,
6413 bool aSearchInFrames, bool aShowDialog,
6414 ErrorResult& aError) {
6415 Unused << aShowDialog;
6416
6417 nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
6418 if (!finder) {
6419 aError.Throw(NS_ERROR_NOT_AVAILABLE);
6420 return false;
6421 }
6422
6423 // Set the options of the search
6424 aError = finder->SetSearchString(aString);
6425 if (aError.Failed()) {
6426 return false;
6427 }
6428 finder->SetMatchCase(aCaseSensitive);
6429 finder->SetFindBackwards(aBackwards);
6430 finder->SetWrapFind(aWrapAround);
6431 finder->SetEntireWord(aWholeWord);
6432 finder->SetSearchFrames(aSearchInFrames);
6433
6434 // the nsIWebBrowserFind is initialized to use this window
6435 // as the search root, but uses focus to set the current search
6436 // frame. If we're being called from JS (as here), this window
6437 // should be the current search frame.
6438 nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
6439 if (framesFinder) {
6440 framesFinder->SetRootSearchFrame(this); // paranoia
6441 framesFinder->SetCurrentSearchFrame(this);
6442 }
6443
6444 if (aString.IsEmpty()) {
6445 return false;
6446 }
6447
6448 // Launch the search with the passed in search string
6449 bool didFind = false;
6450 aError = finder->FindNext(&didFind);
6451 return didFind;
6452}
6453
6454//*****************************************************************************
6455// EventTarget
6456//*****************************************************************************
6457
6458nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOwnerGlobalForBindingsInternal() {
6459 return this;
6460}
6461
6462nsIGlobalObject* nsGlobalWindowOuter::GetOwnerGlobal() const {
6463 return GetCurrentInnerWindowInternal(this);
6464}
6465
6466bool nsGlobalWindowOuter::DispatchEvent(Event& aEvent, CallerType aCallerType,
6467 ErrorResult& aRv) {
6468 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"
, 6468); return false; } return GetCurrentInnerWindowInternal
(this)->DispatchEvent (aEvent, aCallerType, aRv); } while (
0)
;
6469}
6470
6471bool nsGlobalWindowOuter::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
6472 // It's OK that we just return false here on failure to create an
6473 // inner. GetOrCreateListenerManager() will likewise fail, and then
6474 // we won't be adding any listeners anyway.
6475 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)
;
6476}
6477
6478EventListenerManager* nsGlobalWindowOuter::GetOrCreateListenerManager() {
6479 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)
;
6480}
6481
6482EventListenerManager* nsGlobalWindowOuter::GetExistingListenerManager() const {
6483 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"
, 6483); return nullptr; } return GetCurrentInnerWindowInternal
(this)->GetExistingListenerManager (); } while (0)
;
6484}
6485
6486//*****************************************************************************
6487// nsGlobalWindowOuter::nsPIDOMWindow
6488//*****************************************************************************
6489
6490nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateParent() {
6491 nsCOMPtr<nsPIDOMWindowOuter> parent = GetInProcessParent();
6492
6493 if (this == parent) {
6494 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6495 if (!chromeElement)
6496 return nullptr; // This is ok, just means a null parent.
6497
6498 Document* doc = chromeElement->GetComposedDoc();
6499 if (!doc) return nullptr; // This is ok, just means a null parent.
6500
6501 return doc->GetWindow();
6502 }
6503
6504 return parent;
6505}
6506
6507nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateRoot() {
6508 nsCOMPtr<nsPIDOMWindowOuter> top = GetInProcessTop();
6509
6510 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6511 if (chromeElement) {
6512 Document* doc = chromeElement->GetComposedDoc();
6513 if (doc) {
6514 nsCOMPtr<nsPIDOMWindowOuter> parent = doc->GetWindow();
6515 if (parent) {
6516 top = parent->GetInProcessTop();
6517 }
6518 }
6519 }
6520
6521 return top;
6522}
6523
6524// This has a caller in Windows-only code (nsNativeAppSupportWin).
6525Location* nsGlobalWindowOuter::GetLocation() {
6526 // This method can be called on the outer window as well.
6527 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"
, 6527); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Location (); } while (0)
;
6528}
6529
6530void nsGlobalWindowOuter::SetIsBackground(bool aIsBackground) {
6531 bool changed = aIsBackground != IsBackground();
6532 SetIsBackgroundInternal(aIsBackground);
6533
6534 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6535
6536 if (inner && changed) {
6537 inner->UpdateBackgroundState();
6538 }
6539
6540 if (aIsBackground) {
6541 // Notify gamepadManager we are at the background window,
6542 // we need to stop vibrate.
6543 // Stop the vr telemery time spent when it switches to
6544 // the background window.
6545 if (inner && changed) {
6546 inner->StopGamepadHaptics();
6547 inner->StopVRActivity();
6548 // true is for asking to set the delta time to
6549 // the telemetry.
6550 inner->ResetVRTelemetry(true);
6551 }
6552 return;
6553 }
6554
6555 if (inner) {
6556 // When switching to be as a top tab, restart the telemetry.
6557 // false is for only resetting the timestamp.
6558 inner->ResetVRTelemetry(false);
6559 inner->SyncGamepadState();
6560 inner->StartVRActivity();
6561 }
6562}
6563
6564void nsGlobalWindowOuter::SetIsBackgroundInternal(bool aIsBackground) {
6565 mIsBackground = aIsBackground;
6566}
6567
6568void nsGlobalWindowOuter::SetChromeEventHandler(
6569 EventTarget* aChromeEventHandler) {
6570 SetChromeEventHandlerInternal(aChromeEventHandler);
6571 // update the chrome event handler on all our inner windows
6572 RefPtr<nsGlobalWindowInner> inner;
6573 for (PRCList* node = PR_LIST_HEAD(this)(this)->next; node != this;
6574 node = PR_NEXT_LINK(inner)((inner)->next)) {
6575 // This cast is only safe if `node != this`, as nsGlobalWindowOuter is also
6576 // in the list.
6577 inner = static_cast<nsGlobalWindowInner*>(node);
6578 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"
, 6579); MOZ_PretendNoReturn(); } } while (0)
6579 "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"
, 6579); MOZ_PretendNoReturn(); } } while (0)
;
6580 inner->SetChromeEventHandlerInternal(aChromeEventHandler);
6581 }
6582}
6583
6584void nsGlobalWindowOuter::SetFocusedElement(Element* aElement,
6585 uint32_t aFocusMethod,
6586 bool aNeedsFocus) {
6587 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"
, 6588); return; } GetCurrentInnerWindowInternal(this)->SetFocusedElement
(aElement, aFocusMethod, aNeedsFocus); return; } while (0)
6588 (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"
, 6588); return; } GetCurrentInnerWindowInternal(this)->SetFocusedElement
(aElement, aFocusMethod, aNeedsFocus); return; } while (0)
;
6589}
6590
6591uint32_t nsGlobalWindowOuter::GetFocusMethod() {
6592 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"
, 6592); return 0; } return GetCurrentInnerWindowInternal(this
)->GetFocusMethod (); } while (0)
;
6593}
6594
6595bool nsGlobalWindowOuter::ShouldShowFocusRing() {
6596 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"
, 6596); return false; } return GetCurrentInnerWindowInternal
(this)->ShouldShowFocusRing (); } while (0)
;
6597}
6598
6599bool nsGlobalWindowOuter::TakeFocus(bool aFocus, uint32_t aFocusMethod) {
6600 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"
, 6600); return false; } return GetCurrentInnerWindowInternal
(this)->TakeFocus (aFocus, aFocusMethod); } while (0)
;
6601}
6602
6603void nsGlobalWindowOuter::SetReadyForFocus() {
6604 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"
, 6604); return; } GetCurrentInnerWindowInternal(this)->SetReadyForFocus
(); return; } while (0)
;
6605}
6606
6607void nsGlobalWindowOuter::PageHidden(bool aIsEnteringBFCacheInParent) {
6608 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"
, 6608); return; } GetCurrentInnerWindowInternal(this)->PageHidden
(aIsEnteringBFCacheInParent); return; } while (0)
;
6609}
6610
6611already_AddRefed<nsICSSDeclaration>
6612nsGlobalWindowOuter::GetComputedStyleHelperOuter(Element& aElt,
6613 const nsAString& aPseudoElt,
6614 bool aDefaultStylesOnly,
6615 ErrorResult& aRv) {
6616 if (!mDoc) {
6617 return nullptr;
6618 }
6619
6620 RefPtr<nsICSSDeclaration> compStyle = NS_NewComputedDOMStyle(
6621 &aElt, aPseudoElt, mDoc,
6622 aDefaultStylesOnly ? nsComputedDOMStyle::StyleType::DefaultOnly
6623 : nsComputedDOMStyle::StyleType::All,
6624 aRv);
6625
6626 return compStyle.forget();
6627}
6628
6629//*****************************************************************************
6630// nsGlobalWindowOuter::nsIInterfaceRequestor
6631//*****************************************************************************
6632
6633nsresult nsGlobalWindowOuter::GetInterfaceInternal(const nsIID& aIID,
6634 void** aSink) {
6635 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"
, 6635); return NS_ERROR_INVALID_POINTER; } } while (false)
;
6636 *aSink = nullptr;
6637
6638 if (aIID.Equals(NS_GET_IID(nsIWebNavigation)(nsIWebNavigation::COMTypeInfo<nsIWebNavigation, void>::
kIID)
)) {
6639 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
6640 webNav.forget(aSink);
6641 } else if (aIID.Equals(NS_GET_IID(nsIDocShell)(nsIDocShell::COMTypeInfo<nsIDocShell, void>::kIID))) {
6642 nsCOMPtr<nsIDocShell> docShell = mDocShell;
6643 docShell.forget(aSink);
6644 }
6645#ifdef NS_PRINTING1
6646 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint)(nsIWebBrowserPrint::COMTypeInfo<nsIWebBrowserPrint, void>
::kIID)
)) {
6647 if (mDocShell) {
6648 nsCOMPtr<nsIDocumentViewer> viewer;
6649 mDocShell->GetDocViewer(getter_AddRefs(viewer));
6650 if (viewer) {
6651 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
6652 webBrowserPrint.forget(aSink);
6653 }
6654 }
6655 }
6656#endif
6657 else if (aIID.Equals(NS_GET_IID(nsILoadContext)(nsILoadContext::COMTypeInfo<nsILoadContext, void>::kIID
)
)) {
6658 nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(mDocShell));
6659 loadContext.forget(aSink);
6660 }
6661
6662 return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
6663}
6664
6665NS_IMETHODIMPnsresult
6666nsGlobalWindowOuter::GetInterface(const nsIID& aIID, void** aSink) {
6667 nsresult rv = GetInterfaceInternal(aIID, aSink);
6668 if (rv == NS_ERROR_NO_INTERFACE) {
6669 return QueryInterface(aIID, aSink);
6670 }
6671 return rv;
6672}
6673
6674bool nsGlobalWindowOuter::IsSuspended() const {
6675 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"
, 6675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6675; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6676 // No inner means we are effectively suspended
6677 if (!mInnerWindow) {
6678 return true;
6679 }
6680 return mInnerWindow->IsSuspended();
6681}
6682
6683bool nsGlobalWindowOuter::IsFrozen() const {
6684 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"
, 6684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6684; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6685 // No inner means we are effectively frozen
6686 if (!mInnerWindow) {
6687 return true;
6688 }
6689 return mInnerWindow->IsFrozen();
6690}
6691
6692nsresult nsGlobalWindowOuter::FireDelayedDOMEvents(bool aIncludeSubWindows) {
6693 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"
, 6694); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->FireDelayedDOMEvents (aIncludeSubWindows); } while
(0)
6694 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"
, 6694); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->FireDelayedDOMEvents (aIncludeSubWindows); } while
(0)
;
6695}
6696
6697//*****************************************************************************
6698// nsGlobalWindowOuter: Window Control Functions
6699//*****************************************************************************
6700
6701nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessParentInternal() {
6702 nsCOMPtr<nsPIDOMWindowOuter> parent = GetInProcessParent();
6703
6704 if (parent && parent != this) {
6705 return parent;
6706 }
6707
6708 return nullptr;
6709}
6710
6711void nsGlobalWindowOuter::UnblockScriptedClosing() {
6712 mBlockScriptedClosingFlag = false;
6713}
6714
6715class AutoUnblockScriptClosing {
6716 private:
6717 RefPtr<nsGlobalWindowOuter> mWin;
6718
6719 public:
6720 explicit AutoUnblockScriptClosing(nsGlobalWindowOuter* aWin) : mWin(aWin) {
6721 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"
, 6721); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWin" ")");
do { *((volatile int*)__null) = 6721; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6722 }
6723 ~AutoUnblockScriptClosing() {
6724 void (nsGlobalWindowOuter::*run)() =
6725 &nsGlobalWindowOuter::UnblockScriptedClosing;
6726 nsCOMPtr<nsIRunnable> caller = NewRunnableMethod(
23
Calling 'NewRunnableMethod<RefPtr<nsGlobalWindowOuter> &, void (nsGlobalWindowOuter::*)()>'
6727 "AutoUnblockScriptClosing::~AutoUnblockScriptClosing", mWin, run);
6728 mWin->Dispatch(caller.forget());
6729 }
6730};
6731
6732nsresult nsGlobalWindowOuter::OpenInternal(
6733 const nsACString& aUrl, const nsAString& aName, const nsAString& aOptions,
6734 bool aDialog, bool aCalledNoScript, bool aDoJSFixups, bool aNavigate,
6735 nsIArray* aArguments, nsDocShellLoadState* aLoadState, bool aForceNoOpener,
6736 PrintKind aPrintKind, BrowsingContext** aReturn) {
6737 mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
1
Calling defaulted default constructor for 'Maybe<AutoUnblockScriptClosing>'
12
Returning from default constructor for 'Maybe<AutoUnblockScriptClosing>'
6738
6739 // Calls to window.open from script should navigate.
6740 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"
, 6740); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCalledNoScript || aNavigate"
")"); do { *((volatile int*)__null) = 6740; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
13
Assuming 'aCalledNoScript' is true
14
Taking false branch
15
Loop condition is false. Exiting loop
6741
6742 *aReturn = nullptr;
6743
6744 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
6745 if (!chrome) {
16
Taking true branch
6746 // No chrome means we don't want to go through with this open call
6747 // -- see nsIWindowWatcher.idl
6748 return NS_ERROR_NOT_AVAILABLE;
17
Calling implicit destructor for 'Maybe<AutoUnblockScriptClosing>'
18
Calling '~MaybeStorage'
6749 }
6750
6751 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"
, 6751); MOZ_PretendNoReturn(); } } while (0)
;
6752
6753 NS_ConvertUTF16toUTF8 optionsUtf8(aOptions);
6754
6755 WindowFeatures features;
6756 if (!features.Tokenize(optionsUtf8)) {
6757 return NS_ERROR_FAILURE;
6758 }
6759
6760 bool forceNoOpener = aForceNoOpener;
6761 if (features.Exists("noopener")) {
6762 forceNoOpener = features.GetBool("noopener");
6763 features.Remove("noopener");
6764 }
6765
6766 bool forceNoReferrer = false;
6767 if (features.Exists("noreferrer")) {
6768 forceNoReferrer = features.GetBool("noreferrer");
6769 if (forceNoReferrer) {
6770 // noreferrer implies noopener
6771 forceNoOpener = true;
6772 }
6773 features.Remove("noreferrer");
6774 }
6775
6776 nsAutoCString options;
6777 features.Stringify(options);
6778
6779 // If noopener is force-enabled for the current document, then set noopener to
6780 // true, and clear the name to "_blank".
6781 nsAutoString windowName(aName);
6782 if (nsDocShell::Cast(GetDocShell())->NoopenerForceEnabled()) {
6783 // FIXME: Eventually bypass force-enabling noopener if `aPrintKind !=
6784 // PrintKind::None`, so that we can print pages with noopener force-enabled.
6785 // This will require relaxing assertions elsewhere.
6786 if (aPrintKind != PrintKind::None) {
6787 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "printing frames with noopener force-enabled isn't supported yet"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6788)
6788 "printing frames with noopener force-enabled isn't supported yet")NS_DebugBreak(NS_DEBUG_WARNING, "printing frames with noopener force-enabled isn't supported yet"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6788)
;
6789 return NS_ERROR_FAILURE;
6790 }
6791
6792 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"
, 6793); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNavigate"
") (" "cannot OpenNoNavigate if noopener is force-enabled" ")"
); do { *((volatile int*)__null) = 6793; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6793 "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"
, 6793); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNavigate"
") (" "cannot OpenNoNavigate if noopener is force-enabled" ")"
); do { *((volatile int*)__null) = 6793; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6794
6795 forceNoOpener = true;
6796 windowName = u"_blank"_ns;
6797 }
6798
6799 bool windowExists = WindowExists(windowName, forceNoOpener, !aCalledNoScript);
6800
6801 // XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()
6802 // (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.
6803 // But note that if you change this to GetEntryGlobal(), say, then
6804 // OnLinkClickEvent::Run will need a full-blown AutoEntryScript.
6805 const bool checkForPopup =
6806 !nsContentUtils::LegacyIsCallerChromeOrNativeCode() && !aDialog &&
6807 !windowExists;
6808
6809 nsCOMPtr<nsIURI> uri;
6810
6811 // It's important to do this security check before determining whether this
6812 // window opening should be blocked, to ensure that we don't FireAbuseEvents
6813 // for a window opening that wouldn't have succeeded in the first place.
6814 if (!aUrl.IsEmpty()) {
6815 // It's safe to skip the security check below if we're a dialog because
6816 // window.openDialog is not callable from content script. See bug 56851.
6817 //
6818 // If we're not navigating, we assume that whoever *does* navigate the
6819 // window will do a security check of their own.
6820 auto result =
6821 URIfromURLAndMaybeDoSecurityCheck(aUrl, !aDialog && aNavigate);
6822 if (result.isErr()) {
6823 return result.unwrapErr();
6824 }
6825
6826 uri = result.unwrap();
6827 } else if (mDoc) {
6828 mDoc->SetUseCounter(eUseCounter_custom_WindowOpenEmptyUrl);
6829 }
6830
6831 UserActivation::Modifiers modifiers;
6832 mBrowsingContext->GetUserActivationModifiersForPopup(&modifiers);
6833
6834 // Need to create loadState before the user activation is consumed in
6835 // BrowsingContext::RevisePopupAbuseLevel() below.
6836 RefPtr<nsDocShellLoadState> loadState = aLoadState;
6837 if (!loadState && aNavigate && uri) {
6838 loadState = nsWindowWatcher::CreateLoadState(uri, this);
6839 }
6840
6841 PopupBlocker::PopupControlState abuseLevel =
6842 PopupBlocker::GetPopupControlState();
6843 if (checkForPopup) {
6844 abuseLevel = mBrowsingContext->RevisePopupAbuseLevel(abuseLevel);
6845 if (abuseLevel >= PopupBlocker::openBlocked) {
6846 if (!aCalledNoScript) {
6847 // If script in some other window is doing a window.open on us and
6848 // it's being blocked, then it's OK to close us afterwards, probably.
6849 // But if we're doing a window.open on ourselves and block the popup,
6850 // prevent this window from closing until after this script terminates
6851 // so that whatever popup blocker UI the app has will be visible.
6852 nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6853 do_QueryInterface(GetEntryGlobal());
6854 // Note that entryWindow can be null here if some JS component was the
6855 // place where script was entered for this JS execution.
6856 if (entryWindow && entryWindow->GetOuterWindow() == this) {
6857 mBlockScriptedClosingFlag = true;
6858 closeUnblocker.emplace(this);
6859 }
6860 }
6861
6862 FireAbuseEvents(aUrl, windowName, aOptions);
6863 return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
6864 }
6865 }
6866
6867 RefPtr<BrowsingContext> domReturn;
6868
6869 nsresult rv = NS_OK;
6870 nsCOMPtr<nsIWindowWatcher> wwatch =
6871 do_GetService(NS_WINDOWWATCHER_CONTRACTID"@mozilla.org/embedcomp/window-watcher;1", &rv);
6872 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"
, 6872); return rv; } } while (false)
;
6873
6874 NS_ConvertUTF16toUTF8 name(windowName);
6875
6876 nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
6877 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"
, 6877); return NS_ERROR_UNEXPECTED; } } while (false)
;
6878
6879 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"
, 6879); AnnotateMozCrashReason("MOZ_ASSERT" "(" "abuseLevel < PopupBlocker::openBlocked"
")"); do { *((volatile int*)__null) = 6879; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6880 // At this point we should know for a fact that if checkForPopup then
6881 // abuseLevel < PopupBlocker::openBlocked, so we could just check for
6882 // abuseLevel == PopupBlocker::openControlled. But let's be defensive just in
6883 // case and treat anything that fails the above assert as a spam popup too, if
6884 // it ever happens.
6885 bool isPopupSpamWindow =
6886 checkForPopup && (abuseLevel >= PopupBlocker::openControlled);
6887
6888 const auto wwPrintKind = [&] {
6889 switch (aPrintKind) {
6890 case PrintKind::None:
6891 return nsPIWindowWatcher::PRINT_NONE;
6892 case PrintKind::InternalPrint:
6893 return nsPIWindowWatcher::PRINT_INTERNAL;
6894 case PrintKind::WindowDotPrint:
6895 return nsPIWindowWatcher::PRINT_WINDOW_DOT_PRINT;
6896 }
6897 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"
, 6897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Wat" ")"); do { *((volatile int*
)__null) = 6897; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6898 return nsPIWindowWatcher::PRINT_NONE;
6899 }();
6900
6901 {
6902 // Reset popup state while opening a window to prevent the
6903 // current state from being active the whole time a modal
6904 // dialog is open.
6905 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
6906
6907 if (!aCalledNoScript) {
6908 // We asserted at the top of this function that aNavigate is true for
6909 // !aCalledNoScript.
6910 rv = pwwatch->OpenWindow2(this, uri, name, options, modifiers,
6911 /* aCalledFromScript = */ true, aDialog,
6912 aNavigate, aArguments, isPopupSpamWindow,
6913 forceNoOpener, forceNoReferrer, wwPrintKind,
6914 loadState, getter_AddRefs(domReturn));
6915 } else {
6916 // Force a system caller here so that the window watcher won't screw us
6917 // up. We do NOT want this case looking at the JS context on the stack
6918 // when searching. Compare comments on
6919 // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
6920
6921 // Note: Because nsWindowWatcher is so broken, it's actually important
6922 // that we don't force a system caller here, because that screws it up
6923 // when it tries to compute the caller principal to associate with dialog
6924 // arguments. That whole setup just really needs to be rewritten. :-(
6925 AutoNoJSAPI nojsapi;
6926 rv = pwwatch->OpenWindow2(this, uri, name, options, modifiers,
6927 /* aCalledFromScript = */ false, aDialog,
6928 aNavigate, aArguments, isPopupSpamWindow,
6929 forceNoOpener, forceNoReferrer, wwPrintKind,
6930 loadState, getter_AddRefs(domReturn));
6931 }
6932 }
6933
6934 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"
, 6934); return rv; } } while (false)
;
6935
6936 // success!
6937
6938 if (!aCalledNoScript && !windowExists && uri && !forceNoOpener) {
6939 MaybeAllowStorageForOpenedWindow(uri);
6940 }
6941
6942 if (domReturn && aDoJSFixups) {
6943 nsPIDOMWindowOuter* outer = domReturn->GetDOMWindow();
6944 if (outer && !nsGlobalWindowOuter::Cast(outer)->IsChromeWindow()) {
6945 // A new non-chrome window was created from a call to
6946 // window.open() from JavaScript, make sure there's a document in
6947 // the new window. We do this by simply asking the new window for
6948 // its document, this will synchronously create an empty document
6949 // if there is no document in the window.
6950 // XXXbz should this just use EnsureInnerWindow()?
6951
6952 // Force document creation.
6953 nsCOMPtr<Document> doc = outer->GetDoc();
6954 Unused << doc;
6955 }
6956 }
6957
6958 domReturn.forget(aReturn);
6959 return NS_OK;
6960}
6961
6962void nsGlobalWindowOuter::MaybeAllowStorageForOpenedWindow(nsIURI* aURI) {
6963 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6964 if (NS_WARN_IF(!inner)NS_warn_if_impl(!inner, "!inner", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6964)
) {
6965 return;
6966 }
6967
6968 // No 3rd party URL/window.
6969 if (!AntiTrackingUtils::IsThirdPartyWindow(inner, aURI)) {
6970 return;
6971 }
6972
6973 Document* doc = inner->GetDoc();
6974 if (!doc) {
6975 return;
6976 }
6977 nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateContentPrincipal(
6978 aURI, doc->NodePrincipal()->OriginAttributesRef());
6979
6980 // We don't care when the asynchronous work finishes here.
6981 // Without e10s or fission enabled this is run in the parent process.
6982 if (XRE_IsParentProcess()) {
6983 Unused << StorageAccessAPIHelper::AllowAccessForOnParentProcess(
6984 principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
6985 } else {
6986 Unused << StorageAccessAPIHelper::AllowAccessForOnChildProcess(
6987 principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
6988 }
6989}
6990
6991//*****************************************************************************
6992// nsGlobalWindowOuter: Helper Functions
6993//*****************************************************************************
6994
6995already_AddRefed<nsIDocShellTreeOwner> nsPIDOMWindowOuter::GetTreeOwner() {
6996 // If there's no docShellAsItem, this window must have been closed,
6997 // in that case there is no tree owner.
6998
6999 if (!mDocShell) {
7000 return nullptr;
7001 }
7002
7003 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
7004 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
7005 return treeOwner.forget();
7006}
7007
7008already_AddRefed<nsIBaseWindow> nsPIDOMWindowOuter::GetTreeOwnerWindow() {
7009 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
7010
7011 // If there's no mDocShell, this window must have been closed,
7012 // in that case there is no tree owner.
7013
7014 if (mDocShell) {
7015 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
7016 }
7017
7018 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
7019 return baseWindow.forget();
7020}
7021
7022already_AddRefed<nsIWebBrowserChrome>
7023nsPIDOMWindowOuter::GetWebBrowserChrome() {
7024 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
7025
7026 nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
7027 return browserChrome.forget();
7028}
7029
7030ScrollContainerFrame* nsGlobalWindowOuter::GetScrollContainerFrame() {
7031 if (!mDocShell) {
7032 return nullptr;
7033 }
7034
7035 PresShell* presShell = mDocShell->GetPresShell();
7036 if (presShell) {
7037 return presShell->GetRootScrollContainerFrame();
7038 }
7039 return nullptr;
7040}
7041
7042Result<already_AddRefed<nsIURI>, nsresult>
7043nsGlobalWindowOuter::URIfromURLAndMaybeDoSecurityCheck(const nsACString& aURL,
7044 bool aSecurityCheck) {
7045 nsCOMPtr<nsPIDOMWindowInner> sourceWindow =
7046 do_QueryInterface(GetEntryGlobal());
7047 if (!sourceWindow) {
7048 sourceWindow = GetCurrentInnerWindow();
7049 }
7050
7051 // Resolve the baseURI, which could be relative to the calling window.
7052 //
7053 // Note the algorithm to get the base URI should match the one
7054 // used to actually kick off the load in nsWindowWatcher.cpp.
7055 nsCOMPtr<Document> doc = sourceWindow->GetDoc();
7056 nsIURI* baseURI = nullptr;
7057 auto encoding = UTF_8_ENCODING; // default to utf-8
7058 if (doc) {
7059 baseURI = doc->GetDocBaseURI();
7060 encoding = doc->GetDocumentCharacterSet();
7061 }
7062 nsCOMPtr<nsIURI> uri;
7063 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, encoding, baseURI);
7064 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"
, 7064)
) {
7065 return Err(NS_ERROR_DOM_SYNTAX_ERR);
7066 }
7067
7068 if (aSecurityCheck) {
7069 AutoJSContext cx;
7070 nsGlobalWindowInner* sourceWin = nsGlobalWindowInner::Cast(sourceWindow);
7071 JSAutoRealm ar(cx, sourceWin->GetGlobalJSObject());
7072
7073 if (NS_FAILED(nsContentUtils::GetSecurityManager()->CheckLoadURIFromScript(((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckLoadURIFromScript( cx, uri))), 0)))
7074 cx, uri))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckLoadURIFromScript( cx, uri))), 0)))
) {
7075 return Err(NS_ERROR_FAILURE);
7076 }
7077 }
7078
7079 return uri.forget();
7080}
7081
7082void nsGlobalWindowOuter::FlushPendingNotifications(FlushType aType) {
7083 if (mDoc) {
7084 mDoc->FlushPendingNotifications(aType);
7085 }
7086}
7087
7088void nsGlobalWindowOuter::EnsureSizeAndPositionUpToDate() {
7089 // If we're a subframe, make sure our size is up to date. Make sure to go
7090 // through the document chain rather than the window chain to not flush on
7091 // detached iframes, see bug 1545516.
7092 if (mDoc && mDoc->StyleOrLayoutObservablyDependsOnParentDocumentLayout()) {
7093 RefPtr<Document> parent = mDoc->GetInProcessParentDocument();
7094 parent->FlushPendingNotifications(FlushType::Layout);
7095 }
7096}
7097
7098already_AddRefed<nsISupports> nsGlobalWindowOuter::SaveWindowState() {
7099 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"
, 7099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mozilla::SessionHistoryInParent()"
")"); do { *((volatile int*)__null) = 7099; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7100
7101 if (!mContext || !GetWrapperPreserveColor()) {
7102 // The window may be getting torn down; don't bother saving state.
7103 return nullptr;
7104 }
7105
7106 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
7107 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"
, 7107); MOZ_PretendNoReturn(); } } while (0)
;
7108
7109 if (WindowContext* wc = inner->GetWindowContext()) {
7110 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"
, 7110); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wc->GetWindowStateSaved()"
")"); do { *((volatile int*)__null) = 7110; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7111 Unused << wc->SetWindowStateSaved(true);
7112 }
7113
7114 // Don't do anything else to this inner window! After this point, all
7115 // calls to SetTimeoutOrInterval will create entries in the timeout
7116 // list that will only run after this window has come out of the bfcache.
7117 // Also, while we're frozen, we won't dispatch online/offline events
7118 // to the page.
7119 inner->Freeze();
7120
7121 nsCOMPtr<nsISupports> state = new WindowStateHolder(inner);
7122
7123 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)
7124 ("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)
;
7125
7126 return state.forget();
7127}
7128
7129nsresult nsGlobalWindowOuter::RestoreWindowState(nsISupports* aState) {
7130 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"
, 7130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mozilla::SessionHistoryInParent()"
")"); do { *((volatile int*)__null) = 7130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7131
7132 if (!mContext || !GetWrapperPreserveColor()) {
7133 // The window may be getting torn down; don't bother restoring state.
7134 return NS_OK;
7135 }
7136
7137 nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
7138 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"
, 7138); return NS_ERROR_FAILURE; } } while (false)
;
7139
7140 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)
7141 ("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)
;
7142
7143 // And we're ready to go!
7144 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
7145
7146 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
7147 // it easy to tell which link was last clicked when going back a page.
7148 RefPtr<Element> focusedElement = inner->GetFocusedElement();
7149 if (nsContentUtils::ContentIsLink(focusedElement)) {
7150 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
7151 fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
7152 nsIFocusManager::FLAG_SHOWRING);
7153 }
7154 }
7155
7156 if (WindowContext* wc = inner->GetWindowContext()) {
7157 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"
, 7157); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wc->GetWindowStateSaved()"
")"); do { *((volatile int*)__null) = 7157; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7158 Unused << wc->SetWindowStateSaved(false);
7159 }
7160
7161 inner->Thaw();
7162
7163 holder->DidRestoreWindow();
7164
7165 return NS_OK;
7166}
7167
7168void nsGlobalWindowOuter::AddSizeOfIncludingThis(
7169 nsWindowSizes& aWindowSizes) const {
7170 aWindowSizes.mDOMSizes.mDOMOtherSize +=
7171 aWindowSizes.mState.mMallocSizeOf(this);
7172}
7173
7174uint32_t nsGlobalWindowOuter::GetAutoActivateVRDisplayID() {
7175 uint32_t retVal = mAutoActivateVRDisplayID;
7176 mAutoActivateVRDisplayID = 0;
7177 return retVal;
7178}
7179
7180void nsGlobalWindowOuter::SetAutoActivateVRDisplayID(
7181 uint32_t aAutoActivateVRDisplayID) {
7182 mAutoActivateVRDisplayID = aAutoActivateVRDisplayID;
7183}
7184
7185already_AddRefed<nsWindowRoot> nsGlobalWindowOuter::GetWindowRootOuter() {
7186 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
7187 return root.forget().downcast<nsWindowRoot>();
7188}
7189
7190nsIDOMWindowUtils* nsGlobalWindowOuter::WindowUtils() {
7191 if (!mWindowUtils) {
7192 mWindowUtils = new nsDOMWindowUtils(this);
7193 }
7194 return mWindowUtils;
7195}
7196
7197bool nsGlobalWindowOuter::IsInSyncOperation() {
7198 return GetExtantDoc() && GetExtantDoc()->IsInSyncOperation();
7199}
7200
7201// Note: This call will lock the cursor, it will not change as it moves.
7202// To unlock, the cursor must be set back to Auto.
7203void nsGlobalWindowOuter::SetCursorOuter(const nsACString& aCursor,
7204 ErrorResult& aError) {
7205 auto cursor = StyleCursorKind::Auto;
7206 if (!Servo_CursorKind_Parse(&aCursor, &cursor)) {
7207 // FIXME: It's a bit weird that this doesn't throw but stuff below does, but
7208 // matches previous behavior so...
7209 return;
7210 }
7211
7212 RefPtr<nsPresContext> presContext;
7213 if (mDocShell) {
7214 presContext = mDocShell->GetPresContext();
7215 }
7216
7217 if (presContext) {
7218 // Need root widget.
7219 PresShell* presShell = mDocShell->GetPresShell();
7220 if (!presShell) {
7221 aError.Throw(NS_ERROR_FAILURE);
7222 return;
7223 }
7224
7225 nsViewManager* vm = presShell->GetViewManager();
7226 if (!vm) {
7227 aError.Throw(NS_ERROR_FAILURE);
7228 return;
7229 }
7230
7231 nsView* rootView = vm->GetRootView();
7232 if (!rootView) {
7233 aError.Throw(NS_ERROR_FAILURE);
7234 return;
7235 }
7236
7237 nsIWidget* widget = rootView->GetNearestWidget(nullptr);
7238 if (!widget) {
7239 aError.Throw(NS_ERROR_FAILURE);
7240 return;
7241 }
7242
7243 // Call esm and set cursor.
7244 aError = presContext->EventStateManager()->SetCursor(
7245 cursor, nullptr, {}, Nothing(), widget, true);
7246 }
7247}
7248
7249nsIBrowserDOMWindow* nsGlobalWindowOuter::GetBrowserDOMWindow() {
7250 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"
, 7250); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "IsChromeWindow()"
")"); do { *((volatile int*)__null) = 7250; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7251 return mChromeFields.mBrowserDOMWindow;
7252}
7253
7254void nsGlobalWindowOuter::SetBrowserDOMWindowOuter(
7255 nsIBrowserDOMWindow* aBrowserWindow) {
7256 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"
, 7256); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsChromeWindow()"
")"); do { *((volatile int*)__null) = 7256; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7257 mChromeFields.mBrowserDOMWindow = aBrowserWindow;
7258}
7259
7260ChromeMessageBroadcaster* nsGlobalWindowOuter::GetMessageManager() {
7261 if (!mInnerWindow) {
7262 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"
, 7262)
;
7263 return nullptr;
7264 }
7265 return GetCurrentInnerWindowInternal(this)->MessageManager();
7266}
7267
7268ChromeMessageBroadcaster* nsGlobalWindowOuter::GetGroupMessageManager(
7269 const nsAString& aGroup) {
7270 if (!mInnerWindow) {
7271 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"
, 7271)
;
7272 return nullptr;
7273 }
7274 return GetCurrentInnerWindowInternal(this)->GetGroupMessageManager(aGroup);
7275}
7276
7277void nsGlobalWindowOuter::InitWasOffline() { mWasOffline = NS_IsOffline(); }
7278
7279#if defined(_WINDOWS_) && !defined(MOZ_WRAPPED_WINDOWS_H)
7280# pragma message( \
7281 "wrapper failure reason: " MOZ_WINDOWS_WRAPPER_DISABLED_REASON)
7282# error "Never include unwrapped windows.h in this file!"
7283#endif
7284
7285// Helper called by methods that move/resize the window,
7286// to ensure the presContext (if any) is aware of resolution
7287// change that may happen in multi-monitor configuration.
7288void nsGlobalWindowOuter::CheckForDPIChange() {
7289 if (mDocShell) {
7290 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
7291 if (presContext) {
7292 if (presContext->DeviceContext()->CheckDPIChange()) {
7293 presContext->UIResolutionChanged();
7294 }
7295 }
7296 }
7297}
7298
7299nsresult nsGlobalWindowOuter::Dispatch(
7300 already_AddRefed<nsIRunnable>&& aRunnable) const {
7301 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"
, 7301); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 7301; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7302 return NS_DispatchToCurrentThread(std::move(aRunnable));
7303}
7304
7305nsISerialEventTarget* nsGlobalWindowOuter::SerialEventTarget() const {
7306 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"
, 7306); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 7306; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7307 return GetMainThreadSerialEventTarget();
7308}
7309
7310void nsGlobalWindowOuter::MaybeResetWindowName(Document* aNewDocument) {
7311 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"
, 7311); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewDocument"
")"); do { *((volatile int*)__null) = 7311; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7312
7313 if (!StaticPrefs::privacy_window_name_update_enabled()) {
7314 return;
7315 }
7316
7317 const LoadingSessionHistoryInfo* info =
7318 nsDocShell::Cast(mDocShell)->GetLoadingSessionHistoryInfo();
7319 if (!info || info->mForceMaybeResetName.isNothing()) {
7320 // We only reset the window name for the top-level content as well as
7321 // storing in session entries.
7322 if (!GetBrowsingContext()->IsTopContent()) {
7323 return;
7324 }
7325
7326 // Following implements https://html.spec.whatwg.org/#history-traversal:
7327 // Step 4.2. Check if the loading document has a different origin than the
7328 // previous document.
7329
7330 // We don't need to do anything if we haven't loaded a non-initial document.
7331 if (!GetBrowsingContext()->GetHasLoadedNonInitialDocument()) {
7332 return;
7333 }
7334
7335 // If we have an existing document, directly check the document prinicpals
7336 // with the new document to know if it is cross-origin.
7337 //
7338 // Note that there will be an issue of initial document handling in Fission
7339 // when running the WPT unset_context_name-1.html. In the test, the first
7340 // about:blank page would be loaded with the principal of the testing domain
7341 // in Fission and the window.name will be set there. Then, The window.name
7342 // won't be reset after navigating to the testing page because the principal
7343 // is the same. But, it won't be the case for non-Fission mode that the
7344 // first about:blank will be loaded with a null principal and the
7345 // window.name will be reset when loading the test page.
7346 if (mDoc && mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal())) {
7347 return;
7348 }
7349
7350 // If we don't have an existing document, and if it's not the initial
7351 // about:blank, we could be loading a document because of the
7352 // process-switching. In this case, this should be a cross-origin
7353 // navigation.
7354 } else if (!info->mForceMaybeResetName.ref()) {
7355 return;
7356 }
7357
7358 // Step 4.2.2 Store the window.name into all session history entries that have
7359 // the same origin as the previous document.
7360 nsDocShell::Cast(mDocShell)->StoreWindowNameToSHEntries();
7361
7362 // Step 4.2.3 Clear the window.name if the browsing context is the top-level
7363 // content and doesn't have an opener.
7364
7365 // We need to reset the window name in case of a cross-origin navigation,
7366 // without an opener.
7367 RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext();
7368 if (opener) {
7369 return;
7370 }
7371
7372 Unused << mBrowsingContext->SetName(EmptyString());
7373}
7374
7375nsGlobalWindowOuter::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
7376 BrowsingContext* aBC) {
7377 BrowsingContextGroup* group = aBC->Group();
7378 if (!group) {
7379 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"
, 7381); MOZ_PretendNoReturn(); } while (0)
7380 "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"
, 7381); MOZ_PretendNoReturn(); } while (0)
7381 "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"
, 7381); MOZ_PretendNoReturn(); } while (0)
;
7382 return;
7383 }
7384
7385 if (group) {
7386 mGroup = group;
7387 mSavedDialogsEnabled = group->GetAreDialogsEnabled();
7388 group->SetAreDialogsEnabled(false);
7389 }
7390}
7391
7392nsGlobalWindowOuter::TemporarilyDisableDialogs::~TemporarilyDisableDialogs() {
7393 if (mGroup) {
7394 mGroup->SetAreDialogsEnabled(mSavedDialogsEnabled);
7395 }
7396}
7397
7398/* static */
7399already_AddRefed<nsGlobalWindowOuter> nsGlobalWindowOuter::Create(
7400 nsDocShell* aDocShell, bool aIsChrome) {
7401 uint64_t outerWindowID = aDocShell->GetOuterWindowID();
7402 RefPtr<nsGlobalWindowOuter> window = new nsGlobalWindowOuter(outerWindowID);
7403 if (aIsChrome) {
7404 window->mIsChrome = true;
7405 }
7406 window->SetDocShell(aDocShell);
7407
7408 window->InitWasOffline();
7409 return window.forget();
7410}
7411
7412nsIURI* nsPIDOMWindowOuter::GetDocumentURI() const {
7413 return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
7414}
7415
7416void nsPIDOMWindowOuter::MaybeCreateDoc() {
7417 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"
, 7417); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDoc" ")")
; do { *((volatile int*)__null) = 7417; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7418 if (nsIDocShell* docShell = GetDocShell()) {
7419 // Note that |document| here is the same thing as our mDoc, but we
7420 // don't have to explicitly set the member variable because the docshell
7421 // has already called SetNewDocument().
7422 nsCOMPtr<Document> document = docShell->GetDocument();
7423 Unused << document;
7424 }
7425}
7426
7427void nsPIDOMWindowOuter::SetChromeEventHandlerInternal(
7428 EventTarget* aChromeEventHandler) {
7429 // Out-of-line so we don't need to include ContentFrameMessageManager.h in
7430 // nsPIDOMWindow.h.
7431 mChromeEventHandler = aChromeEventHandler;
7432
7433 // mParentTarget and mMessageManager will be set when the next event is
7434 // dispatched or someone asks for our message manager.
7435 mParentTarget = nullptr;
7436 mMessageManager = nullptr;
7437}
7438
7439mozilla::dom::DocGroup* nsPIDOMWindowOuter::GetDocGroup() const {
7440 Document* doc = GetExtantDoc();
7441 if (doc) {
7442 return doc->GetDocGroup();
7443 }
7444 return nullptr;
7445}
7446
7447nsPIDOMWindowOuter::nsPIDOMWindowOuter(uint64_t aWindowID)
7448 : mFrameElement(nullptr),
7449 mModalStateDepth(0),
7450 mSuppressEventHandlingDepth(0),
7451 mIsBackground(false),
7452 mIsRootOuterWindow(false),
7453 mInnerWindow(nullptr),
7454 mWindowID(aWindowID),
7455 mMarkedCCGeneration(0) {}
7456
7457nsPIDOMWindowOuter::~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 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 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() : dummy() {}
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 dummy;
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, 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 */