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-18/lib/clang/18 -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-18/lib/clang/18/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 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -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-07-27-022226-2793976-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 "WindowNamedPropertiesHandler.h"
70#include "nsFrameSelection.h"
71#include "nsNetUtil.h"
72#include "nsVariant.h"
73#include "nsPrintfCString.h"
74#include "mozilla/intl/LocaleService.h"
75#include "WindowDestroyedEvent.h"
76#include "nsDocShellLoadState.h"
77#include "mozilla/dom/WindowGlobalChild.h"
78
79// Helper Classes
80#include "nsJSUtils.h"
81#include "jsapi.h"
82#include "jsfriendapi.h"
83#include "js/CallAndConstruct.h" // JS::Call
84#include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
85#include "js/friend/WindowProxy.h" // js::IsWindowProxy, js::SetWindowProxy
86#include "js/PropertyAndElement.h" // JS_DefineObject, JS_GetProperty
87#include "js/PropertySpec.h"
88#include "js/RealmIterators.h"
89#include "js/Wrapper.h"
90#include "nsLayoutUtils.h"
91#include "nsReadableUtils.h"
92#include "nsJSEnvironment.h"
93#include "mozilla/dom/ScriptSettings.h"
94#include "mozilla/Preferences.h"
95#include "mozilla/Likely.h"
96#include "mozilla/SchedulerGroup.h"
97#include "mozilla/SpinEventLoopUntil.h"
98#include "mozilla/Sprintf.h"
99#include "mozilla/Unused.h"
100
101// Other Classes
102#include "mozilla/dom/BarProps.h"
103#include "nsLayoutStatics.h"
104#include "nsCCUncollectableMarker.h"
105#include "mozilla/dom/WorkerCommon.h"
106#include "mozilla/dom/ToJSValue.h"
107#include "nsJSPrincipals.h"
108#include "mozilla/Attributes.h"
109#include "mozilla/Components.h"
110#include "mozilla/Debug.h"
111#include "mozilla/EventListenerManager.h"
112#include "mozilla/MouseEvents.h"
113#include "mozilla/PresShell.h"
114#include "mozilla/ProcessHangMonitor.h"
115#include "mozilla/StaticPrefs_dom.h"
116#include "mozilla/StaticPrefs_full_screen_api.h"
117#include "mozilla/StaticPrefs_print.h"
118#include "mozilla/StaticPrefs_fission.h"
119#include "mozilla/ThrottledEventQueue.h"
120#include "AudioChannelService.h"
121#include "nsAboutProtocolUtils.h"
122#include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE
123#include "PostMessageEvent.h"
124#include "mozilla/dom/DocGroup.h"
125#include "mozilla/net/CookieJarSettings.h"
126
127// Interfaces Needed
128#include "nsIFrame.h"
129#include "nsCanvasFrame.h"
130#include "nsIWidget.h"
131#include "nsIWidgetListener.h"
132#include "nsIBaseWindow.h"
133#include "nsIDeviceSensors.h"
134#include "nsIContent.h"
135#include "nsIDocShell.h"
136#include "mozilla/dom/Document.h"
137#include "Crypto.h"
138#include "nsDOMString.h"
139#include "nsThreadUtils.h"
140#include "nsILoadContext.h"
141#include "nsView.h"
142#include "nsViewManager.h"
143#include "nsIPrompt.h"
144#include "nsIPromptService.h"
145#include "nsIPromptFactory.h"
146#include "nsIWritablePropertyBag2.h"
147#include "nsIWebNavigation.h"
148#include "nsIWebBrowserChrome.h"
149#include "nsIWebBrowserFind.h" // For window.find()
150#include "nsComputedDOMStyle.h"
151#include "nsDOMCID.h"
152#include "nsDOMWindowUtils.h"
153#include "nsIWindowWatcher.h"
154#include "nsPIWindowWatcher.h"
155#include "nsIDocumentViewer.h"
156#include "nsIScriptError.h"
157#include "nsISHistory.h"
158#include "nsIControllers.h"
159#include "nsGlobalWindowCommands.h"
160#include "nsQueryObject.h"
161#include "nsContentUtils.h"
162#include "nsCSSProps.h"
163#include "nsIURIFixup.h"
164#include "nsIURIMutator.h"
165#include "mozilla/EventDispatcher.h"
166#include "mozilla/EventStateManager.h"
167#include "mozilla/ScrollContainerFrame.h"
168#include "nsIObserverService.h"
169#include "nsFocusManager.h"
170#include "nsIAppWindow.h"
171#include "nsServiceManagerUtils.h"
172#include "mozilla/dom/CustomEvent.h"
173#include "nsIScreenManager.h"
174#include "nsIClassifiedChannel.h"
175#include "nsIXULRuntime.h"
176#include "xpcprivate.h"
177
178#ifdef NS_PRINTING1
179# include "nsIPrintSettings.h"
180# include "nsIPrintSettingsService.h"
181# include "nsIWebBrowserPrint.h"
182#endif
183
184#include "nsWindowRoot.h"
185#include "nsNetCID.h"
186#include "nsIArray.h"
187
188#include "nsIDOMXULCommandDispatcher.h"
189
190#include "mozilla/GlobalKeyListener.h"
191
192#include "nsIDragService.h"
193#include "mozilla/dom/Element.h"
194#include "mozilla/dom/Selection.h"
195#include "nsFrameLoader.h"
196#include "nsFrameLoaderOwner.h"
197#include "nsXPCOMCID.h"
198#include "mozilla/Logging.h"
199#include "mozilla/ProfilerMarkers.h"
200#include "prenv.h"
201
202#include "mozilla/dom/IDBFactory.h"
203#include "mozilla/dom/MessageChannel.h"
204#include "mozilla/dom/Promise.h"
205
206#include "mozilla/dom/Gamepad.h"
207#include "mozilla/dom/GamepadManager.h"
208
209#include "gfxVR.h"
210#include "VRShMem.h"
211#include "FxRWindowManager.h"
212#include "mozilla/dom/VRDisplay.h"
213#include "mozilla/dom/VRDisplayEvent.h"
214#include "mozilla/dom/VRDisplayEventBinding.h"
215#include "mozilla/dom/VREventObserver.h"
216
217#include "nsRefreshDriver.h"
218
219#include "mozilla/extensions/WebExtensionPolicy.h"
220
221#include "mozilla/BasePrincipal.h"
222#include "mozilla/Services.h"
223#include "mozilla/Telemetry.h"
224#include "mozilla/dom/Location.h"
225#include "nsHTMLDocument.h"
226#include "nsWrapperCacheInlines.h"
227#include "mozilla/DOMEventTargetHelper.h"
228#include "prrng.h"
229#include "nsSandboxFlags.h"
230#include "nsXULControllers.h"
231#include "mozilla/dom/AudioContext.h"
232#include "mozilla/dom/BrowserElementDictionariesBinding.h"
233#include "mozilla/dom/BrowsingContextGroup.h"
234#include "mozilla/dom/cache/CacheStorage.h"
235#include "mozilla/dom/Console.h"
236#include "mozilla/dom/Fetch.h"
237#include "mozilla/dom/FunctionBinding.h"
238#include "mozilla/dom/HashChangeEvent.h"
239#include "mozilla/dom/IntlUtils.h"
240#include "mozilla/dom/PopStateEvent.h"
241#include "mozilla/dom/PopupBlockedEvent.h"
242#include "mozilla/dom/PrimitiveConversions.h"
243#include "mozilla/dom/WindowBinding.h"
244#include "nsIBrowserChild.h"
245#include "mozilla/dom/MediaQueryList.h"
246#include "mozilla/dom/NavigatorBinding.h"
247#include "mozilla/dom/ImageBitmap.h"
248#include "mozilla/dom/ImageBitmapBinding.h"
249#include "mozilla/dom/ServiceWorkerRegistration.h"
250#include "mozilla/dom/WebIDLGlobalNameHash.h"
251#include "mozilla/dom/Worklet.h"
252#include "AccessCheck.h"
253
254#ifdef MOZ_WEBSPEECH1
255# include "mozilla/dom/SpeechSynthesis.h"
256#endif
257
258#ifdef ANDROID
259# include <android/log.h>
260#endif
261
262#ifdef XP_WIN
263# include <process.h>
264# define getpid _getpid
265#else
266# include <unistd.h> // for getpid()
267#endif
268
269using namespace mozilla;
270using namespace mozilla::dom;
271using namespace mozilla::dom::ipc;
272using mozilla::BasePrincipal;
273using mozilla::OriginAttributes;
274using mozilla::TimeStamp;
275using mozilla::layout::RemotePrintJobChild;
276
277static inline nsGlobalWindowInner* GetCurrentInnerWindowInternal(
278 const nsGlobalWindowOuter* aOuter) {
279 return nsGlobalWindowInner::Cast(aOuter->GetCurrentInnerWindow());
280}
281
282#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"
, 282); return err_rval; } return GetCurrentInnerWindowInternal
(this)->method args; } while (0)
\
283 PR_BEGIN_MACROdo { \
284 if (!mInnerWindow) { \
285 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"
, 285)
; \
286 return err_rval; \
287 } \
288 return GetCurrentInnerWindowInternal(this)->method args; \
289 PR_END_MACRO} while (0)
290
291#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"
, 291); return; } GetCurrentInnerWindowInternal(this)->method
args; return; } while (0)
\
292 PR_BEGIN_MACROdo { \
293 if (!mInnerWindow) { \
294 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"
, 294)
; \
295 return; \
296 } \
297 GetCurrentInnerWindowInternal(this)->method args; \
298 return; \
299 PR_END_MACRO} while (0)
300
301// Same as FORWARD_TO_INNER, but this will create a fresh inner if an
302// inner doesn't already exists.
303#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)
\
304 PR_BEGIN_MACROdo { \
305 if (!mInnerWindow) { \
306 if (mIsClosed) { \
307 return err_rval; \
308 } \
309 nsCOMPtr<Document> kungFuDeathGrip = GetDoc(); \
310 ::mozilla::Unused << kungFuDeathGrip; \
311 if (!mInnerWindow) { \
312 return err_rval; \
313 } \
314 } \
315 return GetCurrentInnerWindowInternal(this)->method args; \
316 PR_END_MACRO} while (0)
317
318static LazyLogModule gDOMLeakPRLogOuter("DOMLeakOuter");
319extern LazyLogModule gPageCacheLog;
320
321#ifdef DEBUG1
322static LazyLogModule gDocShellAndDOMWindowLeakLogging(
323 "DocShellAndDOMWindowLeak");
324#endif
325
326nsGlobalWindowOuter::OuterWindowByIdTable*
327 nsGlobalWindowOuter::sOuterWindowsById = nullptr;
328
329/* static */
330nsPIDOMWindowOuter* nsPIDOMWindowOuter::GetFromCurrentInner(
331 nsPIDOMWindowInner* aInner) {
332 if (!aInner) {
333 return nullptr;
334 }
335
336 nsPIDOMWindowOuter* outer = aInner->GetOuterWindow();
337 if (!outer || outer->GetCurrentInnerWindow() != aInner) {
338 return nullptr;
339 }
340
341 return outer;
342}
343
344//*****************************************************************************
345// nsOuterWindowProxy: Outer Window Proxy
346//*****************************************************************************
347
348// Give OuterWindowProxyClass 2 reserved slots, like the other wrappers, so
349// JSObject::swap can swap it with CrossCompartmentWrappers without requiring
350// malloc.
351//
352// We store the nsGlobalWindowOuter* in our first slot.
353//
354// We store our holder weakmap in the second slot.
355const 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}
356 "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 */
357
358static const size_t OUTER_WINDOW_SLOT = 0;
359static const size_t HOLDER_WEAKMAP_SLOT = 1;
360
361class nsOuterWindowProxy : public MaybeCrossOriginObject<js::Wrapper> {
362 using Base = MaybeCrossOriginObject<js::Wrapper>;
363
364 public:
365 constexpr nsOuterWindowProxy() : Base(0) {}
366
367 bool finalizeInBackground(const JS::Value& priv) const override {
368 return false;
369 }
370
371 // Standard internal methods
372 /**
373 * Implementation of [[GetOwnProperty]] as defined at
374 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty
375 *
376 * "proxy" is the WindowProxy object involved. It may not be same-compartment
377 * with cx.
378 */
379 bool getOwnPropertyDescriptor(
380 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
381 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const override;
382
383 /*
384 * Implementation of the same-origin case of
385 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty>.
386 */
387 bool definePropertySameOrigin(JSContext* cx, JS::Handle<JSObject*> proxy,
388 JS::Handle<jsid> id,
389 JS::Handle<JS::PropertyDescriptor> desc,
390 JS::ObjectOpResult& result) const override;
391
392 /**
393 * Implementation of [[OwnPropertyKeys]] as defined at
394 *
395 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-ownpropertykeys
396 *
397 * "proxy" is the WindowProxy object involved. It may not be same-compartment
398 * with cx.
399 */
400 bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
401 JS::MutableHandleVector<jsid> props) const override;
402 /**
403 * Implementation of [[Delete]] as defined at
404 * https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-delete
405 *
406 * "proxy" is the WindowProxy object involved. It may not be same-compartment
407 * with cx.
408 */
409 bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
410 JS::ObjectOpResult& result) const override;
411
412 /**
413 * Implementaton of hook for superclass getPrototype() method.
414 */
415 JSObject* getSameOriginPrototype(JSContext* cx) const override;
416
417 /**
418 * Implementation of [[HasProperty]] internal method as defined at
419 * https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p
420 *
421 * "proxy" is the WindowProxy object involved. It may not be same-compartment
422 * with cx.
423 *
424 * Note that the HTML spec does not define an override for this internal
425 * method, so we just want the "normal object" behavior. We have to override
426 * it, because js::Wrapper also overrides, with "not normal" behavior.
427 */
428 bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
429 bool* bp) const override;
430
431 /**
432 * Implementation of [[Get]] internal method as defined at
433 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-get>.
434 *
435 * "proxy" is the WindowProxy object involved. It may or may not be
436 * same-compartment with "cx".
437 *
438 * "receiver" is the receiver ("this") for the get. It will be
439 * same-compartment with "cx".
440 *
441 * "vp" is the return value. It will be same-compartment with "cx".
442 */
443 bool get(JSContext* cx, JS::Handle<JSObject*> proxy,
444 JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
445 JS::MutableHandle<JS::Value> vp) const override;
446
447 /**
448 * Implementation of [[Set]] internal method as defined at
449 * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-set>.
450 *
451 * "proxy" is the WindowProxy object involved. It may or may not be
452 * same-compartment with "cx".
453 *
454 * "v" is the value being set. It will be same-compartment with "cx".
455 *
456 * "receiver" is the receiver ("this") for the set. It will be
457 * same-compartment with "cx".
458 */
459 bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
460 JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
461 JS::ObjectOpResult& result) const override;
462
463 // SpiderMonkey extensions
464 /**
465 * Implementation of SpiderMonkey extension which just checks whether this
466 * object has the property. Basically Object.getOwnPropertyDescriptor(obj,
467 * prop) !== undefined. but does not require reifying the descriptor.
468 *
469 * We have to override this because js::Wrapper overrides it, but we want
470 * different behavior from js::Wrapper.
471 *
472 * "proxy" is the WindowProxy object involved. It may not be same-compartment
473 * with cx.
474 */
475 bool hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
476 bool* bp) const override;
477
478 /**
479 * Implementation of SpiderMonkey extension which is used as a fast path for
480 * enumerating.
481 *
482 * We have to override this because js::Wrapper overrides it, but we want
483 * different behavior from js::Wrapper.
484 *
485 * "proxy" is the WindowProxy object involved. It may not be same-compartment
486 * with cx.
487 */
488 bool getOwnEnumerablePropertyKeys(
489 JSContext* cx, JS::Handle<JSObject*> proxy,
490 JS::MutableHandleVector<jsid> props) const override;
491
492 /**
493 * Hook used by SpiderMonkey to implement Object.prototype.toString.
494 */
495 const char* className(JSContext* cx,
496 JS::Handle<JSObject*> wrapper) const override;
497
498 void finalize(JS::GCContext* gcx, JSObject* proxy) const override;
499 size_t objectMoved(JSObject* proxy, JSObject* old) const override;
500
501 bool isCallable(JSObject* obj) const override { return false; }
502 bool isConstructor(JSObject* obj) const override { return false; }
503
504 static const nsOuterWindowProxy singleton;
505
506 static nsGlobalWindowOuter* GetOuterWindow(JSObject* proxy) {
507 nsGlobalWindowOuter* outerWindow =
508 nsGlobalWindowOuter::FromSupports(static_cast<nsISupports*>(
509 js::GetProxyReservedSlot(proxy, OUTER_WINDOW_SLOT).toPrivate()));
510 return outerWindow;
511 }
512
513 protected:
514 // False return value means we threw an exception. True return value
515 // but false "found" means we didn't have a subframe at that index.
516 bool GetSubframeWindow(JSContext* cx, JS::Handle<JSObject*> proxy,
517 JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
518 bool& found) const;
519
520 // Returns a non-null window only if id is an index and we have a
521 // window at that index.
522 Nullable<WindowProxyHolder> GetSubframeWindow(JSContext* cx,
523 JS::Handle<JSObject*> proxy,
524 JS::Handle<jsid> id) const;
525
526 bool AppendIndexedPropertyNames(JSObject* proxy,
527 JS::MutableHandleVector<jsid> props) const;
528
529 using MaybeCrossOriginObjectMixins::EnsureHolder;
530 bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> proxy,
531 JS::MutableHandle<JSObject*> holder) const override;
532
533 // Helper method for creating a special "print" method that allows printing
534 // our PDF-viewer documents even if you're not same-origin with them.
535 //
536 // aProxy must be our nsOuterWindowProxy. It will not be same-compartment
537 // with aCx, since we only use this on the different-origin codepath!
538 //
539 // Can return true without filling in aDesc, which corresponds to not exposing
540 // a "print" method.
541 static bool MaybeGetPDFJSPrintMethod(
542 JSContext* cx, JS::Handle<JSObject*> proxy,
543 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc);
544
545 // The actual "print" method we use for the PDFJS case.
546 static bool PDFJSPrintMethod(JSContext* cx, unsigned argc, JS::Value* vp);
547
548 // Helper method to get the pre-PDF-viewer-messing-with-it principal from an
549 // inner window. Will return null if this is not a PDF-viewer inner or if the
550 // principal could not be found for some reason.
551 static already_AddRefed<nsIPrincipal> GetNoPDFJSPrincipal(
552 nsGlobalWindowInner* inner);
553};
554
555const char* nsOuterWindowProxy::className(JSContext* cx,
556 JS::Handle<JSObject*> proxy) const {
557 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"
, 557); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsProxy(proxy)"
")"); do { *((volatile int*)__null) = 557; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
558
559 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
560 return "Object";
561 }
562
563 return "Window";
564}
565
566void nsOuterWindowProxy::finalize(JS::GCContext* gcx, JSObject* proxy) const {
567 nsGlobalWindowOuter* outerWindow = GetOuterWindow(proxy);
568 if (outerWindow) {
569 outerWindow->ClearWrapper(proxy);
570 BrowsingContext* bc = outerWindow->GetBrowsingContext();
571 if (bc) {
572 bc->ClearWindowProxy();
573 }
574
575 // Ideally we would use OnFinalize here, but it's possible that
576 // EnsureScriptEnvironment will later be called on the window, and we don't
577 // want to create a new script object in that case. Therefore, we need to
578 // write a non-null value that will reliably crash when dereferenced.
579 outerWindow->PoisonOuterWindowProxy(proxy);
580 }
581}
582
583bool nsOuterWindowProxy::getOwnPropertyDescriptor(
584 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
585 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const {
586 // First check for indexed access. This is
587 // https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getownproperty
588 // step 2, mostly.
589 JS::Rooted<JS::Value> subframe(cx);
590 bool found;
591 if (!GetSubframeWindow(cx, proxy, id, &subframe, found)) {
592 return false;
593 }
594 if (found) {
595 // Step 2.4.
596
597 desc.set(Some(JS::PropertyDescriptor::Data(
598 subframe, {
599 JS::PropertyAttribute::Configurable,
600 JS::PropertyAttribute::Enumerable,
601 })));
602 return true;
603 }
604
605 bool isSameOrigin = IsPlatformObjectSameOrigin(cx, proxy);
606
607 // If we did not find a subframe, we could still have an indexed property
608 // access. In that case we should throw a SecurityError in the cross-origin
609 // case.
610 if (!isSameOrigin && IsArrayIndex(GetArrayIndexFromId(id))) {
611 // Step 2.5.2.
612 return ReportCrossOriginDenial(cx, id, "access"_ns);
613 }
614
615 // Step 2.5.1 is handled via the forwarding to js::Wrapper; it saves us an
616 // IsArrayIndex(GetArrayIndexFromId(id)) here. We'll never have a property on
617 // the Window whose name is an index, because our defineProperty doesn't pass
618 // those on to the Window.
619
620 // Step 3.
621 if (isSameOrigin) {
622 if (StaticPrefs::dom_missing_prop_counters_enabled() && id.isAtom()) {
623 Window_Binding::CountMaybeMissingProperty(proxy, id);
624 }
625
626 // Fall through to js::Wrapper.
627 { // Scope for JSAutoRealm while we are dealing with js::Wrapper.
628 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
629 // for now. That's what js::Wrapper expects, and since we're same-origin
630 // anyway this is not changing any security behavior.
631 JSAutoRealm ar(cx, proxy);
632 JS_MarkCrossZoneId(cx, id);
633 bool ok = js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
634 if (!ok) {
635 return false;
636 }
637
638#if 0
639 // See https://github.com/tc39/ecma262/issues/672 for more information.
640 if (desc.isSome() &&
641 !IsNonConfigurableReadonlyPrimitiveGlobalProp(cx, id)) {
642 (*desc).setConfigurable(true);
643 }
644#endif
645 }
646
647 // Now wrap our descriptor back into the Realm that asked for it.
648 return JS_WrapPropertyDescriptor(cx, desc);
649 }
650
651 // Step 4.
652 if (!CrossOriginGetOwnPropertyHelper(cx, proxy, id, desc)) {
653 return false;
654 }
655
656 // Step 5
657 if (desc.isSome()) {
658 return true;
659 }
660
661 // Non-spec step for the PDF viewer's window.print(). This comes before we
662 // check for named subframes, because in the same-origin case print() would
663 // shadow those.
664 if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_PRINT)) {
665 if (!MaybeGetPDFJSPrintMethod(cx, proxy, desc)) {
666 return false;
667 }
668
669 if (desc.isSome()) {
670 return true;
671 }
672 }
673
674 // Step 6 -- check for named subframes.
675 if (id.isString()) {
676 nsAutoJSString name;
677 if (!name.init(cx, id.toString())) {
678 return false;
679 }
680 nsGlobalWindowOuter* win = GetOuterWindow(proxy);
681 if (RefPtr<BrowsingContext> childDOMWin = win->GetChildWindow(name)) {
682 JS::Rooted<JS::Value> childValue(cx);
683 if (!ToJSValue(cx, WindowProxyHolder(childDOMWin), &childValue)) {
684 return false;
685 }
686 desc.set(Some(JS::PropertyDescriptor::Data(
687 childValue, {JS::PropertyAttribute::Configurable})));
688 return true;
689 }
690 }
691
692 // And step 7.
693 return CrossOriginPropertyFallback(cx, proxy, id, desc);
694}
695
696bool nsOuterWindowProxy::definePropertySameOrigin(
697 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
698 JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result) const {
699 if (IsArrayIndex(GetArrayIndexFromId(id))) {
700 // Spec says to Reject whether this is a supported index or not,
701 // since we have no indexed setter or indexed creator. It is up
702 // to the caller to decide whether to throw a TypeError.
703 return result.failCantDefineWindowElement();
704 }
705
706 JS::ObjectOpResult ourResult;
707 bool ok = js::Wrapper::defineProperty(cx, proxy, id, desc, ourResult);
708 if (!ok) {
709 return false;
710 }
711
712 if (!ourResult.ok()) {
713 // It's possible that this failed because the page got the existing
714 // descriptor (which we force to claim to be configurable) and then tried to
715 // redefine the property with the descriptor it got but a different value.
716 // We want to allow this case to succeed, so check for it and if we're in
717 // that case try again but now with an attempt to define a non-configurable
718 // property.
719 if (!desc.hasConfigurable() || !desc.configurable()) {
720 // The incoming descriptor was not explicitly marked "configurable: true",
721 // so it failed for some other reason. Just propagate that reason out.
722 result = ourResult;
723 return true;
724 }
725
726 JS::Rooted<Maybe<JS::PropertyDescriptor>> existingDesc(cx);
727 ok = js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, &existingDesc);
728 if (!ok) {
729 return false;
730 }
731 if (existingDesc.isNothing() || existingDesc->configurable()) {
732 // We have no existing property, or its descriptor is already configurable
733 // (on the Window itself, where things really can be non-configurable).
734 // So we failed for some other reason, which we should propagate out.
735 result = ourResult;
736 return true;
737 }
738
739 JS::Rooted<JS::PropertyDescriptor> updatedDesc(cx, desc);
740 updatedDesc.setConfigurable(false);
741
742 JS::ObjectOpResult ourNewResult;
743 ok = js::Wrapper::defineProperty(cx, proxy, id, updatedDesc, ourNewResult);
744 if (!ok) {
745 return false;
746 }
747
748 if (!ourNewResult.ok()) {
749 // Twiddling the configurable flag didn't help. Just return this failure
750 // out to the caller.
751 result = ourNewResult;
752 return true;
753 }
754 }
755
756#if 0
757 // See https://github.com/tc39/ecma262/issues/672 for more information.
758 if (desc.hasConfigurable() && !desc.configurable() &&
759 !IsNonConfigurableReadonlyPrimitiveGlobalProp(cx, id)) {
760 // Give callers a way to detect that they failed to "really" define a
761 // non-configurable property.
762 result.failCantDefineWindowNonConfigurable();
763 return true;
764 }
765#endif
766
767 result.succeed();
768 return true;
769}
770
771bool nsOuterWindowProxy::ownPropertyKeys(
772 JSContext* cx, JS::Handle<JSObject*> proxy,
773 JS::MutableHandleVector<jsid> props) const {
774 // Just our indexed stuff followed by our "normal" own property names.
775 if (!AppendIndexedPropertyNames(proxy, props)) {
776 return false;
777 }
778
779 if (IsPlatformObjectSameOrigin(cx, proxy)) {
780 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
781 // for now. That's what js::Wrapper expects, and since we're same-origin
782 // anyway this is not changing any security behavior.
783 JS::RootedVector<jsid> innerProps(cx);
784 { // Scope for JSAutoRealm so we can mark the ids once we exit it
785 JSAutoRealm ar(cx, proxy);
786 if (!js::Wrapper::ownPropertyKeys(cx, proxy, &innerProps)) {
787 return false;
788 }
789 }
790 for (auto& id : innerProps) {
791 JS_MarkCrossZoneId(cx, id);
792 }
793 return js::AppendUnique(cx, props, innerProps);
794 }
795
796 // In the cross-origin case we purposefully exclude subframe names from the
797 // list of property names we report here.
798 JS::Rooted<JSObject*> holder(cx);
799 if (!EnsureHolder(cx, proxy, &holder)) {
800 return false;
801 }
802
803 JS::RootedVector<jsid> crossOriginProps(cx);
804 if (!js::GetPropertyKeys(cx, holder,
805 JSITER_OWNONLY0x8 | JSITER_HIDDEN0x10 | JSITER_SYMBOLS0x20,
806 &crossOriginProps) ||
807 !js::AppendUnique(cx, props, crossOriginProps)) {
808 return false;
809 }
810
811 // Add the "print" property if needed.
812 nsGlobalWindowOuter* outer = GetOuterWindow(proxy);
813 nsGlobalWindowInner* inner =
814 nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
815 if (inner) {
816 nsCOMPtr<nsIPrincipal> targetPrincipal = GetNoPDFJSPrincipal(inner);
817 if (targetPrincipal &&
818 nsContentUtils::SubjectPrincipal(cx)->Equals(targetPrincipal)) {
819 JS::RootedVector<jsid> printProp(cx);
820 if (!printProp.append(GetJSIDByIndex(cx, XPCJSContext::IDX_PRINT)) ||
821 !js::AppendUnique(cx, props, printProp)) {
822 return false;
823 }
824 }
825 }
826
827 return xpc::AppendCrossOriginWhitelistedPropNames(cx, props);
828}
829
830bool nsOuterWindowProxy::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
831 JS::Handle<jsid> id,
832 JS::ObjectOpResult& result) const {
833 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
834 return ReportCrossOriginDenial(cx, id, "delete"_ns);
835 }
836
837 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
838 // Fail (which means throw if strict, else return false).
839 return result.failCantDeleteWindowElement();
840 }
841
842 if (IsArrayIndex(GetArrayIndexFromId(id))) {
843 // Indexed, but not supported. Spec says return true.
844 return result.succeed();
845 }
846
847 // We're same-origin, so it should be safe to enter the Realm of "proxy".
848 // Let's do that, just in case, to avoid cross-compartment issues in our
849 // js::Wrapper caller..
850 JSAutoRealm ar(cx, proxy);
851 JS_MarkCrossZoneId(cx, id);
852 return js::Wrapper::delete_(cx, proxy, id, result);
853}
854
855JSObject* nsOuterWindowProxy::getSameOriginPrototype(JSContext* cx) const {
856 return Window_Binding::GetProtoObjectHandle(cx);
857}
858
859bool nsOuterWindowProxy::has(JSContext* cx, JS::Handle<JSObject*> proxy,
860 JS::Handle<jsid> id, bool* bp) const {
861 // We could just directly forward this method to js::BaseProxyHandler, but
862 // that involves reifying the actual property descriptor, which might be more
863 // work than we have to do for has() on the Window.
864
865 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
866 // In the cross-origin case we only have own properties. Just call hasOwn
867 // directly.
868 return hasOwn(cx, proxy, id, bp);
869 }
870
871 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
872 *bp = true;
873 return true;
874 }
875
876 // Just to be safe in terms of compartment asserts, enter the Realm of
877 // "proxy". We're same-origin with it, so this should be safe.
878 JSAutoRealm ar(cx, proxy);
879 JS_MarkCrossZoneId(cx, id);
880 return js::Wrapper::has(cx, proxy, id, bp);
881}
882
883bool nsOuterWindowProxy::hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy,
884 JS::Handle<jsid> id, bool* bp) const {
885 // We could just directly forward this method to js::BaseProxyHandler, but
886 // that involves reifying the actual property descriptor, which might be more
887 // work than we have to do for hasOwn() on the Window.
888
889 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
890 // Avoiding reifying the property descriptor here would require duplicating
891 // a bunch of "is this property exposed cross-origin" logic, which is
892 // probably not worth it. Just forward this along to the base
893 // implementation.
894 //
895 // It's very important to not forward this to js::Wrapper, because that will
896 // not do the right security and cross-origin checks and will pass through
897 // the call to the Window.
898 //
899 // The BaseProxyHandler code is OK with this happening without entering the
900 // compartment of "proxy".
901 return js::BaseProxyHandler::hasOwn(cx, proxy, id, bp);
902 }
903
904 if (!GetSubframeWindow(cx, proxy, id).IsNull()) {
905 *bp = true;
906 return true;
907 }
908
909 // Just to be safe in terms of compartment asserts, enter the Realm of
910 // "proxy". We're same-origin with it, so this should be safe.
911 JSAutoRealm ar(cx, proxy);
912 JS_MarkCrossZoneId(cx, id);
913 return js::Wrapper::hasOwn(cx, proxy, id, bp);
914}
915
916bool nsOuterWindowProxy::get(JSContext* cx, JS::Handle<JSObject*> proxy,
917 JS::Handle<JS::Value> receiver,
918 JS::Handle<jsid> id,
919 JS::MutableHandle<JS::Value> vp) const {
920 if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
921 xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
922 vp.set(JS::ObjectValue(*proxy));
923 return MaybeWrapValue(cx, vp);
924 }
925
926 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
927 return CrossOriginGet(cx, proxy, receiver, id, vp);
928 }
929
930 bool found;
931 if (!GetSubframeWindow(cx, proxy, id, vp, found)) {
932 return false;
933 }
934
935 if (found) {
936 return true;
937 }
938
939 if (StaticPrefs::dom_missing_prop_counters_enabled() && id.isAtom()) {
940 Window_Binding::CountMaybeMissingProperty(proxy, id);
941 }
942
943 { // Scope for JSAutoRealm
944 // Enter "proxy"'s Realm. We're in the same-origin case, so this should be
945 // safe.
946 JSAutoRealm ar(cx, proxy);
947
948 JS_MarkCrossZoneId(cx, id);
949
950 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
951 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
952 return false;
953 }
954
955 // Fall through to js::Wrapper.
956 if (!js::Wrapper::get(cx, proxy, wrappedReceiver, id, vp)) {
957 return false;
958 }
959 }
960
961 // Make sure our return value is in the caller compartment.
962 return MaybeWrapValue(cx, vp);
963}
964
965bool nsOuterWindowProxy::set(JSContext* cx, JS::Handle<JSObject*> proxy,
966 JS::Handle<jsid> id, JS::Handle<JS::Value> v,
967 JS::Handle<JS::Value> receiver,
968 JS::ObjectOpResult& result) const {
969 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
970 return CrossOriginSet(cx, proxy, id, v, receiver, result);
971 }
972
973 if (IsArrayIndex(GetArrayIndexFromId(id))) {
974 // Reject the set. It's up to the caller to decide whether to throw a
975 // TypeError. If the caller is strict mode JS code, it'll throw.
976 return result.failReadOnly();
977 }
978
979 // Do the rest in the Realm of "proxy", since we're in the same-origin case.
980 JSAutoRealm ar(cx, proxy);
981 JS::Rooted<JS::Value> wrappedArg(cx, v);
982 if (!MaybeWrapValue(cx, &wrappedArg)) {
983 return false;
984 }
985 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
986 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
987 return false;
988 }
989
990 JS_MarkCrossZoneId(cx, id);
991
992 return js::Wrapper::set(cx, proxy, id, wrappedArg, wrappedReceiver, result);
993}
994
995bool nsOuterWindowProxy::getOwnEnumerablePropertyKeys(
996 JSContext* cx, JS::Handle<JSObject*> proxy,
997 JS::MutableHandleVector<jsid> props) const {
998 // We could just stop overring getOwnEnumerablePropertyKeys and let our
999 // superclasses deal (by falling back on the BaseProxyHandler implementation
1000 // that uses a combination of ownPropertyKeys and getOwnPropertyDescriptor to
1001 // only return the enumerable ones. But maybe there's value in having
1002 // somewhat faster for-in iteration on Window objects...
1003
1004 // Like ownPropertyKeys, our indexed stuff followed by our "normal" enumerable
1005 // own property names.
1006 if (!AppendIndexedPropertyNames(proxy, props)) {
1007 return false;
1008 }
1009
1010 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
1011 // All the cross-origin properties other than the indexed props are
1012 // non-enumerable, so we're done here.
1013 return true;
1014 }
1015
1016 // When forwarding to js::Wrapper, we should just enter the Realm of proxy
1017 // for now. That's what js::Wrapper expects, and since we're same-origin
1018 // anyway this is not changing any security behavior.
1019 JS::RootedVector<jsid> innerProps(cx);
1020 { // Scope for JSAutoRealm so we can mark the ids once we exit it.
1021 JSAutoRealm ar(cx, proxy);
1022 if (!js::Wrapper::getOwnEnumerablePropertyKeys(cx, proxy, &innerProps)) {
1023 return false;
1024 }
1025 }
1026
1027 for (auto& id : innerProps) {
1028 JS_MarkCrossZoneId(cx, id);
1029 }
1030
1031 return js::AppendUnique(cx, props, innerProps);
1032}
1033
1034bool nsOuterWindowProxy::GetSubframeWindow(JSContext* cx,
1035 JS::Handle<JSObject*> proxy,
1036 JS::Handle<jsid> id,
1037 JS::MutableHandle<JS::Value> vp,
1038 bool& found) const {
1039 Nullable<WindowProxyHolder> frame = GetSubframeWindow(cx, proxy, id);
1040 if (frame.IsNull()) {
1041 found = false;
1042 return true;
1043 }
1044
1045 found = true;
1046 return WrapObject(cx, frame.Value(), vp);
1047}
1048
1049Nullable<WindowProxyHolder> nsOuterWindowProxy::GetSubframeWindow(
1050 JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const {
1051 uint32_t index = GetArrayIndexFromId(id);
1052 if (!IsArrayIndex(index)) {
1053 return nullptr;
1054 }
1055
1056 nsGlobalWindowOuter* win = GetOuterWindow(proxy);
1057 return win->IndexedGetterOuter(index);
1058}
1059
1060bool nsOuterWindowProxy::AppendIndexedPropertyNames(
1061 JSObject* proxy, JS::MutableHandleVector<jsid> props) const {
1062 uint32_t length = GetOuterWindow(proxy)->Length();
1063 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"
, 1063); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(length) >= 0"
")"); do { *((volatile int*)__null) = 1063; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1064 if (!props.reserve(props.length() + length)) {
1065 return false;
1066 }
1067 for (int32_t i = 0; i < int32_t(length); ++i) {
1068 if (!props.append(JS::PropertyKey::Int(i))) {
1069 return false;
1070 }
1071 }
1072
1073 return true;
1074}
1075
1076bool nsOuterWindowProxy::EnsureHolder(
1077 JSContext* cx, JS::Handle<JSObject*> proxy,
1078 JS::MutableHandle<JSObject*> holder) const {
1079 return EnsureHolder(cx, proxy, HOLDER_WEAKMAP_SLOT,
1080 Window_Binding::sCrossOriginProperties, holder);
1081}
1082
1083size_t nsOuterWindowProxy::objectMoved(JSObject* obj, JSObject* old) const {
1084 nsGlobalWindowOuter* outerWindow = GetOuterWindow(obj);
1085 if (outerWindow) {
1086 outerWindow->UpdateWrapper(obj, old);
1087 BrowsingContext* bc = outerWindow->GetBrowsingContext();
1088 if (bc) {
1089 bc->UpdateWindowProxy(obj, old);
1090 }
1091 }
1092 return 0;
1093}
1094
1095enum { PDFJS_SLOT_CALLEE = 0 };
1096
1097// static
1098bool nsOuterWindowProxy::MaybeGetPDFJSPrintMethod(
1099 JSContext* cx, JS::Handle<JSObject*> proxy,
1100 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) {
1101 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"
, 1101); AnnotateMozCrashReason("MOZ_ASSERT" "(" "proxy" ")")
; do { *((volatile int*)__null) = 1101; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1102 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"
, 1102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!desc.isSome()"
")"); do { *((volatile int*)__null) = 1102; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1103
1104 nsGlobalWindowOuter* outer = GetOuterWindow(proxy);
1105 nsGlobalWindowInner* inner =
1106 nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
1107 if (!inner) {
1108 // No print method to expose.
1109 return true;
1110 }
1111
1112 nsCOMPtr<nsIPrincipal> targetPrincipal = GetNoPDFJSPrincipal(inner);
1113 if (!targetPrincipal) {
1114 // Nothing special to be done.
1115 return true;
1116 }
1117
1118 if (!nsContentUtils::SubjectPrincipal(cx)->Equals(targetPrincipal)) {
1119 // Not our origin's PDF document.
1120 return true;
1121 }
1122
1123 // Get the function we plan to actually call.
1124 JS::Rooted<JSObject*> innerObj(cx, inner->GetGlobalJSObject());
1125 if (!innerObj) {
1126 // Really should not happen, but ok, let's just return.
1127 return true;
1128 }
1129
1130 JS::Rooted<JS::Value> targetFunc(cx);
1131 {
1132 JSAutoRealm ar(cx, innerObj);
1133 if (!JS_GetProperty(cx, innerObj, "print", &targetFunc)) {
1134 return false;
1135 }
1136 }
1137
1138 if (!targetFunc.isObject()) {
1139 // Who knows what's going on. Just return.
1140 return true;
1141 }
1142
1143 // The Realm of cx is the realm our caller is in and the realm we
1144 // should create our function in. Note that we can't use the
1145 // standard XPConnect function forwarder machinery because our
1146 // "this" is cross-origin, so we have to do thus by hand.
1147
1148 // Make sure targetFunc is wrapped into the right compartment.
1149 if (!MaybeWrapValue(cx, &targetFunc)) {
1150 return false;
1151 }
1152
1153 JSFunction* fun =
1154 js::NewFunctionWithReserved(cx, PDFJSPrintMethod, 0, 0, "print");
1155 if (!fun) {
1156 return false;
1157 }
1158
1159 JS::Rooted<JSObject*> funObj(cx, JS_GetFunctionObject(fun));
1160 js::SetFunctionNativeReserved(funObj, PDFJS_SLOT_CALLEE, targetFunc);
1161
1162 // { value: <print>, writable: true, enumerable: true, configurable: true }
1163 // because that's what it would have been in the same-origin case without
1164 // the PDF viewer messing with things.
1165 desc.set(Some(JS::PropertyDescriptor::Data(
1166 JS::ObjectValue(*funObj),
1167 {JS::PropertyAttribute::Configurable, JS::PropertyAttribute::Enumerable,
1168 JS::PropertyAttribute::Writable})));
1169 return true;
1170}
1171
1172// static
1173bool nsOuterWindowProxy::PDFJSPrintMethod(JSContext* cx, unsigned argc,
1174 JS::Value* vp) {
1175 JS::CallArgs args = CallArgsFromVp(argc, vp);
1176
1177 JS::Rooted<JSObject*> realCallee(
1178 cx, &js::GetFunctionNativeReserved(&args.callee(), PDFJS_SLOT_CALLEE)
1179 .toObject());
1180 // Unchecked unwrap, because we want to extract the thing we really had
1181 // before.
1182 realCallee = js::UncheckedUnwrap(realCallee);
1183
1184 JS::Rooted<JS::Value> thisv(cx, args.thisv());
1185 if (thisv.isNullOrUndefined()) {
1186 // Replace it with the global of our stashed callee, simulating the
1187 // global-assuming behavior of DOM methods.
1188 JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(realCallee));
1189 if (!MaybeWrapObject(cx, &global)) {
1190 return false;
1191 }
1192 thisv.setObject(*global);
1193 } else if (!thisv.isObject()) {
1194 return ThrowInvalidThis(cx, args, false, prototypes::id::Window);
1195 }
1196
1197 // We want to do an UncheckedUnwrap here, because we're going to directly
1198 // examine the principal of the inner window, if we have an inner window.
1199 JS::Rooted<JSObject*> unwrappedObj(cx,
1200 js::UncheckedUnwrap(&thisv.toObject()));
1201 nsGlobalWindowInner* inner = nullptr;
1202 {
1203 // Do the unwrap in the Realm of the object we're looking at.
1204 JSAutoRealm ar(cx, unwrappedObj);
1205 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)
;
1206 }
1207 if (!inner) {
1208 return ThrowInvalidThis(cx, args, false, prototypes::id::Window);
1209 }
1210
1211 nsIPrincipal* callerPrincipal = nsContentUtils::SubjectPrincipal(cx);
1212 if (!callerPrincipal->SubsumesConsideringDomain(inner->GetPrincipal())) {
1213 // Check whether it's a PDF viewer from our origin.
1214 nsCOMPtr<nsIPrincipal> pdfPrincipal = GetNoPDFJSPrincipal(inner);
1215 if (!pdfPrincipal || !callerPrincipal->Equals(pdfPrincipal)) {
1216 // Security error.
1217 return ThrowInvalidThis(cx, args, true, prototypes::id::Window);
1218 }
1219 }
1220
1221 // Go ahead and enter the Realm of our real callee to call it. We'll pass it
1222 // our "thisv", just in case someone grabs a "print" method off one PDF
1223 // document and .call()s it on another one.
1224 {
1225 JSAutoRealm ar(cx, realCallee);
1226 if (!MaybeWrapValue(cx, &thisv)) {
1227 return false;
1228 }
1229
1230 // Don't bother passing through the args; they will get ignored anyway.
1231
1232 if (!JS::Call(cx, thisv, realCallee, JS::HandleValueArray::empty(),
1233 args.rval())) {
1234 return false;
1235 }
1236 }
1237
1238 // Wrap the return value (not that there should be any!) into the right
1239 // compartment.
1240 return MaybeWrapValue(cx, args.rval());
1241}
1242
1243// static
1244already_AddRefed<nsIPrincipal> nsOuterWindowProxy::GetNoPDFJSPrincipal(
1245 nsGlobalWindowInner* inner) {
1246 if (!nsContentUtils::IsPDFJS(inner->GetPrincipal())) {
1247 return nullptr;
1248 }
1249
1250 if (Document* doc = inner->GetExtantDoc()) {
1251 if (nsCOMPtr<nsIPropertyBag2> propBag =
1252 do_QueryInterface(doc->GetChannel())) {
1253 nsCOMPtr<nsIPrincipal> principal(
1254 do_GetProperty(propBag, u"noPDFJSPrincipal"_ns));
1255 return principal.forget();
1256 }
1257 }
1258 return nullptr;
1259}
1260
1261const nsOuterWindowProxy nsOuterWindowProxy::singleton;
1262
1263class nsChromeOuterWindowProxy : public nsOuterWindowProxy {
1264 public:
1265 constexpr nsChromeOuterWindowProxy() = default;
1266
1267 const char* className(JSContext* cx,
1268 JS::Handle<JSObject*> wrapper) const override;
1269
1270 static const nsChromeOuterWindowProxy singleton;
1271};
1272
1273const char* nsChromeOuterWindowProxy::className(
1274 JSContext* cx, JS::Handle<JSObject*> proxy) const {
1275 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"
, 1275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsProxy(proxy)"
")"); do { *((volatile int*)__null) = 1275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1276
1277 return "ChromeWindow";
1278}
1279
1280const nsChromeOuterWindowProxy nsChromeOuterWindowProxy::singleton;
1281
1282static JSObject* NewOuterWindowProxy(JSContext* cx,
1283 JS::Handle<JSObject*> global,
1284 bool isChrome) {
1285 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"
, 1285); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JS_IsGlobalObject(global)"
")"); do { *((volatile int*)__null) = 1285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1286
1287 JSAutoRealm ar(cx, global);
1288
1289 js::WrapperOptions options;
1290 options.setClass(&OuterWindowProxyClass);
1291 JSObject* obj =
1292 js::Wrapper::New(cx, global,
1293 isChrome ? &nsChromeOuterWindowProxy::singleton
1294 : &nsOuterWindowProxy::singleton,
1295 options);
1296 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"
, 1296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(obj)"
")"); do { *((volatile int*)__null) = 1296; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1297 return obj;
1298}
1299
1300//*****************************************************************************
1301//*** nsGlobalWindowOuter: Object Management
1302//*****************************************************************************
1303
1304nsGlobalWindowOuter::nsGlobalWindowOuter(uint64_t aWindowID)
1305 : nsPIDOMWindowOuter(aWindowID),
1306 mFullscreenHasChangedDuringProcessing(false),
1307 mForceFullScreenInWidget(false),
1308 mIsClosed(false),
1309 mInClose(false),
1310 mHavePendingClose(false),
1311 mBlockScriptedClosingFlag(false),
1312 mWasOffline(false),
1313 mCreatingInnerWindow(false),
1314 mIsChrome(false),
1315 mAllowScriptsToClose(false),
1316 mTopLevelOuterContentWindow(false),
1317 mDelayedPrintUntilAfterLoad(false),
1318 mDelayedCloseForPrinting(false),
1319 mShouldDelayPrintUntilAfterLoad(false),
1320#ifdef DEBUG1
1321 mSerial(0),
1322 mSetOpenerWindowCalled(false),
1323#endif
1324 mCleanedUp(false),
1325 mCanSkipCCGeneration(0),
1326 mAutoActivateVRDisplayID(0) {
1327 AssertIsOnMainThread();
1328 SetIsOnMainThread();
1329 nsLayoutStatics::AddRef();
1330
1331 // Initialize the PRCList (this).
1332 PR_INIT_CLIST(this)do { (this)->next = (this); (this)->prev = (this); } while
(0)
;
1333
1334 // |this| is an outer window. Outer windows start out frozen and
1335 // remain frozen until they get an inner window.
1336 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"
, 1336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFrozen()"
")"); do { *((volatile int*)__null) = 1336; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1337
1338 // We could have failed the first time through trying
1339 // to create the entropy collector, so we should
1340 // try to get one until we succeed.
1341
1342#ifdef DEBUG1
1343 mSerial = nsContentUtils::InnerOrOuterWindowCreated();
1344
1345 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)
1346 ("++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)
1347 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)
1348 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)
1349 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)
;
1350#endif
1351
1352 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)
1353 ("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)
;
1354
1355 // Add ourselves to the outer windows list.
1356 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"
, 1356); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sOuterWindowsById"
") (" "Outer Windows hash table must be created!" ")"); do {
*((volatile int*)__null) = 1356; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1357
1358 // |this| is an outer window, add to the outer windows list.
1359 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"
, 1360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sOuterWindowsById->Contains(mWindowID)"
") (" "This window shouldn't be in the hash table yet!" ")")
; do { *((volatile int*)__null) = 1360; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1360 "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"
, 1360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sOuterWindowsById->Contains(mWindowID)"
") (" "This window shouldn't be in the hash table yet!" ")")
; do { *((volatile int*)__null) = 1360; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1361 // We seem to see crashes in release builds because of null
1362 // |sOuterWindowsById|.
1363 if (sOuterWindowsById) {
1364 sOuterWindowsById->InsertOrUpdate(mWindowID, this);
1365 }
1366}
1367
1368#ifdef DEBUG1
1369
1370/* static */
1371void nsGlobalWindowOuter::AssertIsOnMainThread() {
1372 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"
, 1372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 1372; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1373}
1374
1375#endif // DEBUG
1376
1377/* static */
1378void nsGlobalWindowOuter::Init() {
1379 AssertIsOnMainThread();
1380
1381 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"
, 1382); MOZ_PretendNoReturn(); } } while (0)
1382 "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"
, 1382); MOZ_PretendNoReturn(); } } while (0)
;
1383
1384 sOuterWindowsById = new OuterWindowByIdTable();
1385}
1386
1387nsGlobalWindowOuter::~nsGlobalWindowOuter() {
1388 AssertIsOnMainThread();
1389
1390 if (sOuterWindowsById) {
1391 sOuterWindowsById->Remove(mWindowID);
1392 }
1393
1394 nsContentUtils::InnerOrOuterWindowDestroyed();
1395
1396#ifdef DEBUG1
1397 if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)(__builtin_expect(!!(mozilla::detail::log_test(gDocShellAndDOMWindowLeakLogging
, LogLevel::Info)), 0))
) {
1398 nsAutoCString url;
1399 if (mLastOpenedURI) {
1400 url = mLastOpenedURI->GetSpecOrDefault();
1401
1402 // Data URLs can be very long, so truncate to avoid flooding the log.
1403 const uint32_t maxURLLength = 1000;
1404 if (url.Length() > maxURLLength) {
1405 url.Truncate(maxURLLength);
1406 }
1407 }
1408
1409 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)
1410 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)
1411 ("--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)
1412 "%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)
1413 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)
1414 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)
1415 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)
;
1416 }
1417#endif
1418
1419 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)
1420 ("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)
;
1421
1422 JSObject* proxy = GetWrapperMaybeDead();
1423 if (proxy) {
1424 if (mBrowsingContext && mBrowsingContext->GetUnbarrieredWindowProxy()) {
1425 nsGlobalWindowOuter* outer = nsOuterWindowProxy::GetOuterWindow(
1426 mBrowsingContext->GetUnbarrieredWindowProxy());
1427 // Check that the current WindowProxy object corresponds to this
1428 // nsGlobalWindowOuter, because we don't want to clear the WindowProxy if
1429 // we've replaced it with a cross-process WindowProxy.
1430 if (outer == this) {
1431 mBrowsingContext->ClearWindowProxy();
1432 }
1433 }
1434 js::SetProxyReservedSlot(proxy, OUTER_WINDOW_SLOT,
1435 JS::PrivateValue(nullptr));
1436 }
1437
1438 // An outer window is destroyed with inner windows still possibly
1439 // alive, iterate through the inner windows and null out their
1440 // back pointer to this outer, and pull them out of the list of
1441 // inner windows.
1442 //
1443 // Our linked list of inner windows both contains (an nsGlobalWindowOuter),
1444 // and our inner windows (nsGlobalWindowInners). This means that we need to
1445 // use PRCList*. We can then compare that PRCList* to `this` to see if its an
1446 // inner or outer window.
1447 PRCList* w;
1448 while ((w = PR_LIST_HEAD(this)(this)->next) != this) {
1449 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)
;
1450 }
1451
1452 DropOuterWindowDocs();
1453
1454 // Outer windows are always supposed to call CleanUp before letting themselves
1455 // be destroyed.
1456 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"
, 1456); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCleanedUp"
")"); do { *((volatile int*)__null) = 1456; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1457
1458 nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID"@mozilla.org/devicesensors;1");
1459 if (ac) ac->RemoveWindowAsListener(this);
1460
1461 nsLayoutStatics::Release();
1462}
1463
1464// static
1465void nsGlobalWindowOuter::ShutDown() {
1466 AssertIsOnMainThread();
1467
1468 delete sOuterWindowsById;
1469 sOuterWindowsById = nullptr;
1470}
1471
1472void nsGlobalWindowOuter::DropOuterWindowDocs() {
1473 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"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDoc->EventHandlingSuppressed()"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1474 mDoc = nullptr;
1475 mSuspendedDocs.Clear();
1476}
1477
1478void nsGlobalWindowOuter::CleanUp() {
1479 // Guarantee idempotence.
1480 if (mCleanedUp) return;
1481 mCleanedUp = true;
1482
1483 StartDying();
1484
1485 mWindowUtils = nullptr;
1486
1487 ClearControllers();
1488
1489 mContext = nullptr; // Forces Release
1490 mChromeEventHandler = nullptr; // Forces Release
1491 mParentTarget = nullptr;
1492 mMessageManager = nullptr;
1493
1494 mArguments = nullptr;
1495}
1496
1497void nsGlobalWindowOuter::ClearControllers() {
1498 if (mControllers) {
1499 uint32_t count;
1500 mControllers->GetControllerCount(&count);
1501
1502 while (count--) {
1503 nsCOMPtr<nsIController> controller;
1504 mControllers->GetControllerAt(count, getter_AddRefs(controller));
1505
1506 nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
1507 if (context) context->SetCommandContext(nullptr);
1508 }
1509
1510 mControllers = nullptr;
1511 }
1512}
1513
1514//*****************************************************************************
1515// nsGlobalWindowOuter::nsISupports
1516//*****************************************************************************
1517
1518// QueryInterface implementation for nsGlobalWindowOuter
1519NS_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"
, 1519); 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
1520 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRYif (aIID.Equals((nsWrapperCache::COMTypeInfo<nsWrapperCache
, void>::kIID))) { *aInstancePtr = static_cast<nsWrapperCache
*>(this); return NS_OK; } else
1521 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
1522 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIDOMWindow>)) foundInterface = static_cast
<nsIDOMWindow*>(this); else
1523 NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIGlobalObject>)) foundInterface
= static_cast<nsIGlobalObject*>(this); else
1524 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIScriptGlobalObject>)) foundInterface
= static_cast<nsIScriptGlobalObject*>(this); else
1525 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIScriptObjectPrincipal>)) foundInterface
= static_cast<nsIScriptObjectPrincipal*>(this); else
1526 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
1527 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowOuter)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsPIDOMWindowOuter>)) foundInterface
= static_cast<nsPIDOMWindowOuter*>(this); else
1528 NS_INTERFACE_MAP_ENTRY(mozIDOMWindowProxy)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, mozIDOMWindowProxy>)) foundInterface
= static_cast<mozIDOMWindowProxy*>(this); else
1529 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
1530 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIInterfaceRequestor>)) foundInterface
= static_cast<nsIInterfaceRequestor*>(this); else
1531NS_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"
, 1531); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 1531; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
1532
1533NS_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"
, 1533); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1533; __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; }
1534NS_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"
, 1534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); 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.decr
(base); NS_LogRelease((this), (count), ("nsGlobalWindowOuter"
)); return count; } void nsGlobalWindowOuter::DeleteCycleCollectable
(void) { delete (this); }
1535
1536NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipReal(void* p
, bool aRemovingAllowed) { nsGlobalWindowOuter* tmp = DowncastCCParticipant
<nsGlobalWindowOuter>(p);
1537 if (tmp->IsBlackForCC(false)) {
1538 if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
1539 return true;
1540 }
1541 tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
1542 if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
1543 elm->MarkForCC();
1544 }
1545 return true;
1546 }
1547NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END(void)tmp; return false; }
1548
1549NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipInCCReal(void
* p) { nsGlobalWindowOuter* tmp = DowncastCCParticipant<nsGlobalWindowOuter
>(p);
1550 return tmp->IsBlackForCC(true);
1551NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END(void)tmp; return false; }
1552
1553NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowOuter)bool nsGlobalWindowOuter::cycleCollection::CanSkipThisReal(void
* p) { nsGlobalWindowOuter* tmp = DowncastCCParticipant<nsGlobalWindowOuter
>(p);
1554 return tmp->IsBlackForCC(false);
1555NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END(void)tmp; return false; }
1556
1557NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowOuter)nsGlobalWindowOuter::cycleCollection nsGlobalWindowOuter::_cycleCollectorGlobal
;
1558
1559NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowOuter)nsresult nsGlobalWindowOuter::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1560 if (MOZ_UNLIKELY(cb.WantDebugInfo())(__builtin_expect(!!(cb.WantDebugInfo()), 0))) {
1561 char name[512];
1562 nsAutoCString uri;
1563 if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
1564 uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
1565 }
1566 SprintfLiteral(name, "nsGlobalWindowOuter # %" PRIu64"l" "u" " outer %s",
1567 tmp->mWindowID, uri.get());
1568 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
1569 } else {
1570 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowOuter, tmp->mRefCnt.get())cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "nsGlobalWindowOuter"
);
1571 }
1572
1573 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)ImplCycleCollectionTraverse(cb, tmp->mContext, "mContext",
0);
1574
1575 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)ImplCycleCollectionTraverse(cb, tmp->mControllers, "mControllers"
, 0);
1576 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)ImplCycleCollectionTraverse(cb, tmp->mArguments, "mArguments"
, 0);
1577
1578 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)ImplCycleCollectionTraverse(cb, tmp->mLocalStorage, "mLocalStorage"
, 0);
1579 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDocs)ImplCycleCollectionTraverse(cb, tmp->mSuspendedDocs, "mSuspendedDocs"
, 0);
1580 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentPrincipal, "mDocumentPrincipal"
, 0);
1581 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCookiePrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentCookiePrincipal
, "mDocumentCookiePrincipal", 0);
1582 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentStoragePrincipal
, "mDocumentStoragePrincipal", 0);
1583 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPartitionedPrincipal)ImplCycleCollectionTraverse(cb, tmp->mDocumentPartitionedPrincipal
, "mDocumentPartitionedPrincipal", 0);
1584 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)ImplCycleCollectionTraverse(cb, tmp->mDoc, "mDoc", 0);
1585
1586 // Traverse stuff from nsPIDOMWindow
1587 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)ImplCycleCollectionTraverse(cb, tmp->mChromeEventHandler, "mChromeEventHandler"
, 0);
1588 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)ImplCycleCollectionTraverse(cb, tmp->mParentTarget, "mParentTarget"
, 0);
1589 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)ImplCycleCollectionTraverse(cb, tmp->mMessageManager, "mMessageManager"
, 0);
1590 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)ImplCycleCollectionTraverse(cb, tmp->mFrameElement, "mFrameElement"
, 0);
1591
1592 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell)ImplCycleCollectionTraverse(cb, tmp->mDocShell, "mDocShell"
, 0);
1593 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)ImplCycleCollectionTraverse(cb, tmp->mBrowsingContext, "mBrowsingContext"
, 0);
1594
1595 tmp->TraverseObjectsInGlobal(cb);
1596
1597 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mBrowserDOMWindow)ImplCycleCollectionTraverse(cb, tmp->mChromeFields.mBrowserDOMWindow
, "mChromeFields.mBrowserDOMWindow", 0);
1598NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END(void)tmp; return NS_OK; }
1599
1600NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowOuter)void nsGlobalWindowOuter::cycleCollection::Unlink(void* p) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1601 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCEtmp->ClearWeakReferences();
1602 if (sOuterWindowsById) {
1603 sOuterWindowsById->Remove(tmp->mWindowID);
1604 }
1605
1606 NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)ImplCycleCollectionUnlink(tmp->mContext);
1607
1608 NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)ImplCycleCollectionUnlink(tmp->mControllers);
1609 NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)ImplCycleCollectionUnlink(tmp->mArguments);
1610
1611 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)ImplCycleCollectionUnlink(tmp->mLocalStorage);
1612 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDocs)ImplCycleCollectionUnlink(tmp->mSuspendedDocs);
1613 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)ImplCycleCollectionUnlink(tmp->mDocumentPrincipal);
1614 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCookiePrincipal)ImplCycleCollectionUnlink(tmp->mDocumentCookiePrincipal);
1615 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)ImplCycleCollectionUnlink(tmp->mDocumentStoragePrincipal);
1616 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPartitionedPrincipal)ImplCycleCollectionUnlink(tmp->mDocumentPartitionedPrincipal
);
1617 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)ImplCycleCollectionUnlink(tmp->mDoc);
1618
1619 // Unlink stuff from nsPIDOMWindow
1620 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)ImplCycleCollectionUnlink(tmp->mChromeEventHandler);
1621 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)ImplCycleCollectionUnlink(tmp->mParentTarget);
1622 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)ImplCycleCollectionUnlink(tmp->mMessageManager);
1623 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)ImplCycleCollectionUnlink(tmp->mFrameElement);
1624
1625 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)ImplCycleCollectionUnlink(tmp->mDocShell);
1626 if (tmp->mBrowsingContext) {
1627 if (tmp->mBrowsingContext->GetUnbarrieredWindowProxy()) {
1628 nsGlobalWindowOuter* outer = nsOuterWindowProxy::GetOuterWindow(
1629 tmp->mBrowsingContext->GetUnbarrieredWindowProxy());
1630 // Check that the current WindowProxy object corresponds to this
1631 // nsGlobalWindowOuter, because we don't want to clear the WindowProxy if
1632 // we've replaced it with a cross-process WindowProxy.
1633 if (outer == tmp) {
1634 tmp->mBrowsingContext->ClearWindowProxy();
1635 }
1636 }
1637 tmp->mBrowsingContext = nullptr;
1638 }
1639
1640 tmp->UnlinkObjectsInGlobal();
1641
1642 if (tmp->IsChromeWindow()) {
1643 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mBrowserDOMWindow)ImplCycleCollectionUnlink(tmp->mChromeFields.mBrowserDOMWindow
);
1644 }
1645
1646 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPERtmp->ReleaseWrapper(p);
1647NS_IMPL_CYCLE_COLLECTION_UNLINK_END(void)tmp; }
1648
1649NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowOuter)void nsGlobalWindowOuter::cycleCollection::Trace( void* p, const
TraceCallbacks& aCallbacks, void* aClosure) { nsGlobalWindowOuter
* tmp = DowncastCCParticipant<nsGlobalWindowOuter>(p);
1650 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPERtmp->TraceWrapper(aCallbacks, aClosure);
1651NS_IMPL_CYCLE_COLLECTION_TRACE_END(void)tmp; }
1652
1653bool nsGlobalWindowOuter::IsBlackForCC(bool aTracingNeeded) {
1654 if (!nsCCUncollectableMarker::sGeneration) {
1655 return false;
1656 }
1657
1658 // Unlike most wrappers, the outer window wrapper is not a wrapper for
1659 // the outer window. Instead, the outer window wrapper holds the inner
1660 // window binding object, which in turn holds the nsGlobalWindowInner, which
1661 // has a strong reference to the nsGlobalWindowOuter. We're using the
1662 // mInnerWindow pointer as a flag for that whole chain.
1663 return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
1664 (mInnerWindow && HasKnownLiveWrapper())) &&
1665 (!aTracingNeeded || HasNothingToTrace(ToSupports(this)));
1666}
1667
1668//*****************************************************************************
1669// nsGlobalWindowOuter::nsIScriptGlobalObject
1670//*****************************************************************************
1671
1672bool nsGlobalWindowOuter::ShouldResistFingerprinting(RFPTarget aTarget) const {
1673 if (mDoc) {
1674 return mDoc->ShouldResistFingerprinting(aTarget);
1675 }
1676 return nsContentUtils::ShouldResistFingerprinting(
1677 "If we do not have a document then we do not have any context"
1678 "to make an informed RFP choice, so we fall back to the global pref",
1679 aTarget);
1680}
1681
1682OriginTrials nsGlobalWindowOuter::Trials() const {
1683 return mInnerWindow ? nsGlobalWindowInner::Cast(mInnerWindow)->Trials()
1684 : OriginTrials();
1685}
1686
1687FontFaceSet* nsGlobalWindowOuter::GetFonts() {
1688 if (mDoc) {
1689 return mDoc->Fonts();
1690 }
1691 return nullptr;
1692}
1693
1694nsresult nsGlobalWindowOuter::EnsureScriptEnvironment() {
1695 if (GetWrapperPreserveColor()) {
1696 return NS_OK;
1697 }
1698
1699 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"
, 1699); return NS_ERROR_UNEXPECTED; } } while (false)
;
1700
1701 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"
, 1702); MOZ_PretendNoReturn(); } } while (0)
1702 "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"
, 1702); MOZ_PretendNoReturn(); } } while (0)
;
1703 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"
, 1703); MOZ_PretendNoReturn(); } } while (0)
;
1704
1705 // If this window is an [i]frame, don't bother GC'ing when the frame's context
1706 // is destroyed since a GC will happen when the frameset or host document is
1707 // destroyed anyway.
1708 mContext = new nsJSContext(mBrowsingContext->IsTop(), this);
1709 return NS_OK;
1710}
1711
1712nsIScriptContext* nsGlobalWindowOuter::GetScriptContext() { return mContext; }
1713
1714bool nsGlobalWindowOuter::WouldReuseInnerWindow(Document* aNewDocument) {
1715 // We reuse the inner window when:
1716 // a. We are currently at our original document.
1717 // b. At least one of the following conditions are true:
1718 // -- The new document is the same as the old document. This means that we're
1719 // getting called from document.open().
1720 // -- The new document has the same origin as what we have loaded right now.
1721
1722 if (!mDoc || !aNewDocument) {
1723 return false;
1724 }
1725
1726 if (!mDoc->IsInitialDocument()) {
1727 return false;
1728 }
1729
1730#ifdef DEBUG1
1731 {
1732 nsCOMPtr<nsIURI> uri;
1733 NS_GetURIWithoutRef(mDoc->GetDocumentURI(), getter_AddRefs(uri));
1734 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"
, 1734); MOZ_PretendNoReturn(); } } while (0)
;
1735 }
1736#endif
1737
1738 // Great, we're the original document, check for one of the other
1739 // conditions.
1740
1741 if (mDoc == aNewDocument) {
1742 return true;
1743 }
1744
1745 if (aNewDocument->IsStaticDocument()) {
1746 return false;
1747 }
1748
1749 if (BasePrincipal::Cast(mDoc->NodePrincipal())
1750 ->FastEqualsConsideringDomain(aNewDocument->NodePrincipal())) {
1751 // The origin is the same.
1752 return true;
1753 }
1754
1755 return false;
1756}
1757
1758void nsGlobalWindowOuter::SetInitialPrincipal(
1759 nsIPrincipal* aNewWindowPrincipal, nsIContentSecurityPolicy* aCSP,
1760 const Maybe<nsILoadInfo::CrossOriginEmbedderPolicy>& aCOEP) {
1761 // We should never create windows with an expanded principal.
1762 // If we have a system principal, make sure we're not using it for a content
1763 // docshell.
1764 // NOTE: Please keep this logic in sync with
1765 // nsAppShellService::JustCreateTopWindow
1766 if (nsContentUtils::IsExpandedPrincipal(aNewWindowPrincipal) ||
1767 (aNewWindowPrincipal->IsSystemPrincipal() &&
1768 GetBrowsingContext()->IsContent())) {
1769 aNewWindowPrincipal = nullptr;
1770 }
1771
1772 // If there's an existing document, bail if it either:
1773 if (mDoc) {
1774 // (a) is not an initial about:blank document, or
1775 if (!mDoc->IsInitialDocument()) return;
1776 // (b) already has the correct principal.
1777 if (mDoc->NodePrincipal() == aNewWindowPrincipal) return;
1778
1779#ifdef DEBUG1
1780 // If we have a document loaded at this point, it had better be about:blank.
1781 // Otherwise, something is really weird. An about:blank page has a
1782 // NullPrincipal.
1783 bool isNullPrincipal;
1784 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"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1786; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1785 &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"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1786; __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"
, 1786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(mDoc->NodePrincipal()->GetIsNullPrincipal( &isNullPrincipal))), 1))) && isNullPrincipal"
")"); do { *((volatile int*)__null) = 1786; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1787#endif
1788 }
1789
1790 // Use the subject (or system) principal as the storage principal too until
1791 // the new window finishes navigating and gets a real storage principal.
1792 nsDocShell::Cast(GetDocShell())
1793 ->CreateAboutBlankDocumentViewer(aNewWindowPrincipal, aNewWindowPrincipal,
1794 aCSP, nullptr,
1795 /* aIsInitialDocument */ true, aCOEP);
1796
1797 if (mDoc) {
1798 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"
, 1799); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc->IsInitialDocument()"
") (" "document should be initial document" ")"); do { *((volatile
int*)__null) = 1799; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
1799 "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"
, 1799); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc->IsInitialDocument()"
") (" "document should be initial document" ")"); do { *((volatile
int*)__null) = 1799; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1800 }
1801
1802 RefPtr<PresShell> presShell = GetDocShell()->GetPresShell();
1803 if (presShell && !presShell->DidInitialize()) {
1804 // Ensure that if someone plays with this document they will get
1805 // layout happening.
1806 presShell->Initialize();
1807 }
1808}
1809
1810#define WINDOWSTATEHOLDER_IID{ 0x0b917c3e, 0xbd50, 0x4683, { 0xaf, 0xc9, 0xc7, 0x81, 0x07,
0xae, 0x33, 0x26 } }
\
1811 { \
1812 0x0b917c3e, 0xbd50, 0x4683, { \
1813 0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26 \
1814 } \
1815 }
1816
1817class WindowStateHolder final : public nsISupports {
1818 public:
1819 NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)template <typename T, typename U> struct COMTypeInfo;
1820 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:
1821
1822 explicit WindowStateHolder(nsGlobalWindowInner* aWindow);
1823
1824 nsGlobalWindowInner* GetInnerWindow() { return mInnerWindow; }
1825
1826 void DidRestoreWindow() {
1827 mInnerWindow = nullptr;
1828 mInnerWindowReflector = nullptr;
1829 }
1830
1831 protected:
1832 ~WindowStateHolder();
1833
1834 nsGlobalWindowInner* mInnerWindow;
1835 // We hold onto this to make sure the inner window doesn't go away. The outer
1836 // window ends up recalculating it anyway.
1837 JS::PersistentRooted<JSObject*> mInnerWindowReflector;
1838};
1839
1840NS_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 } };
1841
1842WindowStateHolder::WindowStateHolder(nsGlobalWindowInner* aWindow)
1843 : mInnerWindow(aWindow),
1844 mInnerWindowReflector(RootingCx(), aWindow->GetWrapper()) {
1845 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"
, 1845); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ") ("
"null window" ")"); do { *((volatile int*)__null) = 1845; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
1846
1847 aWindow->Suspend();
1848
1849 // When a global goes into the bfcache, we disable script.
1850 xpc::Scriptability::Get(mInnerWindowReflector).SetWindowAllowsScript(false);
1851}
1852
1853WindowStateHolder::~WindowStateHolder() {
1854 if (mInnerWindow) {
1855 // This window was left in the bfcache and is now going away. We need to
1856 // free it up.
1857 // Note that FreeInnerObjects may already have been called on the
1858 // inner window if its outer has already had SetDocShell(null)
1859 // called.
1860 mInnerWindow->FreeInnerObjects();
1861 }
1862}
1863
1864NS_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"
, 1864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
1864; __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"
, 1864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WindowStateHolder\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1864; __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"
, 1864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 1864
; __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"
, 1864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WindowStateHolder\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 1864; __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"
, 1864); 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; }
1865
1866bool nsGlobalWindowOuter::ComputeIsSecureContext(Document* aDocument,
1867 SecureContextFlags aFlags) {
1868 nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
1869 if (principal->IsSystemPrincipal()) {
1870 return true;
1871 }
1872
1873 // Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object
1874 // With some modifications to allow for aFlags.
1875
1876 bool hadNonSecureContextCreator = false;
1877
1878 if (WindowContext* parentWindow =
1879 GetBrowsingContext()->GetParentWindowContext()) {
1880 hadNonSecureContextCreator = !parentWindow->GetIsSecureContext();
1881 }
1882
1883 if (hadNonSecureContextCreator) {
1884 return false;
1885 }
1886
1887 if (nsContentUtils::HttpsStateIsModern(aDocument)) {
1888 return true;
1889 }
1890
1891 if (principal->GetIsNullPrincipal()) {
1892 // If the NullPrincipal has a valid precursor URI we want to use it to
1893 // construct the principal otherwise we fall back to the original document
1894 // URI.
1895 nsCOMPtr<nsIPrincipal> precursorPrin = principal->GetPrecursorPrincipal();
1896 nsCOMPtr<nsIURI> uri = precursorPrin ? precursorPrin->GetURI() : nullptr;
1897 if (!uri) {
1898 uri = aDocument->GetOriginalURI();
1899 }
1900 // IsOriginPotentiallyTrustworthy doesn't care about origin attributes so
1901 // it doesn't actually matter what we use here, but reusing the document
1902 // principal's attributes is convenient.
1903 const OriginAttributes& attrs = principal->OriginAttributesRef();
1904 // CreateContentPrincipal correctly gets a useful principal for blob: and
1905 // other URI_INHERITS_SECURITY_CONTEXT URIs.
1906 principal = BasePrincipal::CreateContentPrincipal(uri, attrs);
1907 if (NS_WARN_IF(!principal)NS_warn_if_impl(!principal, "!principal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 1907)
) {
1908 return false;
1909 }
1910 }
1911
1912 return principal->GetIsOriginPotentiallyTrustworthy();
1913}
1914
1915static bool InitializeLegacyNetscapeObject(JSContext* aCx,
1916 JS::Handle<JSObject*> aGlobal) {
1917 JSAutoRealm ar(aCx, aGlobal);
1918
1919 // Note: MathJax depends on window.netscape being exposed. See bug 791526.
1920 JS::Rooted<JSObject*> obj(aCx);
1921 obj = JS_DefineObject(aCx, aGlobal, "netscape", nullptr);
1922 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"
, 1922); return false; } } while (false)
;
1923
1924 obj = JS_DefineObject(aCx, obj, "security", nullptr);
1925 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"
, 1925); return false; } } while (false)
;
1926
1927 return true;
1928}
1929
1930struct MOZ_STACK_CLASS CompartmentFinderState {
1931 explicit CompartmentFinderState(nsIPrincipal* aPrincipal)
1932 : principal(aPrincipal), compartment(nullptr) {}
1933
1934 // Input: we look for a compartment which is same-origin with the
1935 // given principal.
1936 nsIPrincipal* principal;
1937
1938 // Output: We set this member if we find a compartment.
1939 JS::Compartment* compartment;
1940};
1941
1942static JS::CompartmentIterResult FindSameOriginCompartment(
1943 JSContext* aCx, void* aData, JS::Compartment* aCompartment) {
1944 auto* data = static_cast<CompartmentFinderState*>(aData);
1945 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"
, 1945); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!data->compartment"
") (" "Why are we getting called?" ")"); do { *((volatile int
*)__null) = 1945; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1946
1947 // If this compartment is not safe to share across globals, don't do
1948 // anything with it; in particular we should not be getting a
1949 // CompartmentPrivate from such a compartment, because it may be in
1950 // the middle of being collected and its CompartmentPrivate may no
1951 // longer be valid.
1952 if (!js::IsSharableCompartment(aCompartment)) {
1953 return JS::CompartmentIterResult::KeepGoing;
1954 }
1955
1956 auto* compartmentPrivate = xpc::CompartmentPrivate::Get(aCompartment);
1957 if (!compartmentPrivate->CanShareCompartmentWith(data->principal)) {
1958 // Can't reuse this one, keep going.
1959 return JS::CompartmentIterResult::KeepGoing;
1960 }
1961
1962 // We have a winner!
1963 data->compartment = aCompartment;
1964 return JS::CompartmentIterResult::Stop;
1965}
1966
1967static JS::RealmCreationOptions& SelectZone(
1968 JSContext* aCx, nsIPrincipal* aPrincipal, nsGlobalWindowInner* aNewInner,
1969 JS::RealmCreationOptions& aOptions) {
1970 // Use the shared system compartment for chrome windows.
1971 if (aPrincipal->IsSystemPrincipal()) {
1972 return aOptions.setExistingCompartment(xpc::PrivilegedJunkScope());
1973 }
1974
1975 BrowsingContext* bc = aNewInner->GetBrowsingContext();
1976 if (bc->IsTop()) {
1977 // We're a toplevel load. Use a new zone. This way, when we do
1978 // zone-based compartment sharing we won't share compartments
1979 // across navigations.
1980 return aOptions.setNewCompartmentAndZone();
1981 }
1982
1983 // Find the in-process ancestor highest in the hierarchy.
1984 nsGlobalWindowInner* ancestor = nullptr;
1985 for (WindowContext* wc = bc->GetParentWindowContext(); wc;
1986 wc = wc->GetParentWindowContext()) {
1987 if (nsGlobalWindowInner* win = wc->GetInnerWindow()) {
1988 ancestor = win;
1989 }
1990 }
1991
1992 // If we have an ancestor window, use its zone.
1993 if (ancestor && ancestor->GetGlobalJSObject()) {
1994 JS::Zone* zone = JS::GetObjectZone(ancestor->GetGlobalJSObject());
1995 // Now try to find an existing compartment that's same-origin
1996 // with our principal.
1997 CompartmentFinderState data(aPrincipal);
1998 JS_IterateCompartmentsInZone(aCx, zone, &data, FindSameOriginCompartment);
1999 if (data.compartment) {
2000 return aOptions.setExistingCompartment(data.compartment);
2001 }
2002 return aOptions.setNewCompartmentInExistingZone(
2003 ancestor->GetGlobalJSObject());
2004 }
2005
2006 return aOptions.setNewCompartmentAndZone();
2007}
2008
2009/**
2010 * Create a new global object that will be used for an inner window.
2011 * Return the native global and an nsISupports 'holder' that can be used
2012 * to manage the lifetime of it.
2013 */
2014static nsresult CreateNativeGlobalForInner(
2015 JSContext* aCx, nsGlobalWindowInner* aNewInner, Document* aDocument,
2016 JS::MutableHandle<JSObject*> aGlobal, bool aIsSecureContext,
2017 bool aDefineSharedArrayBufferConstructor) {
2018 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"
, 2018); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCx" ")"); do
{ *((volatile int*)__null) = 2018; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2019 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"
, 2019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewInner" ")"
); do { *((volatile int*)__null) = 2019; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2020
2021 nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI();
2022 nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
2023 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"
, 2023); AnnotateMozCrashReason("MOZ_ASSERT" "(" "principal" ")"
); do { *((volatile int*)__null) = 2023; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2024
2025 // DOMWindow with nsEP is not supported, we have to make sure
2026 // no one creates one accidentally.
2027 nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(principal);
2028 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"
, 2028); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!nsEP"
") (" "DOMWindow with nsEP is not supported" ")"); do { *((volatile
int*)__null) = 2028; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2029
2030 JS::RealmOptions options;
2031 JS::RealmCreationOptions& creationOptions = options.creationOptions();
2032
2033 SelectZone(aCx, principal, aNewInner, creationOptions);
2034
2035 // Define the SharedArrayBuffer global constructor property only if shared
2036 // memory may be used and structured-cloned (e.g. through postMessage).
2037 //
2038 // When the global constructor property isn't defined, the SharedArrayBuffer
2039 // constructor can still be reached through Web Assembly. Omitting the global
2040 // property just prevents feature-tests from being misled. See bug 1624266.
2041 creationOptions.setDefineSharedArrayBufferConstructor(
2042 aDefineSharedArrayBufferConstructor);
2043
2044 xpc::InitGlobalObjectOptions(
2045 options, principal->IsSystemPrincipal(), aIsSecureContext,
2046 aDocument->ShouldResistFingerprinting(RFPTarget::JSDateTimeUTC),
2047 aDocument->ShouldResistFingerprinting(RFPTarget::JSMathFdlibm),
2048 aDocument->ShouldResistFingerprinting(RFPTarget::JSLocale));
2049
2050 // Determine if we need the Components object.
2051 bool needComponents = principal->IsSystemPrincipal();
2052 uint32_t flags = needComponents ? 0 : xpc::OMIT_COMPONENTS_OBJECT;
2053 flags |= xpc::DONT_FIRE_ONNEWGLOBALHOOK;
2054
2055 if (!Window_Binding::Wrap(aCx, aNewInner, aNewInner, options,
2056 nsJSPrincipals::get(principal), aGlobal) ||
2057 !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
2058 return NS_ERROR_FAILURE;
2059 }
2060
2061 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"
, 2061); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewInner->GetWrapperPreserveColor() == aGlobal"
")"); do { *((volatile int*)__null) = 2061; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2062
2063 // Set the location information for the new global, so that tools like
2064 // about:memory may use that information
2065 xpc::SetLocationForGlobal(aGlobal, uri);
2066
2067 if (!InitializeLegacyNetscapeObject(aCx, aGlobal)) {
2068 return NS_ERROR_FAILURE;
2069 }
2070
2071 return NS_OK;
2072}
2073
2074nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
2075 nsISupports* aState,
2076 bool aForceReuseInnerWindow,
2077 WindowGlobalChild* aActor) {
2078 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"
, 2079); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPrincipal == nullptr"
") (" "mDocumentPrincipal prematurely set!" ")"); do { *((volatile
int*)__null) = 2079; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
2079 "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"
, 2079); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPrincipal == nullptr"
") (" "mDocumentPrincipal prematurely set!" ")"); do { *((volatile
int*)__null) = 2079; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2080 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"
, 2081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentCookiePrincipal == nullptr"
") (" "mDocumentCookiePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2081; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2081 "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"
, 2081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentCookiePrincipal == nullptr"
") (" "mDocumentCookiePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2081; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2082 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"
, 2083); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentStoragePrincipal == nullptr"
") (" "mDocumentStoragePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2083; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2083 "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"
, 2083); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentStoragePrincipal == nullptr"
") (" "mDocumentStoragePrincipal prematurely set!" ")"); do {
*((volatile int*)__null) = 2083; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2084 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"
, 2085); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPartitionedPrincipal == nullptr"
") (" "mDocumentPartitionedPrincipal prematurely set!" ")");
do { *((volatile int*)__null) = 2085; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2085 "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"
, 2085); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocumentPartitionedPrincipal == nullptr"
") (" "mDocumentPartitionedPrincipal prematurely set!" ")");
do { *((volatile int*)__null) = 2085; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2086 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"
, 2086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")"
); do { *((volatile int*)__null) = 2086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2087
2088 // Bail out early if we're in process of closing down the window.
2089 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"
, 2089); return NS_ERROR_UNEXPECTED; } } while (false)
;
2090
2091 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"
, 2094); MOZ_PretendNoReturn(); } } while (0)
2092 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"
, 2094); MOZ_PretendNoReturn(); } } while (0)
2093 "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"
, 2094); MOZ_PretendNoReturn(); } } while (0)
2094 "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"
, 2094); MOZ_PretendNoReturn(); } } while (0)
;
2095 bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
2096 if (aForceReuseInnerWindow && !wouldReuseInnerWindow && mDoc &&
2097 mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
2098 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"
, 2098); MOZ_PretendNoReturn(); } while (0)
;
2099 return NS_ERROR_UNEXPECTED;
2100 }
2101
2102 if (!mBrowsingContext->AncestorsAreCurrent()) {
2103 return NS_ERROR_NOT_AVAILABLE;
2104 }
2105
2106 RefPtr<Document> oldDoc = mDoc;
2107 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"
, 2107); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "oldDoc != aDocument"
")"); do { *((volatile int*)__null) = 2107; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2108
2109 AutoJSAPI jsapi;
2110 jsapi.Init();
2111 JSContext* cx = jsapi.cx();
2112
2113 // Check if we're anywhere near the stack limit before we reach the
2114 // transplanting code, since it has no good way to handle errors. This uses
2115 // the untrusted script limit, which is not strictly necessary since no
2116 // actual script should run.
2117 js::AutoCheckRecursionLimit recursion(cx);
2118 if (!recursion.checkConservativeDontReport(cx)) {
2119 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"
, 2119)
;
2120 return NS_ERROR_FAILURE;
2121 }
2122
2123 if (!mDoc) {
2124 // First document load.
2125
2126 // Get our private root. If it is equal to us, then we need to
2127 // attach our global key bindings that handles browser scrolling
2128 // and other browser commands.
2129 nsPIDOMWindowOuter* privateRoot = GetPrivateRoot();
2130
2131 if (privateRoot == this) {
2132 RootWindowGlobalKeyListener::AttachKeyHandler(mChromeEventHandler);
2133 }
2134 }
2135
2136 MaybeResetWindowName(aDocument);
2137
2138 /* No mDocShell means we're already been partially closed down. When that
2139 happens, setting status isn't a big requirement, so don't. (Doesn't happen
2140 under normal circumstances, but bug 49615 describes a case.) */
2141
2142 nsContentUtils::AddScriptRunner(
2143 NewRunnableMethod("nsGlobalWindowOuter::ClearStatus", this,
2144 &nsGlobalWindowOuter::ClearStatus));
2145
2146 // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner
2147 // window (see bug 776497). Be safe.
2148 bool reUseInnerWindow = (aForceReuseInnerWindow || wouldReuseInnerWindow) &&
2149 GetCurrentInnerWindowInternal(this);
2150
2151 nsresult rv;
2152
2153 // We set mDoc even though this is an outer window to avoid
2154 // having to *always* reach into the inner window to find the
2155 // document.
2156 mDoc = aDocument;
2157
2158 nsDocShell::Cast(mDocShell)->MaybeRestoreWindowName();
2159
2160 // We drop the print request for the old document on the floor, it never made
2161 // it. We don't close the window here either even if we were asked to.
2162 mShouldDelayPrintUntilAfterLoad = true;
2163 mDelayedCloseForPrinting = false;
2164 mDelayedPrintUntilAfterLoad = false;
2165
2166 // Take this opportunity to clear mSuspendedDocs. Our old inner window is now
2167 // responsible for unsuspending it.
2168 mSuspendedDocs.Clear();
2169
2170#ifdef DEBUG1
2171 mLastOpenedURI = aDocument->GetDocumentURI();
2172#endif
2173
2174 RefPtr<nsGlobalWindowInner> currentInner =
2175 GetCurrentInnerWindowInternal(this);
2176
2177 if (currentInner && currentInner->mNavigator) {
2178 currentInner->mNavigator->OnNavigation();
2179 }
2180
2181 RefPtr<nsGlobalWindowInner> newInnerWindow;
2182 bool createdInnerWindow = false;
2183
2184 bool thisChrome = IsChromeWindow();
2185
2186 nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
2187 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"
, 2188); MOZ_PretendNoReturn(); } } while (0)
2188 "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"
, 2188); MOZ_PretendNoReturn(); } } while (0)
;
2189
2190 bool doomCurrentInner = false;
2191
2192 // Only non-gray (i.e. exposed to JS) objects should be assigned to
2193 // newInnerGlobal.
2194 JS::Rooted<JSObject*> newInnerGlobal(cx);
2195 if (reUseInnerWindow) {
2196 // We're reusing the current inner window.
2197 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"
, 2198); MOZ_PretendNoReturn(); } } while (0)
2198 "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"
, 2198); MOZ_PretendNoReturn(); } } while (0)
;
2199 newInnerWindow = currentInner;
2200 newInnerGlobal = currentInner->GetWrapper();
2201
2202 // We're reusing the inner window, but this still counts as a navigation,
2203 // so all expandos and such defined on the outer window should go away.
2204 // Force all Xray wrappers to be recomputed.
2205 JS::Rooted<JSObject*> rootedObject(cx, GetWrapper());
2206 if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
2207 return NS_ERROR_FAILURE;
2208 }
2209
2210 // Inner windows are only reused for same-origin principals, but the
2211 // principals don't necessarily match exactly. Update the principal on the
2212 // realm to match the new document. NB: We don't just call
2213 // currentInner->RefreshRealmPrincipals() here because we haven't yet set
2214 // its mDoc to aDocument.
2215 JS::Realm* realm = js::GetNonCCWObjectRealm(newInnerGlobal);
2216#ifdef DEBUG1
2217 bool sameOrigin = false;
2218 nsIPrincipal* existing = nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
2219 aDocument->NodePrincipal()->Equals(existing, &sameOrigin);
2220 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"
, 2220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sameOrigin"
")"); do { *((volatile int*)__null) = 2220; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2221#endif
2222 JS::SetRealmPrincipals(realm,
2223 nsJSPrincipals::get(aDocument->NodePrincipal()));
2224 } else {
2225 if (aState) {
2226 newInnerWindow = wsh->GetInnerWindow();
2227 newInnerGlobal = newInnerWindow->GetWrapper();
2228 } else {
2229 newInnerWindow = nsGlobalWindowInner::Create(this, thisChrome, aActor);
2230 if (StaticPrefs::dom_timeout_defer_during_load()) {
2231 // ensure the initial loading state is known
2232 newInnerWindow->SetActiveLoadingState(
2233 aDocument->GetReadyStateEnum() ==
2234 Document::ReadyState::READYSTATE_LOADING);
2235 }
2236
2237 // The outer window is automatically treated as frozen when we
2238 // null out the inner window. As a result, initializing classes
2239 // on the new inner won't end up reaching into the old inner
2240 // window for classes etc.
2241 //
2242 // [This happens with Object.prototype when XPConnect creates
2243 // a temporary global while initializing classes; the reason
2244 // being that xpconnect creates the temp global w/o a parent
2245 // and proto, which makes the JS engine look up classes in
2246 // cx->globalObject, i.e. this outer window].
2247
2248 mInnerWindow = nullptr;
2249
2250 mCreatingInnerWindow = true;
2251
2252 // The SharedArrayBuffer global constructor property should not be present
2253 // in a fresh global object when shared memory objects aren't allowed
2254 // (because COOP/COEP support isn't enabled, or because COOP/COEP don't
2255 // act to isolate this page to a separate process).
2256
2257 // Every script context we are initialized with must create a
2258 // new global.
2259 rv = CreateNativeGlobalForInner(
2260 cx, newInnerWindow, aDocument, &newInnerGlobal,
2261 ComputeIsSecureContext(aDocument),
2262 newInnerWindow->IsSharedMemoryAllowedInternal(
2263 aDocument->NodePrincipal()));
2264 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"
, 2267); MOZ_PretendNoReturn(); } } while (0)
2265 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"
, 2267); MOZ_PretendNoReturn(); } } while (0)
2266 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"
, 2267); MOZ_PretendNoReturn(); } } while (0)
2267 "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"
, 2267); MOZ_PretendNoReturn(); } } while (0)
;
2268
2269 mCreatingInnerWindow = false;
2270 createdInnerWindow = true;
2271
2272 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"
, 2272); return rv; } } while (false)
;
2273 }
2274
2275 if (currentInner && currentInner->GetWrapperPreserveColor()) {
2276 // Don't free objects on our current inner window if it's going to be
2277 // held in the bfcache.
2278 if (!currentInner->IsFrozen()) {
2279 doomCurrentInner = true;
2280 }
2281 }
2282
2283 mInnerWindow = newInnerWindow;
2284 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"
, 2284); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mInnerWindow"
")"); do { *((volatile int*)__null) = 2284; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2285 mInnerWindow->TryToCacheTopInnerWindow();
2286
2287 if (!GetWrapperPreserveColor()) {
2288 JS::Rooted<JSObject*> outer(
2289 cx, NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
2290 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"
, 2290); return NS_ERROR_FAILURE; } } while (false)
;
2291
2292 mBrowsingContext->CleanUpDanglingRemoteOuterWindowProxies(cx, &outer);
2293 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"
, 2293); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(outer)"
")"); do { *((volatile int*)__null) = 2293; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2294
2295 js::SetProxyReservedSlot(outer, OUTER_WINDOW_SLOT,
2296 JS::PrivateValue(ToSupports(this)));
2297
2298 // Inform the nsJSContext, which is the canonical holder of the outer.
2299 mContext->SetWindowProxy(outer);
2300
2301 SetWrapper(mContext->GetWindowProxy());
2302 } else {
2303 JS::Rooted<JSObject*> outerObject(
2304 cx, NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
2305 if (!outerObject) {
2306 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"
, 2306); MOZ_PretendNoReturn(); } while (0)
;
2307 return NS_ERROR_FAILURE;
2308 }
2309
2310 JS::Rooted<JSObject*> obj(cx, GetWrapper());
2311
2312 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"
, 2312); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(obj)"
")"); do { *((volatile int*)__null) = 2312; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2313
2314 js::SetProxyReservedSlot(obj, OUTER_WINDOW_SLOT,
2315 JS::PrivateValue(nullptr));
2316 js::SetProxyReservedSlot(outerObject, OUTER_WINDOW_SLOT,
2317 JS::PrivateValue(nullptr));
2318 js::SetProxyReservedSlot(obj, HOLDER_WEAKMAP_SLOT, JS::UndefinedValue());
2319
2320 outerObject = xpc::TransplantObjectNukingXrayWaiver(cx, obj, outerObject);
2321
2322 if (!outerObject) {
2323 mBrowsingContext->ClearWindowProxy();
2324 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"
, 2324); MOZ_PretendNoReturn(); } while (0)
;
2325 return NS_ERROR_FAILURE;
2326 }
2327
2328 js::SetProxyReservedSlot(outerObject, OUTER_WINDOW_SLOT,
2329 JS::PrivateValue(ToSupports(this)));
2330
2331 SetWrapper(outerObject);
2332
2333 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"
, 2333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal"
")"); do { *((volatile int*)__null) = 2333; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2334
2335 // Inform the nsJSContext, which is the canonical holder of the outer.
2336 mContext->SetWindowProxy(outerObject);
2337 }
2338
2339 // Enter the new global's realm.
2340 JSAutoRealm ar(cx, GetWrapperPreserveColor());
2341
2342 {
2343 JS::Rooted<JSObject*> outer(cx, GetWrapperPreserveColor());
2344 js::SetWindowProxy(cx, newInnerGlobal, outer);
2345 mBrowsingContext->SetWindowProxy(outer);
2346 }
2347
2348 // Set scriptability based on the state of the WindowContext.
2349 WindowContext* wc = mInnerWindow->GetWindowContext();
2350 bool allow =
2351 wc ? wc->CanExecuteScripts() : mBrowsingContext->CanExecuteScripts();
2352 xpc::Scriptability::Get(GetWrapperPreserveColor())
2353 .SetWindowAllowsScript(allow);
2354
2355 if (!aState) {
2356 // Get the "window" property once so it will be cached on our inner. We
2357 // have to do this here, not in binding code, because this has to happen
2358 // after we've created the outer window proxy and stashed it in the outer
2359 // nsGlobalWindowOuter, so GetWrapperPreserveColor() on that outer
2360 // nsGlobalWindowOuter doesn't return null and
2361 // nsGlobalWindowOuter::OuterObject works correctly.
2362 JS::Rooted<JS::Value> unused(cx);
2363 if (!JS_GetProperty(cx, newInnerGlobal, "window", &unused)) {
2364 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"
, 2364); MOZ_PretendNoReturn(); } while (0)
;
2365 return NS_ERROR_FAILURE;
2366 }
2367
2368 // And same thing for the "self" property.
2369 if (!JS_GetProperty(cx, newInnerGlobal, "self", &unused)) {
2370 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"
, 2370); MOZ_PretendNoReturn(); } while (0)
;
2371 return NS_ERROR_FAILURE;
2372 }
2373 }
2374 }
2375
2376 JSAutoRealm ar(cx, GetWrapperPreserveColor());
2377
2378 if (!aState && !reUseInnerWindow) {
2379 // Loading a new page and creating a new inner window, *not*
2380 // restoring from session history.
2381
2382 // Now that both the the inner and outer windows are initialized
2383 // let the script context do its magic to hook them together.
2384 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"
, 2384); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mContext->GetWindowProxy() == GetWrapperPreserveColor()"
")"); do { *((volatile int*)__null) = 2384; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2385#ifdef DEBUG1
2386 JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
2387 JS::Rooted<JSObject*> proto1(cx), proto2(cx);
2388 JS_GetPrototype(cx, rootedJSObject, &proto1);
2389 JS_GetPrototype(cx, newInnerGlobal, &proto2);
2390 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"
, 2391); MOZ_PretendNoReturn(); } } while (0)
2391 "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"
, 2391); MOZ_PretendNoReturn(); } } while (0)
;
2392#endif
2393
2394 mInnerWindow->SyncStateFromParentWindow();
2395 }
2396
2397 // Add an extra ref in case we release mContext during GC.
2398 nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
2399
2400 // Make sure the inner's document is set correctly before we call
2401 // SetScriptGlobalObject, because that might try to examine document-dependent
2402 // state. Unfortunately, we can't do some of the other clearing/resetting
2403 // work we do below until after SetScriptGlobalObject(), because it might
2404 // depend on the document having the right scope object.
2405 if (aState) {
2406 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"
, 2406); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc == aDocument"
")"); do { *((volatile int*)__null) = 2406; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2407 } else {
2408 if (reUseInnerWindow) {
2409 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"
, 2409); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc != aDocument"
")"); do { *((volatile int*)__null) = 2409; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2410 }
2411 newInnerWindow->mDoc = aDocument;
2412 }
2413
2414 aDocument->SetScriptGlobalObject(newInnerWindow);
2415
2416 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"
, 2416); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "newInnerWindow->mDoc == aDocument"
")"); do { *((volatile int*)__null) = 2416; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2417
2418 if (mBrowsingContext->IsTopContent()) {
2419 net::CookieJarSettings::Cast(aDocument->CookieJarSettings())
2420 ->SetTopLevelWindowContextId(aDocument->InnerWindowID());
2421 }
2422
2423 newInnerWindow->RefreshReduceTimerPrecisionCallerType();
2424
2425 if (!aState) {
2426 if (reUseInnerWindow) {
2427 // The StorageAccess state may have changed. Invalidate the cached
2428 // StorageAllowed field, so that the next call to StorageAllowedForWindow
2429 // recomputes it.
2430 newInnerWindow->ClearStorageAllowedCache();
2431
2432 // The storage objects contain the URL of the window. We have to
2433 // recreate them when the innerWindow is reused.
2434 newInnerWindow->mLocalStorage = nullptr;
2435 newInnerWindow->mSessionStorage = nullptr;
2436 newInnerWindow->mPerformance = nullptr;
2437
2438 // This must be called after nullifying the internal objects because
2439 // here we could recreate them, calling the getter methods, and store
2440 // them into the JS slots. If we nullify them after, the slot values and
2441 // the objects will be out of sync.
2442 newInnerWindow->ClearDocumentDependentSlots(cx);
2443 } else {
2444 newInnerWindow->InitDocumentDependentState(cx);
2445
2446 // Initialize DOM classes etc on the inner window.
2447 JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
2448 rv = kungFuDeathGrip->InitClasses(obj);
2449 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"
, 2449); return rv; } } while (false)
;
2450 }
2451
2452 // When replacing an initial about:blank document we call
2453 // ExecutionReady again to update the client creation URL.
2454 rv = newInnerWindow->ExecutionReady();
2455 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"
, 2455); return rv; } } while (false)
;
2456
2457 if (mArguments) {
2458 newInnerWindow->DefineArgumentsProperty(mArguments);
2459 mArguments = nullptr;
2460 }
2461
2462 // Give the new inner window our chrome event handler (since it
2463 // doesn't have one).
2464 newInnerWindow->mChromeEventHandler = mChromeEventHandler;
2465 }
2466
2467 if (!aState && reUseInnerWindow) {
2468 // Notify our WindowGlobalChild that it has a new document. If `aState` was
2469 // passed, we're restoring the window from the BFCache, so the document
2470 // hasn't changed.
2471 // If we didn't have a window global child before, then initializing
2472 // it will have set all the required state, so we don't need to do
2473 // it again.
2474 mInnerWindow->GetWindowGlobalChild()->OnNewDocument(aDocument);
2475 }
2476
2477 // Update the current window for our BrowsingContext.
2478 RefPtr<BrowsingContext> bc = GetBrowsingContext();
2479
2480 if (bc->IsOwnedByProcess()) {
2481 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"
, 2481); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(bc->SetCurrentInnerWindowId(mInnerWindow->WindowID()))"
")"); do { *((volatile int*)__null) = 2481; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2482 }
2483
2484 // We no longer need the old inner window. Start its destruction if
2485 // its not being reused and clear our reference.
2486 if (doomCurrentInner) {
2487 currentInner->FreeInnerObjects();
2488 }
2489 currentInner = nullptr;
2490
2491 // We wait to fire the debugger hook until the window is all set up and hooked
2492 // up with the outer. See bug 969156.
2493 if (createdInnerWindow) {
2494 nsContentUtils::AddScriptRunner(NewRunnableMethod(
2495 "nsGlobalWindowInner::FireOnNewGlobalObject", newInnerWindow,
2496 &nsGlobalWindowInner::FireOnNewGlobalObject));
2497 }
2498
2499 if (!newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
2500 // We should probably notify. However if this is the, arguably bad,
2501 // situation when we're creating a temporary non-chrome-about-blank
2502 // document in a chrome docshell, don't notify just yet. Instead wait
2503 // until we have a real chrome doc.
2504 const bool isContentAboutBlankInChromeDocshell = [&] {
2505 if (!mDocShell) {
2506 return false;
2507 }
2508
2509 RefPtr<BrowsingContext> bc = mDocShell->GetBrowsingContext();
2510 if (!bc || bc->GetType() != BrowsingContext::Type::Chrome) {
2511 return false;
2512 }
2513
2514 return !mDoc->NodePrincipal()->IsSystemPrincipal();
2515 }();
2516
2517 if (!isContentAboutBlankInChromeDocshell) {
2518 newInnerWindow->mHasNotifiedGlobalCreated = true;
2519 nsContentUtils::AddScriptRunner(NewRunnableMethod(
2520 "nsGlobalWindowOuter::DispatchDOMWindowCreated", this,
2521 &nsGlobalWindowOuter::DispatchDOMWindowCreated));
2522 }
2523 }
2524
2525 PreloadLocalStorage();
2526
2527 // Do this here rather than in say the Document constructor, since
2528 // we need a WindowContext available.
2529 mDoc->InitUseCounters();
2530
2531 return NS_OK;
2532}
2533
2534/* static */
2535void nsGlobalWindowOuter::PrepareForProcessChange(JSObject* aProxy) {
2536 JS::Rooted<JSObject*> localProxy(RootingCx(), aProxy);
2537 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"
, 2537); AnnotateMozCrashReason("MOZ_ASSERT" "(" "js::IsWindowProxy(localProxy)"
")"); do { *((volatile int*)__null) = 2537; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2538
2539 RefPtr<nsGlobalWindowOuter> outerWindow =
2540 nsOuterWindowProxy::GetOuterWindow(localProxy);
2541 if (!outerWindow) {
2542 return;
2543 }
2544
2545 AutoJSAPI jsapi;
2546 jsapi.Init();
2547 JSContext* cx = jsapi.cx();
2548
2549 JSAutoRealm ar(cx, localProxy);
2550
2551 // Clear out existing references from the browsing context and outer window to
2552 // the proxy, and from the proxy to the outer window. These references will
2553 // become invalid once the proxy is transplanted. Clearing the window proxy
2554 // from the browsing context is also necessary to indicate that it is for an
2555 // out of process window.
2556 outerWindow->ClearWrapper(localProxy);
2557 RefPtr<BrowsingContext> bc = outerWindow->GetBrowsingContext();
2558 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"
, 2558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc" ")"); do
{ *((volatile int*)__null) = 2558; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2559 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"
, 2559); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc->GetWindowProxy() == localProxy"
")"); do { *((volatile int*)__null) = 2559; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2560 bc->ClearWindowProxy();
2561 js::SetProxyReservedSlot(localProxy, OUTER_WINDOW_SLOT,
2562 JS::PrivateValue(nullptr));
2563 js::SetProxyReservedSlot(localProxy, HOLDER_WEAKMAP_SLOT,
2564 JS::UndefinedValue());
2565
2566 // Create a new remote outer window proxy, and transplant to it.
2567 JS::Rooted<JSObject*> remoteProxy(cx);
2568
2569 if (!mozilla::dom::GetRemoteOuterWindowProxy(cx, bc, localProxy,
2570 &remoteProxy)) {
2571 MOZ_CRASH("PrepareForProcessChange GetRemoteOuterWindowProxy")do { do { } while (false); MOZ_ReportCrash("" "PrepareForProcessChange GetRemoteOuterWindowProxy"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2571); AnnotateMozCrashReason("MOZ_CRASH(" "PrepareForProcessChange GetRemoteOuterWindowProxy"
")"); do { *((volatile int*)__null) = 2571; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2572 }
2573
2574 if (!xpc::TransplantObjectNukingXrayWaiver(cx, localProxy, remoteProxy)) {
2575 MOZ_CRASH("PrepareForProcessChange TransplantObject")do { do { } while (false); MOZ_ReportCrash("" "PrepareForProcessChange TransplantObject"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 2575); AnnotateMozCrashReason("MOZ_CRASH(" "PrepareForProcessChange TransplantObject"
")"); do { *((volatile int*)__null) = 2575; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2576 }
2577}
2578
2579void nsGlobalWindowOuter::PreloadLocalStorage() {
2580 if (!Storage::StoragePrefIsEnabled()) {
2581 return;
2582 }
2583
2584 if (IsChromeWindow()) {
2585 return;
2586 }
2587
2588 nsIPrincipal* principal = GetPrincipal();
2589 nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
2590 if (!principal || !storagePrincipal) {
2591 return;
2592 }
2593
2594 nsresult rv;
2595
2596 nsCOMPtr<nsIDOMStorageManager> storageManager =
2597 do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
2598 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2599 return;
2600 }
2601
2602 // private browsing windows do not persist local storage to disk so we should
2603 // only try to precache storage when we're not a private browsing window.
2604 if (principal->GetPrivateBrowsingId() == 0) {
2605 RefPtr<Storage> storage;
2606 rv = storageManager->PrecacheStorage(principal, storagePrincipal,
2607 getter_AddRefs(storage));
2608 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2609 mLocalStorage = storage;
2610 }
2611 }
2612}
2613
2614void nsGlobalWindowOuter::DispatchDOMWindowCreated() {
2615 if (!mDoc) {
2616 return;
2617 }
2618
2619 // Fire DOMWindowCreated at chrome event listeners
2620 nsContentUtils::DispatchChromeEvent(mDoc, mDoc, u"DOMWindowCreated"_ns,
2621 CanBubble::eYes, Cancelable::eNo);
2622
2623 nsCOMPtr<nsIObserverService> observerService =
2624 mozilla::services::GetObserverService();
2625
2626 // The event dispatching could possibly cause docshell destory, and
2627 // consequently cause mDoc to be set to nullptr by DropOuterWindowDocs(),
2628 // so check it again here.
2629 if (observerService && mDoc) {
2630 nsAutoString origin;
2631 nsIPrincipal* principal = mDoc->NodePrincipal();
2632 nsContentUtils::GetWebExposedOriginSerialization(principal, origin);
2633 observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
2634 principal->IsSystemPrincipal()
2635 ? "chrome-document-global-created"
2636 : "content-document-global-created",
2637 origin.get());
2638 }
2639}
2640
2641void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); }
2642
2643void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) {
2644 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"
, 2644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocShell" ")"
); do { *((volatile int*)__null) = 2644; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2645
2646 if (aDocShell == mDocShell) {
2647 return;
2648 }
2649
2650 mDocShell = aDocShell;
2651 mBrowsingContext = aDocShell->GetBrowsingContext();
2652
2653 RefPtr<BrowsingContext> parentContext = mBrowsingContext->GetParent();
2654
2655 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"
, 2656); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
")"); do { *((volatile int*)__null) = 2656; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2656 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"
, 2656); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!parentContext || GetBrowsingContextGroup() == parentContext->Group()"
")"); do { *((volatile int*)__null) = 2656; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2657
2658 mTopLevelOuterContentWindow = mBrowsingContext->IsTopContent();
2659
2660 // Get our enclosing chrome shell and retrieve its global window impl, so
2661 // that we can do some forwarding to the chrome document.
2662 RefPtr<EventTarget> chromeEventHandler;
2663 mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2664 mChromeEventHandler = chromeEventHandler;
2665 if (!mChromeEventHandler) {
2666 // We have no chrome event handler. If we have a parent,
2667 // get our chrome event handler from the parent. If
2668 // we don't have a parent, then we need to make a new
2669 // window root object that will function as a chrome event
2670 // handler and receive all events that occur anywhere inside
2671 // our window.
2672 nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetInProcessParent();
2673 if (parentWindow.get() != this) {
2674 mChromeEventHandler = parentWindow->GetChromeEventHandler();
2675 } else {
2676 mChromeEventHandler = NS_NewWindowRoot(this);
2677 mIsRootOuterWindow = true;
2678 }
2679 }
2680
2681 SetIsBackgroundInternal(!mBrowsingContext->IsActive());
2682}
2683
2684void nsGlobalWindowOuter::DetachFromDocShell(bool aIsBeingDiscarded) {
2685 // DetachFromDocShell means the window is being torn down. Drop our
2686 // reference to the script context, allowing it to be deleted
2687 // later. Meanwhile, keep our weak reference to the script object
2688 // so that it can be retrieved later (until it is finalized by the JS GC).
2689
2690 // Call FreeInnerObjects on all inner windows, not just the current
2691 // one, since some could be held by WindowStateHolder objects that
2692 // are GC-owned.
2693 RefPtr<nsGlobalWindowInner> inner;
2694 for (PRCList* node = PR_LIST_HEAD(this)(this)->next; node != this;
2695 node = PR_NEXT_LINK(inner)((inner)->next)) {
2696 // This cast is safe because `node != this`. Non-this nodes are inner
2697 // windows.
2698 inner = static_cast<nsGlobalWindowInner*>(node);
2699 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"
, 2699); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inner->mOuterWindow || inner->mOuterWindow == this"
")"); do { *((volatile int*)__null) = 2699; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2700 inner->FreeInnerObjects();
2701 }
2702
2703 // Don't report that we were detached to the nsWindowMemoryReporter, as it
2704 // only tracks inner windows.
2705
2706 NotifyWindowIDDestroyed("outer-window-destroyed");
2707
2708 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(this);
2709
2710 if (currentInner) {
2711 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"
, 2711); MOZ_PretendNoReturn(); } } while (0)
;
2712
2713 // Remember the document's principal and URI.
2714 mDocumentPrincipal = mDoc->NodePrincipal();
2715 mDocumentCookiePrincipal = mDoc->EffectiveCookiePrincipal();
2716 mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
2717 mDocumentPartitionedPrincipal = mDoc->PartitionedPrincipal();
2718 mDocumentURI = mDoc->GetDocumentURI();
2719
2720 // Release our document reference
2721 DropOuterWindowDocs();
2722 }
2723
2724 ClearControllers();
2725
2726 mChromeEventHandler = nullptr; // force release now
2727
2728 if (mContext) {
2729 // When we're about to destroy a top level content window
2730 // (for example a tab), we trigger a full GC by passing null as the last
2731 // param. We also trigger a full GC for chrome windows.
2732 nsJSContext::PokeGC(JS::GCReason::SET_DOC_SHELL,
2733 (mTopLevelOuterContentWindow || mIsChrome)
2734 ? nullptr
2735 : GetWrapperPreserveColor());
2736 mContext = nullptr;
2737 }
2738
2739 if (aIsBeingDiscarded) {
2740 // If our BrowsingContext is being discarded, make a note that our current
2741 // inner window was active at the time it went away.
2742 if (nsGlobalWindowInner* currentInner =
2743 GetCurrentInnerWindowInternal(this)) {
2744 currentInner->SetWasCurrentInnerWindow();
2745 }
2746 }
2747
2748 mDocShell = nullptr;
2749 mBrowsingContext->ClearDocShell();
2750
2751 CleanUp();
2752}
2753
2754void nsGlobalWindowOuter::UpdateParentTarget() {
2755 // NOTE: This method is nearly identical to
2756 // nsGlobalWindowInner::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
2757 // UPDATE THE OTHER ONE TOO! The one difference is that this method updates
2758 // mMessageManager as well, which inner windows don't have.
2759
2760 // Try to get our frame element's tab child global (its in-process message
2761 // manager). If that fails, fall back to the chrome event handler's tab
2762 // child global, and if it doesn't have one, just use the chrome event
2763 // handler itself.
2764
2765 nsCOMPtr<Element> frameElement = GetFrameElementInternal();
2766 mMessageManager = nsContentUtils::TryGetBrowserChildGlobal(frameElement);
2767
2768 if (!mMessageManager) {
2769 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
2770 if (topWin) {
2771 frameElement = topWin->GetFrameElementInternal();
2772 mMessageManager = nsContentUtils::TryGetBrowserChildGlobal(frameElement);
2773 }
2774 }
2775
2776 if (!mMessageManager) {
2777 mMessageManager =
2778 nsContentUtils::TryGetBrowserChildGlobal(mChromeEventHandler);
2779 }
2780
2781 if (mMessageManager) {
2782 mParentTarget = mMessageManager;
2783 } else {
2784 mParentTarget = mChromeEventHandler;
2785 }
2786}
2787
2788EventTarget* nsGlobalWindowOuter::GetTargetForEventTargetChain() {
2789 return GetCurrentInnerWindowInternal(this);
2790}
2791
2792void nsGlobalWindowOuter::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
2793 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"
, 2793); AnnotateMozCrashReason("MOZ_CRASH(" "The outer window should not be part of an event path"
")"); do { *((volatile int*)__null) = 2793; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2794}
2795
2796bool nsGlobalWindowOuter::ShouldPromptToBlockDialogs() {
2797 if (!nsContentUtils::GetCurrentJSContext()) {
2798 return false; // non-scripted caller.
2799 }
2800
2801 BrowsingContextGroup* group = GetBrowsingContextGroup();
2802 if (!group) {
2803 return true;
2804 }
2805
2806 return group->DialogsAreBeingAbused();
2807}
2808
2809bool nsGlobalWindowOuter::AreDialogsEnabled() {
2810 BrowsingContextGroup* group = mBrowsingContext->Group();
2811 if (!group) {
2812 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"
, 2812); MOZ_PretendNoReturn(); } while (0)
;
2813 return false;
2814 }
2815
2816 // Dialogs are blocked if the content viewer is hidden
2817 if (mDocShell) {
2818 nsCOMPtr<nsIDocumentViewer> viewer;
2819 mDocShell->GetDocViewer(getter_AddRefs(viewer));
2820
2821 bool isHidden;
2822 viewer->GetIsHidden(&isHidden);
2823 if (isHidden) {
2824 return false;
2825 }
2826 }
2827
2828 // Dialogs are also blocked if the document is sandboxed with SANDBOXED_MODALS
2829 // (or if we have no document, of course). Which document? Who knows; the
2830 // spec is daft. See <https://github.com/whatwg/html/issues/1206>. For now
2831 // just go ahead and check mDoc, since in everything except edge cases in
2832 // which a frame is allow-same-origin but not allow-scripts and is being poked
2833 // at by some other window this should be the right thing anyway.
2834 if (!mDoc || (mDoc->GetSandboxFlags() & SANDBOXED_MODALS)) {
2835 return false;
2836 }
2837
2838 return group->GetAreDialogsEnabled();
2839}
2840
2841bool nsGlobalWindowOuter::ConfirmDialogIfNeeded() {
2842 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"
, 2842); return false; } } while (false)
;
2843 nsCOMPtr<nsIPromptService> promptSvc =
2844 do_GetService("@mozilla.org/prompter;1");
2845
2846 if (!promptSvc) {
2847 return true;
2848 }
2849
2850 // Reset popup state while opening a modal dialog, and firing events
2851 // about the dialog, to prevent the current state from being active
2852 // the whole time a modal dialog is open.
2853 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
2854
2855 bool disableDialog = false;
2856 nsAutoString label, title;
2857 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2858 "ScriptDialogLabel", label);
2859 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2860 "ScriptDialogPreventTitle", title);
2861 promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
2862 if (disableDialog) {
2863 DisableDialogs();
2864 return false;
2865 }
2866
2867 return true;
2868}
2869
2870void nsGlobalWindowOuter::DisableDialogs() {
2871 BrowsingContextGroup* group = mBrowsingContext->Group();
2872 if (!group) {
2873 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"
, 2873); MOZ_PretendNoReturn(); } while (0)
;
2874 return;
2875 }
2876
2877 if (group) {
2878 group->SetAreDialogsEnabled(false);
2879 }
2880}
2881
2882void nsGlobalWindowOuter::EnableDialogs() {
2883 BrowsingContextGroup* group = mBrowsingContext->Group();
2884 if (!group) {
2885 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"
, 2885); MOZ_PretendNoReturn(); } while (0)
;
2886 return;
2887 }
2888
2889 if (group) {
2890 group->SetAreDialogsEnabled(true);
2891 }
2892}
2893
2894nsresult nsGlobalWindowOuter::PostHandleEvent(EventChainPostVisitor& aVisitor) {
2895 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"
, 2895); AnnotateMozCrashReason("MOZ_CRASH(" "The outer window should not be part of an event path"
")"); do { *((volatile int*)__null) = 2895; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2896}
2897
2898void nsGlobalWindowOuter::PoisonOuterWindowProxy(JSObject* aObject) {
2899 if (aObject == GetWrapperMaybeDead()) {
2900 PoisonWrapper();
2901 }
2902}
2903
2904nsresult nsGlobalWindowOuter::SetArguments(nsIArray* aArguments) {
2905 nsresult rv;
2906
2907 // We've now mostly separated them, but the difference is still opaque to
2908 // nsWindowWatcher (the caller of SetArguments in this little back-and-forth
2909 // embedding waltz we do here).
2910 //
2911 // So we need to demultiplex the two cases here.
2912 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(this);
2913
2914 mArguments = aArguments;
2915 rv = currentInner->DefineArgumentsProperty(aArguments);
2916 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"
, 2916); return rv; } } while (false)
;
2917
2918 return NS_OK;
2919}
2920
2921//*****************************************************************************
2922// nsGlobalWindowOuter::nsIScriptObjectPrincipal
2923//*****************************************************************************
2924
2925nsIPrincipal* nsGlobalWindowOuter::GetPrincipal() {
2926 if (mDoc) {
2927 // If we have a document, get the principal from the document
2928 return mDoc->NodePrincipal();
2929 }
2930
2931 if (mDocumentPrincipal) {
2932 return mDocumentPrincipal;
2933 }
2934
2935 // If we don't have a principal and we don't have a document we
2936 // ask the parent window for the principal. This can happen when
2937 // loading a frameset that has a <frame src="javascript:xxx">, in
2938 // that case the global window is used in JS before we've loaded
2939 // a document into the window.
2940
2941 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2942 do_QueryInterface(GetInProcessParentInternal());
2943
2944 if (objPrincipal) {
2945 return objPrincipal->GetPrincipal();
2946 }
2947
2948 return nullptr;
2949}
2950
2951nsIPrincipal* nsGlobalWindowOuter::GetEffectiveCookiePrincipal() {
2952 if (mDoc) {
2953 // If we have a document, get the principal from the document
2954 return mDoc->EffectiveCookiePrincipal();
2955 }
2956
2957 if (mDocumentCookiePrincipal) {
2958 return mDocumentCookiePrincipal;
2959 }
2960
2961 // If we don't have a cookie principal and we don't have a document we ask
2962 // the parent window for the cookie principal.
2963
2964 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2965 do_QueryInterface(GetInProcessParentInternal());
2966
2967 if (objPrincipal) {
2968 return objPrincipal->GetEffectiveCookiePrincipal();
2969 }
2970
2971 return nullptr;
2972}
2973
2974nsIPrincipal* nsGlobalWindowOuter::GetEffectiveStoragePrincipal() {
2975 if (mDoc) {
2976 // If we have a document, get the principal from the document
2977 return mDoc->EffectiveStoragePrincipal();
2978 }
2979
2980 if (mDocumentStoragePrincipal) {
2981 return mDocumentStoragePrincipal;
2982 }
2983
2984 // If we don't have a storage principal and we don't have a document we ask
2985 // the parent window for the storage principal.
2986
2987 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2988 do_QueryInterface(GetInProcessParentInternal());
2989
2990 if (objPrincipal) {
2991 return objPrincipal->GetEffectiveStoragePrincipal();
2992 }
2993
2994 return nullptr;
2995}
2996
2997nsIPrincipal* nsGlobalWindowOuter::PartitionedPrincipal() {
2998 if (mDoc) {
2999 // If we have a document, get the principal from the document
3000 return mDoc->PartitionedPrincipal();
3001 }
3002
3003 if (mDocumentPartitionedPrincipal) {
3004 return mDocumentPartitionedPrincipal;
3005 }
3006
3007 // If we don't have a partitioned principal and we don't have a document we
3008 // ask the parent window for the partitioned principal.
3009
3010 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
3011 do_QueryInterface(GetInProcessParentInternal());
3012
3013 if (objPrincipal) {
3014 return objPrincipal->PartitionedPrincipal();
3015 }
3016
3017 return nullptr;
3018}
3019
3020//*****************************************************************************
3021// nsGlobalWindowOuter::nsIDOMWindow
3022//*****************************************************************************
3023
3024Element* nsPIDOMWindowOuter::GetFrameElementInternal() const {
3025 return mFrameElement;
3026}
3027
3028void nsPIDOMWindowOuter::SetFrameElementInternal(Element* aFrameElement) {
3029 mFrameElement = aFrameElement;
3030}
3031
3032Navigator* nsGlobalWindowOuter::GetNavigator() {
3033 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"
, 3033); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Navigator (); } while (0)
;
3034}
3035
3036nsScreen* nsGlobalWindowOuter::GetScreen() {
3037 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"
, 3037); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Screen (); } while (0)
;
3038}
3039
3040void nsPIDOMWindowOuter::ActivateMediaComponents() {
3041 if (!ShouldDelayMediaFromStart()) {
3042 return;
3043 }
3044 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)
3045 ("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)
3046 "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)
3047 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)
;
3048 if (BrowsingContext* bc = GetBrowsingContext()) {
3049 Unused << bc->Top()->SetShouldDelayMediaFromStart(false);
3050 }
3051 NotifyResumingDelayedMedia();
3052}
3053
3054bool nsPIDOMWindowOuter::ShouldDelayMediaFromStart() const {
3055 BrowsingContext* bc = GetBrowsingContext();
3056 return bc && bc->Top()->GetShouldDelayMediaFromStart();
3057}
3058
3059void nsPIDOMWindowOuter::NotifyResumingDelayedMedia() {
3060 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
3061 if (service) {
3062 service->NotifyResumingDelayedMedia(this);
3063 }
3064}
3065
3066bool nsPIDOMWindowOuter::GetAudioMuted() const {
3067 BrowsingContext* bc = GetBrowsingContext();
3068 return bc && bc->Top()->GetMuted();
3069}
3070
3071void nsPIDOMWindowOuter::RefreshMediaElementsVolume() {
3072 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
3073 if (service) {
3074 // TODO: RefreshAgentsVolume can probably be simplified further.
3075 service->RefreshAgentsVolume(this, 1.0f, GetAudioMuted());
3076 }
3077}
3078
3079mozilla::dom::BrowsingContextGroup*
3080nsPIDOMWindowOuter::GetBrowsingContextGroup() const {
3081 return mBrowsingContext ? mBrowsingContext->Group() : nullptr;
3082}
3083
3084Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetParentOuter() {
3085 BrowsingContext* bc = GetBrowsingContext();
3086 return bc ? bc->GetParent(IgnoreErrors()) : nullptr;
3087}
3088
3089/**
3090 * GetInProcessScriptableParent used to be called when a script read
3091 * window.parent. Under Fission, that is now handled by
3092 * BrowsingContext::GetParent, and the result is a WindowProxyHolder rather than
3093 * an actual global window. This method still exists for legacy callers which
3094 * relied on the old logic, and require in-process windows. However, it only
3095 * works correctly when no out-of-process frames exist between this window and
3096 * the top-level window, so it should not be used in new code.
3097 *
3098 * In contrast to GetRealParent, GetInProcessScriptableParent respects <iframe
3099 * mozbrowser> boundaries, so if |this| is contained by an <iframe
3100 * mozbrowser>, we will return |this| as its own parent.
3101 */
3102nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableParent() {
3103 if (!mDocShell) {
3104 return nullptr;
3105 }
3106
3107 if (BrowsingContext* parentBC = GetBrowsingContext()->GetParent()) {
3108 if (nsCOMPtr<nsPIDOMWindowOuter> parent = parentBC->GetDOMWindow()) {
3109 return parent;
3110 }
3111 }
3112 return this;
3113}
3114
3115/**
3116 * Behavies identically to GetInProcessScriptableParent extept that it returns
3117 * null if GetInProcessScriptableParent would return this window.
3118 */
3119nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableParentOrNull() {
3120 nsPIDOMWindowOuter* parent = GetInProcessScriptableParent();
3121 return (nsGlobalWindowOuter::Cast(parent) == this) ? nullptr : parent;
3122}
3123
3124already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetInProcessParent() {
3125 if (!mDocShell) {
3126 return nullptr;
3127 }
3128
3129 if (auto* parentBC = GetBrowsingContext()->GetParent()) {
3130 if (auto* parent = parentBC->GetDOMWindow()) {
3131 return do_AddRef(parent);
3132 }
3133 }
3134 return do_AddRef(this);
3135}
3136
3137static nsresult GetTopImpl(nsGlobalWindowOuter* aWin, nsIURI* aURIBeingLoaded,
3138 nsPIDOMWindowOuter** aTop, bool aScriptable,
3139 bool aExcludingExtensionAccessibleContentFrames) {
3140 *aTop = nullptr;
3141
3142 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"
, 3142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aScriptable"
")"); do { *((volatile int*)__null) = 3142; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3143
3144 // Walk up the parent chain.
3145
3146 nsCOMPtr<nsPIDOMWindowOuter> prevParent = aWin;
3147 nsCOMPtr<nsPIDOMWindowOuter> parent = aWin;
3148 do {
3149 if (!parent) {
3150 break;
3151 }
3152
3153 prevParent = parent;
3154
3155 if (aScriptable) {
3156 parent = parent->GetInProcessScriptableParent();
3157 } else {
3158 parent = parent->GetInProcessParent();
3159 }
3160
3161 if (aExcludingExtensionAccessibleContentFrames) {
3162 if (auto* p = nsGlobalWindowOuter::Cast(parent)) {
3163 nsGlobalWindowInner* currentInner = GetCurrentInnerWindowInternal(p);
3164 nsIURI* uri = prevParent->GetDocumentURI();
3165 if (!uri) {
3166 // If our parent doesn't have a URI yet, we have a document that is in
3167 // the process of being loaded. In that case, our caller is
3168 // responsible for passing in the URI for the document that is being
3169 // loaded, so we fall back to using that URI here.
3170 uri = aURIBeingLoaded;
3171 }
3172
3173 if (currentInner && uri) {
3174 // If we find an inner window, we better find the uri for the current
3175 // window we're looking at. If we can't find it directly, it is the
3176 // responsibility of our caller to provide it to us.
3177 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"
, 3177); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "uri"
")"); do { *((volatile int*)__null) = 3177; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3178
3179 // If the new parent has permission to load the current page, we're
3180 // at a moz-extension:// frame which has a host permission that allows
3181 // it to load the document that we've loaded. In that case, stop at
3182 // this frame and consider it the top-level frame.
3183 //
3184 // Note that it's possible for the set of URIs accepted by
3185 // AddonAllowsLoad() to change at runtime, but we don't need to cache
3186 // the result of this check, since the important consumer of this code
3187 // (which is nsIHttpChannelInternal.topWindowURI) already caches the
3188 // result after computing it the first time.
3189 if (BasePrincipal::Cast(p->GetPrincipal())
3190 ->AddonAllowsLoad(uri, true)) {
3191 parent = prevParent;
3192 break;
3193 }
3194 }
3195 }
3196 }
3197
3198 } while (parent != prevParent);
3199
3200 if (parent) {
3201 parent.swap(*aTop);
3202 }
3203
3204 return NS_OK;
3205}
3206
3207/**
3208 * GetInProcessScriptableTop used to be called when a script read window.top.
3209 * Under Fission, that is now handled by BrowsingContext::Top, and the result is
3210 * a WindowProxyHolder rather than an actual global window. This method still
3211 * exists for legacy callers which relied on the old logic, and require
3212 * in-process windows. However, it only works correctly when no out-of-process
3213 * frames exist between this window and the top-level window, so it should not
3214 * be used in new code.
3215 *
3216 * In contrast to GetRealTop, GetInProcessScriptableTop respects <iframe
3217 * mozbrowser> boundaries. If we encounter a window owned by an <iframe
3218 * mozbrowser> while walking up the window hierarchy, we'll stop and return that
3219 * window.
3220 */
3221nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessScriptableTop() {
3222 nsCOMPtr<nsPIDOMWindowOuter> window;
3223 GetTopImpl(this, /* aURIBeingLoaded = */ nullptr, getter_AddRefs(window),
3224 /* aScriptable = */ true,
3225 /* aExcludingExtensionAccessibleContentFrames = */ false);
3226 return window.get();
3227}
3228
3229already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetInProcessTop() {
3230 nsCOMPtr<nsPIDOMWindowOuter> window;
3231 GetTopImpl(this, /* aURIBeingLoaded = */ nullptr, getter_AddRefs(window),
3232 /* aScriptable = */ false,
3233 /* aExcludingExtensionAccessibleContentFrames = */ false);
3234 return window.forget();
3235}
3236
3237already_AddRefed<nsPIDOMWindowOuter>
3238nsGlobalWindowOuter::GetTopExcludingExtensionAccessibleContentFrames(
3239 nsIURI* aURIBeingLoaded) {
3240 // There is a parent-process equivalent of this in DocumentLoadListener.cpp
3241 // GetTopWindowExcludingExtensionAccessibleContentFrames
3242 nsCOMPtr<nsPIDOMWindowOuter> window;
3243 GetTopImpl(this, aURIBeingLoaded, getter_AddRefs(window),
3244 /* aScriptable = */ false,
3245 /* aExcludingExtensionAccessibleContentFrames = */ true);
3246 return window.forget();
3247}
3248
3249void nsGlobalWindowOuter::GetContentOuter(JSContext* aCx,
3250 JS::MutableHandle<JSObject*> aRetval,
3251 CallerType aCallerType,
3252 ErrorResult& aError) {
3253 RefPtr<BrowsingContext> content = GetContentInternal(aCallerType, aError);
3254 if (aError.Failed()) {
3255 return;
3256 }
3257
3258 if (!content) {
3259 aRetval.set(nullptr);
3260 return;
3261 }
3262
3263 JS::Rooted<JS::Value> val(aCx);
3264 if (!ToJSValue(aCx, WindowProxyHolder{content}, &val)) {
3265 aError.Throw(NS_ERROR_UNEXPECTED);
3266 return;
3267 }
3268
3269 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"
, 3269); AnnotateMozCrashReason("MOZ_ASSERT" "(" "val.isObjectOrNull()"
")"); do { *((volatile int*)__null) = 3269; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3270 aRetval.set(val.toObjectOrNull());
3271}
3272
3273already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetContentInternal(
3274 CallerType aCallerType, ErrorResult& aError) {
3275 // First check for a named frame named "content"
3276 if (RefPtr<BrowsingContext> named = GetChildWindow(u"content"_ns)) {
3277 return named.forget();
3278 }
3279
3280 // If we're in the parent process, and being called by system code, `content`
3281 // should return the current primary content frame (if it's in-process).
3282 //
3283 // We return `nullptr` if the current primary content frame is out-of-process,
3284 // rather than a remote window proxy, as that is the existing behaviour as of
3285 // bug 1597437.
3286 if (XRE_IsParentProcess() && aCallerType == CallerType::System) {
3287 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
3288 if (!treeOwner) {
3289 aError.Throw(NS_ERROR_FAILURE);
3290 return nullptr;
3291 }
3292
3293 nsCOMPtr<nsIDocShellTreeItem> primaryContent;
3294 treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
3295 if (!primaryContent) {
3296 return nullptr;
3297 }
3298
3299 return do_AddRef(primaryContent->GetBrowsingContext());
3300 }
3301
3302 // For legacy untrusted callers we always return the same value as
3303 // `window.top`
3304 if (mDoc && aCallerType != CallerType::System) {
3305 mDoc->WarnOnceAbout(DeprecatedOperations::eWindowContentUntrusted);
3306 }
3307
3308 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"
, 3308); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBrowsingContext->IsContent()"
")"); do { *((volatile int*)__null) = 3308; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3309 return do_AddRef(mBrowsingContext->Top());
3310}
3311
3312nsresult nsGlobalWindowOuter::GetPrompter(nsIPrompt** aPrompt) {
3313 if (!mDocShell) return NS_ERROR_FAILURE;
3314
3315 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
3316 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"
, 3316); return NS_ERROR_NO_INTERFACE; } } while (false)
;
3317
3318 prompter.forget(aPrompt);
3319 return NS_OK;
3320}
3321
3322bool nsGlobalWindowOuter::GetClosedOuter() {
3323 // If someone called close(), or if we don't have a docshell, we're closed.
3324 return mIsClosed || !mDocShell;
3325}
3326
3327bool nsGlobalWindowOuter::Closed() { return GetClosedOuter(); }
3328
3329Nullable<WindowProxyHolder> nsGlobalWindowOuter::IndexedGetterOuter(
3330 uint32_t aIndex) {
3331 BrowsingContext* bc = GetBrowsingContext();
3332 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"
, 3332); return nullptr; } } while (false)
;
3333
3334 Span<RefPtr<BrowsingContext>> children = bc->NonSyntheticChildren();
3335
3336 if (aIndex < children.Length()) {
3337 return WindowProxyHolder(children[aIndex]);
3338 }
3339 return nullptr;
3340}
3341
3342nsIControllers* nsGlobalWindowOuter::GetControllersOuter(ErrorResult& aError) {
3343 if (!mControllers) {
3344 mControllers = new nsXULControllers();
3345 if (!mControllers) {
3346 aError.Throw(NS_ERROR_FAILURE);
3347 return nullptr;
3348 }
3349
3350 // Add in the default controller
3351 RefPtr<nsBaseCommandController> commandController =
3352 nsBaseCommandController::CreateWindowController();
3353 if (!commandController) {
3354 aError.Throw(NS_ERROR_FAILURE);
3355 return nullptr;
3356 }
3357
3358 mControllers->InsertControllerAt(0, commandController);
3359 commandController->SetCommandContext(static_cast<nsIDOMWindow*>(this));
3360 }
3361
3362 return mControllers;
3363}
3364
3365nsresult nsGlobalWindowOuter::GetControllers(nsIControllers** aResult) {
3366 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"
, 3366); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetControllers (aResult); } while (0)
;
3367}
3368
3369already_AddRefed<BrowsingContext>
3370nsGlobalWindowOuter::GetOpenerBrowsingContext() {
3371 RefPtr<BrowsingContext> opener = GetBrowsingContext()->GetOpener();
3372 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"
, 3373); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!opener || opener->Group() == GetBrowsingContext()->Group()"
")"); do { *((volatile int*)__null) = 3373; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3373 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"
, 3373); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!opener || opener->Group() == GetBrowsingContext()->Group()"
")"); do { *((volatile int*)__null) = 3373; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3374 if (!opener || opener->Group() != GetBrowsingContext()->Group()) {
3375 return nullptr;
3376 }
3377
3378 // Catch the case where we're chrome but the opener is not...
3379 if (nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
3380 GetPrincipal() == nsContentUtils::GetSystemPrincipal()) {
3381 auto* openerWin = nsGlobalWindowOuter::Cast(opener->GetDOMWindow());
3382 if (!openerWin ||
3383 openerWin->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
3384 return nullptr;
3385 }
3386 }
3387
3388 return opener.forget();
3389}
3390
3391nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSameProcessOpener() {
3392 if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
3393 return opener->GetDOMWindow();
3394 }
3395 return nullptr;
3396}
3397
3398Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpenerWindowOuter() {
3399 if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
3400 return WindowProxyHolder(std::move(opener));
3401 }
3402 return nullptr;
3403}
3404
3405Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpener() {
3406 return GetOpenerWindowOuter();
3407}
3408
3409void nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus) {
3410 aStatus = mStatus;
3411}
3412
3413void nsGlobalWindowOuter::SetStatusOuter(const nsAString& aStatus) {
3414 mStatus = aStatus;
3415
3416 // We don't support displaying window.status in the UI, so there's nothing
3417 // left to do here.
3418}
3419
3420void nsGlobalWindowOuter::GetNameOuter(nsAString& aName) {
3421 if (mDocShell) {
3422 mDocShell->GetName(aName);
3423 }
3424}
3425
3426void nsGlobalWindowOuter::SetNameOuter(const nsAString& aName,
3427 mozilla::ErrorResult& aError) {
3428 if (mDocShell) {
3429 aError = mDocShell->SetName(aName);
3430 }
3431}
3432
3433// NOTE: The idea of this function is that it should return the same as
3434// nsPresContext::CSSToDeviceScale() if it was in aWindow synchronously. For
3435// that, we use the UnscaledDevicePixelsPerCSSPixel() (which contains the device
3436// scale and the OS zoom scale) and then account for the browsing context full
3437// zoom. See the declaration of this function for context about why this is
3438// needed.
3439CSSToLayoutDeviceScale nsGlobalWindowOuter::CSSToDevScaleForBaseWindow(
3440 nsIBaseWindow* aWindow) {
3441 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"
, 3441); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ")"
); do { *((volatile int*)__null) = 3441; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3442 auto scale = aWindow->UnscaledDevicePixelsPerCSSPixel();
3443 if (mBrowsingContext) {
3444 scale.scale *= mBrowsingContext->FullZoom();
3445 }
3446 return scale;
3447}
3448
3449nsresult nsGlobalWindowOuter::GetInnerSize(CSSSize& aSize) {
3450 EnsureSizeAndPositionUpToDate();
3451
3452 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"
, 3452); return NS_ERROR_UNEXPECTED; } } while (false)
;
3453
3454 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3455 PresShell* presShell = mDocShell->GetPresShell();
3456
3457 if (!presContext || !presShell) {
3458 aSize = {};
3459 return NS_OK;
3460 }
3461
3462 // Whether or not the css viewport has been overridden, we can get the
3463 // correct value by looking at the visible area of the presContext.
3464 if (RefPtr<nsViewManager> viewManager = presShell->GetViewManager()) {
3465 viewManager->FlushDelayedResize();
3466 }
3467
3468 // FIXME: Bug 1598487 - Return the layout viewport instead of the ICB.
3469 nsSize viewportSize = presContext->GetVisibleArea().Size();
3470 if (presContext->GetDynamicToolbarState() == DynamicToolbarState::Collapsed) {
3471 viewportSize =
3472 nsLayoutUtils::ExpandHeightForViewportUnits(presContext, viewportSize);
3473 }
3474
3475 aSize = CSSPixel::FromAppUnits(viewportSize);
3476
3477 switch (StaticPrefs::dom_innerSize_rounding()) {
3478 case 1:
3479 aSize.width = std::roundf(aSize.width);
3480 aSize.height = std::roundf(aSize.height);
3481 break;
3482 case 2:
3483 aSize.width = std::truncf(aSize.width);
3484 aSize.height = std::truncf(aSize.height);
3485 break;
3486 default:
3487 break;
3488 }
3489
3490 return NS_OK;
3491}
3492
3493double nsGlobalWindowOuter::GetInnerWidthOuter(ErrorResult& aError) {
3494 CSSSize size;
3495 aError = GetInnerSize(size);
3496 return size.width;
3497}
3498
3499nsresult nsGlobalWindowOuter::GetInnerWidth(double* aInnerWidth) {
3500 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"
, 3500); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetInnerWidth (aInnerWidth); } while (0)
;
3501}
3502
3503double nsGlobalWindowOuter::GetInnerHeightOuter(ErrorResult& aError) {
3504 CSSSize size;
3505 aError = GetInnerSize(size);
3506 return size.height;
3507}
3508
3509nsresult nsGlobalWindowOuter::GetInnerHeight(double* aInnerHeight) {
3510 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"
, 3510); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->GetInnerHeight (aInnerHeight); } while (0)
;
3511}
3512
3513CSSIntSize nsGlobalWindowOuter::GetOuterSize(CallerType aCallerType,
3514 ErrorResult& aError) {
3515 if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
3516 RFPTarget::WindowOuterSize)) {
3517 CSSSize size;
3518 aError = GetInnerSize(size);
3519 return RoundedToInt(size);
3520 }
3521
3522 // Windows showing documents in RDM panes and any subframes within them
3523 // return the simulated device size.
3524 if (mDoc) {
3525 Maybe<CSSIntSize> deviceSize = GetRDMDeviceSize(*mDoc);
3526 if (deviceSize.isSome()) {
3527 return *deviceSize;
3528 }
3529 }
3530
3531 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3532 if (!treeOwnerAsWin) {
3533 aError.Throw(NS_ERROR_FAILURE);
3534 return {};
3535 }
3536
3537 return RoundedToInt(treeOwnerAsWin->GetSize() /
3538 CSSToDevScaleForBaseWindow(treeOwnerAsWin));
3539}
3540
3541int32_t nsGlobalWindowOuter::GetOuterWidthOuter(CallerType aCallerType,
3542 ErrorResult& aError) {
3543 return GetOuterSize(aCallerType, aError).width;
3544}
3545
3546int32_t nsGlobalWindowOuter::GetOuterHeightOuter(CallerType aCallerType,
3547 ErrorResult& aError) {
3548 return GetOuterSize(aCallerType, aError).height;
3549}
3550
3551CSSPoint nsGlobalWindowOuter::ScreenEdgeSlop() {
3552 if (NS_WARN_IF(!mDocShell)NS_warn_if_impl(!mDocShell, "!mDocShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3552)
) {
3553 return {};
3554 }
3555 RefPtr<nsPresContext> pc = mDocShell->GetPresContext();
3556 if (NS_WARN_IF(!pc)NS_warn_if_impl(!pc, "!pc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3556)
) {
3557 return {};
3558 }
3559 nsCOMPtr<nsIWidget> widget = GetMainWidget();
3560 if (NS_WARN_IF(!widget)NS_warn_if_impl(!widget, "!widget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 3560)
) {
3561 return {};
3562 }
3563 LayoutDeviceIntPoint pt = widget->GetScreenEdgeSlop();
3564 auto auPoint =
3565 LayoutDeviceIntPoint::ToAppUnits(pt, pc->AppUnitsPerDevPixel());
3566 return CSSPoint::FromAppUnits(auPoint);
3567}
3568
3569CSSIntPoint nsGlobalWindowOuter::GetScreenXY(CallerType aCallerType,
3570 ErrorResult& aError) {
3571 // When resisting fingerprinting, always return (0,0)
3572 if (nsIGlobalObject::ShouldResistFingerprinting(aCallerType,
3573 RFPTarget::WindowScreenXY)) {
3574 return CSSIntPoint(0, 0);
3575 }
3576
3577 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3578 if (!treeOwnerAsWin) {
3579 aError.Throw(NS_ERROR_FAILURE);
3580 return CSSIntPoint(0, 0);
3581 }
3582
3583 LayoutDeviceIntPoint windowPos;
3584 aError = treeOwnerAsWin->GetPosition(&windowPos.x.value, &windowPos.y.value);
3585
3586 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3587 if (!presContext) {
3588 // XXX Fishy LayoutDevice to CSS conversion?
3589 return CSSIntPoint(windowPos.x, windowPos.y);
3590 }
3591
3592 nsDeviceContext* context = presContext->DeviceContext();
3593 auto windowPosAppUnits = LayoutDeviceIntPoint::ToAppUnits(
3594 windowPos, context->AppUnitsPerDevPixel());
3595 return CSSIntPoint::FromAppUnitsRounded(windowPosAppUnits);
3596}
3597
3598int32_t nsGlobalWindowOuter::GetScreenXOuter(CallerType aCallerType,
3599 ErrorResult& aError) {
3600 return GetScreenXY(aCallerType, aError).x;
3601}
3602
3603nsRect nsGlobalWindowOuter::GetInnerScreenRect() {
3604 if (!mDocShell) {
3605 return nsRect();
3606 }
3607
3608 EnsureSizeAndPositionUpToDate();
3609
3610 if (!mDocShell) {
3611 return nsRect();
3612 }
3613
3614 PresShell* presShell = mDocShell->GetPresShell();
3615 if (!presShell) {
3616 return nsRect();
3617 }
3618 nsIFrame* rootFrame = presShell->GetRootFrame();
3619 if (!rootFrame) {
3620 return nsRect();
3621 }
3622
3623 return rootFrame->GetScreenRectInAppUnits();
3624}
3625
3626Maybe<CSSIntSize> nsGlobalWindowOuter::GetRDMDeviceSize(
3627 const Document& aDocument) {
3628 // RDM device size should reflect the simulated device resolution, and
3629 // be independent of any full zoom or resolution zoom applied to the
3630 // content. To get this value, we get the "unscaled" browser child size,
3631 // and divide by the full zoom. "Unscaled" in this case means unscaled
3632 // from device to screen but it has been affected (multiplied) by the
3633 // full zoom and we need to compensate for that.
3634 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"
, 3634); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3634; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3635
3636 // Bug 1576256: This does not work for cross-process subframes.
3637 const Document* topInProcessContentDoc =
3638 aDocument.GetTopLevelContentDocumentIfSameProcess();
3639 BrowsingContext* bc = topInProcessContentDoc
3640 ? topInProcessContentDoc->GetBrowsingContext()
3641 : nullptr;
3642 if (bc && bc->InRDMPane()) {
3643 nsIDocShell* docShell = topInProcessContentDoc->GetDocShell();
3644 if (docShell) {
3645 nsPresContext* presContext = docShell->GetPresContext();
3646 if (presContext) {
3647 nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild();
3648 if (child) {
3649 // We intentionally use GetFullZoom here instead of
3650 // GetDeviceFullZoom, because the unscaledInnerSize is based
3651 // on the full zoom and not the device full zoom (which is
3652 // rounded to result in integer device pixels).
3653 float zoom = presContext->GetFullZoom();
3654 BrowserChild* bc = static_cast<BrowserChild*>(child.get());
3655 CSSSize unscaledSize = bc->GetUnscaledInnerSize();
3656 return Some(CSSIntSize(gfx::RoundedToInt(unscaledSize / zoom)));
3657 }
3658 }
3659 }
3660 }
3661 return Nothing();
3662}
3663
3664float nsGlobalWindowOuter::GetMozInnerScreenXOuter(CallerType aCallerType) {
3665 // When resisting fingerprinting, always return 0.
3666 if (nsIGlobalObject::ShouldResistFingerprinting(
3667 aCallerType, RFPTarget::WindowInnerScreenXY)) {
3668 return 0.0;
3669 }
3670
3671 nsRect r = GetInnerScreenRect();
3672 return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3673}
3674
3675float nsGlobalWindowOuter::GetMozInnerScreenYOuter(CallerType aCallerType) {
3676 // Return 0 to prevent fingerprinting.
3677 if (nsIGlobalObject::ShouldResistFingerprinting(
3678 aCallerType, RFPTarget::WindowInnerScreenXY)) {
3679 return 0.0;
3680 }
3681
3682 nsRect r = GetInnerScreenRect();
3683 return nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3684}
3685
3686int32_t nsGlobalWindowOuter::GetScreenYOuter(CallerType aCallerType,
3687 ErrorResult& aError) {
3688 return GetScreenXY(aCallerType, aError).y;
3689}
3690
3691// NOTE: Arguments to this function should have values scaled to
3692// CSS pixels, not device pixels.
3693void nsGlobalWindowOuter::CheckSecurityWidthAndHeight(int32_t* aWidth,
3694 int32_t* aHeight,
3695 CallerType aCallerType) {
3696 if (aCallerType != CallerType::System) {
3697 // if attempting to resize the window, hide any open popups
3698 nsContentUtils::HidePopupsInDocument(mDoc);
3699 }
3700
3701 // This one is easy. Just ensure the variable is greater than 100;
3702 if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
3703 // Check security state for use in determing window dimensions
3704
3705 if (aCallerType != CallerType::System) {
3706 // sec check failed
3707 if (aWidth && *aWidth < 100) {
3708 *aWidth = 100;
3709 }
3710 if (aHeight && *aHeight < 100) {
3711 *aHeight = 100;
3712 }
3713 }
3714 }
3715}
3716
3717// NOTE: Arguments to this function should have values in app units
3718void nsGlobalWindowOuter::SetCSSViewportWidthAndHeight(nscoord aInnerWidth,
3719 nscoord aInnerHeight) {
3720 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
3721
3722 nsRect shellArea = presContext->GetVisibleArea();
3723 shellArea.SetHeight(aInnerHeight);
3724 shellArea.SetWidth(aInnerWidth);
3725
3726 // FIXME(emilio): This doesn't seem to be ok, this doesn't reflow or
3727 // anything... Should go through PresShell::ResizeReflow.
3728 //
3729 // But I don't think this can be reached by content, as we don't allow to set
3730 // inner{Width,Height}.
3731 presContext->SetVisibleArea(shellArea);
3732}
3733
3734// NOTE: Arguments to this function should have values scaled to
3735// CSS pixels, not device pixels.
3736void nsGlobalWindowOuter::CheckSecurityLeftAndTop(int32_t* aLeft, int32_t* aTop,
3737 CallerType aCallerType) {
3738 // This one is harder. We have to get the screen size and window dimensions.
3739
3740 // Check security state for use in determing window dimensions
3741
3742 if (aCallerType != CallerType::System) {
3743 // if attempting to move the window, hide any open popups
3744 nsContentUtils::HidePopupsInDocument(mDoc);
3745
3746 if (nsGlobalWindowOuter* rootWindow =
3747 nsGlobalWindowOuter::Cast(GetPrivateRoot())) {
3748 rootWindow->FlushPendingNotifications(FlushType::Layout);
3749 }
3750
3751 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3752
3753 RefPtr<nsScreen> screen = GetScreen();
3754
3755 if (treeOwnerAsWin && screen) {
3756 CSSToLayoutDeviceScale scale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
3757 CSSIntRect winRect =
3758 CSSIntRect::Round(treeOwnerAsWin->GetPositionAndSize() / scale);
3759
3760 // Get the screen dimensions
3761 // XXX This should use nsIScreenManager once it's fully fleshed out.
3762 int32_t screenLeft = screen->AvailLeft();
3763 int32_t screenWidth = screen->AvailWidth();
3764 int32_t screenHeight = screen->AvailHeight();
3765#if defined(XP_MACOSX)
3766 /* The mac's coordinate system is different from the assumed Windows'
3767 system. It offsets by the height of the menubar so that a window
3768 placed at (0,0) will be entirely visible. Unfortunately that
3769 correction is made elsewhere (in Widget) and the meaning of
3770 the Avail... coordinates is overloaded. Here we allow a window
3771 to be placed at (0,0) because it does make sense to do so.
3772 */
3773 int32_t screenTop = screen->Top();
3774#else
3775 int32_t screenTop = screen->AvailTop();
3776#endif
3777
3778 if (aLeft) {
3779 if (screenLeft + screenWidth < *aLeft + winRect.width)
3780 *aLeft = screenLeft + screenWidth - winRect.width;
3781 if (screenLeft > *aLeft) *aLeft = screenLeft;
3782 }
3783 if (aTop) {
3784 if (screenTop + screenHeight < *aTop + winRect.height)
3785 *aTop = screenTop + screenHeight - winRect.height;
3786 if (screenTop > *aTop) *aTop = screenTop;
3787 }
3788 } else {
3789 if (aLeft) *aLeft = 0;
3790 if (aTop) *aTop = 0;
3791 }
3792 }
3793}
3794
3795int32_t nsGlobalWindowOuter::GetScrollBoundaryOuter(Side aSide) {
3796 FlushPendingNotifications(FlushType::Layout);
3797 if (ScrollContainerFrame* sf = GetScrollContainerFrame()) {
3798 return nsPresContext::AppUnitsToIntCSSPixels(
3799 sf->GetScrollRange().Edge(aSide));
3800 }
3801 return 0;
3802}
3803
3804CSSPoint nsGlobalWindowOuter::GetScrollXY(bool aDoFlush) {
3805 if (aDoFlush) {
3806 FlushPendingNotifications(FlushType::Layout);
3807 } else {
3808 EnsureSizeAndPositionUpToDate();
3809 }
3810
3811 ScrollContainerFrame* sf = GetScrollContainerFrame();
3812 if (!sf) {
3813 return CSSIntPoint(0, 0);
3814 }
3815
3816 nsPoint scrollPos = sf->GetScrollPosition();
3817 if (scrollPos != nsPoint(0, 0) && !aDoFlush) {
3818 // Oh, well. This is the expensive case -- the window is scrolled and we
3819 // didn't actually flush yet. Repeat, but with a flush, since the content
3820 // may get shorter and hence our scroll position may decrease.
3821 return GetScrollXY(true);
3822 }
3823
3824 return CSSPoint::FromAppUnits(scrollPos);
3825}
3826
3827double nsGlobalWindowOuter::GetScrollXOuter() { return GetScrollXY(false).x; }
3828
3829double nsGlobalWindowOuter::GetScrollYOuter() { return GetScrollXY(false).y; }
3830
3831uint32_t nsGlobalWindowOuter::Length() {
3832 BrowsingContext* bc = GetBrowsingContext();
3833 return bc ? bc->NonSyntheticChildren().Length() : 0;
3834}
3835
3836Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetTopOuter() {
3837 BrowsingContext* bc = GetBrowsingContext();
3838 return bc ? bc->GetTop(IgnoreErrors()) : nullptr;
3839}
3840
3841already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetChildWindow(
3842 const nsAString& aName) {
3843 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"
, 3843); return nullptr; } } while (false)
;
3844 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"
, 3844); return nullptr; } } while (false)
;
3845 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"
, 3845); return nullptr; } } while (false)
;
3846
3847 return do_AddRef(mBrowsingContext->FindChildWithName(
3848 aName, *mInnerWindow->GetWindowGlobalChild()));
3849}
3850
3851bool nsGlobalWindowOuter::DispatchCustomEvent(
3852 const nsAString& aEventName, ChromeOnlyDispatch aChromeOnlyDispatch) {
3853 bool defaultActionEnabled = true;
3854
3855 if (aChromeOnlyDispatch == ChromeOnlyDispatch::eYes) {
3856 nsContentUtils::DispatchEventOnlyToChrome(mDoc, this, aEventName,
3857 CanBubble::eYes, Cancelable::eYes,
3858 &defaultActionEnabled);
3859 } else {
3860 nsContentUtils::DispatchTrustedEvent(mDoc, this, aEventName,
3861 CanBubble::eYes, Cancelable::eYes,
3862 &defaultActionEnabled);
3863 }
3864
3865 return defaultActionEnabled;
3866}
3867
3868bool nsGlobalWindowOuter::DispatchResizeEvent(const CSSIntSize& aSize) {
3869 ErrorResult res;
3870 RefPtr<Event> domEvent =
3871 mDoc->CreateEvent(u"CustomEvent"_ns, CallerType::System, res);
3872 if (res.Failed()) {
3873 return false;
3874 }
3875
3876 // We don't init the AutoJSAPI with ourselves because we don't want it
3877 // reporting errors to our onerror handlers.
3878 AutoJSAPI jsapi;
3879 jsapi.Init();
3880 JSContext* cx = jsapi.cx();
3881 JSAutoRealm ar(cx, GetWrapperPreserveColor());
3882
3883 DOMWindowResizeEventDetail detail;
3884 detail.mWidth = aSize.width;
3885 detail.mHeight = aSize.height;
3886 JS::Rooted<JS::Value> detailValue(cx);
3887 if (!ToJSValue(cx, detail, &detailValue)) {
3888 return false;
3889 }
3890
3891 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
3892 customEvent->InitCustomEvent(cx, u"DOMWindowResize"_ns,
3893 /* aCanBubble = */ true,
3894 /* aCancelable = */ true, detailValue);
3895
3896 domEvent->SetTrusted(true);
3897 domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
3898
3899 nsCOMPtr<EventTarget> target = this;
3900 domEvent->SetTarget(target);
3901
3902 return target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
3903}
3904
3905bool nsGlobalWindowOuter::WindowExists(const nsAString& aName,
3906 bool aForceNoOpener,
3907 bool aLookForCallerOnJSStack) {
3908 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"
, 3908); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDocShell" ") ("
"Must have docshell" ")"); do { *((volatile int*)__null) = 3908
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3909
3910 if (aForceNoOpener) {
3911 return aName.LowerCaseEqualsLiteral("_self") ||
3912 aName.LowerCaseEqualsLiteral("_top") ||
3913 aName.LowerCaseEqualsLiteral("_parent");
3914 }
3915
3916 if (WindowGlobalChild* wgc = mInnerWindow->GetWindowGlobalChild()) {
3917 return wgc->FindBrowsingContextWithName(aName, aLookForCallerOnJSStack);
3918 }
3919 return false;
3920}
3921
3922already_AddRefed<nsIWidget> nsGlobalWindowOuter::GetMainWidget() {
3923 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
3924
3925 nsCOMPtr<nsIWidget> widget;
3926
3927 if (treeOwnerAsWin) {
3928 treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
3929 }
3930
3931 return widget.forget();
3932}
3933
3934nsIWidget* nsGlobalWindowOuter::GetNearestWidget() const {
3935 nsIDocShell* docShell = GetDocShell();
3936 if (!docShell) {
3937 return nullptr;
3938 }
3939 PresShell* presShell = docShell->GetPresShell();
3940 if (!presShell) {
3941 return nullptr;
3942 }
3943 nsIFrame* rootFrame = presShell->GetRootFrame();
3944 if (!rootFrame) {
3945 return nullptr;
3946 }
3947 return rootFrame->GetView()->GetNearestWidget(nullptr);
3948}
3949
3950void nsGlobalWindowOuter::SetFullscreenOuter(bool aFullscreen,
3951 mozilla::ErrorResult& aError) {
3952 aError =
3953 SetFullscreenInternal(FullscreenReason::ForFullscreenMode, aFullscreen);
3954}
3955
3956nsresult nsGlobalWindowOuter::SetFullScreen(bool aFullscreen) {
3957 return SetFullscreenInternal(FullscreenReason::ForFullscreenMode,
3958 aFullscreen);
3959}
3960
3961static void FinishDOMFullscreenChange(Document* aDoc, bool aInDOMFullscreen) {
3962 if (aInDOMFullscreen) {
3963 // Ask the document to handle any pending DOM fullscreen change.
3964 if (!Document::HandlePendingFullscreenRequests(aDoc)) {
3965 // If we don't end up having anything in fullscreen,
3966 // async request exiting fullscreen.
3967 Document::AsyncExitFullscreen(aDoc);
3968 }
3969 } else {
3970 // If the window is leaving fullscreen state, also ask the document
3971 // to exit from DOM Fullscreen.
3972 Document::ExitFullscreenInDocTree(aDoc);
3973 }
3974}
3975
3976struct FullscreenTransitionDuration {
3977 // The unit of the durations is millisecond
3978 uint16_t mFadeIn = 0;
3979 uint16_t mFadeOut = 0;
3980 bool IsSuppressed() const { return mFadeIn == 0 && mFadeOut == 0; }
3981};
3982
3983static void GetFullscreenTransitionDuration(
3984 bool aEnterFullscreen, FullscreenTransitionDuration* aDuration) {
3985 const char* pref = aEnterFullscreen
3986 ? "full-screen-api.transition-duration.enter"
3987 : "full-screen-api.transition-duration.leave";
3988 nsAutoCString prefValue;
3989 Preferences::GetCString(pref, prefValue);
3990 if (!prefValue.IsEmpty()) {
3991 sscanf(prefValue.get(), "%hu%hu", &aDuration->mFadeIn,
3992 &aDuration->mFadeOut);
3993 }
3994}
3995
3996class FullscreenTransitionTask : public Runnable {
3997 public:
3998 FullscreenTransitionTask(const FullscreenTransitionDuration& aDuration,
3999 nsGlobalWindowOuter* aWindow, bool aFullscreen,
4000 nsIWidget* aWidget, nsISupports* aTransitionData)
4001 : mozilla::Runnable("FullscreenTransitionTask"),
4002 mWindow(aWindow),
4003 mWidget(aWidget),
4004 mTransitionData(aTransitionData),
4005 mDuration(aDuration),
4006 mStage(eBeforeToggle),
4007 mFullscreen(aFullscreen) {}
4008
4009 NS_IMETHODvirtual nsresult Run() override;
4010
4011 private:
4012 ~FullscreenTransitionTask() override = default;
4013
4014 /**
4015 * The flow of fullscreen transition:
4016 *
4017 * parent process | child process
4018 * ----------------------------------------------------------------
4019 *
4020 * | request/exit fullscreen
4021 * <-----|
4022 * BeforeToggle stage |
4023 * |
4024 * ToggleFullscreen stage *1 |----->
4025 * | HandleFullscreenRequests
4026 * |
4027 * <-----| MozAfterPaint event
4028 * AfterToggle stage *2 |
4029 * |
4030 * End stage |
4031 *
4032 * Note we also start a timer at *1 so that if we don't get MozAfterPaint
4033 * from the child process in time, we continue going to *2.
4034 */
4035 enum Stage {
4036 // BeforeToggle stage happens before we enter or leave fullscreen
4037 // state. In this stage, the task triggers the pre-toggle fullscreen
4038 // transition on the widget.
4039 eBeforeToggle,
4040 // ToggleFullscreen stage actually executes the fullscreen toggle,
4041 // and wait for the next paint on the content to continue.
4042 eToggleFullscreen,
4043 // AfterToggle stage happens after we toggle the fullscreen state.
4044 // In this stage, the task triggers the post-toggle fullscreen
4045 // transition on the widget.
4046 eAfterToggle,
4047 // End stage is triggered after the final transition finishes.
4048 eEnd
4049 };
4050
4051 class Observer final : public nsIObserver, public nsINamed {
4052 public:
4053 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:
4054 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
4055 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
4056
4057 explicit Observer(FullscreenTransitionTask* aTask) : mTask(aTask) {}
4058
4059 private:
4060 ~Observer() = default;
4061
4062 RefPtr<FullscreenTransitionTask> mTask;
4063 };
4064
4065 static const char* const kPaintedTopic;
4066
4067 RefPtr<nsGlobalWindowOuter> mWindow;
4068 nsCOMPtr<nsIWidget> mWidget;
4069 nsCOMPtr<nsITimer> mTimer;
4070 nsCOMPtr<nsISupports> mTransitionData;
4071
4072 TimeStamp mFullscreenChangeStartTime;
4073 FullscreenTransitionDuration mDuration;
4074 Stage mStage;
4075 bool mFullscreen;
4076};
4077
4078const char* const FullscreenTransitionTask::kPaintedTopic =
4079 "fullscreen-painted";
4080
4081NS_IMETHODIMPnsresult
4082FullscreenTransitionTask::Run() {
4083 Stage stage = mStage;
4084 mStage = Stage(mStage + 1);
4085 if (MOZ_UNLIKELY(mWidget->Destroyed())(__builtin_expect(!!(mWidget->Destroyed()), 0))) {
4086 // If the widget has been destroyed before we get here, don't try to
4087 // do anything more. Just let it go and release ourselves.
4088 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"
, 4088)
;
4089 mWindow->mIsInFullScreenTransition = false;
4090 return NS_OK;
4091 }
4092 if (stage == eBeforeToggle) {
4093 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)
;
4094
4095 mWindow->mIsInFullScreenTransition = true;
4096
4097 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4098 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"
, 4098); return NS_ERROR_FAILURE; } } while (false)
;
4099 obs->NotifyObservers(nullptr, "fullscreen-transition-start", nullptr);
4100
4101 mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,
4102 mDuration.mFadeIn, mTransitionData,
4103 this);
4104 } else if (stage == eToggleFullscreen) {
4105 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)
;
4106 mFullscreenChangeStartTime = TimeStamp::Now();
4107 // Toggle the fullscreen state on the widget
4108 if (!mWindow->SetWidgetFullscreen(FullscreenReason::ForFullscreenAPI,
4109 mFullscreen, mWidget)) {
4110 // Fail to setup the widget, call FinishFullscreenChange to
4111 // complete fullscreen change directly.
4112 mWindow->FinishFullscreenChange(mFullscreen);
4113 }
4114 // Set observer for the next content paint.
4115 nsCOMPtr<nsIObserver> observer = new Observer(this);
4116 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4117 obs->AddObserver(observer, kPaintedTopic, false);
4118 // There are several edge cases where we may never get the paint
4119 // notification, including:
4120 // 1. the window/tab is closed before the next paint;
4121 // 2. the user has switched to another tab before we get here.
4122 // Completely fixing those cases seems to be tricky, and since they
4123 // should rarely happen, it probably isn't worth to fix. Hence we
4124 // simply add a timeout here to ensure we never hang forever.
4125 // In addition, if the page is complicated or the machine is less
4126 // powerful, layout could take a long time, in which case, staying
4127 // in black screen for that long could hurt user experience even
4128 // more than exposing an intermediate state.
4129 uint32_t timeout =
4130 Preferences::GetUint("full-screen-api.transition.timeout", 1000);
4131 NS_NewTimerWithObserver(getter_AddRefs(mTimer), observer, timeout,
4132 nsITimer::TYPE_ONE_SHOT);
4133 } else if (stage == eAfterToggle) {
4134 Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,
4135 mFullscreenChangeStartTime);
4136 mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
4137 mDuration.mFadeOut, mTransitionData,
4138 this);
4139 } else if (stage == eEnd) {
4140 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)
;
4141
4142 mWindow->mIsInFullScreenTransition = false;
4143
4144 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4145 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"
, 4145); return NS_ERROR_FAILURE; } } while (false)
;
4146 obs->NotifyObservers(nullptr, "fullscreen-transition-end", nullptr);
4147
4148 mWidget->CleanupFullscreenTransition();
4149 }
4150 return NS_OK;
4151}
4152
4153NS_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"
, 4153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
4153; __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"
, 4153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionTask::Observer\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 4153; __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"
, 4153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 4153
; __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"
, 4153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionTask::Observer\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 4153; __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"
, 4153); 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; }
4154
4155NS_IMETHODIMPnsresult
4156FullscreenTransitionTask::Observer::Observe(nsISupports* aSubject,
4157 const char* aTopic,
4158 const char16_t* aData) {
4159 bool shouldContinue = false;
4160 if (strcmp(aTopic, FullscreenTransitionTask::kPaintedTopic) == 0) {
4161 nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aSubject));
4162 nsCOMPtr<nsIWidget> widget =
4163 win ? nsGlobalWindowInner::Cast(win)->GetMainWidget() : nullptr;
4164 if (widget == mTask->mWidget) {
4165 // The paint notification arrives first. Cancel the timer.
4166 mTask->mTimer->Cancel();
4167 shouldContinue = true;
4168 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)
;
4169 }
4170 } else {
4171#ifdef DEBUG1
4172 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"
, 4173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"timer-callback\") == 0"
") (" "Should only get fullscreen-painted or timer-callback"
")"); do { *((volatile int*)__null) = 4173; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4173 "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"
, 4173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"timer-callback\") == 0"
") (" "Should only get fullscreen-painted or timer-callback"
")"); do { *((volatile int*)__null) = 4173; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4174 nsCOMPtr<nsITimer> timer(do_QueryInterface(aSubject));
4175 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"
, 4176); AnnotateMozCrashReason("MOZ_ASSERT" "(" "timer && timer == mTask->mTimer"
") (" "Should only trigger this with the timer the task created"
")"); do { *((volatile int*)__null) = 4176; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4176 "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"
, 4176); AnnotateMozCrashReason("MOZ_ASSERT" "(" "timer && timer == mTask->mTimer"
") (" "Should only trigger this with the timer the task created"
")"); do { *((volatile int*)__null) = 4176; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4177#endif
4178 shouldContinue = true;
4179 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)
;
4180 }
4181 if (shouldContinue) {
4182 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4183 obs->RemoveObserver(this, kPaintedTopic);
4184 mTask->mTimer = nullptr;
4185 mTask->Run();
4186 }
4187 return NS_OK;
4188}
4189
4190NS_IMETHODIMPnsresult
4191FullscreenTransitionTask::Observer::GetName(nsACString& aName) {
4192 aName.AssignLiteral("FullscreenTransitionTask");
4193 return NS_OK;
4194}
4195
4196static bool MakeWidgetFullscreen(nsGlobalWindowOuter* aWindow,
4197 FullscreenReason aReason, bool aFullscreen) {
4198 nsCOMPtr<nsIWidget> widget = aWindow->GetMainWidget();
4199 if (!widget) {
4200 return false;
4201 }
4202
4203 FullscreenTransitionDuration duration;
4204 bool performTransition = false;
4205 nsCOMPtr<nsISupports> transitionData;
4206 if (aReason == FullscreenReason::ForFullscreenAPI) {
4207 GetFullscreenTransitionDuration(aFullscreen, &duration);
4208 if (!duration.IsSuppressed()) {
4209 performTransition = widget->PrepareForFullscreenTransition(
4210 getter_AddRefs(transitionData));
4211 }
4212 }
4213
4214 if (!performTransition) {
4215 return aWindow->SetWidgetFullscreen(aReason, aFullscreen, widget);
4216 }
4217
4218 nsCOMPtr<nsIRunnable> task = new FullscreenTransitionTask(
4219 duration, aWindow, aFullscreen, widget, transitionData);
4220 task->Run();
4221 return true;
4222}
4223
4224nsresult nsGlobalWindowOuter::ProcessWidgetFullscreenRequest(
4225 FullscreenReason aReason, bool aFullscreen) {
4226 mInProcessFullscreenRequest.emplace(aReason, aFullscreen);
4227
4228 // Prevent chrome documents which are still loading from resizing
4229 // the window after we set fullscreen mode.
4230 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4231 nsCOMPtr<nsIAppWindow> appWin(do_GetInterface(treeOwnerAsWin));
4232 if (aFullscreen && appWin) {
4233 appWin->SetIntrinsicallySized(false);
4234 }
4235
4236 // Sometimes we don't want the top-level widget to actually go fullscreen:
4237 // - in the B2G desktop client, we don't want the emulated screen dimensions
4238 // to appear to increase when entering fullscreen mode; we just want the
4239 // content to fill the entire client area of the emulator window.
4240 // - in FxR Desktop, we don't want fullscreen to take over the monitor, but
4241 // instead we want fullscreen to fill the FxR window in the the headset.
4242 if (!StaticPrefs::full_screen_api_ignore_widgets() &&
4243 !mForceFullScreenInWidget) {
4244 if (MakeWidgetFullscreen(this, aReason, aFullscreen)) {
4245 // The rest of code for switching fullscreen is in nsGlobalWindowOuter::
4246 // FinishFullscreenChange() which will be called after sizemodechange
4247 // event is dispatched.
4248 return NS_OK;
4249 }
4250 }
4251
4252#if defined(NIGHTLY_BUILD1) && defined(XP_WIN)
4253 if (FxRWindowManager::GetInstance()->IsFxRWindow(mWindowID)) {
4254 mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/);
4255 shmem.SendFullscreenState(mWindowID, aFullscreen);
4256 }
4257#endif // NIGHTLY_BUILD && XP_WIN
4258 FinishFullscreenChange(aFullscreen);
4259 return NS_OK;
4260}
4261
4262nsresult nsGlobalWindowOuter::SetFullscreenInternal(FullscreenReason aReason,
4263 bool aFullscreen) {
4264 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"
, 4266); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4266; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4265 "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"
, 4266); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4266; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4266 "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"
, 4266); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::IsSafeToRunScript()"
") (" "Requires safe to run script as it " "may call FinishDOMFullscreenChange"
")"); do { *((volatile int*)__null) = 4266; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4267
4268 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"
, 4268); return NS_ERROR_FAILURE; } } while (false)
;
4269
4270 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"
, 4273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4273; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4271 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"
, 4273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4273; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4272 "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"
, 4273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4273; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4273 "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"
, 4273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aReason != FullscreenReason::ForForceExitFullscreen || !aFullscreen"
") (" "FullscreenReason::ForForceExitFullscreen can " "only be used with exiting fullscreen"
")"); do { *((volatile int*)__null) = 4273; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4274
4275 // Only chrome can change our fullscreen mode. Otherwise, the state
4276 // can only be changed for DOM fullscreen.
4277 if (aReason == FullscreenReason::ForFullscreenMode &&
4278 !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
4279 return NS_OK;
4280 }
4281
4282 // SetFullscreen needs to be called on the root window, so get that
4283 // via the DocShell tree, and if we are not already the root,
4284 // call SetFullscreen on that window instead.
4285 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4286 mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
4287 nsCOMPtr<nsPIDOMWindowOuter> window =
4288 rootItem ? rootItem->GetWindow() : nullptr;
4289 if (!window) return NS_ERROR_FAILURE;
4290 if (rootItem != mDocShell)
4291 return window->SetFullscreenInternal(aReason, aFullscreen);
4292
4293 // make sure we don't try to set full screen on a non-chrome window,
4294 // which might happen in embedding world
4295 if (mDocShell->ItemType() != nsIDocShellTreeItem::typeChrome)
4296 return NS_ERROR_FAILURE;
4297
4298 // FullscreenReason::ForForceExitFullscreen can only be used with exiting
4299 // fullscreen
4300 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"
, 4302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4302; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4301 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"
, 4302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4302; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4302 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"
, 4302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForForceExitFullscreen"
")"); do { *((volatile int*)__null) = 4302; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4303
4304 // If we are already in full screen mode, just return, we don't care about the
4305 // reason here, because,
4306 // - If we are in fullscreen mode due to browser fullscreen mode, requesting
4307 // DOM fullscreen does not change anything.
4308 // - If we are in fullscreen mode due to DOM fullscreen, requesting browser
4309 // fullscreen should not change anything, either. Note that we should not
4310 // update reason to ForFullscreenMode, otherwise the subsequent DOM
4311 // fullscreen exit will be ignored and user will be confused. And ideally
4312 // this should never happen as `window.fullscreen` returns `true` for DOM
4313 // fullscreen as well.
4314 if (mFullscreen.isSome() == aFullscreen) {
4315 // How come we get browser fullscreen request while we are already in DOM
4316 // fullscreen?
4317 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"
, 4318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForFullscreenAPI"
")"); do { *((volatile int*)__null) = 4318; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4318 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"
, 4318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFullscreen.value() != FullscreenReason::ForFullscreenAPI"
")"); do { *((volatile int*)__null) = 4318; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4319 return NS_OK;
4320 }
4321
4322 // Note that although entering DOM fullscreen could also cause
4323 // consequential calls to this method, those calls will be skipped
4324 // at the condition above.
4325 if (aReason == FullscreenReason::ForFullscreenMode) {
4326 if (!aFullscreen && mFullscreen &&
4327 mFullscreen.value() == FullscreenReason::ForFullscreenAPI) {
4328 // If we are exiting fullscreen mode, but we actually didn't
4329 // entered browser fullscreen mode, the fullscreen state was only for
4330 // the Fullscreen API. Change the reason here so that we can
4331 // perform transition for it.
4332 aReason = FullscreenReason::ForFullscreenAPI;
4333 }
4334 } else {
4335 // If we are exiting from DOM fullscreen while we initially make
4336 // the window fullscreen because of browser fullscreen mode, don't restore
4337 // the window. But we still need to exit the DOM fullscreen state.
4338 if (!aFullscreen && mFullscreen &&
4339 mFullscreen.value() == FullscreenReason::ForFullscreenMode) {
4340 // If there is a in-process fullscreen request, FinishDOMFullscreenChange
4341 // will be called when the request is finished.
4342 if (!mInProcessFullscreenRequest.isSome()) {
4343 FinishDOMFullscreenChange(mDoc, false);
4344 }
4345 return NS_OK;
4346 }
4347 }
4348
4349 // Set this before so if widget sends an event indicating its
4350 // gone full screen, the state trap above works.
4351 if (aFullscreen) {
4352 mFullscreen.emplace(aReason);
4353 } else {
4354 mFullscreen.reset();
4355 }
4356
4357 // If we are in process of fullscreen request, only keep the latest fullscreen
4358 // state, we will sync up later while the processing request is finished.
4359 if (mInProcessFullscreenRequest.isSome()) {
4360 mFullscreenHasChangedDuringProcessing = true;
4361 return NS_OK;
4362 }
4363
4364 return ProcessWidgetFullscreenRequest(aReason, aFullscreen);
4365}
4366
4367// Support a per-window, dynamic equivalent of enabling
4368// full-screen-api.ignore-widgets
4369void nsGlobalWindowOuter::ForceFullScreenInWidget() {
4370 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"
, 4370); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4370; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4371
4372 mForceFullScreenInWidget = true;
4373}
4374
4375bool nsGlobalWindowOuter::SetWidgetFullscreen(FullscreenReason aReason,
4376 bool aIsFullscreen,
4377 nsIWidget* aWidget) {
4378 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"
, 4379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this == GetInProcessTopInternal()"
") (" "Only topmost window should call this" ")"); do { *((volatile
int*)__null) = 4379; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
4379 "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"
, 4379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this == GetInProcessTopInternal()"
") (" "Only topmost window should call this" ")"); do { *((volatile
int*)__null) = 4379; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4380 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"
, 4380); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetFrameElementInternal()"
") (" "Content window should not call this" ")"); do { *((volatile
int*)__null) = 4380; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4381 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"
, 4381); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_GetProcessType() == GeckoProcessType_Default"
")"); do { *((volatile int*)__null) = 4381; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4382
4383 if (!NS_WARN_IF(!IsChromeWindow())NS_warn_if_impl(!IsChromeWindow(), "!IsChromeWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4383)
) {
4384 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"
, 4384)
) {
4385 if (PresShell* presShell = mDocShell->GetPresShell()) {
4386 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
4387 mChromeFields.mFullscreenPresShell = do_GetWeakReference(presShell);
4388 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"
, 4388); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChromeFields.mFullscreenPresShell"
")"); do { *((volatile int*)__null) = 4388; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4389 rd->SetIsResizeSuppressed();
4390 rd->Freeze();
4391 }
4392 }
4393 }
4394 }
4395 nsresult rv = aReason == FullscreenReason::ForFullscreenMode
4396 ?
4397 // If we enter fullscreen for fullscreen mode, we want
4398 // the native system behavior.
4399 aWidget->MakeFullScreenWithNativeTransition(aIsFullscreen)
4400 : aWidget->MakeFullScreen(aIsFullscreen);
4401 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
4402}
4403
4404/* virtual */
4405void nsGlobalWindowOuter::FullscreenWillChange(bool aIsFullscreen) {
4406 if (!mInProcessFullscreenRequest.isSome()) {
4407 // If there is no in-process fullscreen request, the fullscreen state change
4408 // is triggered from the OS directly, e.g. user use built-in window button
4409 // to enter/exit fullscreen on macOS.
4410 mInProcessFullscreenRequest.emplace(FullscreenReason::ForFullscreenMode,
4411 aIsFullscreen);
4412 if (mFullscreen.isSome() != aIsFullscreen) {
4413 if (aIsFullscreen) {
4414 mFullscreen.emplace(FullscreenReason::ForFullscreenMode);
4415 } else {
4416 mFullscreen.reset();
4417 }
4418 } else {
4419 // It is possible that FullscreenWillChange is notified with current
4420 // fullscreen state, e.g. browser goes into fullscreen when widget
4421 // fullscreen is prevented, and then user triggers fullscreen from the OS
4422 // directly again.
4423 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"
, 4425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4424 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"
, 4425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4425 "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"
, 4425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "StaticPrefs::full_screen_api_ignore_widgets() || mForceFullScreenInWidget"
") (" "This should only happen when widget fullscreen is prevented"
")"); do { *((volatile int*)__null) = 4425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4426 }
4427 }
4428 if (aIsFullscreen) {
4429 DispatchCustomEvent(u"willenterfullscreen"_ns, ChromeOnlyDispatch::eYes);
4430 } else {
4431 DispatchCustomEvent(u"willexitfullscreen"_ns, ChromeOnlyDispatch::eYes);
4432 }
4433}
4434
4435/* virtual */
4436void nsGlobalWindowOuter::FinishFullscreenChange(bool aIsFullscreen) {
4437 mozilla::Maybe<FullscreenRequest> currentInProcessRequest =
4438 std::move(mInProcessFullscreenRequest);
4439 if (!mFullscreenHasChangedDuringProcessing &&
4440 aIsFullscreen != mFullscreen.isSome()) {
4441 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"
, 4441)
;
4442 // We failed to make the widget enter fullscreen.
4443 // Stop further changes and restore the state.
4444 if (!aIsFullscreen) {
4445 mFullscreen.reset();
4446 } else {
4447#ifndef XP_MACOSX
4448 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"
, 4448); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Failed to exit fullscreen?" ")")
; do { *((volatile int*)__null) = 4448; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4449#endif
4450 // Restore fullscreen state with FullscreenReason::ForFullscreenAPI reason
4451 // in order to make subsequent DOM fullscreen exit request can exit
4452 // browser fullscreen mode.
4453 mFullscreen.emplace(FullscreenReason::ForFullscreenAPI);
4454 }
4455 return;
4456 }
4457
4458 // Note that we must call this to toggle the DOM fullscreen state
4459 // of the document before dispatching the "fullscreen" event, so
4460 // that the chrome can distinguish between browser fullscreen mode
4461 // and DOM fullscreen.
4462 FinishDOMFullscreenChange(mDoc, aIsFullscreen);
4463
4464 // dispatch a "fullscreen" DOM event so that XUL apps can
4465 // respond visually if we are kicked into full screen mode
4466 DispatchCustomEvent(u"fullscreen"_ns, ChromeOnlyDispatch::eYes);
4467
4468 if (!NS_WARN_IF(!IsChromeWindow())NS_warn_if_impl(!IsChromeWindow(), "!IsChromeWindow()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 4468)
) {
4469 if (RefPtr<PresShell> presShell =
4470 do_QueryReferent(mChromeFields.mFullscreenPresShell)) {
4471 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
4472 rd->Thaw();
4473 }
4474 mChromeFields.mFullscreenPresShell = nullptr;
4475 }
4476 }
4477
4478 // If fullscreen state has changed during processing fullscreen request, we
4479 // need to ensure widget matches our latest fullscreen state here.
4480 if (mFullscreenHasChangedDuringProcessing) {
4481 mFullscreenHasChangedDuringProcessing = false;
4482 // Widget doesn't care about the reason that makes it entering/exiting
4483 // fullscreen, so here we just need to ensure the fullscreen state is
4484 // matched.
4485 if (aIsFullscreen != mFullscreen.isSome()) {
4486 // If we end up need to exit fullscreen, use the same reason that brings
4487 // us into fullscreen mode, so that we will perform the same fullscreen
4488 // transistion effect for exiting.
4489 ProcessWidgetFullscreenRequest(
4490 mFullscreen.isSome() ? mFullscreen.value()
4491 : currentInProcessRequest.value().mReason,
4492 mFullscreen.isSome());
4493 }
4494 }
4495}
4496
4497/* virtual */
4498void nsGlobalWindowOuter::MacFullscreenMenubarOverlapChanged(
4499 mozilla::DesktopCoord aOverlapAmount) {
4500 ErrorResult res;
4501 RefPtr<Event> domEvent =
4502 mDoc->CreateEvent(u"CustomEvent"_ns, CallerType::System, res);
4503 if (res.Failed()) {
4504 return;
4505 }
4506
4507 AutoJSAPI jsapi;
4508 jsapi.Init();
4509 JSContext* cx = jsapi.cx();
4510 JSAutoRealm ar(cx, GetWrapperPreserveColor());
4511
4512 JS::Rooted<JS::Value> detailValue(cx);
4513 if (!ToJSValue(cx, aOverlapAmount, &detailValue)) {
4514 return;
4515 }
4516
4517 CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
4518 customEvent->InitCustomEvent(cx, u"MacFullscreenMenubarRevealUpdate"_ns,
4519 /* aCanBubble = */ true,
4520 /* aCancelable = */ true, detailValue);
4521 domEvent->SetTrusted(true);
4522 domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
4523
4524 nsCOMPtr<EventTarget> target = this;
4525 domEvent->SetTarget(target);
4526
4527 target->DispatchEvent(*domEvent, CallerType::System, IgnoreErrors());
4528}
4529
4530bool nsGlobalWindowOuter::Fullscreen() const {
4531 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"
, 4531); return mFullscreen.isSome(); } } while (false)
;
4532
4533 // Get the fullscreen value of the root window, to always have the value
4534 // accurate, even when called from content.
4535 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4536 mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
4537 if (rootItem == mDocShell) {
4538 if (!XRE_IsContentProcess()) {
4539 // We are the root window. Return our internal value.
4540 return mFullscreen.isSome();
4541 }
4542 if (nsCOMPtr<nsIWidget> widget = GetNearestWidget()) {
4543 // We are in content process, figure out the value from
4544 // the sizemode of the puppet widget.
4545 return widget->SizeMode() == nsSizeMode_Fullscreen;
4546 }
4547 return false;
4548 }
4549
4550 nsCOMPtr<nsPIDOMWindowOuter> window = rootItem->GetWindow();
4551 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"
, 4551); return mFullscreen.isSome(); } } while (false)
;
4552
4553 return nsGlobalWindowOuter::Cast(window)->Fullscreen();
4554}
4555
4556bool nsGlobalWindowOuter::GetFullscreenOuter() { return Fullscreen(); }
4557
4558bool nsGlobalWindowOuter::GetFullScreen() {
4559 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"
, 4559); return false; } return GetCurrentInnerWindowInternal
(this)->GetFullScreen (); } while (0)
;
4560}
4561
4562void nsGlobalWindowOuter::EnsureReflowFlushAndPaint() {
4563 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"
, 4565); MOZ_PretendNoReturn(); } } while (0)
4564 "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"
, 4565); MOZ_PretendNoReturn(); } } while (0)
4565 "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"
, 4565); MOZ_PretendNoReturn(); } } while (0)
;
4566
4567 if (!mDocShell) return;
4568
4569 RefPtr<PresShell> presShell = mDocShell->GetPresShell();
4570 if (!presShell) {
4571 return;
4572 }
4573
4574 // Flush pending reflows.
4575 if (mDoc) {
4576 mDoc->FlushPendingNotifications(FlushType::Layout);
4577 }
4578
4579 // Unsuppress painting.
4580 presShell->UnsuppressPainting();
4581}
4582
4583// static
4584void nsGlobalWindowOuter::MakeMessageWithPrincipal(
4585 nsAString& aOutMessage, nsIPrincipal* aSubjectPrincipal, bool aUseHostPort,
4586 const char* aNullMessage, const char* aContentMessage,
4587 const char* aFallbackMessage) {
4588 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"
, 4588); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSubjectPrincipal"
")"); do { *((volatile int*)__null) = 4588; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4589
4590 aOutMessage.Truncate();
4591
4592 // Try to get a host from the running principal -- this will do the
4593 // right thing for javascript: and data: documents.
4594
4595 nsAutoCString contentDesc;
4596
4597 if (aSubjectPrincipal->GetIsNullPrincipal()) {
4598 nsContentUtils::GetLocalizedString(
4599 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, aNullMessage, aOutMessage);
4600 } else {
4601 auto* addonPolicy = BasePrincipal::Cast(aSubjectPrincipal)->AddonPolicy();
4602 if (addonPolicy) {
4603 nsContentUtils::FormatLocalizedString(
4604 aOutMessage, nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4605 aContentMessage, addonPolicy->Name());
4606 } else {
4607 nsresult rv = NS_ERROR_FAILURE;
4608 if (aUseHostPort) {
4609 nsCOMPtr<nsIURI> uri = aSubjectPrincipal->GetURI();
4610 if (uri) {
4611 rv = uri->GetDisplayHostPort(contentDesc);
4612 }
4613 }
4614 if (!aUseHostPort || NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4615 rv = aSubjectPrincipal->GetExposablePrePath(contentDesc);
4616 }
4617 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !contentDesc.IsEmpty()) {
4618 NS_ConvertUTF8toUTF16 ucsPrePath(contentDesc);
4619 nsContentUtils::FormatLocalizedString(
4620 aOutMessage, nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4621 aContentMessage, ucsPrePath);
4622 }
4623 }
4624 }
4625
4626 if (aOutMessage.IsEmpty()) {
4627 // We didn't find a host so use the generic heading
4628 nsContentUtils::GetLocalizedString(
4629 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, aFallbackMessage,
4630 aOutMessage);
4631 }
4632
4633 // Just in case
4634 if (aOutMessage.IsEmpty()) {
4635 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"
, 4636)
4636 "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"
, 4636)
;
4637 aOutMessage.AssignLiteral("[Script]");
4638 }
4639}
4640
4641bool nsGlobalWindowOuter::CanMoveResizeWindows(CallerType aCallerType) {
4642 // When called from chrome, we can avoid the following checks.
4643 if (aCallerType != CallerType::System) {
4644 // Don't allow scripts to move or resize windows that were not opened by a
4645 // script.
4646 if (!mBrowsingContext->GetTopLevelCreatedByWebContent()) {
4647 return false;
4648 }
4649
4650 if (!CanSetProperty("dom.disable_window_move_resize")) {
4651 return false;
4652 }
4653
4654 // Ignore the request if we have more than one tab in the window.
4655 if (mBrowsingContext->Top()->HasSiblings()) {
4656 return false;
4657 }
4658 }
4659
4660 if (mDocShell) {
4661 bool allow;
4662 nsresult rv = mDocShell->GetAllowWindowControl(&allow);
4663 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !allow) return false;
4664 }
4665
4666 if (nsGlobalWindowInner::sMouseDown &&
4667 !nsGlobalWindowInner::sDragServiceDisabled) {
4668 nsCOMPtr<nsIDragService> ds =
4669 do_GetService("@mozilla.org/widget/dragservice;1");
4670 if (ds) {
4671 nsGlobalWindowInner::sDragServiceDisabled = true;
4672 ds->Suppress();
4673 }
4674 }
4675 return true;
4676}
4677
4678bool nsGlobalWindowOuter::AlertOrConfirm(bool aAlert, const nsAString& aMessage,
4679 nsIPrincipal& aSubjectPrincipal,
4680 ErrorResult& aError) {
4681 // XXX This method is very similar to nsGlobalWindowOuter::Prompt, make
4682 // sure any modifications here don't need to happen over there!
4683 if (!AreDialogsEnabled()) {
4684 // Just silently return. In the case of alert(), the return value is
4685 // ignored. In the case of confirm(), returning false is the same thing as
4686 // would happen if the user cancels.
4687 return false;
4688 }
4689
4690 // Reset popup state while opening a modal dialog, and firing events
4691 // about the dialog, to prevent the current state from being active
4692 // the whole time a modal dialog is open.
4693 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
4694
4695 // Before bringing up the window, unsuppress painting and flush
4696 // pending reflows.
4697 EnsureReflowFlushAndPaint();
4698
4699 nsAutoString title;
4700 MakeMessageWithPrincipal(title, &aSubjectPrincipal, false,
4701 "ScriptDlgNullPrincipalHeading", "ScriptDlgHeading",
4702 "ScriptDlgGenericHeading");
4703
4704 // Remove non-terminating null characters from the
4705 // string. See bug #310037.
4706 nsAutoString final;
4707 nsContentUtils::StripNullChars(aMessage, final);
4708 nsContentUtils::PlatformToDOMLineBreaks(final);
4709
4710 nsresult rv;
4711 nsCOMPtr<nsIPromptFactory> promptFac =
4712 do_GetService("@mozilla.org/prompter;1", &rv);
4713 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4714 aError.Throw(rv);
4715 return false;
4716 }
4717
4718 nsCOMPtr<nsIPrompt> prompt;
4719 aError =
4720 promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt)(nsIPrompt::COMTypeInfo<nsIPrompt, void>::kIID), getter_AddRefs(prompt));
4721 if (aError.Failed()) {
4722 return false;
4723 }
4724
4725 // Always allow content modal prompts for alert and confirm.
4726 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4727 promptBag->SetPropertyAsUint32(u"modalType"_ns,
4728 nsIPrompt::MODAL_TYPE_CONTENT);
4729 }
4730
4731 bool result = false;
4732 nsAutoSyncOperation sync(mDoc, SyncOperationBehavior::eSuspendInput);
4733 if (ShouldPromptToBlockDialogs()) {
4734 bool disallowDialog = false;
4735 nsAutoString label;
4736 MakeMessageWithPrincipal(
4737 label, &aSubjectPrincipal, true, "ScriptDialogLabelNullPrincipal",
4738 "ScriptDialogLabelContentPrincipal", "ScriptDialogLabelNullPrincipal");
4739
4740 aError = aAlert
4741 ? prompt->AlertCheck(title.get(), final.get(), label.get(),
4742 &disallowDialog)
4743 : prompt->ConfirmCheck(title.get(), final.get(), label.get(),
4744 &disallowDialog, &result);
4745
4746 if (disallowDialog) {
4747 DisableDialogs();
4748 }
4749 } else {
4750 aError = aAlert ? prompt->Alert(title.get(), final.get())
4751 : prompt->Confirm(title.get(), final.get(), &result);
4752 }
4753
4754 return result;
4755}
4756
4757void nsGlobalWindowOuter::AlertOuter(const nsAString& aMessage,
4758 nsIPrincipal& aSubjectPrincipal,
4759 ErrorResult& aError) {
4760 AlertOrConfirm(/* aAlert = */ true, aMessage, aSubjectPrincipal, aError);
4761}
4762
4763bool nsGlobalWindowOuter::ConfirmOuter(const nsAString& aMessage,
4764 nsIPrincipal& aSubjectPrincipal,
4765 ErrorResult& aError) {
4766 return AlertOrConfirm(/* aAlert = */ false, aMessage, aSubjectPrincipal,
4767 aError);
4768}
4769
4770void nsGlobalWindowOuter::PromptOuter(const nsAString& aMessage,
4771 const nsAString& aInitial,
4772 nsAString& aReturn,
4773 nsIPrincipal& aSubjectPrincipal,
4774 ErrorResult& aError) {
4775 // XXX This method is very similar to nsGlobalWindowOuter::AlertOrConfirm,
4776 // make sure any modifications here don't need to happen over there!
4777 SetDOMStringToNull(aReturn);
4778
4779 if (!AreDialogsEnabled()) {
4780 // Return null, as if the user just canceled the prompt.
4781 return;
4782 }
4783
4784 // Reset popup state while opening a modal dialog, and firing events
4785 // about the dialog, to prevent the current state from being active
4786 // the whole time a modal dialog is open.
4787 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
4788
4789 // Before bringing up the window, unsuppress painting and flush
4790 // pending reflows.
4791 EnsureReflowFlushAndPaint();
4792
4793 nsAutoString title;
4794 MakeMessageWithPrincipal(title, &aSubjectPrincipal, false,
4795 "ScriptDlgNullPrincipalHeading", "ScriptDlgHeading",
4796 "ScriptDlgGenericHeading");
4797
4798 // Remove non-terminating null characters from the
4799 // string. See bug #310037.
4800 nsAutoString fixedMessage, fixedInitial;
4801 nsContentUtils::StripNullChars(aMessage, fixedMessage);
4802 nsContentUtils::PlatformToDOMLineBreaks(fixedMessage);
4803 nsContentUtils::StripNullChars(aInitial, fixedInitial);
4804
4805 nsresult rv;
4806 nsCOMPtr<nsIPromptFactory> promptFac =
4807 do_GetService("@mozilla.org/prompter;1", &rv);
4808 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4809 aError.Throw(rv);
4810 return;
4811 }
4812
4813 nsCOMPtr<nsIPrompt> prompt;
4814 aError =
4815 promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt)(nsIPrompt::COMTypeInfo<nsIPrompt, void>::kIID), getter_AddRefs(prompt));
4816 if (aError.Failed()) {
4817 return;
4818 }
4819
4820 // Always allow content modal prompts for prompt.
4821 if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
4822 promptBag->SetPropertyAsUint32(u"modalType"_ns,
4823 nsIPrompt::MODAL_TYPE_CONTENT);
4824 }
4825
4826 // Pass in the default value, if any.
4827 char16_t* inoutValue = ToNewUnicode(fixedInitial);
4828 bool disallowDialog = false;
4829
4830 nsAutoString label;
4831 label.SetIsVoid(true);
4832 if (ShouldPromptToBlockDialogs()) {
4833 nsContentUtils::GetLocalizedString(
4834 nsContentUtils::eCOMMON_DIALOG_PROPERTIES, "ScriptDialogLabel", label);
4835 }
4836
4837 nsAutoSyncOperation sync(mDoc, SyncOperationBehavior::eSuspendInput);
4838 bool ok;
4839 aError = prompt->Prompt(title.get(), fixedMessage.get(), &inoutValue,
4840 label.IsVoid() ? nullptr : label.get(),
4841 &disallowDialog, &ok);
4842
4843 if (disallowDialog) {
4844 DisableDialogs();
4845 }
4846
4847 // XXX Doesn't this leak inoutValue?
4848 if (aError.Failed()) {
4849 return;
4850 }
4851
4852 nsString outValue;
4853 outValue.Adopt(inoutValue);
4854 if (ok && inoutValue) {
4855 aReturn = std::move(outValue);
4856 }
4857}
4858
4859void nsGlobalWindowOuter::FocusOuter(CallerType aCallerType,
4860 bool aFromOtherProcess,
4861 uint64_t aActionId) {
4862 RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
4863 if (MOZ_UNLIKELY(!fm)(__builtin_expect(!!(!fm), 0))) {
4864 return;
4865 }
4866
4867 auto [canFocus, isActive] = GetBrowsingContext()->CanFocusCheck(aCallerType);
4868 if (aFromOtherProcess) {
4869 // We trust that the check passed in a process that's, in principle,
4870 // untrusted, because we don't have the required caller context available
4871 // here. Also, the worst that the other process can do in this case is to
4872 // raise a window it's not supposed to be allowed to raise.
4873 // https://bugzilla.mozilla.org/show_bug.cgi?id=1677899
4874 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"
, 4875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "Parent should not trust other processes." ")"); do { *
((volatile int*)__null) = 4875; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
4875 "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"
, 4875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
") (" "Parent should not trust other processes." ")"); do { *
((volatile int*)__null) = 4875; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4876 canFocus = true;
4877 }
4878
4879 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
4880 if (treeOwnerAsWin && (canFocus || isActive)) {
4881 bool isEnabled = true;
4882 if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled))((bool)(__builtin_expect(!!(!NS_FAILED_impl(treeOwnerAsWin->
GetEnabled(&isEnabled))), 1)))
&& !isEnabled) {
4883 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"
, 4883)
;
4884 return;
4885 }
4886 }
4887
4888 if (!mDocShell) {
4889 return;
4890 }
4891
4892 // If the window has a child frame focused, clear the focus. This
4893 // ensures that focus will be in this frame and not in a child.
4894 if (nsIContent* content = GetFocusedElement()) {
4895 if (HTMLIFrameElement::FromNode(content)) {
4896 fm->ClearFocus(this);
4897 }
4898 }
4899
4900 RefPtr<BrowsingContext> parent;
4901 BrowsingContext* bc = GetBrowsingContext();
4902 if (bc) {
4903 parent = bc->GetParent();
4904 if (!parent && XRE_IsParentProcess()) {
4905 parent = bc->Canonical()->GetParentCrossChromeBoundary();
4906 }
4907 }
4908 if (parent) {
4909 if (!parent->IsInProcess()) {
4910 if (isActive) {
4911 OwningNonNull<nsGlobalWindowOuter> kungFuDeathGrip(*this);
4912 fm->WindowRaised(kungFuDeathGrip, aActionId);
4913 } else {
4914 ContentChild* contentChild = ContentChild::GetSingleton();
4915 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"
, 4915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 4915; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4916 contentChild->SendFinalizeFocusOuter(bc, canFocus, aCallerType);
4917 }
4918 return;
4919 }
4920
4921 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"
, 4921); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDoc" ") ("
"Call chain should have ensured document creation." ")"); do
{ *((volatile int*)__null) = 4921; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4922 if (mDoc) {
4923 if (Element* frame = mDoc->GetEmbedderElement()) {
4924 nsContentUtils::RequestFrameFocus(*frame, canFocus, aCallerType);
4925 }
4926 }
4927 return;
4928 }
4929
4930 if (canFocus) {
4931 // if there is no parent, this must be a toplevel window, so raise the
4932 // window if canFocus is true. If this is a child process, the raise
4933 // window request will get forwarded to the parent by the puppet widget.
4934 OwningNonNull<nsGlobalWindowOuter> kungFuDeathGrip(*this);
4935 fm->RaiseWindow(kungFuDeathGrip, aCallerType, aActionId);
4936 }
4937}
4938
4939nsresult nsGlobalWindowOuter::Focus(CallerType aCallerType) {
4940 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"
, 4940); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->Focus (aCallerType); } while (0)
;
4941}
4942
4943void nsGlobalWindowOuter::BlurOuter(CallerType aCallerType) {
4944 if (!GetBrowsingContext()->CanBlurCheck(aCallerType)) {
4945 return;
4946 }
4947
4948 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
4949 if (chrome) {
4950 chrome->Blur();
4951 }
4952}
4953
4954void nsGlobalWindowOuter::StopOuter(ErrorResult& aError) {
4955 // IsNavigationAllowed checks are usually done in nsDocShell directly,
4956 // however nsDocShell::Stop has a bunch of internal users that would fail
4957 // the IsNavigationAllowed check.
4958 if (!mDocShell || !nsDocShell::Cast(mDocShell)->IsNavigationAllowed()) {
4959 return;
4960 }
4961
4962 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4963 if (webNav) {
4964 aError = webNav->Stop(nsIWebNavigation::STOP_ALL);
4965 }
4966}
4967
4968void nsGlobalWindowOuter::PrintOuter(ErrorResult& aError) {
4969 if (!AreDialogsEnabled()) {
4970 // Per spec, silently return. https://github.com/whatwg/html/commit/21a1de1
4971 return;
4972 }
4973
4974 // Printing is disabled, silently return.
4975 if (!StaticPrefs::print_enabled()) {
4976 return;
4977 }
4978
4979 // If we're loading, queue the print for later. This is a special-case that
4980 // only applies to the window.print() call, for compat with other engines and
4981 // pre-existing behavior.
4982 if (mShouldDelayPrintUntilAfterLoad) {
4983 if (nsIDocShell* docShell = GetDocShell()) {
4984 if (docShell->GetBusyFlags() & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) {
4985 mDelayedPrintUntilAfterLoad = true;
4986 return;
4987 }
4988 }
4989 }
4990
4991#ifdef NS_PRINTING1
4992 RefPtr<BrowsingContext> top =
4993 mBrowsingContext ? mBrowsingContext->Top() : nullptr;
4994 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"
, 4994)
) {
4995 return;
4996 }
4997
4998 if (top) {
4999 Unused << top->SetIsPrinting(true);
5000 }
5001
5002 auto unset = MakeScopeExit([&] {
5003 if (top) {
5004 Unused << top->SetIsPrinting(false);
5005 }
5006 });
5007
5008 const bool forPreview = !StaticPrefs::print_always_print_silent();
5009 Print(nullptr, nullptr, nullptr, nullptr, IsPreview(forPreview),
5010 IsForWindowDotPrint::Yes, nullptr, nullptr, aError);
5011#endif
5012}
5013
5014class MOZ_RAII AutoModalState {
5015 public:
5016 explicit AutoModalState(nsGlobalWindowOuter& aWin)
5017 : mModalStateWin(aWin.EnterModalState()) {}
5018
5019 ~AutoModalState() {
5020 if (mModalStateWin) {
5021 mModalStateWin->LeaveModalState();
5022 }
5023 }
5024
5025 RefPtr<nsGlobalWindowOuter> mModalStateWin;
5026};
5027
5028Nullable<WindowProxyHolder> nsGlobalWindowOuter::Print(
5029 nsIPrintSettings* aPrintSettings, RemotePrintJobChild* aRemotePrintJob,
5030 nsIWebProgressListener* aListener, nsIDocShell* aDocShellToCloneInto,
5031 IsPreview aIsPreview, IsForWindowDotPrint aForWindowDotPrint,
5032 PrintPreviewResolver&& aPrintPreviewCallback,
5033 RefPtr<BrowsingContext>* aCachedBrowsingContext, ErrorResult& aError) {
5034#ifdef NS_PRINTING1
5035 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
5036 do_GetService("@mozilla.org/gfx/printsettings-service;1");
5037 if (!printSettingsService) {
5038 // we currently return here in headless mode - should we?
5039 aError.ThrowNotSupportedError("No print settings service");
5040 return nullptr;
5041 }
5042
5043 nsCOMPtr<nsIPrintSettings> ps = aPrintSettings;
5044 if (!ps) {
5045 // We shouldn't need this once bug 1776169 is fixed.
5046 printSettingsService->GetDefaultPrintSettingsForPrinting(
5047 getter_AddRefs(ps));
5048 }
5049
5050 RefPtr<Document> docToPrint = mDoc;
5051 if (NS_WARN_IF(!docToPrint)NS_warn_if_impl(!docToPrint, "!docToPrint", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5051)
) {
5052 aError.ThrowNotSupportedError("Document is gone");
5053 return nullptr;
5054 }
5055
5056 RefPtr<BrowsingContext> sourceBC = docToPrint->GetBrowsingContext();
5057 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"
, 5057); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "sourceBC"
")"); do { *((volatile int*)__null) = 5057; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5058 if (!sourceBC) {
5059 aError.ThrowNotSupportedError("No browsing context for source document");
5060 return nullptr;
5061 }
5062
5063 nsAutoSyncOperation sync(docToPrint, SyncOperationBehavior::eAllowInput);
5064 AutoModalState modalState(*this);
5065
5066 nsCOMPtr<nsIDocumentViewer> viewer;
5067 RefPtr<BrowsingContext> bc;
5068 bool hasPrintCallbacks = false;
5069 bool wasStaticDocument = docToPrint->IsStaticDocument();
5070 bool usingCachedBrowsingContext = false;
5071 if (aCachedBrowsingContext && *aCachedBrowsingContext) {
5072 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"
, 5074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5074; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
5073 "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"
, 5074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5074; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
5074 "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"
, 5074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wasStaticDocument"
") (" "Why pass in non-empty aCachedBrowsingContext if original "
"document is already static?" ")"); do { *((volatile int*)__null
) = 5074; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
5075 if (!wasStaticDocument) {
5076 // The passed in document is not a static clone and the caller passed in a
5077 // static clone to reuse, so swap it in.
5078 docToPrint = (*aCachedBrowsingContext)->GetDocument();
5079 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"
, 5079); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docToPrint"
")"); do { *((volatile int*)__null) = 5079; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5080 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"
, 5080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docToPrint->IsStaticDocument()"
")"); do { *((volatile int*)__null) = 5080; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5081 wasStaticDocument = true;
5082 usingCachedBrowsingContext = true;
5083 }
5084 }
5085 if (wasStaticDocument) {
5086 if (aForWindowDotPrint == IsForWindowDotPrint::Yes) {
5087 aError.ThrowNotSupportedError(
5088 "Calling print() from a print preview is unsupported, did you intend "
5089 "to call printPreview() instead?");
5090 return nullptr;
5091 }
5092 if (usingCachedBrowsingContext) {
5093 bc = docToPrint->GetBrowsingContext();
5094 } else {
5095 // We're already a print preview window, just reuse our browsing context /
5096 // content viewer.
5097 bc = sourceBC;
5098 }
5099 nsCOMPtr<nsIDocShell> docShell = bc->GetDocShell();
5100 if (!docShell) {
5101 aError.ThrowNotSupportedError("No docshell");
5102 return nullptr;
5103 }
5104 // We could handle this if needed.
5105 if (aDocShellToCloneInto && aDocShellToCloneInto != docShell) {
5106 aError.ThrowNotSupportedError(
5107 "We don't handle cloning a print preview doc into a different "
5108 "docshell");
5109 return nullptr;
5110 }
5111 docShell->GetDocViewer(getter_AddRefs(viewer));
5112 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"
, 5112); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "viewer"
")"); do { *((volatile int*)__null) = 5112; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5113 } else {
5114 if (aDocShellToCloneInto) {
5115 // Ensure the content viewer is created if needed.
5116 Unused << aDocShellToCloneInto->GetDocument();
5117 bc = aDocShellToCloneInto->GetBrowsingContext();
5118 } else {
5119 AutoNoJSAPI nojsapi;
5120 auto printKind = aForWindowDotPrint == IsForWindowDotPrint::Yes
5121 ? PrintKind::WindowDotPrint
5122 : PrintKind::InternalPrint;
5123 // For PrintKind::WindowDotPrint, this call will not only make the parent
5124 // process create a CanonicalBrowsingContext for the returned `bc`, but
5125 // it will also make the parent process initiate the print/print preview.
5126 // See the handling of OPEN_PRINT_BROWSER in browser.js.
5127 aError = OpenInternal(u""_ns, u""_ns, u""_ns,
5128 false, // aDialog
5129 false, // aContentModal
5130 true, // aCalledNoScript
5131 false, // aDoJSFixups
5132 true, // aNavigate
5133 nullptr, nullptr, // No args
5134 nullptr, // aLoadState
5135 false, // aForceNoOpener
5136 printKind, getter_AddRefs(bc));
5137 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"
, 5137)
) {
5138 return nullptr;
5139 }
5140 if (aCachedBrowsingContext) {
5141 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"
, 5141); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!*aCachedBrowsingContext"
")"); do { *((volatile int*)__null) = 5141; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5142 *aCachedBrowsingContext = bc;
5143 }
5144 }
5145 if (!bc) {
5146 aError.ThrowNotAllowedError("No browsing context");
5147 return nullptr;
5148 }
5149
5150 Unused << bc->Top()->SetIsPrinting(true);
5151 nsCOMPtr<nsIDocShell> cloneDocShell = bc->GetDocShell();
5152 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"
, 5152); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "cloneDocShell"
")"); do { *((volatile int*)__null) = 5152; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5153 cloneDocShell->GetDocViewer(getter_AddRefs(viewer));
5154 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"
, 5154); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "viewer"
")"); do { *((volatile int*)__null) = 5154; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5155 if (!viewer) {
5156 aError.ThrowNotSupportedError("Didn't end up with a content viewer");
5157 return nullptr;
5158 }
5159
5160 if (bc != sourceBC) {
5161 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"
, 5161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc->IsTopContent()"
")"); do { *((volatile int*)__null) = 5161; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5162 // If we are cloning from a document in a different BrowsingContext, we
5163 // need to make sure to copy over our opener policy information from that
5164 // BrowsingContext. In the case where the source is an iframe, this
5165 // information needs to be copied from the toplevel source
5166 // BrowsingContext, as we may be making a static clone of a single
5167 // subframe.
5168 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"
, 5169); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")"); do { *((volatile int*)__null) = 5169; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5169 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"
, 5169); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(bc->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()))"
")"); do { *((volatile int*)__null) = 5169; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
5170 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"
, 5170); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "bc->Group() == sourceBC->Group()"
")"); do { *((volatile int*)__null) = 5170; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5171 }
5172
5173 if (RefPtr<Document> doc = viewer->GetDocument()) {
5174 if (doc->IsShowing()) {
5175 // We're going to drop this document on the floor, in the SetDocument
5176 // call below. Make sure to run OnPageHide() to keep state consistent
5177 // and avoids assertions in the document destructor.
5178 doc->OnPageHide(false, nullptr);
5179 }
5180 }
5181
5182 AutoPrintEventDispatcher dispatcher(*docToPrint);
5183
5184 nsAutoScriptBlocker blockScripts;
5185 RefPtr<Document> clone = docToPrint->CreateStaticClone(
5186 cloneDocShell, viewer, ps, &hasPrintCallbacks);
5187 if (!clone) {
5188 aError.ThrowNotSupportedError("Clone operation for printing failed");
5189 return nullptr;
5190 }
5191 }
5192
5193 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint = do_QueryInterface(viewer);
5194 if (!webBrowserPrint) {
5195 aError.ThrowNotSupportedError(
5196 "Content viewer didn't implement nsIWebBrowserPrint");
5197 return nullptr;
5198 }
5199 bool closeWindowAfterPrint;
5200 if (wasStaticDocument) {
5201 // Here the document was a static clone to begin with that this code did not
5202 // create, so we should not clean it up.
5203 // The exception is if we're using the passed-in aCachedBrowsingContext, in
5204 // which case this is the second print with this static document clone that
5205 // we created the first time through, and we are responsible for cleaning it
5206 // up.
5207 closeWindowAfterPrint = usingCachedBrowsingContext;
5208 } else {
5209 // In this case the document was not a static clone, so we made a static
5210 // clone for printing purposes and must clean it up after the print is done.
5211 // The exception is if aCachedBrowsingContext is non-NULL, meaning the
5212 // caller is intending to print this document again, so we need to defer the
5213 // cleanup until after the second print.
5214 closeWindowAfterPrint = !aCachedBrowsingContext;
5215 }
5216 webBrowserPrint->SetCloseWindowAfterPrint(closeWindowAfterPrint);
5217
5218 // For window.print(), we postpone making these calls until the round-trip to
5219 // the parent process (triggered by the OpenInternal call above) calls us
5220 // again. Only a call from the parent can provide a valid nsPrintSettings
5221 // object and RemotePrintJobChild object.
5222 if (aForWindowDotPrint == IsForWindowDotPrint::No) {
5223 if (aIsPreview == IsPreview::Yes) {
5224 aError = webBrowserPrint->PrintPreview(ps, aListener,
5225 std::move(aPrintPreviewCallback));
5226 if (aError.Failed()) {
5227 return nullptr;
5228 }
5229 } else {
5230 // Historically we've eaten this error.
5231 webBrowserPrint->Print(ps, aRemotePrintJob, aListener);
5232 }
5233 }
5234
5235 // When using window.print() with the new UI, we usually want to block until
5236 // the print dialog is hidden. But we can't really do that if we have print
5237 // callbacks, because we are inside a sync operation, and we want to run
5238 // microtasks / etc that the print callbacks may create. It is really awkward
5239 // to have this subtle behavior difference...
5240 //
5241 // We also want to do this for fuzzing, so that they can test window.print().
5242 const bool shouldBlock = [&] {
5243 if (aForWindowDotPrint == IsForWindowDotPrint::No) {
5244 return false;
5245 }
5246 if (aIsPreview == IsPreview::Yes) {
5247 return !hasPrintCallbacks;
5248 }
5249 return StaticPrefs::dom_window_print_fuzzing_block_while_printing();
5250 }();
5251
5252 if (shouldBlock) {
5253 SpinEventLoopUntil("nsGlobalWindowOuter::Print"_ns,
5254 [&] { return bc->IsDiscarded(); });
5255 }
5256
5257 return WindowProxyHolder(std::move(bc));
5258#else
5259 return nullptr;
5260#endif // NS_PRINTING
5261}
5262
5263void nsGlobalWindowOuter::MoveToOuter(int32_t aXPos, int32_t aYPos,
5264 CallerType aCallerType,
5265 ErrorResult& aError) {
5266 /*
5267 * If caller is not chrome and the user has not explicitly exempted the site,
5268 * prevent window.moveTo() by exiting early
5269 */
5270
5271 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5272 return;
5273 }
5274
5275 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5276 if (!treeOwnerAsWin) {
5277 aError.Throw(NS_ERROR_FAILURE);
5278 return;
5279 }
5280
5281 // We need to do the same transformation GetScreenXY does.
5282 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
5283 if (!presContext) {
5284 return;
5285 }
5286
5287 CSSIntPoint cssPos(aXPos, aYPos);
5288 CheckSecurityLeftAndTop(&cssPos.x.value, &cssPos.y.value, aCallerType);
5289
5290 nsDeviceContext* context = presContext->DeviceContext();
5291
5292 auto devPos = LayoutDeviceIntPoint::FromAppUnitsRounded(
5293 CSSIntPoint::ToAppUnits(cssPos), context->AppUnitsPerDevPixel());
5294
5295 aError = treeOwnerAsWin->SetPosition(devPos.x, devPos.y);
5296 CheckForDPIChange();
5297}
5298
5299void nsGlobalWindowOuter::MoveByOuter(int32_t aXDif, int32_t aYDif,
5300 CallerType aCallerType,
5301 ErrorResult& aError) {
5302 /*
5303 * If caller is not chrome and the user has not explicitly exempted the site,
5304 * prevent window.moveBy() by exiting early
5305 */
5306
5307 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5308 return;
5309 }
5310
5311 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5312 if (!treeOwnerAsWin) {
5313 aError.Throw(NS_ERROR_FAILURE);
5314 return;
5315 }
5316
5317 // To do this correctly we have to convert what we get from GetPosition
5318 // into CSS pixels, add the arguments, do the security check, and
5319 // then convert back to device pixels for the call to SetPosition.
5320
5321 int32_t x, y;
5322 aError = treeOwnerAsWin->GetPosition(&x, &y);
5323 if (aError.Failed()) {
5324 return;
5325 }
5326
5327 auto cssScale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
5328 CSSIntPoint cssPos = RoundedToInt(treeOwnerAsWin->GetPosition() / cssScale);
5329
5330 cssPos.x += aXDif;
5331 cssPos.y += aYDif;
5332
5333 CheckSecurityLeftAndTop(&cssPos.x.value, &cssPos.y.value, aCallerType);
5334
5335 LayoutDeviceIntPoint newDevPos = RoundedToInt(cssPos * cssScale);
5336 aError = treeOwnerAsWin->SetPosition(newDevPos.x, newDevPos.y);
5337
5338 CheckForDPIChange();
5339}
5340
5341nsresult nsGlobalWindowOuter::MoveBy(int32_t aXDif, int32_t aYDif) {
5342 ErrorResult rv;
5343 MoveByOuter(aXDif, aYDif, CallerType::System, rv);
5344
5345 return rv.StealNSResult();
5346}
5347
5348void nsGlobalWindowOuter::ResizeToOuter(int32_t aWidth, int32_t aHeight,
5349 CallerType aCallerType,
5350 ErrorResult& aError) {
5351 /*
5352 * If caller is not chrome and the user has not explicitly exempted the site,
5353 * prevent window.resizeTo() by exiting early
5354 */
5355
5356 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5357 return;
5358 }
5359
5360 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5361 if (!treeOwnerAsWin) {
5362 aError.Throw(NS_ERROR_FAILURE);
5363 return;
5364 }
5365
5366 CSSIntSize cssSize(aWidth, aHeight);
5367 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5368
5369 LayoutDeviceIntSize devSize =
5370 RoundedToInt(cssSize * CSSToDevScaleForBaseWindow(treeOwnerAsWin));
5371 aError = treeOwnerAsWin->SetSize(devSize.width, devSize.height, true);
5372
5373 CheckForDPIChange();
5374}
5375
5376void nsGlobalWindowOuter::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif,
5377 CallerType aCallerType,
5378 ErrorResult& aError) {
5379 /*
5380 * If caller is not chrome and the user has not explicitly exempted the site,
5381 * prevent window.resizeBy() by exiting early
5382 */
5383
5384 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5385 return;
5386 }
5387
5388 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
5389 if (!treeOwnerAsWin) {
5390 aError.Throw(NS_ERROR_FAILURE);
5391 return;
5392 }
5393
5394 LayoutDeviceIntSize size = treeOwnerAsWin->GetSize();
5395
5396 // To do this correctly we have to convert what we got from GetSize
5397 // into CSS pixels, add the arguments, do the security check, and
5398 // then convert back to device pixels for the call to SetSize.
5399
5400 auto scale = CSSToDevScaleForBaseWindow(treeOwnerAsWin);
5401 CSSIntSize cssSize = RoundedToInt(size / scale);
5402
5403 cssSize.width += aWidthDif;
5404 cssSize.height += aHeightDif;
5405
5406 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5407
5408 LayoutDeviceIntSize newDevSize = RoundedToInt(cssSize * scale);
5409
5410 aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true);
5411
5412 CheckForDPIChange();
5413}
5414
5415void nsGlobalWindowOuter::SizeToContentOuter(
5416 CallerType aCallerType, const SizeToContentConstraints& aConstraints,
5417 ErrorResult& aError) {
5418 if (!mDocShell) {
5419 return;
5420 }
5421
5422 /*
5423 * If caller is not chrome and the user has not explicitly exempted the site,
5424 * prevent window.sizeToContent() by exiting early
5425 */
5426
5427 if (!CanMoveResizeWindows(aCallerType) || mBrowsingContext->IsSubframe()) {
5428 return;
5429 }
5430
5431 // The content viewer does a check to make sure that it's a content
5432 // viewer for a toplevel docshell.
5433 nsCOMPtr<nsIDocumentViewer> viewer;
5434 mDocShell->GetDocViewer(getter_AddRefs(viewer));
5435 if (!viewer) {
5436 return aError.Throw(NS_ERROR_FAILURE);
5437 }
5438
5439 auto contentSize = viewer->GetContentSize(
5440 aConstraints.mMaxWidth, aConstraints.mMaxHeight, aConstraints.mPrefWidth);
5441 if (!contentSize) {
5442 return aError.Throw(NS_ERROR_FAILURE);
5443 }
5444
5445 // Make sure the new size is following the CheckSecurityWidthAndHeight
5446 // rules.
5447 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
5448 if (!treeOwner) {
5449 return aError.Throw(NS_ERROR_FAILURE);
5450 }
5451
5452 // Don't use DevToCSSIntPixelsForBaseWindow() nor
5453 // CSSToDevIntPixelsForBaseWindow() here because contentSize is comes from
5454 // nsIDocumentViewer::GetContentSize() and it's computed with nsPresContext so
5455 // that we need to work with nsPresContext here too.
5456 RefPtr<nsPresContext> presContext = viewer->GetPresContext();
5457 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"
, 5459); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5459; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5458 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"
, 5459); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5459; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5459 "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"
, 5459); AnnotateMozCrashReason("MOZ_ASSERT" "(" "presContext"
") (" "Should be non-nullptr if nsIDocumentViewer::GetContentSize() succeeded"
")"); do { *((volatile int*)__null) = 5459; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5460 CSSIntSize cssSize = *contentSize;
5461 CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerType);
5462
5463 LayoutDeviceIntSize newDevSize(
5464 presContext->CSSPixelsToDevPixels(cssSize.width),
5465 presContext->CSSPixelsToDevPixels(cssSize.height));
5466
5467 nsCOMPtr<nsIDocShell> docShell = mDocShell;
5468 aError =
5469 treeOwner->SizeShellTo(docShell, newDevSize.width, newDevSize.height);
5470}
5471
5472already_AddRefed<nsPIWindowRoot> nsGlobalWindowOuter::GetTopWindowRoot() {
5473 nsPIDOMWindowOuter* piWin = GetPrivateRoot();
5474 if (!piWin) {
5475 return nullptr;
5476 }
5477
5478 nsCOMPtr<nsPIWindowRoot> window =
5479 do_QueryInterface(piWin->GetChromeEventHandler());
5480 return window.forget();
5481}
5482
5483void nsGlobalWindowOuter::FirePopupBlockedEvent(
5484 Document* aDoc, nsIURI* aPopupURI, const nsAString& aPopupWindowName,
5485 const nsAString& aPopupWindowFeatures) {
5486 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"
, 5486); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDoc" ")");
do { *((volatile int*)__null) = 5486; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5487
5488 // Fire a "DOMPopupBlocked" event so that the UI can hear about
5489 // blocked popups.
5490 PopupBlockedEventInit init;
5491 init.mBubbles = true;
5492 init.mCancelable = true;
5493 // XXX: This is a different object, but webidl requires an inner window here
5494 // now.
5495 init.mRequestingWindow = GetCurrentInnerWindowInternal(this);
5496 init.mPopupWindowURI = aPopupURI;
5497 init.mPopupWindowName = aPopupWindowName;
5498 init.mPopupWindowFeatures = aPopupWindowFeatures;
5499
5500 RefPtr<PopupBlockedEvent> event =
5501 PopupBlockedEvent::Constructor(aDoc, u"DOMPopupBlocked"_ns, init);
5502
5503 event->SetTrusted(true);
5504
5505 aDoc->DispatchEvent(*event);
5506}
5507
5508// static
5509bool nsGlobalWindowOuter::CanSetProperty(const char* aPrefName) {
5510 // Chrome can set any property.
5511 if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
5512 return true;
5513 }
5514
5515 // If the pref is set to true, we can not set the property
5516 // and vice versa.
5517 return !Preferences::GetBool(aPrefName, true);
5518}
5519
5520/* If a window open is blocked, fire the appropriate DOM events. */
5521void nsGlobalWindowOuter::FireAbuseEvents(
5522 const nsAString& aPopupURL, const nsAString& aPopupWindowName,
5523 const nsAString& aPopupWindowFeatures) {
5524 // fetch the URI of the window requesting the opened window
5525 nsCOMPtr<Document> currentDoc = GetDoc();
5526 nsCOMPtr<nsIURI> popupURI;
5527
5528 // build the URI of the would-have-been popup window
5529 // (see nsWindowWatcher::URIfromURL)
5530
5531 // first, fetch the opener's base URI
5532
5533 nsIURI* baseURL = nullptr;
5534
5535 nsCOMPtr<Document> doc = GetEntryDocument();
5536 if (doc) baseURL = doc->GetDocBaseURI();
5537
5538 // use the base URI to build what would have been the popup's URI
5539 nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID"@mozilla.org/network/io-service;1"));
5540 if (ios)
5541 ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), nullptr, baseURL,
5542 getter_AddRefs(popupURI));
5543
5544 // fire an event block full of informative URIs
5545 FirePopupBlockedEvent(currentDoc, popupURI, aPopupWindowName,
5546 aPopupWindowFeatures);
5547}
5548
5549Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenOuter(
5550 const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
5551 ErrorResult& aError) {
5552 RefPtr<BrowsingContext> bc;
5553 nsresult rv = OpenJS(aUrl, aName, aOptions, getter_AddRefs(bc));
5554 if (rv == NS_ERROR_MALFORMED_URI) {
5555 aError.ThrowSyntaxError("Unable to open a window with invalid URL '"_ns +
5556 NS_ConvertUTF16toUTF8(aUrl) + "'."_ns);
5557 return nullptr;
5558 }
5559
5560 // XXX Is it possible that some internal errors are thrown here?
5561 aError = rv;
5562
5563 if (!bc) {
5564 return nullptr;
5565 }
5566 return WindowProxyHolder(std::move(bc));
5567}
5568
5569nsresult nsGlobalWindowOuter::Open(const nsAString& aUrl,
5570 const nsAString& aName,
5571 const nsAString& aOptions,
5572 nsDocShellLoadState* aLoadState,
5573 bool aForceNoOpener,
5574 BrowsingContext** _retval) {
5575 return OpenInternal(aUrl, aName, aOptions,
5576 false, // aDialog
5577 false, // aContentModal
5578 true, // aCalledNoScript
5579 false, // aDoJSFixups
5580 true, // aNavigate
5581 nullptr, nullptr, // No args
5582 aLoadState, aForceNoOpener, PrintKind::None, _retval);
5583}
5584
5585nsresult nsGlobalWindowOuter::OpenJS(const nsAString& aUrl,
5586 const nsAString& aName,
5587 const nsAString& aOptions,
5588 BrowsingContext** _retval) {
5589 return OpenInternal(aUrl, aName, aOptions,
5590 false, // aDialog
5591 false, // aContentModal
5592 false, // aCalledNoScript
5593 true, // aDoJSFixups
5594 true, // aNavigate
5595 nullptr, nullptr, // No args
5596 nullptr, // aLoadState
5597 false, // aForceNoOpener
5598 PrintKind::None, _retval);
5599}
5600
5601// like Open, but attaches to the new window any extra parameters past
5602// [features] as a JS property named "arguments"
5603nsresult nsGlobalWindowOuter::OpenDialog(const nsAString& aUrl,
5604 const nsAString& aName,
5605 const nsAString& aOptions,
5606 nsISupports* aExtraArgument,
5607 BrowsingContext** _retval) {
5608 return OpenInternal(aUrl, aName, aOptions,
5609 true, // aDialog
5610 false, // aContentModal
5611 true, // aCalledNoScript
5612 false, // aDoJSFixups
5613 true, // aNavigate
5614 nullptr, aExtraArgument, // Arguments
5615 nullptr, // aLoadState
5616 false, // aForceNoOpener
5617 PrintKind::None, _retval);
5618}
5619
5620// Like Open, but passes aNavigate=false.
5621/* virtual */
5622nsresult nsGlobalWindowOuter::OpenNoNavigate(const nsAString& aUrl,
5623 const nsAString& aName,
5624 const nsAString& aOptions,
5625 BrowsingContext** _retval) {
5626 return OpenInternal(aUrl, aName, aOptions,
5627 false, // aDialog
5628 false, // aContentModal
5629 true, // aCalledNoScript
5630 false, // aDoJSFixups
5631 false, // aNavigate
5632 nullptr, nullptr, // No args
5633 nullptr, // aLoadState
5634 false, // aForceNoOpener
5635 PrintKind::None, _retval);
5636}
5637
5638Nullable<WindowProxyHolder> nsGlobalWindowOuter::OpenDialogOuter(
5639 JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
5640 const nsAString& aOptions, const Sequence<JS::Value>& aExtraArgument,
5641 ErrorResult& aError) {
5642 nsCOMPtr<nsIJSArgArray> argvArray;
5643 aError =
5644 NS_CreateJSArgv(aCx, aExtraArgument.Length(), aExtraArgument.Elements(),
5645 getter_AddRefs(argvArray));
5646 if (aError.Failed()) {
5647 return nullptr;
5648 }
5649
5650 RefPtr<BrowsingContext> dialog;
5651 aError = OpenInternal(aUrl, aName, aOptions,
5652 true, // aDialog
5653 false, // aContentModal
5654 false, // aCalledNoScript
5655 false, // aDoJSFixups
5656 true, // aNavigate
5657 argvArray, nullptr, // Arguments
5658 nullptr, // aLoadState
5659 false, // aForceNoOpener
5660 PrintKind::None, getter_AddRefs(dialog));
5661 if (!dialog) {
5662 return nullptr;
5663 }
5664 return WindowProxyHolder(std::move(dialog));
5665}
5666
5667WindowProxyHolder nsGlobalWindowOuter::GetFramesOuter() {
5668 RefPtr<nsPIDOMWindowOuter> frames(this);
5669 FlushPendingNotifications(FlushType::ContentAndNotify);
5670 return WindowProxyHolder(mBrowsingContext);
5671}
5672
5673/* static */
5674bool nsGlobalWindowOuter::GatherPostMessageData(
5675 JSContext* aCx, const nsAString& aTargetOrigin, BrowsingContext** aSource,
5676 nsAString& aOrigin, nsIURI** aTargetOriginURI,
5677 nsIPrincipal** aCallerPrincipal, nsGlobalWindowInner** aCallerInnerWindow,
5678 nsIURI** aCallerURI, Maybe<nsID>* aCallerAgentClusterId,
5679 nsACString* aScriptLocation, ErrorResult& aError) {
5680 //
5681 // Window.postMessage is an intentional subversion of the same-origin policy.
5682 // As such, this code must be particularly careful in the information it
5683 // exposes to calling code.
5684 //
5685 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5686 //
5687
5688 // First, get the caller's window
5689 RefPtr<nsGlobalWindowInner> callerInnerWin =
5690 nsContentUtils::IncumbentInnerWindow();
5691 nsIPrincipal* callerPrin;
5692 if (callerInnerWin) {
5693 RefPtr<Document> doc = callerInnerWin->GetExtantDoc();
5694 if (!doc) {
5695 return false;
5696 }
5697 NS_IF_ADDREF(*aCallerURI = doc->GetDocumentURI())ns_if_addref(*aCallerURI = doc->GetDocumentURI());
5698
5699 // Compute the caller's origin either from its principal or, in the case the
5700 // principal doesn't carry a URI (e.g. the system principal), the caller's
5701 // document. We must get this now instead of when the event is created and
5702 // dispatched, because ultimately it is the identity of the calling window
5703 // *now* that determines who sent the message (and not an identity which
5704 // might have changed due to intervening navigations).
5705 callerPrin = callerInnerWin->GetPrincipal();
5706 } else {
5707 // In case the global is not a window, it can be a sandbox, and the
5708 // sandbox's principal can be used for the security check.
5709 nsIGlobalObject* global = GetIncumbentGlobal();
5710 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"
, 5710); MOZ_PretendNoReturn(); } } while (0)
;
5711 callerPrin = global->PrincipalOrNull();
5712 if (callerPrin) {
5713 BasePrincipal::Cast(callerPrin)->GetScriptLocation(*aScriptLocation);
5714 }
5715 }
5716 if (!callerPrin) {
5717 return false;
5718 }
5719
5720 // if the principal has a URI, use that to generate the origin
5721 if (!callerPrin->IsSystemPrincipal()) {
5722 nsAutoCString webExposedOriginSerialization;
5723 callerPrin->GetWebExposedOriginSerialization(webExposedOriginSerialization);
5724 CopyUTF8toUTF16(webExposedOriginSerialization, aOrigin);
5725 } else if (callerInnerWin) {
5726 if (!*aCallerURI) {
5727 return false;
5728 }
5729 // otherwise use the URI of the document to generate origin
5730 nsContentUtils::GetWebExposedOriginSerialization(*aCallerURI, aOrigin);
5731 } else {
5732 // in case of a sandbox with a system principal origin can be empty
5733 if (!callerPrin->IsSystemPrincipal()) {
5734 return false;
5735 }
5736 }
5737 NS_IF_ADDREF(*aCallerPrincipal = callerPrin)ns_if_addref(*aCallerPrincipal = callerPrin);
5738
5739 // "/" indicates same origin as caller, "*" indicates no specific origin is
5740 // required.
5741 if (!aTargetOrigin.EqualsASCII("/") && !aTargetOrigin.EqualsASCII("*")) {
5742 nsCOMPtr<nsIURI> targetOriginURI;
5743 if (NS_FAILED(NS_NewURI(getter_AddRefs(targetOriginURI), aTargetOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(targetOriginURI), aTargetOrigin))), 0)))
) {
5744 aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
5745 return false;
5746 }
5747
5748 nsresult rv = NS_MutateURI(targetOriginURI)
5749 .SetUserPass(""_ns)
5750 .SetPathQueryRef(""_ns)
5751 .Finalize(aTargetOriginURI);
5752 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5753 return false;
5754 }
5755 }
5756
5757 if (!nsContentUtils::IsCallerChrome() && callerInnerWin &&
5758 callerInnerWin->GetOuterWindowInternal()) {
5759 NS_ADDREF(*aSource = callerInnerWin->GetOuterWindowInternal()(*aSource = callerInnerWin->GetOuterWindowInternal() ->
GetBrowsingContext())->AddRef()
5760 ->GetBrowsingContext())(*aSource = callerInnerWin->GetOuterWindowInternal() ->
GetBrowsingContext())->AddRef()
;
5761 } else {
5762 *aSource = nullptr;
5763 }
5764
5765 if (aCallerAgentClusterId && callerInnerWin &&
5766 callerInnerWin->GetDocGroup()) {
5767 *aCallerAgentClusterId =
5768 Some(callerInnerWin->GetDocGroup()->AgentClusterId());
5769 }
5770
5771 callerInnerWin.forget(aCallerInnerWindow);
5772
5773 return true;
5774}
5775
5776bool nsGlobalWindowOuter::GetPrincipalForPostMessage(
5777 const nsAString& aTargetOrigin, nsIURI* aTargetOriginURI,
5778 nsIPrincipal* aCallerPrincipal, nsIPrincipal& aSubjectPrincipal,
5779 nsIPrincipal** aProvidedPrincipal) {
5780 //
5781 // Window.postMessage is an intentional subversion of the same-origin policy.
5782 // As such, this code must be particularly careful in the information it
5783 // exposes to calling code.
5784 //
5785 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5786 //
5787
5788 // Convert the provided origin string into a URI for comparison purposes.
5789 nsCOMPtr<nsIPrincipal> providedPrincipal;
5790
5791 if (aTargetOrigin.EqualsASCII("/")) {
5792 providedPrincipal = aCallerPrincipal;
5793 }
5794 // "*" indicates no specific origin is required.
5795 else if (!aTargetOrigin.EqualsASCII("*")) {
5796 OriginAttributes attrs = aSubjectPrincipal.OriginAttributesRef();
5797 if (aSubjectPrincipal.IsSystemPrincipal()) {
5798 auto principal = BasePrincipal::Cast(GetPrincipal());
5799
5800 if (attrs != principal->OriginAttributesRef()) {
5801 nsAutoCString targetURL;
5802 nsAutoCString sourceOrigin;
5803 nsAutoCString targetOrigin;
5804
5805 if (NS_FAILED(principal->GetAsciiSpec(targetURL))((bool)(__builtin_expect(!!(NS_FAILED_impl(principal->GetAsciiSpec
(targetURL))), 0)))
||
5806 NS_FAILED(principal->GetOrigin(targetOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(principal->GetOrigin
(targetOrigin))), 0)))
||
5807 NS_FAILED(aSubjectPrincipal.GetOrigin(sourceOrigin))((bool)(__builtin_expect(!!(NS_FAILED_impl(aSubjectPrincipal.
GetOrigin(sourceOrigin))), 0)))
) {
5808 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"
, 5808)
;
5809 return false;
5810 }
5811
5812 nsContentUtils::LogSimpleConsoleError(
5813 NS_ConvertUTF8toUTF16(nsPrintfCString(
5814 R"(Attempting to post a message to window with url "%s" and )"
5815 R"(origin "%s" from a system principal scope with mismatched )"
5816 R"(origin "%s".)",
5817 targetURL.get(), targetOrigin.get(), sourceOrigin.get())),
5818 "DOM"_ns, !!principal->PrivateBrowsingId(),
5819 principal->IsSystemPrincipal());
5820
5821 attrs = principal->OriginAttributesRef();
5822 }
5823 }
5824
5825 // Create a nsIPrincipal inheriting the app/browser attributes from the
5826 // caller.
5827 providedPrincipal =
5828 BasePrincipal::CreateContentPrincipal(aTargetOriginURI, attrs);
5829 if (NS_WARN_IF(!providedPrincipal)NS_warn_if_impl(!providedPrincipal, "!providedPrincipal", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 5829)
) {
5830 return false;
5831 }
5832 } else {
5833 // We still need to check the originAttributes if the target origin is '*'.
5834 // But we will ingore the FPD here since the FPDs are possible to be
5835 // different.
5836 auto principal = BasePrincipal::Cast(GetPrincipal());
5837 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"
, 5837); return false; } } while (false)
;
5838
5839 OriginAttributes targetAttrs = principal->OriginAttributesRef();
5840 OriginAttributes sourceAttrs = aSubjectPrincipal.OriginAttributesRef();
5841 // We have to exempt the check of OA if the subject prioncipal is a system
5842 // principal since there are many tests try to post messages to content from
5843 // chrome with a mismatch OA. For example, using the ContentTask.spawn() to
5844 // post a message into a private browsing window. The injected code in
5845 // ContentTask.spawn() will be executed under the system principal and the
5846 // OA of the system principal mismatches with the OA of a private browsing
5847 // window.
5848 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"
, 5849); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
")"); do { *((volatile int*)__null) = 5849; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5849 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"
, 5849); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSubjectPrincipal.IsSystemPrincipal() || sourceAttrs.EqualsIgnoringFPD(targetAttrs)"
")"); do { *((volatile int*)__null) = 5849; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5850
5851 // If 'privacy.firstparty.isolate.block_post_message' is true, we will block
5852 // postMessage across different first party domains.
5853 if (OriginAttributes::IsBlockPostMessageForFPI() &&
5854 !aSubjectPrincipal.IsSystemPrincipal() &&
5855 sourceAttrs.mFirstPartyDomain != targetAttrs.mFirstPartyDomain) {
5856 return false;
5857 }
5858 }
5859
5860 providedPrincipal.forget(aProvidedPrincipal);
5861 return true;
5862}
5863
5864void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
5865 JS::Handle<JS::Value> aMessage,
5866 const nsAString& aTargetOrigin,
5867 JS::Handle<JS::Value> aTransfer,
5868 nsIPrincipal& aSubjectPrincipal,
5869 ErrorResult& aError) {
5870 RefPtr<BrowsingContext> sourceBc;
5871 nsAutoString origin;
5872 nsCOMPtr<nsIURI> targetOriginURI;
5873 nsCOMPtr<nsIPrincipal> callerPrincipal;
5874 RefPtr<nsGlobalWindowInner> callerInnerWindow;
5875 nsCOMPtr<nsIURI> callerURI;
5876 Maybe<nsID> callerAgentClusterId = Nothing();
5877 nsAutoCString scriptLocation;
5878 if (!GatherPostMessageData(
5879 aCx, aTargetOrigin, getter_AddRefs(sourceBc), origin,
5880 getter_AddRefs(targetOriginURI), getter_AddRefs(callerPrincipal),
5881 getter_AddRefs(callerInnerWindow), getter_AddRefs(callerURI),
5882 &callerAgentClusterId, &scriptLocation, aError)) {
5883 return;
5884 }
5885
5886 nsCOMPtr<nsIPrincipal> providedPrincipal;
5887 if (!GetPrincipalForPostMessage(aTargetOrigin, targetOriginURI,
5888 callerPrincipal, aSubjectPrincipal,
5889 getter_AddRefs(providedPrincipal))) {
5890 return;
5891 }
5892
5893 // Create and asynchronously dispatch a runnable which will handle actual DOM
5894 // event creation and dispatch.
5895 RefPtr<PostMessageEvent> event = new PostMessageEvent(
5896 sourceBc, origin, this, providedPrincipal,
5897 callerInnerWindow ? callerInnerWindow->WindowID() : 0, callerURI,
5898 scriptLocation, callerAgentClusterId);
5899
5900 JS::CloneDataPolicy clonePolicy;
5901
5902 if (GetDocGroup() && callerAgentClusterId.isSome() &&
5903 GetDocGroup()->AgentClusterId().Equals(callerAgentClusterId.value())) {
5904 clonePolicy.allowIntraClusterClonableSharedObjects();
5905 }
5906
5907 if (callerInnerWindow && callerInnerWindow->IsSharedMemoryAllowed()) {
5908 clonePolicy.allowSharedMemoryObjects();
5909 }
5910
5911 event->Write(aCx, aMessage, aTransfer, clonePolicy, aError);
5912 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"
, 5912)
) {
5913 return;
5914 }
5915
5916 event->DispatchToTargetThread(aError);
5917}
5918
5919class nsCloseEvent : public Runnable {
5920 RefPtr<nsGlobalWindowOuter> mWindow;
5921 bool mIndirect;
5922
5923 nsCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect)
5924 : mozilla::Runnable("nsCloseEvent"),
5925 mWindow(aWindow),
5926 mIndirect(aIndirect) {}
5927
5928 public:
5929 static nsresult PostCloseEvent(nsGlobalWindowOuter* aWindow, bool aIndirect) {
5930 nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
5931 return aWindow->Dispatch(ev.forget());
5932 }
5933
5934 NS_IMETHODvirtual nsresult Run() override {
5935 if (mWindow) {
5936 if (mIndirect) {
5937 return PostCloseEvent(mWindow, false);
5938 }
5939 mWindow->ReallyCloseWindow();
5940 }
5941 return NS_OK;
5942 }
5943};
5944
5945bool nsGlobalWindowOuter::CanClose() {
5946 if (mIsChrome) {
5947 nsCOMPtr<nsIBrowserDOMWindow> bwin = GetBrowserDOMWindow();
5948
5949 bool canClose = true;
5950 if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))((bool)(__builtin_expect(!!(!NS_FAILED_impl(bwin->CanClose
(&canClose))), 1)))
) {
5951 return canClose;
5952 }
5953 }
5954
5955 if (!mDocShell) {
5956 return true;
5957 }
5958
5959 nsCOMPtr<nsIDocumentViewer> viewer;
5960 mDocShell->GetDocViewer(getter_AddRefs(viewer));
5961 if (viewer) {
5962 bool canClose;
5963 nsresult rv = viewer->PermitUnload(&canClose);
5964 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !canClose) return false;
5965 }
5966
5967 // If we still have to print, we delay the closing until print has happened.
5968 if (mShouldDelayPrintUntilAfterLoad && mDelayedPrintUntilAfterLoad) {
5969 mDelayedCloseForPrinting = true;
5970 return false;
5971 }
5972
5973 return true;
5974}
5975
5976void nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller) {
5977 if (!mDocShell || IsInModalState() || mBrowsingContext->IsSubframe()) {
5978 // window.close() is called on a frame in a frameset, on a window
5979 // that's already closed, or on a window for which there's
5980 // currently a modal dialog open. Ignore such calls.
5981 return;
5982 }
5983
5984 if (mHavePendingClose) {
5985 // We're going to be closed anyway; do nothing since we don't want
5986 // to double-close
5987 return;
5988 }
5989
5990 if (mBlockScriptedClosingFlag) {
5991 // A script's popup has been blocked and we don't want
5992 // the window to be closed directly after this event,
5993 // so the user can see that there was a blocked popup.
5994 return;
5995 }
5996
5997 // Don't allow scripts from content to close non-neterror windows that
5998 // were not opened by script.
5999 if (mDoc) {
6000 nsAutoString url;
6001 nsresult rv = mDoc->GetURL(url);
6002 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"
, 6002); return; } } while (false)
;
6003
6004 if (!StringBeginsWith(url, u"about:neterror"_ns) &&
6005 !mBrowsingContext->GetTopLevelCreatedByWebContent() &&
6006 !aTrustedCaller && !IsOnlyTopLevelDocumentInSHistory()) {
6007 bool allowClose =
6008 mAllowScriptsToClose ||
6009 Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
6010 if (!allowClose) {
6011 // We're blocking the close operation
6012 // report localized error msg in JS console
6013 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
6014 "DOM Window"_ns,
6015 mDoc, // Better name for the category?
6016 nsContentUtils::eDOM_PROPERTIES,
6017 "WindowCloseByScriptBlockedWarning");
6018
6019 return;
6020 }
6021 }
6022 }
6023
6024 if (!mInClose && !mIsClosed && !CanClose()) {
6025 return;
6026 }
6027
6028 // Fire a DOM event notifying listeners that this window is about to
6029 // be closed. The tab UI code may choose to cancel the default
6030 // action for this event, if so, we won't actually close the window
6031 // (since the tab UI code will close the tab in stead). Sure, this
6032 // could be abused by content code, but do we care? I don't think
6033 // so...
6034
6035 bool wasInClose = mInClose;
6036 mInClose = true;
6037
6038 if (!DispatchCustomEvent(u"DOMWindowClose"_ns, ChromeOnlyDispatch::eYes)) {
6039 // Someone chose to prevent the default action for this event, if
6040 // so, let's not close this window after all...
6041
6042 mInClose = wasInClose;
6043 return;
6044 }
6045
6046 FinalClose();
6047}
6048
6049bool nsGlobalWindowOuter::IsOnlyTopLevelDocumentInSHistory() {
6050 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"
, 6050); return false; } } while (false)
;
6051 // Disabled since IsFrame() is buggy in Fission
6052 // MOZ_ASSERT(mBrowsingContext->IsTop());
6053
6054 if (mozilla::SessionHistoryInParent()) {
6055 return mBrowsingContext->GetIsSingleToplevelInHistory();
6056 }
6057
6058 RefPtr<ChildSHistory> csh = nsDocShell::Cast(mDocShell)->GetSessionHistory();
6059 if (csh && csh->LegacySHistory()) {
6060 return csh->LegacySHistory()->IsEmptyOrHasEntriesForSingleTopLevelPage();
6061 }
6062
6063 return false;
6064}
6065
6066nsresult nsGlobalWindowOuter::Close() {
6067 CloseOuter(/* aTrustedCaller = */ true);
6068 return NS_OK;
6069}
6070
6071void nsGlobalWindowOuter::ForceClose() {
6072 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"
, 6072); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_GetProcessType() == GeckoProcessType_Default"
")"); do { *((volatile int*)__null) = 6072; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6073
6074 if (mBrowsingContext->IsSubframe() || !mDocShell) {
6075 // This may be a frame in a frameset, or a window that's already closed.
6076 // Ignore such calls.
6077 return;
6078 }
6079
6080 if (mHavePendingClose) {
6081 // We're going to be closed anyway; do nothing since we don't want
6082 // to double-close
6083 return;
6084 }
6085
6086 mInClose = true;
6087
6088 DispatchCustomEvent(u"DOMWindowClose"_ns, ChromeOnlyDispatch::eYes);
6089
6090 FinalClose();
6091}
6092
6093void nsGlobalWindowOuter::FinalClose() {
6094 // Flag that we were closed.
6095 mIsClosed = true;
6096
6097 if (!mBrowsingContext->IsDiscarded()) {
6098 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"
, 6098); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(mBrowsingContext->SetClosed(true))" ")"
); do { *((volatile int*)__null) = 6098; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6099 }
6100
6101 // If we get here from CloseOuter then it means that the parent process is
6102 // going to close our window for us. It's just important to set mIsClosed.
6103 if (XRE_GetProcessType() == GeckoProcessType_Content) {
6104 return;
6105 }
6106
6107 // This stuff is non-sensical but incredibly fragile. The reasons for the
6108 // behavior here don't make sense today and may not have ever made sense,
6109 // but various bits of frontend code break when you change them. If you need
6110 // to fix up this behavior, feel free to. It's a righteous task, but involves
6111 // wrestling with various download manager tests, frontend code, and possible
6112 // broken addons. The chrome tests in toolkit/mozapps/downloads are a good
6113 // testing ground.
6114 //
6115 // In particular, if some inner of |win| is the entry global, we must
6116 // complete _two_ round-trips to the event loop before the call to
6117 // ReallyCloseWindow. This allows setTimeout handlers that are set after
6118 // FinalClose() is called to run before the window is torn down.
6119 nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6120 do_QueryInterface(GetEntryGlobal());
6121 bool indirect = entryWindow && entryWindow->GetOuterWindow() == this;
6122 if (NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsCloseEvent::PostCloseEvent
(this, indirect))), 0)))
) {
6123 ReallyCloseWindow();
6124 } else {
6125 mHavePendingClose = true;
6126 }
6127}
6128
6129void nsGlobalWindowOuter::ReallyCloseWindow() {
6130 // Make sure we never reenter this method.
6131 mHavePendingClose = true;
6132
6133 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
6134 if (!treeOwnerAsWin) {
6135 return;
6136 }
6137
6138 treeOwnerAsWin->Destroy();
6139 CleanUp();
6140}
6141
6142void nsGlobalWindowOuter::SuppressEventHandling() {
6143 if (mSuppressEventHandlingDepth == 0) {
6144 if (BrowsingContext* bc = GetBrowsingContext()) {
6145 bc->PreOrderWalk([&](BrowsingContext* aBC) {
6146 if (nsCOMPtr<nsPIDOMWindowOuter> win = aBC->GetDOMWindow()) {
6147 if (RefPtr<Document> doc = win->GetExtantDoc()) {
6148 mSuspendedDocs.AppendElement(doc);
6149 // Note: Document::SuppressEventHandling will also automatically
6150 // suppress event handling for any in-process sub-documents.
6151 // However, since we need to deal with cases where remote
6152 // BrowsingContexts may be interleaved with in-process ones, we
6153 // still need to walk the entire tree ourselves. This may be
6154 // slightly redundant in some cases, but since event handling
6155 // suppressions maintain a count of current blockers, it does not
6156 // cause any problems.
6157 doc->SuppressEventHandling();
6158 }
6159 }
6160 });
6161 }
6162 }
6163 mSuppressEventHandlingDepth++;
6164}
6165
6166void nsGlobalWindowOuter::UnsuppressEventHandling() {
6167 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"
, 6167); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSuppressEventHandlingDepth != 0"
")"); do { *((volatile int*)__null) = 6167; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6168 mSuppressEventHandlingDepth--;
6169
6170 if (mSuppressEventHandlingDepth == 0 && mSuspendedDocs.Length()) {
6171 RefPtr<Document> currentDoc = GetExtantDoc();
6172 bool fireEvent = currentDoc == mSuspendedDocs[0];
6173 nsTArray<RefPtr<Document>> suspendedDocs = std::move(mSuspendedDocs);
6174 for (const auto& doc : suspendedDocs) {
6175 doc->UnsuppressEventHandlingAndFireEvents(fireEvent);
6176 }
6177 }
6178}
6179
6180nsGlobalWindowOuter* nsGlobalWindowOuter::EnterModalState() {
6181 // GetInProcessScriptableTop, not GetInProcessTop, so that EnterModalState
6182 // works properly with <iframe mozbrowser>.
6183 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6184
6185 if (!topWin) {
6186 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"
, 6186); MOZ_PretendNoReturn(); } while (0)
;
6187 return nullptr;
6188 }
6189
6190 // If there is an active ESM in this window, clear it. Otherwise, this can
6191 // cause a problem if a modal state is entered during a mouseup event.
6192 EventStateManager* activeESM = static_cast<EventStateManager*>(
6193 EventStateManager::GetActiveEventStateManager());
6194 if (activeESM && activeESM->GetPresContext()) {
6195 PresShell* activePresShell = activeESM->GetPresContext()->GetPresShell();
6196 if (activePresShell && (nsContentUtils::ContentIsCrossDocDescendantOf(
6197 activePresShell->GetDocument(), mDoc) ||
6198 nsContentUtils::ContentIsCrossDocDescendantOf(
6199 mDoc, activePresShell->GetDocument()))) {
6200 EventStateManager::ClearGlobalActiveContent(activeESM);
6201
6202 PresShell::ReleaseCapturingContent();
6203
6204 if (activePresShell) {
6205 RefPtr<nsFrameSelection> frameSelection =
6206 activePresShell->FrameSelection();
6207 frameSelection->SetDragState(false);
6208 }
6209 }
6210 }
6211
6212 // If there are any drag and drop operations in flight, try to end them.
6213 nsCOMPtr<nsIDragService> ds =
6214 do_GetService("@mozilla.org/widget/dragservice;1");
6215 if (ds && topWin->GetDocShell()) {
6216 if (PresShell* presShell = topWin->GetDocShell()->GetPresShell()) {
6217 if (nsViewManager* vm = presShell->GetViewManager()) {
6218 RefPtr<nsIWidget> widget = vm->GetRootWidget();
6219 if (nsCOMPtr<nsIDragSession> session = ds->GetCurrentSession(widget)) {
6220 session->EndDragSession(true, 0);
6221 }
6222 }
6223 }
6224 }
6225
6226 // Clear the capturing content if it is under topDoc.
6227 // Usually the activeESM check above does that, but there are cases when
6228 // we don't have activeESM, or it is for different document.
6229 Document* topDoc = topWin->GetExtantDoc();
6230 nsIContent* capturingContent = PresShell::GetCapturingContent();
6231 if (capturingContent && topDoc &&
6232 nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent, topDoc)) {
6233 PresShell::ReleaseCapturingContent();
6234 }
6235
6236 if (topWin->mModalStateDepth == 0) {
6237 topWin->SuppressEventHandling();
6238
6239 if (nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(topWin)) {
6240 inner->Suspend();
6241 }
6242 }
6243 topWin->mModalStateDepth++;
6244 return topWin;
6245}
6246
6247void nsGlobalWindowOuter::LeaveModalState() {
6248 {
6249 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6250 if (!topWin) {
6251 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"
, 6251)
;
6252 return;
6253 }
6254
6255 if (topWin != this) {
6256 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"
, 6256); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSuspended()"
")"); do { *((volatile int*)__null) = 6256; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6257 return topWin->LeaveModalState();
6258 }
6259 }
6260
6261 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"
, 6261); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mModalStateDepth != 0"
")"); do { *((volatile int*)__null) = 6261; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6262 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"
, 6262); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsSuspended()"
")"); do { *((volatile int*)__null) = 6262; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6263 mModalStateDepth--;
6264
6265 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6266 if (mModalStateDepth == 0) {
6267 if (inner) {
6268 inner->Resume();
6269 }
6270
6271 UnsuppressEventHandling();
6272 }
6273
6274 // Remember the time of the last dialog quit.
6275 if (auto* bcg = GetBrowsingContextGroup()) {
6276 bcg->SetLastDialogQuitTime(TimeStamp::Now());
6277 }
6278
6279 if (mModalStateDepth == 0) {
6280 RefPtr<Event> event = NS_NewDOMEvent(inner, nullptr, nullptr);
6281 event->InitEvent(u"endmodalstate"_ns, true, false);
6282 event->SetTrusted(true);
6283 event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
6284 DispatchEvent(*event);
6285 }
6286}
6287
6288bool nsGlobalWindowOuter::IsInModalState() {
6289 nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
6290
6291 if (!topWin) {
6292 // IsInModalState() getting called w/o a reachable top window is a bit
6293 // iffy, but valid enough not to make noise about it. See bug 404828
6294 return false;
6295 }
6296
6297 return topWin->mModalStateDepth != 0;
6298}
6299
6300void nsGlobalWindowOuter::NotifyWindowIDDestroyed(const char* aTopic) {
6301 nsCOMPtr<nsIRunnable> runnable =
6302 new WindowDestroyedEvent(this, mWindowID, aTopic);
6303 Dispatch(runnable.forget());
6304}
6305
6306Element* nsGlobalWindowOuter::GetFrameElement(nsIPrincipal& aSubjectPrincipal) {
6307 // Per HTML5, the frameElement getter returns null in cross-origin situations.
6308 Element* element = GetFrameElement();
6309 if (!element) {
6310 return nullptr;
6311 }
6312
6313 if (!aSubjectPrincipal.SubsumesConsideringDomain(element->NodePrincipal())) {
6314 return nullptr;
6315 }
6316
6317 return element;
6318}
6319
6320Element* nsGlobalWindowOuter::GetFrameElement() {
6321 if (!mBrowsingContext || mBrowsingContext->IsTop()) {
6322 return nullptr;
6323 }
6324 return mBrowsingContext->GetEmbedderElement();
6325}
6326
6327namespace {
6328class ChildCommandDispatcher : public Runnable {
6329 public:
6330 ChildCommandDispatcher(nsPIWindowRoot* aRoot, nsIBrowserChild* aBrowserChild,
6331 nsPIDOMWindowOuter* aWindow, const nsAString& aAction)
6332 : mozilla::Runnable("ChildCommandDispatcher"),
6333 mRoot(aRoot),
6334 mBrowserChild(aBrowserChild),
6335 mWindow(aWindow),
6336 mAction(aAction) {}
6337
6338 NS_IMETHODvirtual nsresult Run() override {
6339 AutoTArray<nsCString, 70> enabledCommands, disabledCommands;
6340 mRoot->GetEnabledDisabledCommands(enabledCommands, disabledCommands);
6341 if (enabledCommands.Length() || disabledCommands.Length()) {
6342 BrowserChild* bc = static_cast<BrowserChild*>(mBrowserChild.get());
6343 bc->SendEnableDisableCommands(mWindow->GetBrowsingContext(), mAction,
6344 enabledCommands, disabledCommands);
6345 }
6346
6347 return NS_OK;
6348 }
6349
6350 private:
6351 nsCOMPtr<nsPIWindowRoot> mRoot;
6352 nsCOMPtr<nsIBrowserChild> mBrowserChild;
6353 nsCOMPtr<nsPIDOMWindowOuter> mWindow;
6354 nsString mAction;
6355};
6356
6357class CommandDispatcher : public Runnable {
6358 public:
6359 CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
6360 const nsAString& aAction)
6361 : mozilla::Runnable("CommandDispatcher"),
6362 mDispatcher(aDispatcher),
6363 mAction(aAction) {}
6364
6365 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230, bug 1535398)
6366 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODvirtual nsresult Run() override {
6367 return mDispatcher->UpdateCommands(mAction);
6368 }
6369
6370 const nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
6371 nsString mAction;
6372};
6373} // anonymous namespace
6374
6375void nsGlobalWindowOuter::UpdateCommands(const nsAString& anAction) {
6376 // If this is a child process, redirect to the parent process.
6377 if (nsIDocShell* docShell = GetDocShell()) {
6378 if (nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild()) {
6379 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
6380 if (root) {
6381 nsContentUtils::AddScriptRunner(
6382 new ChildCommandDispatcher(root, child, this, anAction));
6383 }
6384 return;
6385 }
6386 }
6387
6388 nsPIDOMWindowOuter* rootWindow = GetPrivateRoot();
6389 if (!rootWindow) {
6390 return;
6391 }
6392
6393 Document* doc = rootWindow->GetExtantDoc();
6394
6395 if (!doc) {
6396 return;
6397 }
6398
6399 // Retrieve the command dispatcher and call updateCommands on it.
6400 nsIDOMXULCommandDispatcher* xulCommandDispatcher =
6401 doc->GetCommandDispatcher();
6402 if (xulCommandDispatcher) {
6403 nsContentUtils::AddScriptRunner(
6404 new CommandDispatcher(xulCommandDispatcher, anAction));
6405 }
6406}
6407
6408Selection* nsGlobalWindowOuter::GetSelectionOuter() {
6409 if (!mDocShell) {
6410 return nullptr;
6411 }
6412
6413 PresShell* presShell = mDocShell->GetPresShell();
6414 if (!presShell) {
6415 return nullptr;
6416 }
6417 return presShell->GetCurrentSelection(SelectionType::eNormal);
6418}
6419
6420already_AddRefed<Selection> nsGlobalWindowOuter::GetSelection() {
6421 RefPtr<Selection> selection = GetSelectionOuter();
6422 return selection.forget();
6423}
6424
6425bool nsGlobalWindowOuter::FindOuter(const nsAString& aString,
6426 bool aCaseSensitive, bool aBackwards,
6427 bool aWrapAround, bool aWholeWord,
6428 bool aSearchInFrames, bool aShowDialog,
6429 ErrorResult& aError) {
6430 Unused << aShowDialog;
6431
6432 nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
6433 if (!finder) {
6434 aError.Throw(NS_ERROR_NOT_AVAILABLE);
6435 return false;
6436 }
6437
6438 // Set the options of the search
6439 aError = finder->SetSearchString(aString);
6440 if (aError.Failed()) {
6441 return false;
6442 }
6443 finder->SetMatchCase(aCaseSensitive);
6444 finder->SetFindBackwards(aBackwards);
6445 finder->SetWrapFind(aWrapAround);
6446 finder->SetEntireWord(aWholeWord);
6447 finder->SetSearchFrames(aSearchInFrames);
6448
6449 // the nsIWebBrowserFind is initialized to use this window
6450 // as the search root, but uses focus to set the current search
6451 // frame. If we're being called from JS (as here), this window
6452 // should be the current search frame.
6453 nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
6454 if (framesFinder) {
6455 framesFinder->SetRootSearchFrame(this); // paranoia
6456 framesFinder->SetCurrentSearchFrame(this);
6457 }
6458
6459 if (aString.IsEmpty()) {
6460 return false;
6461 }
6462
6463 // Launch the search with the passed in search string
6464 bool didFind = false;
6465 aError = finder->FindNext(&didFind);
6466 return didFind;
6467}
6468
6469//*****************************************************************************
6470// EventTarget
6471//*****************************************************************************
6472
6473nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOwnerGlobalForBindingsInternal() {
6474 return this;
6475}
6476
6477nsIGlobalObject* nsGlobalWindowOuter::GetOwnerGlobal() const {
6478 return GetCurrentInnerWindowInternal(this);
6479}
6480
6481bool nsGlobalWindowOuter::DispatchEvent(Event& aEvent, CallerType aCallerType,
6482 ErrorResult& aRv) {
6483 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"
, 6483); return false; } return GetCurrentInnerWindowInternal
(this)->DispatchEvent (aEvent, aCallerType, aRv); } while (
0)
;
6484}
6485
6486bool nsGlobalWindowOuter::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
6487 // It's OK that we just return false here on failure to create an
6488 // inner. GetOrCreateListenerManager() will likewise fail, and then
6489 // we won't be adding any listeners anyway.
6490 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)
;
6491}
6492
6493EventListenerManager* nsGlobalWindowOuter::GetOrCreateListenerManager() {
6494 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)
;
6495}
6496
6497EventListenerManager* nsGlobalWindowOuter::GetExistingListenerManager() const {
6498 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"
, 6498); return nullptr; } return GetCurrentInnerWindowInternal
(this)->GetExistingListenerManager (); } while (0)
;
6499}
6500
6501//*****************************************************************************
6502// nsGlobalWindowOuter::nsPIDOMWindow
6503//*****************************************************************************
6504
6505nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateParent() {
6506 nsCOMPtr<nsPIDOMWindowOuter> parent = GetInProcessParent();
6507
6508 if (this == parent) {
6509 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6510 if (!chromeElement)
6511 return nullptr; // This is ok, just means a null parent.
6512
6513 Document* doc = chromeElement->GetComposedDoc();
6514 if (!doc) return nullptr; // This is ok, just means a null parent.
6515
6516 return doc->GetWindow();
6517 }
6518
6519 return parent;
6520}
6521
6522nsPIDOMWindowOuter* nsGlobalWindowOuter::GetPrivateRoot() {
6523 nsCOMPtr<nsPIDOMWindowOuter> top = GetInProcessTop();
6524
6525 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6526 if (chromeElement) {
6527 Document* doc = chromeElement->GetComposedDoc();
6528 if (doc) {
6529 nsCOMPtr<nsPIDOMWindowOuter> parent = doc->GetWindow();
6530 if (parent) {
6531 top = parent->GetInProcessTop();
6532 }
6533 }
6534 }
6535
6536 return top;
6537}
6538
6539// This has a caller in Windows-only code (nsNativeAppSupportWin).
6540Location* nsGlobalWindowOuter::GetLocation() {
6541 // This method can be called on the outer window as well.
6542 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"
, 6542); return nullptr; } return GetCurrentInnerWindowInternal
(this)->Location (); } while (0)
;
6543}
6544
6545void nsGlobalWindowOuter::SetIsBackground(bool aIsBackground) {
6546 bool changed = aIsBackground != IsBackground();
6547 SetIsBackgroundInternal(aIsBackground);
6548
6549 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6550
6551 if (inner && changed) {
6552 inner->UpdateBackgroundState();
6553 }
6554
6555 if (aIsBackground) {
6556 // Notify gamepadManager we are at the background window,
6557 // we need to stop vibrate.
6558 // Stop the vr telemery time spent when it switches to
6559 // the background window.
6560 if (inner && changed) {
6561 inner->StopGamepadHaptics();
6562 inner->StopVRActivity();
6563 // true is for asking to set the delta time to
6564 // the telemetry.
6565 inner->ResetVRTelemetry(true);
6566 }
6567 return;
6568 }
6569
6570 if (inner) {
6571 // When switching to be as a top tab, restart the telemetry.
6572 // false is for only resetting the timestamp.
6573 inner->ResetVRTelemetry(false);
6574 inner->SyncGamepadState();
6575 inner->StartVRActivity();
6576 }
6577}
6578
6579void nsGlobalWindowOuter::SetIsBackgroundInternal(bool aIsBackground) {
6580 mIsBackground = aIsBackground;
6581}
6582
6583void nsGlobalWindowOuter::SetChromeEventHandler(
6584 EventTarget* aChromeEventHandler) {
6585 SetChromeEventHandlerInternal(aChromeEventHandler);
6586 // update the chrome event handler on all our inner windows
6587 RefPtr<nsGlobalWindowInner> inner;
6588 for (PRCList* node = PR_LIST_HEAD(this)(this)->next; node != this;
6589 node = PR_NEXT_LINK(inner)((inner)->next)) {
6590 // This cast is only safe if `node != this`, as nsGlobalWindowOuter is also
6591 // in the list.
6592 inner = static_cast<nsGlobalWindowInner*>(node);
6593 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"
, 6594); MOZ_PretendNoReturn(); } } while (0)
6594 "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"
, 6594); MOZ_PretendNoReturn(); } } while (0)
;
6595 inner->SetChromeEventHandlerInternal(aChromeEventHandler);
6596 }
6597}
6598
6599void nsGlobalWindowOuter::SetFocusedElement(Element* aElement,
6600 uint32_t aFocusMethod,
6601 bool aNeedsFocus) {
6602 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"
, 6603); return; } GetCurrentInnerWindowInternal(this)->SetFocusedElement
(aElement, aFocusMethod, aNeedsFocus); return; } while (0)
6603 (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"
, 6603); return; } GetCurrentInnerWindowInternal(this)->SetFocusedElement
(aElement, aFocusMethod, aNeedsFocus); return; } while (0)
;
6604}
6605
6606uint32_t nsGlobalWindowOuter::GetFocusMethod() {
6607 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"
, 6607); return 0; } return GetCurrentInnerWindowInternal(this
)->GetFocusMethod (); } while (0)
;
6608}
6609
6610bool nsGlobalWindowOuter::ShouldShowFocusRing() {
6611 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"
, 6611); return false; } return GetCurrentInnerWindowInternal
(this)->ShouldShowFocusRing (); } while (0)
;
6612}
6613
6614bool nsGlobalWindowOuter::TakeFocus(bool aFocus, uint32_t aFocusMethod) {
6615 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"
, 6615); return false; } return GetCurrentInnerWindowInternal
(this)->TakeFocus (aFocus, aFocusMethod); } while (0)
;
6616}
6617
6618void nsGlobalWindowOuter::SetReadyForFocus() {
6619 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"
, 6619); return; } GetCurrentInnerWindowInternal(this)->SetReadyForFocus
(); return; } while (0)
;
6620}
6621
6622void nsGlobalWindowOuter::PageHidden() {
6623 FORWARD_TO_INNER_VOID(PageHidden, ())do { if (!mInnerWindow) { NS_DebugBreak(NS_DEBUG_WARNING, "No inner window available!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6623); return; } GetCurrentInnerWindowInternal(this)->PageHidden
(); return; } while (0)
;
6624}
6625
6626already_AddRefed<nsICSSDeclaration>
6627nsGlobalWindowOuter::GetComputedStyleHelperOuter(Element& aElt,
6628 const nsAString& aPseudoElt,
6629 bool aDefaultStylesOnly,
6630 ErrorResult& aRv) {
6631 if (!mDoc) {
6632 return nullptr;
6633 }
6634
6635 RefPtr<nsICSSDeclaration> compStyle = NS_NewComputedDOMStyle(
6636 &aElt, aPseudoElt, mDoc,
6637 aDefaultStylesOnly ? nsComputedDOMStyle::StyleType::DefaultOnly
6638 : nsComputedDOMStyle::StyleType::All,
6639 aRv);
6640
6641 return compStyle.forget();
6642}
6643
6644//*****************************************************************************
6645// nsGlobalWindowOuter::nsIInterfaceRequestor
6646//*****************************************************************************
6647
6648nsresult nsGlobalWindowOuter::GetInterfaceInternal(const nsIID& aIID,
6649 void** aSink) {
6650 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"
, 6650); return NS_ERROR_INVALID_POINTER; } } while (false)
;
6651 *aSink = nullptr;
6652
6653 if (aIID.Equals(NS_GET_IID(nsIWebNavigation)(nsIWebNavigation::COMTypeInfo<nsIWebNavigation, void>::
kIID)
)) {
6654 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
6655 webNav.forget(aSink);
6656 } else if (aIID.Equals(NS_GET_IID(nsIDocShell)(nsIDocShell::COMTypeInfo<nsIDocShell, void>::kIID))) {
6657 nsCOMPtr<nsIDocShell> docShell = mDocShell;
6658 docShell.forget(aSink);
6659 }
6660#ifdef NS_PRINTING1
6661 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint)(nsIWebBrowserPrint::COMTypeInfo<nsIWebBrowserPrint, void>
::kIID)
)) {
6662 if (mDocShell) {
6663 nsCOMPtr<nsIDocumentViewer> viewer;
6664 mDocShell->GetDocViewer(getter_AddRefs(viewer));
6665 if (viewer) {
6666 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
6667 webBrowserPrint.forget(aSink);
6668 }
6669 }
6670 }
6671#endif
6672 else if (aIID.Equals(NS_GET_IID(nsILoadContext)(nsILoadContext::COMTypeInfo<nsILoadContext, void>::kIID
)
)) {
6673 nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(mDocShell));
6674 loadContext.forget(aSink);
6675 }
6676
6677 return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
6678}
6679
6680NS_IMETHODIMPnsresult
6681nsGlobalWindowOuter::GetInterface(const nsIID& aIID, void** aSink) {
6682 nsresult rv = GetInterfaceInternal(aIID, aSink);
6683 if (rv == NS_ERROR_NO_INTERFACE) {
6684 return QueryInterface(aIID, aSink);
6685 }
6686 return rv;
6687}
6688
6689bool nsGlobalWindowOuter::IsSuspended() const {
6690 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"
, 6690); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6690; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6691 // No inner means we are effectively suspended
6692 if (!mInnerWindow) {
6693 return true;
6694 }
6695 return mInnerWindow->IsSuspended();
6696}
6697
6698bool nsGlobalWindowOuter::IsFrozen() const {
6699 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"
, 6699); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6699; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6700 // No inner means we are effectively frozen
6701 if (!mInnerWindow) {
6702 return true;
6703 }
6704 return mInnerWindow->IsFrozen();
6705}
6706
6707nsresult nsGlobalWindowOuter::FireDelayedDOMEvents(bool aIncludeSubWindows) {
6708 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"
, 6709); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->FireDelayedDOMEvents (aIncludeSubWindows); } while
(0)
6709 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"
, 6709); return NS_ERROR_UNEXPECTED; } return GetCurrentInnerWindowInternal
(this)->FireDelayedDOMEvents (aIncludeSubWindows); } while
(0)
;
6710}
6711
6712//*****************************************************************************
6713// nsGlobalWindowOuter: Window Control Functions
6714//*****************************************************************************
6715
6716nsPIDOMWindowOuter* nsGlobalWindowOuter::GetInProcessParentInternal() {
6717 nsCOMPtr<nsPIDOMWindowOuter> parent = GetInProcessParent();
6718
6719 if (parent && parent != this) {
6720 return parent;
6721 }
6722
6723 return nullptr;
6724}
6725
6726void nsGlobalWindowOuter::UnblockScriptedClosing() {
6727 mBlockScriptedClosingFlag = false;
6728}
6729
6730class AutoUnblockScriptClosing {
6731 private:
6732 RefPtr<nsGlobalWindowOuter> mWin;
6733
6734 public:
6735 explicit AutoUnblockScriptClosing(nsGlobalWindowOuter* aWin) : mWin(aWin) {
6736 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"
, 6736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWin" ")");
do { *((volatile int*)__null) = 6736; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6737 }
6738 ~AutoUnblockScriptClosing() {
6739 void (nsGlobalWindowOuter::*run)() =
6740 &nsGlobalWindowOuter::UnblockScriptedClosing;
6741 nsCOMPtr<nsIRunnable> caller = NewRunnableMethod(
31
Calling 'NewRunnableMethod<RefPtr<nsGlobalWindowOuter> &, void (nsGlobalWindowOuter::*)()>'
6742 "AutoUnblockScriptClosing::~AutoUnblockScriptClosing", mWin, run);
6743 mWin->Dispatch(caller.forget());
6744 }
6745};
6746
6747nsresult nsGlobalWindowOuter::OpenInternal(
6748 const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
6749 bool aDialog, bool aContentModal, bool aCalledNoScript, bool aDoJSFixups,
6750 bool aNavigate, nsIArray* argv, nsISupports* aExtraArgument,
6751 nsDocShellLoadState* aLoadState, bool aForceNoOpener, PrintKind aPrintKind,
6752 BrowsingContext** aReturn) {
6753#ifdef DEBUG1
6754 uint32_t argc = 0;
6755 if (argv) argv->GetLength(&argc);
1
Assuming 'argv' is null
2
Taking false branch
6756#endif
6757
6758 MOZ_ASSERT(!aExtraArgument || (!argv && argc == 0),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aExtraArgument || (!argv && argc == 0))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aExtraArgument || (!argv && argc == 0)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!aExtraArgument || (!argv && argc == 0)"
" (" "Can't pass in arguments both ways" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6759); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aExtraArgument || (!argv && argc == 0)"
") (" "Can't pass in arguments both ways" ")"); do { *((volatile
int*)__null) = 6759; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
3
Assuming 'aExtraArgument' is non-null
4
Taking false branch
5
Loop condition is false. Exiting loop
6759 "Can't pass in arguments both ways")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aExtraArgument || (!argv && argc == 0))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aExtraArgument || (!argv && argc == 0)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!aExtraArgument || (!argv && argc == 0)"
" (" "Can't pass in arguments both ways" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6759); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aExtraArgument || (!argv && argc == 0)"
") (" "Can't pass in arguments both ways" ")"); do { *((volatile
int*)__null) = 6759; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
6760 MOZ_ASSERT(!aCalledNoScript || (!argv && argc == 0),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aCalledNoScript || (!argv && argc == 0))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aCalledNoScript || (!argv && argc == 0)))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!aCalledNoScript || (!argv && argc == 0)"
" (" "Can't pass JS args when called via the noscript methods"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6761); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aCalledNoScript || (!argv && argc == 0)"
") (" "Can't pass JS args when called via the noscript methods"
")"); do { *((volatile int*)__null) = 6761; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6
Assuming 'aCalledNoScript' is false
7
Taking false branch
8
Loop condition is false. Exiting loop
6761 "Can't pass JS args when called via the noscript methods")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aCalledNoScript || (!argv && argc == 0))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!aCalledNoScript || (!argv && argc == 0)))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!aCalledNoScript || (!argv && argc == 0)"
" (" "Can't pass JS args when called via the noscript methods"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6761); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aCalledNoScript || (!argv && argc == 0)"
") (" "Can't pass JS args when called via the noscript methods"
")"); do { *((volatile int*)__null) = 6761; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6762
6763 mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
9
Calling defaulted default constructor for 'Maybe<AutoUnblockScriptClosing>'
20
Returning from default constructor for 'Maybe<AutoUnblockScriptClosing>'
6764
6765 // Calls to window.open from script should navigate.
6766 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"
, 6766); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCalledNoScript || aNavigate"
")"); do { *((volatile int*)__null) = 6766; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
21
Assuming the condition is false
22
Taking false branch
23
Loop condition is false. Exiting loop
6767
6768 *aReturn = nullptr;
6769
6770 nsCOMPtr<nsIWebBrowserChrome> chrome = GetWebBrowserChrome();
6771 if (!chrome) {
24
Taking true branch
6772 // No chrome means we don't want to go through with this open call
6773 // -- see nsIWindowWatcher.idl
6774 return NS_ERROR_NOT_AVAILABLE;
25
Calling implicit destructor for 'Maybe<AutoUnblockScriptClosing>'
26
Calling '~MaybeStorage'
6775 }
6776
6777 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"
, 6777); MOZ_PretendNoReturn(); } } while (0)
;
6778
6779 NS_ConvertUTF16toUTF8 optionsUtf8(aOptions);
6780
6781 WindowFeatures features;
6782 if (!features.Tokenize(optionsUtf8)) {
6783 return NS_ERROR_FAILURE;
6784 }
6785
6786 bool forceNoOpener = aForceNoOpener;
6787 if (features.Exists("noopener")) {
6788 forceNoOpener = features.GetBool("noopener");
6789 features.Remove("noopener");
6790 }
6791
6792 bool forceNoReferrer = false;
6793 if (features.Exists("noreferrer")) {
6794 forceNoReferrer = features.GetBool("noreferrer");
6795 if (forceNoReferrer) {
6796 // noreferrer implies noopener
6797 forceNoOpener = true;
6798 }
6799 features.Remove("noreferrer");
6800 }
6801
6802 nsAutoCString options;
6803 features.Stringify(options);
6804
6805 // If noopener is force-enabled for the current document, then set noopener to
6806 // true, and clear the name to "_blank".
6807 nsAutoString windowName(aName);
6808 if (nsDocShell::Cast(GetDocShell())->NoopenerForceEnabled()) {
6809 // FIXME: Eventually bypass force-enabling noopener if `aPrintKind !=
6810 // PrintKind::None`, so that we can print pages with noopener force-enabled.
6811 // This will require relaxing assertions elsewhere.
6812 if (aPrintKind != PrintKind::None) {
6813 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"
, 6814)
6814 "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"
, 6814)
;
6815 return NS_ERROR_FAILURE;
6816 }
6817
6818 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"
, 6819); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNavigate"
") (" "cannot OpenNoNavigate if noopener is force-enabled" ")"
); do { *((volatile int*)__null) = 6819; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6819 "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"
, 6819); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aNavigate"
") (" "cannot OpenNoNavigate if noopener is force-enabled" ")"
); do { *((volatile int*)__null) = 6819; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6820
6821 forceNoOpener = true;
6822 windowName = u"_blank"_ns;
6823 }
6824
6825 bool windowExists = WindowExists(windowName, forceNoOpener, !aCalledNoScript);
6826
6827 // XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()
6828 // (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.
6829 // But note that if you change this to GetEntryGlobal(), say, then
6830 // OnLinkClickEvent::Run will need a full-blown AutoEntryScript.
6831 const bool checkForPopup =
6832 !nsContentUtils::LegacyIsCallerChromeOrNativeCode() && !aDialog &&
6833 !windowExists;
6834
6835 nsCOMPtr<nsIURI> uri;
6836
6837 // It's important to do this security check before determining whether this
6838 // window opening should be blocked, to ensure that we don't FireAbuseEvents
6839 // for a window opening that wouldn't have succeeded in the first place.
6840 if (!aUrl.IsEmpty()) {
6841 // Note: the Void handling here is very important, because the window
6842 // watcher expects a null URL string (not an empty string) if there is no
6843 // URL to load.
6844 nsCString url;
6845 url.SetIsVoid(true);
6846 AppendUTF16toUTF8(aUrl, url);
6847
6848 // It's safe to skip the security check below if we're a dialog because
6849 // window.openDialog is not callable from content script. See bug 56851.
6850 //
6851 // If we're not navigating, we assume that whoever *does* navigate the
6852 // window will do a security check of their own.
6853 if (!url.IsVoid()) {
6854 auto result =
6855 URIfromURLAndMaybeDoSecurityCheck(url, !aDialog && aNavigate);
6856 if (result.isErr()) {
6857 return result.unwrapErr();
6858 }
6859
6860 uri = result.unwrap();
6861 }
6862 } else if (mDoc) {
6863 mDoc->SetUseCounter(eUseCounter_custom_WindowOpenEmptyUrl);
6864 }
6865
6866 UserActivation::Modifiers modifiers;
6867 mBrowsingContext->GetUserActivationModifiersForPopup(&modifiers);
6868
6869 PopupBlocker::PopupControlState abuseLevel =
6870 PopupBlocker::GetPopupControlState();
6871 if (checkForPopup) {
6872 abuseLevel = mBrowsingContext->RevisePopupAbuseLevel(abuseLevel);
6873 if (abuseLevel >= PopupBlocker::openBlocked) {
6874 if (!aCalledNoScript) {
6875 // If script in some other window is doing a window.open on us and
6876 // it's being blocked, then it's OK to close us afterwards, probably.
6877 // But if we're doing a window.open on ourselves and block the popup,
6878 // prevent this window from closing until after this script terminates
6879 // so that whatever popup blocker UI the app has will be visible.
6880 nsCOMPtr<nsPIDOMWindowInner> entryWindow =
6881 do_QueryInterface(GetEntryGlobal());
6882 // Note that entryWindow can be null here if some JS component was the
6883 // place where script was entered for this JS execution.
6884 if (entryWindow && entryWindow->GetOuterWindow() == this) {
6885 mBlockScriptedClosingFlag = true;
6886 closeUnblocker.emplace(this);
6887 }
6888 }
6889
6890 FireAbuseEvents(aUrl, windowName, aOptions);
6891 return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
6892 }
6893 }
6894
6895 RefPtr<BrowsingContext> domReturn;
6896
6897 nsresult rv = NS_OK;
6898 nsCOMPtr<nsIWindowWatcher> wwatch =
6899 do_GetService(NS_WINDOWWATCHER_CONTRACTID"@mozilla.org/embedcomp/window-watcher;1", &rv);
6900 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"
, 6900); return rv; } } while (false)
;
6901
6902 NS_ConvertUTF16toUTF8 name(windowName);
6903
6904 nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
6905 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"
, 6905); return NS_ERROR_UNEXPECTED; } } while (false)
;
6906
6907 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"
, 6907); AnnotateMozCrashReason("MOZ_ASSERT" "(" "abuseLevel < PopupBlocker::openBlocked"
")"); do { *((volatile int*)__null) = 6907; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6908 // At this point we should know for a fact that if checkForPopup then
6909 // abuseLevel < PopupBlocker::openBlocked, so we could just check for
6910 // abuseLevel == PopupBlocker::openControlled. But let's be defensive just in
6911 // case and treat anything that fails the above assert as a spam popup too, if
6912 // it ever happens.
6913 bool isPopupSpamWindow =
6914 checkForPopup && (abuseLevel >= PopupBlocker::openControlled);
6915
6916 const auto wwPrintKind = [&] {
6917 switch (aPrintKind) {
6918 case PrintKind::None:
6919 return nsPIWindowWatcher::PRINT_NONE;
6920 case PrintKind::InternalPrint:
6921 return nsPIWindowWatcher::PRINT_INTERNAL;
6922 case PrintKind::WindowDotPrint:
6923 return nsPIWindowWatcher::PRINT_WINDOW_DOT_PRINT;
6924 }
6925 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"
, 6925); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Wat" ")"); do { *((volatile int*
)__null) = 6925; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
6926 return nsPIWindowWatcher::PRINT_NONE;
6927 }();
6928
6929 {
6930 // Reset popup state while opening a window to prevent the
6931 // current state from being active the whole time a modal
6932 // dialog is open.
6933 AutoPopupStatePusherAutoPopupStatePusherInternal popupStatePusher(PopupBlocker::openAbused, true);
6934
6935 if (!aCalledNoScript) {
6936 // We asserted at the top of this function that aNavigate is true for
6937 // !aCalledNoScript.
6938 rv = pwwatch->OpenWindow2(this, uri, name, options, modifiers,
6939 /* aCalledFromScript = */ true, aDialog,
6940 aNavigate, argv, isPopupSpamWindow,
6941 forceNoOpener, forceNoReferrer, wwPrintKind,
6942 aLoadState, getter_AddRefs(domReturn));
6943 } else {
6944 // Force a system caller here so that the window watcher won't screw us
6945 // up. We do NOT want this case looking at the JS context on the stack
6946 // when searching. Compare comments on
6947 // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
6948
6949 // Note: Because nsWindowWatcher is so broken, it's actually important
6950 // that we don't force a system caller here, because that screws it up
6951 // when it tries to compute the caller principal to associate with dialog
6952 // arguments. That whole setup just really needs to be rewritten. :-(
6953 Maybe<AutoNoJSAPI> nojsapi;
6954 if (!aContentModal) {
6955 nojsapi.emplace();
6956 }
6957
6958 rv = pwwatch->OpenWindow2(this, uri, name, options, modifiers,
6959 /* aCalledFromScript = */ false, aDialog,
6960 aNavigate, aExtraArgument, isPopupSpamWindow,
6961 forceNoOpener, forceNoReferrer, wwPrintKind,
6962 aLoadState, getter_AddRefs(domReturn));
6963 }
6964 }
6965
6966 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"
, 6966); return rv; } } while (false)
;
6967
6968 // success!
6969
6970 if (!aCalledNoScript && !windowExists && uri && !forceNoOpener) {
6971 MaybeAllowStorageForOpenedWindow(uri);
6972 }
6973
6974 if (domReturn && aDoJSFixups) {
6975 nsPIDOMWindowOuter* outer = domReturn->GetDOMWindow();
6976 if (outer && !nsGlobalWindowOuter::Cast(outer)->IsChromeWindow()) {
6977 // A new non-chrome window was created from a call to
6978 // window.open() from JavaScript, make sure there's a document in
6979 // the new window. We do this by simply asking the new window for
6980 // its document, this will synchronously create an empty document
6981 // if there is no document in the window.
6982 // XXXbz should this just use EnsureInnerWindow()?
6983
6984 // Force document creation.
6985 nsCOMPtr<Document> doc = outer->GetDoc();
6986 Unused << doc;
6987 }
6988 }
6989
6990 domReturn.forget(aReturn);
6991 return NS_OK;
6992}
6993
6994void nsGlobalWindowOuter::MaybeAllowStorageForOpenedWindow(nsIURI* aURI) {
6995 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
6996 if (NS_WARN_IF(!inner)NS_warn_if_impl(!inner, "!inner", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsGlobalWindowOuter.cpp"
, 6996)
) {
6997 return;
6998 }
6999
7000 // No 3rd party URL/window.
7001 if (!AntiTrackingUtils::IsThirdPartyWindow(inner, aURI)) {
7002 return;
7003 }
7004
7005 Document* doc = inner->GetDoc();
7006 if (!doc) {
7007 return;
7008 }
7009 nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateContentPrincipal(
7010 aURI, doc->NodePrincipal()->OriginAttributesRef());
7011
7012 // We don't care when the asynchronous work finishes here.
7013 // Without e10s or fission enabled this is run in the parent process.
7014 if (XRE_IsParentProcess()) {
7015 Unused << StorageAccessAPIHelper::AllowAccessForOnParentProcess(
7016 principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
7017 } else {
7018 Unused << StorageAccessAPIHelper::AllowAccessForOnChildProcess(
7019 principal, GetBrowsingContext(), ContentBlockingNotifier::eOpener);
7020 }
7021}
7022
7023//*****************************************************************************
7024// nsGlobalWindowOuter: Helper Functions
7025//*****************************************************************************
7026
7027already_AddRefed<nsIDocShellTreeOwner> nsPIDOMWindowOuter::GetTreeOwner() {
7028 // If there's no docShellAsItem, this window must have been closed,
7029 // in that case there is no tree owner.
7030
7031 if (!mDocShell) {
7032 return nullptr;
7033 }
7034
7035 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
7036 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
7037 return treeOwner.forget();
7038}
7039
7040already_AddRefed<nsIBaseWindow> nsPIDOMWindowOuter::GetTreeOwnerWindow() {
7041 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
7042
7043 // If there's no mDocShell, this window must have been closed,
7044 // in that case there is no tree owner.
7045
7046 if (mDocShell) {
7047 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
7048 }
7049
7050 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
7051 return baseWindow.forget();
7052}
7053
7054already_AddRefed<nsIWebBrowserChrome>
7055nsPIDOMWindowOuter::GetWebBrowserChrome() {
7056 nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
7057
7058 nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
7059 return browserChrome.forget();
7060}
7061
7062ScrollContainerFrame* nsGlobalWindowOuter::GetScrollContainerFrame() {
7063 if (!mDocShell) {
7064 return nullptr;
7065 }
7066
7067 PresShell* presShell = mDocShell->GetPresShell();
7068 if (presShell) {
7069 return presShell->GetRootScrollContainerFrame();
7070 }
7071 return nullptr;
7072}
7073
7074Result<already_AddRefed<nsIURI>, nsresult>
7075nsGlobalWindowOuter::URIfromURLAndMaybeDoSecurityCheck(const nsACString& aURL,
7076 bool aSecurityCheck) {
7077 nsCOMPtr<nsPIDOMWindowInner> sourceWindow =
7078 do_QueryInterface(GetEntryGlobal());
7079 if (!sourceWindow) {
7080 sourceWindow = GetCurrentInnerWindow();
7081 }
7082
7083 // Resolve the baseURI, which could be relative to the calling window.
7084 //
7085 // Note the algorithm to get the base URI should match the one
7086 // used to actually kick off the load in nsWindowWatcher.cpp.
7087 nsCOMPtr<Document> doc = sourceWindow->GetDoc();
7088 nsIURI* baseURI = nullptr;
7089 auto encoding = UTF_8_ENCODING; // default to utf-8
7090 if (doc) {
7091 baseURI = doc->GetDocBaseURI();
7092 encoding = doc->GetDocumentCharacterSet();
7093 }
7094 nsCOMPtr<nsIURI> uri;
7095 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, encoding, baseURI);
7096 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"
, 7096)
) {
7097 return Err(NS_ERROR_DOM_SYNTAX_ERR);
7098 }
7099
7100 if (aSecurityCheck) {
7101 AutoJSContext cx;
7102 nsGlobalWindowInner* sourceWin = nsGlobalWindowInner::Cast(sourceWindow);
7103 JSAutoRealm ar(cx, sourceWin->GetGlobalJSObject());
7104
7105 if (NS_FAILED(nsContentUtils::GetSecurityManager()->CheckLoadURIFromScript(((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckLoadURIFromScript( cx, uri))), 0)))
7106 cx, uri))((bool)(__builtin_expect(!!(NS_FAILED_impl(nsContentUtils::GetSecurityManager
()->CheckLoadURIFromScript( cx, uri))), 0)))
) {
7107 return Err(NS_ERROR_FAILURE);
7108 }
7109 }
7110
7111 return uri.forget();
7112}
7113
7114void nsGlobalWindowOuter::FlushPendingNotifications(FlushType aType) {
7115 if (mDoc) {
7116 mDoc->FlushPendingNotifications(aType);
7117 }
7118}
7119
7120void nsGlobalWindowOuter::EnsureSizeAndPositionUpToDate() {
7121 // If we're a subframe, make sure our size is up to date. Make sure to go
7122 // through the document chain rather than the window chain to not flush on
7123 // detached iframes, see bug 1545516.
7124 if (mDoc && mDoc->StyleOrLayoutObservablyDependsOnParentDocumentLayout()) {
7125 RefPtr<Document> parent = mDoc->GetInProcessParentDocument();
7126 parent->FlushPendingNotifications(FlushType::Layout);
7127 }
7128}
7129
7130already_AddRefed<nsISupports> nsGlobalWindowOuter::SaveWindowState() {
7131 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"
, 7131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mozilla::SessionHistoryInParent()"
")"); do { *((volatile int*)__null) = 7131; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7132
7133 if (!mContext || !GetWrapperPreserveColor()) {
7134 // The window may be getting torn down; don't bother saving state.
7135 return nullptr;
7136 }
7137
7138 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
7139 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"
, 7139); MOZ_PretendNoReturn(); } } while (0)
;
7140
7141 if (WindowContext* wc = inner->GetWindowContext()) {
7142 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"
, 7142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!wc->GetWindowStateSaved()"
")"); do { *((volatile int*)__null) = 7142; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7143 Unused << wc->SetWindowStateSaved(true);
7144 }
7145
7146 // Don't do anything else to this inner window! After this point, all
7147 // calls to SetTimeoutOrInterval will create entries in the timeout
7148 // list that will only run after this window has come out of the bfcache.
7149 // Also, while we're frozen, we won't dispatch online/offline events
7150 // to the page.
7151 inner->Freeze();
7152
7153 nsCOMPtr<nsISupports> state = new WindowStateHolder(inner);
7154
7155 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)
7156 ("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)
;
7157
7158 return state.forget();
7159}
7160
7161nsresult nsGlobalWindowOuter::RestoreWindowState(nsISupports* aState) {
7162 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"
, 7162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mozilla::SessionHistoryInParent()"
")"); do { *((volatile int*)__null) = 7162; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7163
7164 if (!mContext || !GetWrapperPreserveColor()) {
7165 // The window may be getting torn down; don't bother restoring state.
7166 return NS_OK;
7167 }
7168
7169 nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
7170 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"
, 7170); return NS_ERROR_FAILURE; } } while (false)
;
7171
7172 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)
7173 ("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)
;
7174
7175 // And we're ready to go!
7176 nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal(this);
7177
7178 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
7179 // it easy to tell which link was last clicked when going back a page.
7180 RefPtr<Element> focusedElement = inner->GetFocusedElement();
7181 if (nsContentUtils::ContentIsLink(focusedElement)) {
7182 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
7183 fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
7184 nsIFocusManager::FLAG_SHOWRING);
7185 }
7186 }
7187
7188 if (WindowContext* wc = inner->GetWindowContext()) {
7189 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"
, 7189); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wc->GetWindowStateSaved()"
")"); do { *((volatile int*)__null) = 7189; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7190 Unused << wc->SetWindowStateSaved(false);
7191 }
7192
7193 inner->Thaw();
7194
7195 holder->DidRestoreWindow();
7196
7197 return NS_OK;
7198}
7199
7200void nsGlobalWindowOuter::AddSizeOfIncludingThis(
7201 nsWindowSizes& aWindowSizes) const {
7202 aWindowSizes.mDOMSizes.mDOMOtherSize +=
7203 aWindowSizes.mState.mMallocSizeOf(this);
7204}
7205
7206uint32_t nsGlobalWindowOuter::GetAutoActivateVRDisplayID() {
7207 uint32_t retVal = mAutoActivateVRDisplayID;
7208 mAutoActivateVRDisplayID = 0;
7209 return retVal;
7210}
7211
7212void nsGlobalWindowOuter::SetAutoActivateVRDisplayID(
7213 uint32_t aAutoActivateVRDisplayID) {
7214 mAutoActivateVRDisplayID = aAutoActivateVRDisplayID;
7215}
7216
7217already_AddRefed<nsWindowRoot> nsGlobalWindowOuter::GetWindowRootOuter() {
7218 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
7219 return root.forget().downcast<nsWindowRoot>();
7220}
7221
7222nsIDOMWindowUtils* nsGlobalWindowOuter::WindowUtils() {
7223 if (!mWindowUtils) {
7224 mWindowUtils = new nsDOMWindowUtils(this);
7225 }
7226 return mWindowUtils;
7227}
7228
7229bool nsGlobalWindowOuter::IsInSyncOperation() {
7230 return GetExtantDoc() && GetExtantDoc()->IsInSyncOperation();
7231}
7232
7233// Note: This call will lock the cursor, it will not change as it moves.
7234// To unlock, the cursor must be set back to Auto.
7235void nsGlobalWindowOuter::SetCursorOuter(const nsACString& aCursor,
7236 ErrorResult& aError) {
7237 auto cursor = StyleCursorKind::Auto;
7238 if (!Servo_CursorKind_Parse(&aCursor, &cursor)) {
7239 // FIXME: It's a bit weird that this doesn't throw but stuff below does, but
7240 // matches previous behavior so...
7241 return;
7242 }
7243
7244 RefPtr<nsPresContext> presContext;
7245 if (mDocShell) {
7246 presContext = mDocShell->GetPresContext();
7247 }
7248
7249 if (presContext) {
7250 // Need root widget.
7251 PresShell* presShell = mDocShell->GetPresShell();
7252 if (!presShell) {
7253 aError.Throw(NS_ERROR_FAILURE);
7254 return;
7255 }
7256
7257 nsViewManager* vm = presShell->GetViewManager();
7258 if (!vm) {
7259 aError.Throw(NS_ERROR_FAILURE);
7260 return;
7261 }
7262
7263 nsView* rootView = vm->GetRootView();
7264 if (!rootView) {
7265 aError.Throw(NS_ERROR_FAILURE);
7266 return;
7267 }
7268
7269 nsIWidget* widget = rootView->GetNearestWidget(nullptr);
7270 if (!widget) {
7271 aError.Throw(NS_ERROR_FAILURE);
7272 return;
7273 }
7274
7275 // Call esm and set cursor.
7276 aError = presContext->EventStateManager()->SetCursor(
7277 cursor, nullptr, {}, Nothing(), widget, true);
7278 }
7279}
7280
7281nsIBrowserDOMWindow* nsGlobalWindowOuter::GetBrowserDOMWindow() {
7282 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"
, 7282); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "IsChromeWindow()"
")"); do { *((volatile int*)__null) = 7282; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7283 return mChromeFields.mBrowserDOMWindow;
7284}
7285
7286void nsGlobalWindowOuter::SetBrowserDOMWindowOuter(
7287 nsIBrowserDOMWindow* aBrowserWindow) {
7288 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"
, 7288); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsChromeWindow()"
")"); do { *((volatile int*)__null) = 7288; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7289 mChromeFields.mBrowserDOMWindow = aBrowserWindow;
7290}
7291
7292ChromeMessageBroadcaster* nsGlobalWindowOuter::GetMessageManager() {
7293 if (!mInnerWindow) {
7294 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"
, 7294)
;
7295 return nullptr;
7296 }
7297 return GetCurrentInnerWindowInternal(this)->MessageManager();
7298}
7299
7300ChromeMessageBroadcaster* nsGlobalWindowOuter::GetGroupMessageManager(
7301 const nsAString& aGroup) {
7302 if (!mInnerWindow) {
7303 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"
, 7303)
;
7304 return nullptr;
7305 }
7306 return GetCurrentInnerWindowInternal(this)->GetGroupMessageManager(aGroup);
7307}
7308
7309void nsGlobalWindowOuter::InitWasOffline() { mWasOffline = NS_IsOffline(); }
7310
7311#if defined(_WINDOWS_) && !defined(MOZ_WRAPPED_WINDOWS_H)
7312# pragma message( \
7313 "wrapper failure reason: " MOZ_WINDOWS_WRAPPER_DISABLED_REASON)
7314# error "Never include unwrapped windows.h in this file!"
7315#endif
7316
7317// Helper called by methods that move/resize the window,
7318// to ensure the presContext (if any) is aware of resolution
7319// change that may happen in multi-monitor configuration.
7320void nsGlobalWindowOuter::CheckForDPIChange() {
7321 if (mDocShell) {
7322 RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
7323 if (presContext) {
7324 if (presContext->DeviceContext()->CheckDPIChange()) {
7325 presContext->UIResolutionChanged();
7326 }
7327 }
7328 }
7329}
7330
7331nsresult nsGlobalWindowOuter::Dispatch(
7332 already_AddRefed<nsIRunnable>&& aRunnable) const {
7333 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"
, 7333); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 7333; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7334 return NS_DispatchToCurrentThread(std::move(aRunnable));
7335}
7336
7337nsISerialEventTarget* nsGlobalWindowOuter::SerialEventTarget() const {
7338 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"
, 7338); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 7338; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7339 return GetMainThreadSerialEventTarget();
7340}
7341
7342void nsGlobalWindowOuter::MaybeResetWindowName(Document* aNewDocument) {
7343 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"
, 7343); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewDocument"
")"); do { *((volatile int*)__null) = 7343; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7344
7345 if (!StaticPrefs::privacy_window_name_update_enabled()) {
7346 return;
7347 }
7348
7349 const LoadingSessionHistoryInfo* info =
7350 nsDocShell::Cast(mDocShell)->GetLoadingSessionHistoryInfo();
7351 if (!info || info->mForceMaybeResetName.isNothing()) {
7352 // We only reset the window name for the top-level content as well as
7353 // storing in session entries.
7354 if (!GetBrowsingContext()->IsTopContent()) {
7355 return;
7356 }
7357
7358 // Following implements https://html.spec.whatwg.org/#history-traversal:
7359 // Step 4.2. Check if the loading document has a different origin than the
7360 // previous document.
7361
7362 // We don't need to do anything if we haven't loaded a non-initial document.
7363 if (!GetBrowsingContext()->GetHasLoadedNonInitialDocument()) {
7364 return;
7365 }
7366
7367 // If we have an existing document, directly check the document prinicpals
7368 // with the new document to know if it is cross-origin.
7369 //
7370 // Note that there will be an issue of initial document handling in Fission
7371 // when running the WPT unset_context_name-1.html. In the test, the first
7372 // about:blank page would be loaded with the principal of the testing domain
7373 // in Fission and the window.name will be set there. Then, The window.name
7374 // won't be reset after navigating to the testing page because the principal
7375 // is the same. But, it won't be the case for non-Fission mode that the
7376 // first about:blank will be loaded with a null principal and the
7377 // window.name will be reset when loading the test page.
7378 if (mDoc && mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal())) {
7379 return;
7380 }
7381
7382 // If we don't have an existing document, and if it's not the initial
7383 // about:blank, we could be loading a document because of the
7384 // process-switching. In this case, this should be a cross-origin
7385 // navigation.
7386 } else if (!info->mForceMaybeResetName.ref()) {
7387 return;
7388 }
7389
7390 // Step 4.2.2 Store the window.name into all session history entries that have
7391 // the same origin as the previous document.
7392 nsDocShell::Cast(mDocShell)->StoreWindowNameToSHEntries();
7393
7394 // Step 4.2.3 Clear the window.name if the browsing context is the top-level
7395 // content and doesn't have an opener.
7396
7397 // We need to reset the window name in case of a cross-origin navigation,
7398 // without an opener.
7399 RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext();
7400 if (opener) {
7401 return;
7402 }
7403
7404 Unused << mBrowsingContext->SetName(EmptyString());
7405}
7406
7407nsGlobalWindowOuter::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
7408 BrowsingContext* aBC) {
7409 BrowsingContextGroup* group = aBC->Group();
7410 if (!group) {
7411 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"
, 7413); MOZ_PretendNoReturn(); } while (0)
7412 "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"
, 7413); MOZ_PretendNoReturn(); } while (0)
7413 "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"
, 7413); MOZ_PretendNoReturn(); } while (0)
;
7414 return;
7415 }
7416
7417 if (group) {
7418 mGroup = group;
7419 mSavedDialogsEnabled = group->GetAreDialogsEnabled();
7420 group->SetAreDialogsEnabled(false);
7421 }
7422}
7423
7424nsGlobalWindowOuter::TemporarilyDisableDialogs::~TemporarilyDisableDialogs() {
7425 if (mGroup) {
7426 mGroup->SetAreDialogsEnabled(mSavedDialogsEnabled);
7427 }
7428}
7429
7430/* static */
7431already_AddRefed<nsGlobalWindowOuter> nsGlobalWindowOuter::Create(
7432 nsDocShell* aDocShell, bool aIsChrome) {
7433 uint64_t outerWindowID = aDocShell->GetOuterWindowID();
7434 RefPtr<nsGlobalWindowOuter> window = new nsGlobalWindowOuter(outerWindowID);
7435 if (aIsChrome) {
7436 window->mIsChrome = true;
7437 }
7438 window->SetDocShell(aDocShell);
7439
7440 window->InitWasOffline();
7441 return window.forget();
7442}
7443
7444nsIURI* nsPIDOMWindowOuter::GetDocumentURI() const {
7445 return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
7446}
7447
7448void nsPIDOMWindowOuter::MaybeCreateDoc() {
7449 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"
, 7449); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDoc" ")")
; do { *((volatile int*)__null) = 7449; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7450 if (nsIDocShell* docShell = GetDocShell()) {
7451 // Note that |document| here is the same thing as our mDoc, but we
7452 // don't have to explicitly set the member variable because the docshell
7453 // has already called SetNewDocument().
7454 nsCOMPtr<Document> document = docShell->GetDocument();
7455 Unused << document;
7456 }
7457}
7458
7459void nsPIDOMWindowOuter::SetChromeEventHandlerInternal(
7460 EventTarget* aChromeEventHandler) {
7461 // Out-of-line so we don't need to include ContentFrameMessageManager.h in
7462 // nsPIDOMWindow.h.
7463 mChromeEventHandler = aChromeEventHandler;
7464
7465 // mParentTarget and mMessageManager will be set when the next event is
7466 // dispatched or someone asks for our message manager.
7467 mParentTarget = nullptr;
7468 mMessageManager = nullptr;
7469}
7470
7471mozilla::dom::DocGroup* nsPIDOMWindowOuter::GetDocGroup() const {
7472 Document* doc = GetExtantDoc();
7473 if (doc) {
7474 return doc->GetDocGroup();
7475 }
7476 return nullptr;
7477}
7478
7479nsPIDOMWindowOuter::nsPIDOMWindowOuter(uint64_t aWindowID)
7480 : mFrameElement(nullptr),
7481 mModalStateDepth(0),
7482 mSuppressEventHandlingDepth(0),
7483 mIsBackground(false),
7484 mIsRootOuterWindow(false),
7485 mInnerWindow(nullptr),
7486 mWindowID(aWindowID),
7487 mMarkedCCGeneration(0) {}
7488
7489nsPIDOMWindowOuter::~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;
11
Calling defaulted default constructor for 'MaybeStorageBase<AutoUnblockScriptClosing, false>'
16
Returning from default constructor for 'MaybeStorageBase<AutoUnblockScriptClosing, false>'
17
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
26.1
Field 'mIsSome' is 0
26.1
Field 'mIsSome' is 0
26.1
Field 'mIsSome' is 0
26.1
Field 'mIsSome' is 0
26.1
Field 'mIsSome' is 0
26.1
Field 'mIsSome' is 0
) {
27
Taking false branch
274 this->addr()->T::~T();
275 }
276 }
28
Calling implicit destructor for 'MaybeStorageBase<AutoUnblockScriptClosing, false>'
29
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;
10
Calling defaulted default constructor for 'MaybeStorage<AutoUnblockScriptClosing, false>'
18
Returning from default constructor for 'MaybeStorage<AutoUnblockScriptClosing, false>'
19
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() {}
13
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() {}
30
Calling '~AutoUnblockScriptClosing'
44
45 NonConstT val;
46 } mStorage;
47
48 public:
49 MaybeStorageBase() = default;
12
Calling default constructor for 'Union'
14
Returning from default constructor for 'Union'
15
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)),
35
Calling 'forward<RefPtr<nsGlobalWindowOuter> &>'
36
Returning from 'forward<RefPtr<nsGlobalWindowOuter> &>'
37
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>(
34
Calling constructor for 'RunnableMethodImpl<RefPtr<nsGlobalWindowOuter>, void (nsGlobalWindowOuter::*)(), true, mozilla::RunnableKind::Standard, >'
1348 aName, std::forward<PtrType>(aPtr), aMethod));
32
Calling 'forward<RefPtr<nsGlobalWindowOuter> &>'
33
Returning from 'forward<RefPtr<nsGlobalWindowOuter> &>'
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;
1819} // namespace dom
1820
1821// Specialized methods must be explicitly predeclared.
1822template <>
1823LogTaskBase<nsIRunnable>::Run::Run(nsIRunnable* aEvent, bool aWillRunAgain);
1824template <>
1825LogTaskBase<Task>::Run::Run(Task* aTask, bool aWillRunAgain);
1826template <>
1827void LogTaskBase<IPC::Message>::LogDispatchWithPid(IPC::Message* aEvent,
1828 int32_t aPid);
1829template <>
1830LogTaskBase<IPC::Message>::Run::Run(IPC::Message* aMessage, bool aWillRunAgain);
1831template <>
1832LogTaskBase<nsTimerImpl>::Run::Run(nsTimerImpl* aEvent, bool aWillRunAgain);
1833
1834typedef LogTaskBase<nsIRunnable> LogRunnable;
1835typedef LogTaskBase<MicroTaskRunnable> LogMicroTaskRunnable;
1836typedef LogTaskBase<IPC::Message> LogIPCMessage;
1837typedef LogTaskBase<nsTimerImpl> LogTimerEvent;
1838typedef LogTaskBase<Task> LogTask;
1839typedef LogTaskBase<PresShell> LogPresShellObserver;
1840typedef LogTaskBase<dom::FrameRequestCallback> LogFrameRequestCallback;
1841// If you add new types don't forget to add:
1842// `template class LogTaskBase<YourType>;` to nsThreadUtils.cpp
1843
1844} // namespace mozilla
1845
1846#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);
39
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();
38
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 */