Bug Summary

File:Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/page/LocalDOMWindow.cpp
Warning:line 2028, column 11
Local variable 'document' is unchecked and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-macosx26.2.0 -O2 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name UnifiedSource281.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -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 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -target-sdk-version=26.2 -fdepfile-entry=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/SDKSettings.json -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fno-modulemap-allow-subdirectory-search -fdefine-target-os-macros -enable-tlsdesc -target-cpu apple-m1 -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +ccpp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +flagm -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -dwarf-ext-refs -fmodule-format=obj -debug-info-kind=standalone -dwarf-version=5 -debugger-tuning=lldb -fdebug-compilation-dir=/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1230.1 -fcoverage-compilation-dir=/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -resource-dir /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21 -dependency-file /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource281.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-generated-files.hmap -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-project-headers.hmap -isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/2635492409325514188/WebCorePrefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D NDEBUG -D BUILDING_WEBKIT -D GL_SILENCE_DEPRECATION=1 -D GLES_SILENCE_DEPRECATION=1 -D ENGINEERING_BUILD=1 -D __clang_analyzer__ -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-own-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-all-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/include -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/usr/include/libxml2 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebCore -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/macosx26.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/usr/local/include/webm -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources -F/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/usr/local/include -internal-isystem /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.2.sdk/Library/Frameworks -Wno-trigraphs -Werror -Wno-missing-field-initializers -Wmissing-prototypes -Wunreachable-code -Wnon-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wsign-compare -Wno-shorten-64-to-32 -Wnewline-eof -Wno-c++11-extensions -Wno-implicit-fallthrough -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wall -Wc99-designator -Wconditional-uninitialized -Wextra -Wdeprecated-enum-enum-conversion -Wdeprecated-enum-float-conversion -Wenum-float-conversion -Wfinal-dtor-non-final-class -Wformat=2 -Wmisleading-indentation -Wpointer-to-int-cast -Wreorder-init-list -Wundef -Wunused-but-set-variable -Wvla -Werror=unguarded-availability -Wno-elaborated-enum-base -Wcast-qual -Wchar-subscripts -Wextra-tokens -Winit-self -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough -Wvla -Wno-unknown-warning-option -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wno-backend-plugin -Wunsafe-buffer-usage -std=c++2b -fdeprecated-macro -ferror-limit 19 -fmacro-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden -stack-protector 1 -fblocks -fencode-extended-block-signature -fno-rtti -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -fno-implicit-modules -fskip-odr-check-in-gmf -fpascal-strings -fmax-type-align=16 -fdiagnostics-show-note-include-stack -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config report-in-main-source-file=true -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -analyzer-checker optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker security.insecureAPI.UncheckedReturn -analyzer-checker security.insecureAPI.getpw -analyzer-checker security.insecureAPI.gets -analyzer-checker security.insecureAPI.mkstemp -analyzer-checker security.insecureAPI.mktemp -analyzer-disable-checker security.insecureAPI.rand -analyzer-disable-checker security.insecureAPI.strcpy -analyzer-checker security.insecureAPI.vfork -analyzer-disable-checker alpha,apiModeling,core,cplusplus,deadcode,debug,fuchsia,nullability,optin,osx,security,unix,webkit -analyzer-checker alpha.webkit.ForwardDeclChecker,alpha.webkit.MemoryUnsafeCastChecker,alpha.webkit.NoDeleteChecker,alpha.webkit.NoUncheckedPtrMemberChecker,alpha.webkit.NoUnretainedMemberChecker,alpha.webkit.RetainPtrCtorAdoptChecker,alpha.webkit.UncheckedCallArgsChecker,alpha.webkit.UncheckedLocalVarsChecker,alpha.webkit.UncountedCallArgsChecker,alpha.webkit.UncountedLocalVarsChecker,alpha.webkit.UnretainedCallArgsChecker,alpha.webkit.UnretainedLambdaCapturesChecker,alpha.webkit.UnretainedLocalVarsChecker,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,webkit.UncountedLambdaCapturesChecker -analyzer-config max-nodes=10000000 -analyzer-config verbose-report-filename=true -fdwarf2-cfi-asm -o /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource281.plist -x c++ /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebCore/unified-sources/UnifiedSource281.cpp
1/*
2 * Copyright (C) 2006-2025 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "LocalDOMWindow.h"
29
30#include "BackForwardController.h"
31#include "BarProp.h"
32#include "CSSComputedStyleDeclaration.h"
33#include "CSSRule.h"
34#include "CSSRuleList.h"
35#include "CSSSelectorParser.h"
36#include "Chrome.h"
37#include "ChromeClient.h"
38#include "CloseWatcherManager.h"
39#include "ComposedTreeIterator.h"
40#include "ContentExtensionActions.h"
41#include "ContentExtensionRule.h"
42#include "ContentRuleListResults.h"
43#include "ContentSecurityPolicy.h"
44#include "ContextDestructionObserverInlines.h"
45#include "CookieStore.h"
46#include "CrossOriginMode.h"
47#include "CrossOriginOpenerPolicy.h"
48#include "Crypto.h"
49#include "CustomElementRegistry.h"
50#include "DOMSelection.h"
51#include "DOMStringList.h"
52#include "DOMTimer.h"
53#include "DOMTokenList.h"
54#include "DeviceMotionController.h"
55#include "DeviceMotionData.h"
56#include "DeviceMotionEvent.h"
57#include "DeviceOrientationAndMotionAccessController.h"
58#include "DeviceOrientationController.h"
59#include "Document.h"
60#include "DocumentEventLoop.h"
61#include "DocumentInlines.h"
62#include "DocumentLoader.h"
63#include "DocumentPage.h"
64#include "DocumentQuirks.h"
65#include "DocumentSecurityOrigin.h"
66#include "DocumentView.h"
67#include "DocumentWindow.h"
68#include "Editor.h"
69#include "Element.h"
70#include "EventCounts.h"
71#include "EventHandler.h"
72#include "EventListener.h"
73#include "EventLoop.h"
74#include "EventNames.h"
75#include "EventPath.h"
76#include "FloatRect.h"
77#include "FocusController.h"
78#include "FrameConsoleClient.h"
79#include "FrameDestructionObserverInlines.h"
80#include "FrameInlines.h"
81#include "FrameLoadRequest.h"
82#include "FrameLoader.h"
83#include "FrameTree.h"
84#include "HTMLFrameOwnerElement.h"
85#include "HTTPParsers.h"
86#include "History.h"
87#include "IdleRequestOptions.h"
88#include "InputEvent.h"
89#include "InspectorInstrumentation.h"
90#include "JSDOMConvertBoolean.h"
91#include "JSDOMConvertEnumeration.h"
92#include "JSDOMConvertInterface.h"
93#include "JSDOMConvertNullable.h"
94#include "JSDOMExceptionHandling.h"
95#include "JSDOMPromiseDeferred.h"
96#include "JSDOMWindowBase.h"
97#include "JSExecState.h"
98#include "JSPushSubscription.h"
99#include "KeyboardEvent.h"
100#include "LocalFrame.h"
101#include "LocalFrameInlines.h"
102#include "LocalFrameLoaderClient.h"
103#include "LocalFrameView.h"
104#include "Location.h"
105#include "Logging.h"
106#include "MediaQueryList.h"
107#include "MediaQueryMatcher.h"
108#include "MessageEvent.h"
109#include "MessageWithMessagePorts.h"
110#include "MouseEvent.h"
111#include "Navigation.h"
112#include "NavigationScheduler.h"
113#include "Navigator.h"
114#include "OriginAccessPatterns.h"
115#include "Page.h"
116#include "PageTransitionEvent.h"
117#include "Performance.h"
118#include "PerformanceEventTiming.h"
119#include "PerformanceNavigationTiming.h"
120#include "PermissionsPolicy.h"
121#include "PlatformStrategies.h"
122#include "PseudoElementUtilities.h"
123#include "PushManager.h"
124#include "PushStrategy.h"
125#include "RemoteFrame.h"
126#include "RequestAnimationFrameCallback.h"
127#include "ResourceLoadInfo.h"
128#include "ResourceLoadObserver.h"
129#include "ScheduledAction.h"
130#include "Screen.h"
131#include "ScrollAnimator.h"
132#include "ScrollToOptions.h"
133#include "SecurityOrigin.h"
134#include "SecurityOriginData.h"
135#include "SecurityPolicy.h"
136#include "SelectorQuery.h"
137#include "SerializedScriptValue.h"
138#include "Settings.h"
139#include "StaticNodeList.h"
140#include "Storage.h"
141#include "StorageArea.h"
142#include "StorageNamespace.h"
143#include "StorageNamespaceProvider.h"
144#include "StyleMedia.h"
145#include "StyleResolver.h"
146#include "StyleScope.h"
147#include "SuddenTermination.h"
148#include "UserContentProvider.h"
149#include "UserGestureIndicator.h"
150#include "VisualViewport.h"
151#include "WebCoreOpaqueRoot.h"
152#include "WebKitPoint.h"
153#include "WindowFeatures.h"
154#include "WindowFocusAllowedIndicator.h"
155#include "WindowPostMessageOptions.h"
156#include "WindowProxy.h"
157#include <JavaScriptCore/ScriptCallStack.h>
158#include <JavaScriptCore/ScriptCallStackFactory.h>
159#include <algorithm>
160#include <cmath>
161#include <memory>
162#include <wtf/Assertions.h>
163#include <wtf/Borrow.h>
164#include <wtf/CryptographicallyRandomNumber.h>
165#include <wtf/Language.h>
166#include <wtf/MainThread.h>
167#include <wtf/MathExtras.h>
168#include <wtf/NeverDestroyed.h>
169#include <wtf/Ref.h>
170#include <wtf/RuntimeApplicationChecks.h>
171#include <wtf/SetForScope.h>
172#include <wtf/SystemTracing.h>
173#include <wtf/TZoneMallocInlines.h>
174#include <wtf/URL.h>
175#include <wtf/text/MakeString.h>
176#include <wtf/text/WTFString.h>
177
178#if ENABLE(USER_MESSAGE_HANDLERS)(defined 1 && 1)
179#include "UserContentController.h"
180#include "UserMessageHandlerDescriptor.h"
181#include "WebKitNamespace.h"
182#endif
183
184#if ENABLE(GAMEPAD)(defined 1 && 1)
185#include "GamepadManager.h"
186#endif
187
188#if ENABLE(GEOLOCATION)(defined 1 && 1)
189#include "NavigatorGeolocation.h"
190#endif
191
192#if ENABLE(POINTER_LOCK)(defined 1 && 1)
193#include "PointerLockController.h"
194#endif
195
196namespace WebCore {
197using namespace Inspector;
198
199static constexpr Seconds defaultTransientActivationDuration { 5_s };
200
201static WeakHashSet<LocalDOMWindow, WeakPtrImplWithEventTargetData>& NODELETE[[clang::annotate_type("webkit.nodelete")]] windowsInterestedInStorageEvents()
202{
203 static MainThreadNeverDestroyed<WeakHashSet<LocalDOMWindow, WeakPtrImplWithEventTargetData>> set;
204 return set;
205}
206
207void LocalDOMWindow::forEachWindowInterestedInStorageEvents(NOESCAPE[[clang::noescape]] const Function<void(LocalDOMWindow&)>& apply)
208{
209 for (auto& window : copyToVectorOf<Ref<LocalDOMWindow>>(windowsInterestedInStorageEvents()))
210 apply(window);
211}
212
213static std::optional<Seconds>& NODELETE[[clang::annotate_type("webkit.nodelete")]] transientActivationDurationOverrideForTesting()
214{
215 static NeverDestroyed<std::optional<Seconds>> overrideForTesting;
216 return overrideForTesting;
217}
218
219Seconds LocalDOMWindow::transientActivationDuration()
220{
221 if (auto override = transientActivationDurationOverrideForTesting())
222 return *override;
223 return defaultTransientActivationDuration;
224}
225
226WTF_MAKE_TZONE_ALLOCATED_IMPL(LocalDOMWindow)::bmalloc::api::HeapRef LocalDOMWindow::s_heapRef; const TZoneSpecification
LocalDOMWindow::s_heapSpec = { &LocalDOMWindow::s_heapRef
, TZoneSpecification::encodeSize<LocalDOMWindow>(), TZoneSpecification
::encodeAlignment<LocalDOMWindow>(), TZoneSpecification
::encodeCategory<LocalDOMWindow>(), ::bmalloc::api::compactAllocationMode
<LocalDOMWindow>(), TZoneSpecification::encodeDescriptor
<LocalDOMWindow>(), }; void* LocalDOMWindow::operatorNewSlow
(size_t size) { if constexpr (::bmalloc::api::compactAllocationMode
<LocalDOMWindow>() == CompactAllocationMode::Compact) return
::bmalloc::api::tzoneAllocateCompactSlow(size, s_heapSpec); return
::bmalloc::api::tzoneAllocateNonCompactSlow(size, s_heapSpec
); } using __makeBtzoneMallocedInlineMacroSemicolonifier __attribute__
((unused)) = int
;
227
228typedef HashCountedSet<LocalDOMWindow*> LocalDOMWindowSet;
229
230static LocalDOMWindowSet& NODELETE[[clang::annotate_type("webkit.nodelete")]] windowsWithUnloadEventListeners()
231{
232 static NeverDestroyed<LocalDOMWindowSet> windowsWithUnloadEventListeners;
233 return windowsWithUnloadEventListeners;
234}
235
236static LocalDOMWindowSet& NODELETE[[clang::annotate_type("webkit.nodelete")]] windowsWithBeforeUnloadEventListeners()
237{
238 static NeverDestroyed<LocalDOMWindowSet> windowsWithBeforeUnloadEventListeners;
239 return windowsWithBeforeUnloadEventListeners;
240}
241
242static void addUnloadEventListener(LocalDOMWindow* domWindow)
243{
244 if (windowsWithUnloadEventListeners().add(domWindow).isNewEntry)
245 domWindow->disableSuddenTermination();
246}
247
248static void removeUnloadEventListener(LocalDOMWindow* domWindow)
249{
250 if (windowsWithUnloadEventListeners().remove(domWindow))
251 domWindow->enableSuddenTermination();
252}
253
254static void removeAllUnloadEventListeners(LocalDOMWindow* domWindow)
255{
256 if (windowsWithUnloadEventListeners().removeAll(domWindow))
257 domWindow->enableSuddenTermination();
258}
259
260static void addBeforeUnloadEventListener(LocalDOMWindow* domWindow)
261{
262 if (windowsWithBeforeUnloadEventListeners().add(domWindow).isNewEntry)
263 domWindow->disableSuddenTermination();
264}
265
266static void removeBeforeUnloadEventListener(LocalDOMWindow* domWindow)
267{
268 if (windowsWithBeforeUnloadEventListeners().remove(domWindow))
269 domWindow->enableSuddenTermination();
270}
271
272static void removeAllBeforeUnloadEventListeners(LocalDOMWindow* domWindow)
273{
274 if (windowsWithBeforeUnloadEventListeners().removeAll(domWindow))
275 domWindow->enableSuddenTermination();
276}
277
278static bool NODELETE[[clang::annotate_type("webkit.nodelete")]] allowsBeforeUnloadListeners(LocalDOMWindow* window)
279{
280 ASSERT_ARG(window, window)((void)0);
281 auto* frame = window->frame();
282 if (!frame)
283 return false;
284 if (!frame->page())
285 return false;
286 return frame->isMainFrame();
287}
288
289bool LocalDOMWindow::dispatchAllPendingBeforeUnloadEvents()
290{
291 auto& set = windowsWithBeforeUnloadEventListeners();
292 if (set.isEmpty())
293 return true;
294
295 static bool alreadyDispatched = false;
296 ASSERT(!alreadyDispatched)((void)0);
297 if (alreadyDispatched)
298 return true;
299
300 auto windows = WTF::map(set, [](auto& entry) -> Ref<LocalDOMWindow> {
301 return *entry.key;
302 });
303
304 for (auto& window : windows) {
305 if (!set.contains(window.ptr()))
306 continue;
307
308 RefPtr frame = window->frame();
309 if (!frame)
310 continue;
311
312 if (!frame->loader().shouldClose())
313 return false;
314
315 window->enableSuddenTermination();
316 }
317
318 alreadyDispatched = true;
319 return true;
320}
321
322unsigned LocalDOMWindow::pendingUnloadEventListeners() const
323{
324 return windowsWithUnloadEventListeners().count(const_cast<LocalDOMWindow*>(this));
325}
326
327void LocalDOMWindow::dispatchAllPendingUnloadEvents()
328{
329 auto& set = windowsWithUnloadEventListeners();
330 if (set.isEmpty())
331 return;
332
333 static bool alreadyDispatched = false;
334 ASSERT(!alreadyDispatched)((void)0);
335 if (alreadyDispatched)
336 return;
337
338 auto windows = WTF::map(set, [] (auto& keyValue) {
339 return Ref<LocalDOMWindow>(*(keyValue.key));
340 });
341
342 auto& eventNames = WebCore::eventNames();
343 for (auto& window : windows) {
344 if (!set.contains(window.ptr()))
345 continue;
346
347 RefPtr document = window->document();
348 if (document)
349 document->dispatchPagehideEvent(PageshowEventPersistence::NotPersisted);
350 window->dispatchEvent(Event::create(eventNames.unloadEvent, Event::CanBubble::No, Event::IsCancelable::No), document.get());
351
352 window->enableSuddenTermination();
353 }
354
355 alreadyDispatched = true;
356}
357
358// This function:
359// 1) Validates the pending changes are not changing any value to NaN; in that case keep original value.
360// 2) Constrains the window rect to the minimum window size and no bigger than the float rect's dimensions.
361// 3) Constrains the window rect to within the top and left boundaries of the available screen rect.
362// 4) Constrains the window rect to within the bottom and right boundaries of the available screen rect.
363// 5) Translate the window rect coordinates to be within the coordinate space of the screen.
364FloatRect LocalDOMWindow::adjustWindowRect(Page& page, const FloatRect& pendingChanges)
365{
366 FloatRect screen = screenAvailableRect(page.mainFrame().virtualView());
367 FloatRect window = page.chrome().windowRect();
368
369 // Make sure we're in a valid state before adjusting dimensions.
370 ASSERT(std::isfinite(screen.x()))((void)0);
371 ASSERT(std::isfinite(screen.y()))((void)0);
372 ASSERT(std::isfinite(screen.width()))((void)0);
373 ASSERT(std::isfinite(screen.height()))((void)0);
374 ASSERT(std::isfinite(window.x()))((void)0);
375 ASSERT(std::isfinite(window.y()))((void)0);
376 ASSERT(std::isfinite(window.width()))((void)0);
377 ASSERT(std::isfinite(window.height()))((void)0);
378
379 // Update window values if new requested values are not NaN.
380 if (!std::isnan(pendingChanges.x()))
381 window.setX(pendingChanges.x());
382 if (!std::isnan(pendingChanges.y()))
383 window.setY(pendingChanges.y());
384 if (!std::isnan(pendingChanges.width()))
385 window.setWidth(pendingChanges.width());
386 if (!std::isnan(pendingChanges.height()))
387 window.setHeight(pendingChanges.height());
388
389 FloatSize minimumSize = page.chrome().client().minimumWindowSize();
390 window.setWidth(std::min(std::max(minimumSize.width(), window.width()), screen.width()));
391 window.setHeight(std::min(std::max(minimumSize.height(), window.height()), screen.height()));
392
393 // Constrain the window position within the valid screen area.
394 window.setX(std::max(screen.x(), std::min(window.x(), screen.maxX() - window.width())));
395 window.setY(std::max(screen.y(), std::min(window.y(), screen.maxY() - window.height())));
396
397 return window;
398}
399
400bool LocalDOMWindow::allowPopUp(LocalFrame& firstFrame)
401{
402 if (auto* documentLoader = firstFrame.loader().documentLoader()) {
403 // If pop-up policy was set during navigation, use it. If not, use the global settings.
404 PopUpPolicy popUpPolicy = documentLoader->popUpPolicy();
405 if (popUpPolicy == PopUpPolicy::Allow)
406 return true;
407
408 if (popUpPolicy == PopUpPolicy::Block)
409 return false;
410 }
411
412 return UserGestureIndicator::processingUserGesture()
413 || firstFrame.settings().javaScriptCanOpenWindowsAutomatically();
414}
415
416bool LocalDOMWindow::allowPopUp()
417{
418 RefPtr frame = this->frame();
419 return frame && allowPopUp(*frame);
420}
421
422bool LocalDOMWindow::canShowModalDialog(const LocalFrame& frame)
423{
424 // Override support for layout testing purposes.
425 if (auto* document = frame.document()) {
426 if (auto* window = document->window()) {
427 if (window->m_canShowModalDialogOverride)
428 return window->m_canShowModalDialogOverride.value();
429 }
430 }
431
432 RefPtr page = frame.page();
433 return page && page->chrome().canRunModal();
434}
435
436static void languagesChangedCallback(void* context)
437{
438 Ref window = *static_cast<LocalDOMWindow*>(context);
439 window->languagesChanged();
440}
441
442void LocalDOMWindow::setCanShowModalDialogOverride(bool allow)
443{
444 m_canShowModalDialogOverride = allow;
445}
446
447LocalDOMWindow::LocalDOMWindow(Document& document)
448 : DOMWindow(GlobalWindowIdentifier { Process::identifier(), WindowIdentifier::generate() }, DOMWindowType::Local)
449 , ContextDestructionObserver(&document)
450{
451 ASSERT(frame())((void)0);
452 addLanguageChangeObserver(this, &languagesChangedCallback);
453}
454
455ScriptExecutionContext* LocalDOMWindow::scriptExecutionContext() const
456{
457 return ContextDestructionObserver::scriptExecutionContext();
458}
459
460void LocalDOMWindow::didSecureTransitionTo(Document& document)
461{
462 RefPtr oldDocument = downcast<Document>(scriptExecutionContext());
463 observeContext(&document);
464
465 if (auto* eventTargetData = this->eventTargetData()) {
466 eventTargetData->eventListenerMap.enumerateEventListenerTypes([&](auto& eventType, uint16_t capturingCount, uint16_t bubblingCount) {
467 if (capturingCount) {
468 if (oldDocument)
469 oldDocument->didRemoveEventListenersOfType(eventType, Document::IsCapture::Yes, capturingCount);
470 document.didAddEventListenersOfType(eventType, Document::IsCapture::Yes, capturingCount);
471 }
472 if (bubblingCount) {
473 if (oldDocument)
474 oldDocument->didRemoveEventListenersOfType(eventType, Document::IsCapture::No, bubblingCount);
475 document.didAddEventListenersOfType(eventType, Document::IsCapture::No, bubblingCount);
476 }
477 });
478 }
479
480 // The Window is being transferred from one document to another so we need to reset data
481 // members that store the window's document (rather than the window itself).
482 m_crypto = nullptr;
483 m_navigator = nullptr;
484 m_performance = nullptr;
485 m_customElementRegistry = nullptr;
486}
487
488void LocalDOMWindow::prewarmLocalStorageIfNecessary()
489{
490 RefPtr page = this->page();
491
492 // No need to prewarm for ephemeral sessions since the data is in memory only.
493 if (!page || page->usesEphemeralSession())
494 return;
495
496 // This eagerly constructs the StorageArea, which will load items from disk.
497 auto localStorageResult = this->localStorage();
498 if (localStorageResult.hasException())
499 return;
500
501 RefPtr localStorage = localStorageResult.returnValue();
502 if (!localStorage)
503 return;
504
505 protect(localStorage->area())->prewarm();
506}
507
508LocalDOMWindow::~LocalDOMWindow()
509{
510 if (m_suspendedForDocumentSuspension)
511 willDestroyCachedFrame();
512 else
513 willDestroyDocumentInFrame();
514
515 removeAllUnloadEventListeners(this);
516 removeAllBeforeUnloadEventListeners(this);
517
518#if ENABLE(GAMEPAD)(defined 1 && 1)
519 if (m_gamepadEventListenerCount)
520 GamepadManager::singleton().unregisterDOMWindow(*this);
521#endif
522
523 removeLanguageChangeObserver(this);
524
525 windowsInterestedInStorageEvents().remove(*this);
526}
527
528RefPtr<MediaQueryList> LocalDOMWindow::matchMedia(const String& media)
529{
530 if (RefPtr document = this->document())
531 return document->mediaQueryMatcher().matchMedia(media);
532 return nullptr;
533}
534
535Page* LocalDOMWindow::page() const
536{
537 auto* frame = this->frame();
538 return frame ? frame->page() : nullptr;
539}
540
541void LocalDOMWindow::frameDestroyed()
542{
543 Ref protectedThis { *this };
544
545 willDestroyDocumentInFrame();
546 JSDOMWindowBase::fireFrameClearedWatchpointsForWindow(this);
547}
548
549void LocalDOMWindow::willDestroyCachedFrame()
550{
551 // It is necessary to copy m_observers to a separate vector because the LocalDOMWindowObserver may
552 // unregister themselves from the LocalDOMWindow as a result of the call to willDestroyGlobalObjectInCachedFrame.
553 m_observers.forEach([](auto& observer) {
554 Ref { observer }->willDestroyGlobalObjectInCachedFrame();
555 });
556}
557
558void LocalDOMWindow::willDestroyDocumentInFrame()
559{
560 // It is necessary to copy m_observers to a separate vector because the LocalDOMWindowObserver may
561 // unregister themselves from the LocalDOMWindow as a result of the call to willDestroyGlobalObjectInFrame.
562 m_observers.forEach([](auto& observer) {
563 Ref { observer }->willDestroyGlobalObjectInFrame();
564 });
565}
566
567void LocalDOMWindow::willDetachDocumentFromFrame()
568{
569 if (!frame())
570 return;
571
572 RELEASE_ASSERT(!m_isSuspendingObservers)do { if (__builtin_expect(!!(!(!m_isSuspendingObservers)), 0)
) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash(
); WTFCrashWithInfo(572, "/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/page/LocalDOMWindow.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
573
574 // It is necessary to copy m_observers to a separate vector because the LocalDOMWindowObserver may
575 // unregister themselves from the LocalDOMWindow as a result of the call to willDetachGlobalObjectFromFrame.
576 m_observers.forEach([](auto& observer) {
577 Ref { observer }->willDetachGlobalObjectFromFrame();
578 });
579
580 if (RefPtr performance = m_performance)
581 performance->clearResourceTimings();
582
583 windowsInterestedInStorageEvents().remove(*this);
584
585 JSDOMWindowBase::fireFrameClearedWatchpointsForWindow(this);
586 InspectorInstrumentation::frameWindowDiscarded(*protect(frame()), this);
587}
588
589#if ENABLE(GAMEPAD)(defined 1 && 1)
590
591void LocalDOMWindow::incrementGamepadEventListenerCount()
592{
593 if (++m_gamepadEventListenerCount == 1)
594 GamepadManager::singleton().registerDOMWindow(*this);
595}
596
597void LocalDOMWindow::decrementGamepadEventListenerCount()
598{
599 ASSERT(m_gamepadEventListenerCount)((void)0);
600
601 if (!--m_gamepadEventListenerCount)
602 GamepadManager::singleton().unregisterDOMWindow(*this);
603}
604
605#endif
606
607void LocalDOMWindow::registerObserver(LocalDOMWindowObserver& observer)
608{
609 m_observers.add(observer);
610}
611
612void LocalDOMWindow::unregisterObserver(LocalDOMWindowObserver& observer)
613{
614 m_observers.remove(observer);
615}
616
617void LocalDOMWindow::resetUnlessSuspendedForDocumentSuspension()
618{
619 if (m_suspendedForDocumentSuspension)
620 return;
621 willDestroyDocumentInFrame();
622}
623
624void LocalDOMWindow::suspendForBackForwardCache()
625{
626 // Without this, entries queued just before navigation would have their
627 // duration computed after restoration:
628 if (m_performanceEventTimingCandidates.size())
629 LOG_WITH_STREAM(PerformanceTimeline, stream << "Dispatching event timing entries before suspending to back-forward cache.")((void)0);
630 finalizeAndQueueEventTimingEntries();
631
632 SetForScope isSuspendingObservers(m_isSuspendingObservers, true);
633 RELEASE_ASSERT(frame())do { if (__builtin_expect(!!(!(frame())), 0)) do { WTF::isIntegralOrPointerType
(); compilerFenceForCrash(); WTFCrashWithInfo(633, "/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/page/LocalDOMWindow.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
634
635 m_observers.forEach([](auto& observer) {
636 Ref { observer }->suspendForBackForwardCache();
637 });
638 RELEASE_ASSERT(frame())do { if (__builtin_expect(!!(!(frame())), 0)) do { WTF::isIntegralOrPointerType
(); compilerFenceForCrash(); WTFCrashWithInfo(638, "/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/page/LocalDOMWindow.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
639
640 m_suspendedForDocumentSuspension = true;
641}
642
643void LocalDOMWindow::resumeFromBackForwardCache()
644{
645 m_observers.forEach([](auto& observer) {
646 Ref { observer }->resumeFromBackForwardCache();
647 });
648
649 m_suspendedForDocumentSuspension = false;
650}
651
652CustomElementRegistry& LocalDOMWindow::ensureCustomElementRegistry()
653{
654 if (!m_customElementRegistry) {
655 m_customElementRegistry = CustomElementRegistry::create(*scriptExecutionContext(), *this);
656 for (Ref shadowRoot : document()->inDocumentShadowRoots()) {
657 if (shadowRoot->mode() == ShadowRootMode::UserAgent || shadowRoot->hasScopedCustomElementRegistry())
658 continue;
659 const_cast<ShadowRoot&>(shadowRoot.get()).setCustomElementRegistry(*m_customElementRegistry);
660 }
661 document()->setCustomElementRegistry(*m_customElementRegistry);
662 }
663 ASSERT(!m_customElementRegistry->isScoped())((void)0);
664 ASSERT(m_customElementRegistry->scriptExecutionContext() == document())((void)0);
665 return *m_customElementRegistry;
666}
667
668static ExceptionOr<SelectorQuery&> selectorQueryInFrame(LocalFrame* frame, const String& selectors)
669{
670 if (!frame)
671 return Exception { ExceptionCode::NotSupportedError };
672
673 RefPtr document = frame->document();
674 if (!document)
675 return Exception { ExceptionCode::NotSupportedError };
676
677 return document->selectorQueryForString(selectors);
678}
679
680ExceptionOr<Ref<NodeList>> LocalDOMWindow::collectMatchingElementsInFlatTree(Node& scope, const String& selectors)
681{
682 auto queryOrException = selectorQueryInFrame(frame(), selectors);
683 if (queryOrException.hasException())
684 return queryOrException.releaseException();
685
686 RefPtr scopeContainer = dynamicDowncast<ContainerNode>(scope);
687 if (!scopeContainer)
688 return Ref<NodeList> { StaticElementList::create() };
689
690 SelectorQuery& query = queryOrException.releaseReturnValue();
691
692 Vector<Ref<Element>> result;
693 for (Ref node : composedTreeDescendants(*scopeContainer)) {
694 if (RefPtr element = dynamicDowncast<Element>(node.ptr()); element && query.matches(*element) && !element->isInUserAgentShadowTree())
695 result.append(element.releaseNonNull());
696 }
697
698 return Ref<NodeList> { StaticElementList::create(WTF::move(result)) };
699}
700
701ExceptionOr<RefPtr<Element>> LocalDOMWindow::matchingElementInFlatTree(Node& scope, const String& selectors)
702{
703 auto queryOrException = selectorQueryInFrame(frame(), selectors);
704 if (queryOrException.hasException())
705 return queryOrException.releaseException();
706
707 RefPtr scopeContainer = dynamicDowncast<ContainerNode>(scope);
708 if (!scopeContainer)
709 return RefPtr<Element> { nullptr };
710
711 SelectorQuery& query = queryOrException.releaseReturnValue();
712
713 for (Ref node : composedTreeDescendants(*scopeContainer)) {
714 if (RefPtr element = dynamicDowncast<Element>(node.ptr()); element && query.matches(*element) && !element->isInUserAgentShadowTree())
715 return element;
716 }
717
718 return RefPtr<Element> { nullptr };
719}
720
721#if ENABLE(ORIENTATION_EVENTS)(defined 0 && 0)
722IntDegrees LocalDOMWindow::orientation() const
723{
724 auto* frame = this->frame();
725 if (!frame)
726 return 0;
727 return frame->orientation();
728}
729#endif
730
731Screen& LocalDOMWindow::screen()
732{
733 if (!m_screen)
734 m_screen = Screen::create(*this);
735 return *m_screen;
736}
737
738History& LocalDOMWindow::history()
739{
740 if (!m_history)
741 m_history = History::create(*this);
742 return *m_history;
743}
744
745Navigation& LocalDOMWindow::navigation()
746{
747 if (!m_navigation)
748 m_navigation = Navigation::create(*this);
749 return *m_navigation;
750}
751
752Crypto& LocalDOMWindow::crypto() const
753{
754 if (!m_crypto)
755 m_crypto = Crypto::create(protect(document()).get());
756 ASSERT(m_crypto->scriptExecutionContext() == document())((void)0);
757 return *m_crypto;
758}
759
760BarProp& LocalDOMWindow::locationbar()
761{
762 if (!m_locationbar)
763 m_locationbar = BarProp::create(*this);
764 return *m_locationbar;
765}
766
767BarProp& LocalDOMWindow::menubar()
768{
769 if (!m_menubar)
770 m_menubar = BarProp::create(*this);
771 return *m_menubar;
772}
773
774BarProp& LocalDOMWindow::personalbar()
775{
776 if (!m_personalbar)
777 m_personalbar = BarProp::create(*this);
778 return *m_personalbar;
779}
780
781BarProp& LocalDOMWindow::scrollbars()
782{
783 if (!m_scrollbars)
784 m_scrollbars = BarProp::create(*this);
785 return *m_scrollbars;
786}
787
788BarProp& LocalDOMWindow::statusbar()
789{
790 if (!m_statusbar)
791 m_statusbar = BarProp::create(*this);
792 return *m_statusbar;
793}
794
795BarProp& LocalDOMWindow::toolbar()
796{
797 if (!m_toolbar)
798 m_toolbar = BarProp::create(*this);
799 return *m_toolbar;
800}
801
802Navigator& LocalDOMWindow::navigator()
803{
804 if (!m_navigator)
805 m_navigator = Navigator::create(protect(scriptExecutionContext()).get(), *this);
806 ASSERT(m_navigator->scriptExecutionContext() == document())((void)0);
807
808 return *m_navigator;
809}
810
811Performance& LocalDOMWindow::performance() const
812{
813 if (!m_performance) {
814 RefPtr documentLoader = document() ? document()->loader() : nullptr;
815 auto timeOrigin = documentLoader ? documentLoader->timing().timeOrigin() : MonotonicTime::now();
816 m_performance = Performance::create(protect(document()).get(), timeOrigin);
817 }
818 ASSERT(m_performance->scriptExecutionContext() == document())((void)0);
819 return *m_performance;
820}
821
822ReducedResolutionSeconds LocalDOMWindow::nowTimestamp() const
823{
824 return performance().nowInReducedResolutionSeconds();
825}
826
827void LocalDOMWindow::freezeNowTimestamp()
828{
829 m_frozenNowTimestamp = nowTimestamp();
830}
831
832void LocalDOMWindow::unfreezeNowTimestamp()
833{
834 m_frozenNowTimestamp = std::nullopt;
835}
836
837ReducedResolutionSeconds LocalDOMWindow::frozenNowTimestamp() const
838{
839 return m_frozenNowTimestamp.value_or(nowTimestamp());
840}
841
842VisualViewport& LocalDOMWindow::visualViewport()
843{
844 if (!m_visualViewport)
845 m_visualViewport = VisualViewport::create(*this);
846 return *m_visualViewport;
847}
848
849#if ENABLE(USER_MESSAGE_HANDLERS)(defined 1 && 1)
850
851bool LocalDOMWindow::shouldHaveWebKitNamespaceForWorld(DOMWrapperWorld& world, JSC::JSGlobalObject* globalObject)
852{
853 if (world.allowNodeSerialization())
854 return true;
855
856 if (downcast<JSDOMGlobalObject>(globalObject)->allowsJSHandleCreation())
857 return true;
858
859 RefPtr frame = this->frame();
860 if (!frame)
861 return false;
862
863 RefPtr userContentProvider = frame->userContentProvider();
864 if (!userContentProvider)
865 return false;
866
867 bool hasUserMessageHandler = false;
868 userContentProvider->forEachUserMessageHandler([&](const UserMessageHandlerDescriptor& descriptor) {
869 if (&descriptor.world() == &world) {
870 hasUserMessageHandler = true;
871 return;
872 }
873 });
874
875 if (hasUserMessageHandler)
876 return true;
877
878 return userContentProvider->hasBuffersForWorld(world);
879}
880
881WebKitNamespace* LocalDOMWindow::webkitNamespace()
882{
883 if (!isCurrentlyDisplayedInFrame())
884 return nullptr;
885 RefPtr frame = this->frame();
886 if (!frame)
887 return nullptr;
888 RefPtr userContentProvider = frame->userContentProvider();
889 if (!userContentProvider)
890 return nullptr;
891 if (!m_webkitNamespace)
892 m_webkitNamespace = WebKitNamespace::create(*this, *userContentProvider);
893 return m_webkitNamespace.get();
894}
895
896#endif
897
898ExceptionOr<Storage*> LocalDOMWindow::sessionStorage()
899{
900 if (!isCurrentlyDisplayedInFrame())
901 return nullptr;
902
903 RefPtr document = this->document();
904 if (!document)
905 return nullptr;
906
907 if (document->canAccessResource(ScriptExecutionContext::ResourceType::SessionStorage) == ScriptExecutionContext::HasResourceAccess::No)
908 return Exception { ExceptionCode::SecurityError };
909
910 if (m_sessionStorage)
911 return m_sessionStorage.get();
912
913 RefPtr page = document->page();
914 if (!page)
915 return nullptr;
916
917 if (!page->settings().sessionStorageEnabled())
918 return nullptr;
919
920 Ref storageArea = page->storageNamespaceProvider().sessionStorageArea(*document);
921 m_sessionStorage = Storage::create(*this, WTF::move(storageArea));
922 if (hasEventListeners(eventNames().storageEvent))
923 windowsInterestedInStorageEvents().add(*this);
924 return m_sessionStorage.get();
925}
926
927ExceptionOr<Storage*> LocalDOMWindow::localStorage()
928{
929 if (!isCurrentlyDisplayedInFrame())
930 return nullptr;
931
932 RefPtr document = this->document();
933 if (!document)
934 return nullptr;
935
936 if (document->canAccessResource(ScriptExecutionContext::ResourceType::LocalStorage) == ScriptExecutionContext::HasResourceAccess::No)
937 return Exception { ExceptionCode::SecurityError };
938
939 RefPtr page = document->page();
940 // FIXME: We should consider supporting access/modification to local storage
941 // after calling window.close(). See <https://bugs.webkit.org/show_bug.cgi?id=135330>.
942 if (!page || !page->isClosing()) {
943 if (m_localStorage)
944 return m_localStorage.get();
945 }
946
947 if (!page)
948 return nullptr;
949
950 if (page->isClosing())
951 return nullptr;
952
953 if (!page->settings().localStorageEnabled())
954 return nullptr;
955
956 Ref storageArea = page->storageNamespaceProvider().localStorageArea(*document);
957 m_localStorage = Storage::create(*this, WTF::move(storageArea));
958 if (hasEventListeners(eventNames().storageEvent))
959 windowsInterestedInStorageEvents().add(*this);
960 return m_localStorage.get();
961}
962
963void LocalDOMWindow::processPostMessage(JSC::JSGlobalObject& lexicalGlobalObject, Ref<SecurityOrigin>&& sourceOrigin, const MessageWithMessagePorts& message, RefPtr<WindowProxy>&& incumbentWindowProxy, RefPtr<SecurityOrigin>&& targetOrigin)
964{
965 // Capture stack trace only when inspector front-end is loaded as it may be time consuming.
966 RefPtr document = this->document();
967 RefPtr<ScriptCallStack> stackTrace;
968 if (InspectorInstrumentation::consoleAgentEnabled(document.get()))
969 stackTrace = createScriptCallStack(JSExecState::currentState());
970
971 auto postMessageIdentifier = InspectorInstrumentation::willPostMessage(*frame());
972
973 auto userGestureToForward = UserGestureIndicator::currentUserGesture();
974
975 protect(document->eventLoop())->queueTask(TaskSource::PostedMessageQueue, [this, protectedThis = Ref { *this }, message = message, incumbentWindowProxy = WTF::move(incumbentWindowProxy), sourceOrigin = WTF::move(sourceOrigin), userGestureToForward = WTF::move(userGestureToForward), postMessageIdentifier, stackTrace = WTF::move(stackTrace), targetOrigin = WTF::move(targetOrigin)]() mutable {
976 if (!isCurrentlyDisplayedInFrame())
977 return;
978
979 RefPtr document = this->document();
980 Ref frame = *this->frame();
981 if (targetOrigin) {
982 // Check target origin now since the target document may have changed since the timer was scheduled.
983 if (!targetOrigin->isSameSchemeHostPort(protect(document->securityOrigin()))) {
984 if (CheckedPtr frameConsole = console()) {
985 auto message = makeString("Unable to post message to "_s, targetOrigin->toString(), ". Recipient has origin "_s, document->securityOrigin().toString(), ".\n"_s);
986 if (stackTrace)
987 frameConsole->addMessage(MessageSource::Security, MessageLevel::Error, message, *stackTrace);
988 else
989 frameConsole->addMessage(MessageSource::Security, MessageLevel::Error, message);
990 }
991
992 InspectorInstrumentation::didFailPostMessage(frame, postMessageIdentifier);
993 return;
994 }
995 }
996
997 auto* globalObject = document->globalObject();
998 if (!globalObject)
999 return;
1000
1001 auto& vm = globalObject->vm();
1002 auto scope = DECLARE_TOP_EXCEPTION_SCOPE(vm)JSC::TopExceptionScope((vm));
1003
1004 if (userGestureToForward && userGestureToForward->hasExpired(UserGestureToken::maximumIntervalForUserGestureForwarding))
1005 userGestureToForward = nullptr;
1006
1007 if (userGestureToForward && userGestureToForward->hasExpired(UserGestureToken::maximumIntervalForUserGestureForwarding))
1008 userGestureToForward = nullptr;
1009
1010 if (userGestureToForward && userGestureToForward->hasExpired(UserGestureToken::maximumIntervalForUserGestureForwarding))
1011 userGestureToForward = nullptr;
1012
1013 UserGestureIndicator userGestureIndicator(userGestureToForward);
1014 InspectorInstrumentation::willDispatchPostMessage(frame, postMessageIdentifier);
1015
1016 auto ports = MessagePort::entanglePorts(*document, WTF::move(message.transferredPorts));
1017 auto event = MessageEvent::create(*globalObject, message.message.releaseNonNull(), WTF::move(sourceOrigin), { }, incumbentWindowProxy ? std::optional { MessageEventSource(incumbentWindowProxy.releaseNonNull()) } : std::nullopt, WTF::move(ports));
1018 if (scope.exception()) [[unlikely]] {
1019 // Currently, we assume that the only way we can get here is if we have a termination.
1020 RELEASE_ASSERT(vm.hasPendingTerminationException())do { if (__builtin_expect(!!(!(vm.hasPendingTerminationException
())), 0)) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(1020, "/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/page/LocalDOMWindow.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
1021 return;
1022 }
1023
1024 dispatchEvent(event.event);
1025
1026 InspectorInstrumentation::didDispatchPostMessage(frame, postMessageIdentifier);
1027 });
1028
1029 InspectorInstrumentation::didPostMessage(*protect(frame()), postMessageIdentifier, lexicalGlobalObject);
1030}
1031
1032ExceptionOr<void> LocalDOMWindow::postMessage(JSC::JSGlobalObject& lexicalGlobalObject, LocalDOMWindow& incumbentWindow, JSC::JSValue messageValue, WindowPostMessageOptions&& options)
1033{
1034 if (!isCurrentlyDisplayedInFrame())
1035 return { };
1036
1037 RefPtr sourceDocument = incumbentWindow.document();
1038 if (!sourceDocument)
1039 return { };
1040
1041 auto targetSecurityOrigin = createTargetOriginForPostMessage(options.targetOrigin, *sourceDocument);
1042 if (targetSecurityOrigin.hasException())
1043 return targetSecurityOrigin.releaseException();
1044
1045 Vector<Ref<MessagePort>> ports;
1046 auto messageData = SerializedScriptValue::create(lexicalGlobalObject, messageValue, WTF::move(options.transfer), ports, SerializationForStorage::No);
1047 if (messageData.hasException())
1048 return messageData.releaseException();
1049
1050 auto disentangledPorts = MessagePort::disentanglePorts(WTF::move(ports));
1051 if (disentangledPorts.hasException())
1052 return disentangledPorts.releaseException();
1053
1054 // Capture the source of the message. We need to do this synchronously
1055 // in order to capture the source of the message correctly.
1056 Ref sourceOrigin = sourceDocument->securityOrigin();
1057
1058 // Schedule the message.
1059 RefPtr incumbentWindowProxy = incumbentWindow.frame() ? &incumbentWindow.frame()->windowProxy() : nullptr;
1060 MessageWithMessagePorts message { messageData.releaseReturnValue(), disentangledPorts.releaseReturnValue() };
1061 processPostMessage(lexicalGlobalObject, WTF::move(sourceOrigin), message, WTF::move(incumbentWindowProxy), targetSecurityOrigin.releaseReturnValue());
1062 return { };
1063}
1064
1065void LocalDOMWindow::postMessageFromRemoteFrame(JSC::JSGlobalObject& lexicalGlobalObject, RefPtr<WindowProxy>&& source, const WebCore::SecurityOriginData& sourceOrigin, std::optional<WebCore::SecurityOriginData>&& targetOriginData, const WebCore::MessageWithMessagePorts& message)
1066{
1067 if (!frame())
1068 return;
1069
1070 RefPtr<SecurityOrigin> targetOrigin;
1071 if (targetOriginData)
1072 targetOrigin = targetOriginData->securityOrigin();
1073
1074 processPostMessage(lexicalGlobalObject, sourceOrigin.securityOrigin(), message, WTF::move(source), WTF::move(targetOrigin));
1075}
1076
1077DOMSelection* LocalDOMWindow::getSelection()
1078{
1079 if (!isCurrentlyDisplayedInFrame())
1080 return nullptr;
1081 if (!m_selection)
1082 m_selection = DOMSelection::create(*this);
1083 return m_selection.get();
1084}
1085
1086HTMLFrameOwnerElement* LocalDOMWindow::frameElement() const
1087{
1088 auto* frame = this->frame();
1089 if (!frame)
1090 return nullptr;
1091
1092 return frame->ownerElement();
1093}
1094
1095void LocalDOMWindow::focus(LocalDOMWindow& incumbentWindow)
1096{
1097 RefPtr frame = this->frame();
1098 RefPtr openerFrame = frame ? frame->opener() : nullptr;
1099 focus([&] {
1100 if (!openerFrame || openerFrame == frame || incumbentWindow.frame() != openerFrame)
1101 return false;
1102
1103 auto* page = openerFrame->page();
1104 return page && page->isVisibleAndActive();
1105 }());
1106}
1107
1108void LocalDOMWindow::focus(bool allowFocus)
1109{
1110 RefPtr frame = this->frame();
1111 if (!frame)
1112 return;
1113
1114 RefPtr page = frame->page();
1115 if (!page)
1116 return;
1117
1118 allowFocus = allowFocus || WindowFocusAllowedIndicator::windowFocusAllowed() || !frame->settings().windowFocusRestricted();
1119
1120 // If we're a top level window, bring the window to the front.
1121 if (frame->isMainFrame() && allowFocus)
1122 page->chrome().focus();
1123
1124 if (!frame->hasHadUserInteraction() && !isSameSecurityOriginAsMainFrame())
1125 return;
1126
1127 // Clear the current frame's focused node if a new frame is about to be focused.
1128 RefPtr focusedFrame = page->focusController().localFocusedFrame();
1129 if (focusedFrame && focusedFrame != frame)
1130 protect(focusedFrame->document())->setFocusedElement(nullptr);
1131
1132 frame->eventHandler().focusDocumentView();
1133}
1134
1135void LocalDOMWindow::blur()
1136{
1137 RefPtr frame = this->frame();
1138 if (!frame)
1139 return;
1140
1141 RefPtr page = frame->page();
1142 if (!page)
1143 return;
1144
1145 if (frame->settings().windowFocusRestricted())
1146 return;
1147
1148 if (!frame->isMainFrame())
1149 return;
1150
1151 page->chrome().unfocus();
1152}
1153
1154void LocalDOMWindow::closePage()
1155{
1156 protect(protect(document())->eventLoop())->queueTask(TaskSource::DOMManipulation, [this, protectedThis = Ref { *this }] {
1157 // Calling closeWindow() may destroy the page.
1158 if (RefPtr page = this->page())
1159 page->chrome().closeWindow();
1160 });
1161}
1162
1163void LocalDOMWindow::print()
1164{
1165 RefPtr frame = this->frame();
1166 if (!frame)
1167 return;
1168
1169 RefPtr page = frame->page();
1170 if (!page)
1171 return;
1172
1173 if (!page->arePromptsAllowed()) {
1174 printErrorMessage("Use of window.print is not allowed while unloading a page."_s);
1175 return;
1176 }
1177
1178 if (page->isControlledByAutomation())
1179 return;
1180
1181 if (auto* loader = frame->loader().activeDocumentLoader(); loader && loader->isLoading()) {
1182 m_shouldPrintWhenFinishedLoading = true;
1183 return;
1184 }
1185 m_shouldPrintWhenFinishedLoading = false;
1186 page->chrome().print(*frame);
1187}
1188
1189void LocalDOMWindow::stop()
1190{
1191 RefPtr frame = this->frame();
1192 if (!frame)
1193 return;
1194
1195 SetForScope isStopping { m_isStopping, true };
1196 // We must check whether the load is complete asynchronously, because we might still be parsing
1197 // the document until the callstack unwinds.
1198 frame->loader().stopForUserCancel(true);
1199}
1200
1201void LocalDOMWindow::alert(const String& message)
1202{
1203 RefPtr frame = this->frame();
1204 if (!frame)
1205 return;
1206
1207 RefPtr document = this->document();
1208 if (document->isSandboxed(SandboxFlag::Modals)) {
1209 printErrorMessage("Use of window.alert is not allowed in a sandboxed frame when the allow-modals flag is not set."_s);
1210 return;
1211 }
1212
1213 RefPtr page = frame->page();
1214 if (!page)
1215 return;
1216
1217 if (!page->arePromptsAllowed()) {
1218 printErrorMessage("Use of window.alert is not allowed while unloading a page."_s);
1219 return;
1220 }
1221
1222 document->updateStyleIfNeeded();
1223#if ENABLE(POINTER_LOCK)(defined 1 && 1)
1224 page->pointerLockController().requestPointerUnlock();
1225#endif
1226
1227 page->chrome().runJavaScriptAlert(*frame, message);
1228}
1229
1230bool LocalDOMWindow::confirmForBindings(const String& message)
1231{
1232 RefPtr frame = this->frame();
1233 if (!frame)
1234 return false;
1235
1236 RefPtr document = this->document();
1237 if (document->isSandboxed(SandboxFlag::Modals)) {
1238 printErrorMessage("Use of window.confirm is not allowed in a sandboxed frame when the allow-modals flag is not set."_s);
1239 return false;
1240 }
1241
1242 RefPtr page = frame->page();
1243 if (!page)
1244 return false;
1245
1246 if (!page->arePromptsAllowed()) {
1247 printErrorMessage("Use of window.confirm is not allowed while unloading a page."_s);
1248 return false;
1249 }
1250
1251 document->updateStyleIfNeeded();
1252#if ENABLE(POINTER_LOCK)(defined 1 && 1)
1253 page->pointerLockController().requestPointerUnlock();
1254#endif
1255
1256 return page->chrome().runJavaScriptConfirm(*frame, message);
1257}
1258
1259String LocalDOMWindow::prompt(const String& message, const String& defaultValue)
1260{
1261 RefPtr frame = this->frame();
1262 if (!frame)
1263 return String();
1264
1265 RefPtr document = this->document();
1266 if (document->isSandboxed(SandboxFlag::Modals)) {
1267 printErrorMessage("Use of window.prompt is not allowed in a sandboxed frame when the allow-modals flag is not set."_s);
1268 return String();
1269 }
1270
1271 RefPtr page = frame->page();
1272 if (!page)
1273 return String();
1274
1275 if (!page->arePromptsAllowed()) {
1276 printErrorMessage("Use of window.prompt is not allowed while unloading a page."_s);
1277 return String();
1278 }
1279
1280 document->updateStyleIfNeeded();
1281#if ENABLE(POINTER_LOCK)(defined 1 && 1)
1282 page->pointerLockController().requestPointerUnlock();
1283#endif
1284
1285 String returnValue;
1286 if (page->chrome().runJavaScriptPrompt(*frame, message, defaultValue, returnValue))
1287 return returnValue;
1288
1289 return String();
1290}
1291
1292bool LocalDOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const
1293{
1294 // SearchBuffer allocates memory much larger than the searched string, so it's necessary to limit its length.
1295 // Most searches are for a phrase or a paragraph, so an upper limit of 64kB is more than enough in practice.
1296 constexpr auto maximumStringLength = std::numeric_limits<uint16_t>::max();
1297 if (!isCurrentlyDisplayedInFrame() || string.length() > maximumStringLength)
1298 return false;
1299
1300 // FIXME (13016): Support wholeWord, searchInFrames and showDialog.
1301 FindOptions options { FindOption::DoNotTraverseFlatTree };
1302 if (backwards)
1303 options.add(FindOption::Backwards);
1304 if (!caseSensitive)
1305 options.add(FindOption::CaseInsensitive);
1306 if (wrap)
1307 options.add(FindOption::WrapAround);
1308 return frame()->editor().findString(string, options).has_value();
1309}
1310
1311bool LocalDOMWindow::offscreenBuffering() const
1312{
1313 return true;
1314}
1315
1316int LocalDOMWindow::outerHeight() const
1317{
1318 RefPtr frame = this->frame();
1319 if (!frame)
1320 return 0;
1321
1322 RefPtr page = frame->page();
1323 if (!page)
1324 return 0;
1325
1326 if (page->shouldApplyScreenFingerprintingProtections(*protect(document())))
1327 return innerHeight();
1328
1329#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
1330 RefPtr localFrame = dynamicDowncast<LocalFrame>(frame->mainFrame());
1331 if (!localFrame)
1332 return 0;
1333
1334 RefPtr view = frame->isMainFrame() ? frame->view() : localFrame->view();
1335 if (!view)
1336 return 0;
1337
1338 return view->frameRect().height();
1339#else
1340 return static_cast<int>(page->chrome().windowRect().height());
1341#endif
1342}
1343
1344int LocalDOMWindow::outerWidth() const
1345{
1346 RefPtr frame = this->frame();
1347 if (!frame)
1348 return 0;
1349
1350 RefPtr page = frame->page();
1351 if (!page)
1352 return 0;
1353
1354 if (page->shouldApplyScreenFingerprintingProtections(*protect(document())))
1355 return innerWidth();
1356
1357#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
1358 RefPtr localFrame = dynamicDowncast<LocalFrame>(frame->mainFrame());
1359 if (!localFrame)
1360 return 0;
1361
1362 RefPtr view = frame->isMainFrame() ? frame->view() : localFrame->view();
1363 if (!view)
1364 return 0;
1365
1366 return view->frameRect().width();
1367#else
1368 return static_cast<int>(page->chrome().windowRect().width());
1369#endif
1370}
1371
1372int LocalDOMWindow::innerHeight() const
1373{
1374 if (!frame())
1375 return 0;
1376
1377 // Force enough layout in the parent document to ensure that the FrameView has been resized.
1378 if (RefPtr ownerElement = frameElement())
1379 protect(ownerElement->document())->updateLayoutIfDimensionsOutOfDate(*ownerElement, { DimensionsCheck::Height });
1380
1381 RefPtr frame = this->frame();
1382 if (!frame)
1383 return 0;
1384
1385 RefPtr view = frame->view();
1386 if (!view)
1387 return 0;
1388
1389 return view->mapFromLayoutToCSSUnits(static_cast<int>(view->unobscuredContentRectIncludingScrollbars().height()));
1390}
1391
1392int LocalDOMWindow::innerWidth() const
1393{
1394 if (!frame())
1395 return 0;
1396
1397 // Force enough layout in the parent document to ensure that the FrameView has been resized.
1398 if (RefPtr ownerElement = frameElement())
1399 protect(ownerElement->document())->updateLayoutIfDimensionsOutOfDate(*ownerElement, { DimensionsCheck::Width });
1400
1401 RefPtr frame = this->frame();
1402 if (!frame)
1403 return 0;
1404
1405 RefPtr view = frame->view();
1406 if (!view)
1407 return 0;
1408
1409 return view->mapFromLayoutToCSSUnits(static_cast<int>(view->unobscuredContentRectIncludingScrollbars().width()));
1410}
1411
1412int LocalDOMWindow::screenX() const
1413{
1414 RefPtr frame = this->frame();
1415 if (!frame)
1416 return 0;
1417
1418 RefPtr page = frame->page();
1419 if (!page || page->shouldApplyScreenFingerprintingProtections(*protect(document())))
1420 return 0;
1421
1422 return static_cast<int>(page->chrome().windowRect().x());
1423}
1424
1425int LocalDOMWindow::screenY() const
1426{
1427 RefPtr frame = this->frame();
1428 if (!frame)
1429 return 0;
1430
1431 RefPtr page = frame->page();
1432 if (!page || page->shouldApplyScreenFingerprintingProtections(*protect(document())))
1433 return 0;
1434
1435 return static_cast<int>(page->chrome().windowRect().y());
1436}
1437
1438int LocalDOMWindow::scrollX() const
1439{
1440 RefPtr frame = this->frame();
1441 if (!frame)
1442 return 0;
1443
1444 RefPtr view = frame->view();
1445 if (!view)
1446 return 0;
1447
1448 int scrollX = view->contentsScrollPosition().x();
1449 if (!scrollX)
1450 return 0;
1451
1452 protect(frame->document())->updateLayoutIgnorePendingStylesheets();
1453
1454 // Layout may have affected the current frame:
1455 RefPtr frameAfterLayout = this->frame();
1456 if (!frameAfterLayout)
1457 return 0;
1458
1459 RefPtr viewAfterLayout = frameAfterLayout->view();
1460 if (!viewAfterLayout)
1461 return 0;
1462
1463 return viewAfterLayout->mapFromLayoutToCSSUnits(viewAfterLayout->contentsScrollPosition().x());
1464}
1465
1466int LocalDOMWindow::scrollY() const
1467{
1468 RefPtr frame = this->frame();
1469 if (!frame)
1470 return 0;
1471
1472 RefPtr view = frame->view();
1473 if (!view)
1474 return 0;
1475
1476 int scrollY = view->contentsScrollPosition().y();
1477 if (!scrollY)
1478 return 0;
1479
1480 protect(frame->document())->updateLayoutIgnorePendingStylesheets();
1481
1482 // Layout may have affected the current frame:
1483 RefPtr frameAfterLayout = this->frame();
1484 if (!frameAfterLayout)
1485 return 0;
1486
1487 RefPtr viewAfterLayout = frameAfterLayout->view();
1488 if (!viewAfterLayout)
1489 return 0;
1490
1491 return viewAfterLayout->mapFromLayoutToCSSUnits(viewAfterLayout->contentsScrollPosition().y());
1492}
1493
1494unsigned LocalDOMWindow::length() const
1495{
1496 if (!isCurrentlyDisplayedInFrame())
1497 return 0;
1498
1499 return frame()->tree().scopedChildCount();
1500}
1501
1502AtomString LocalDOMWindow::name() const
1503{
1504 auto* frame = this->frame();
1505 if (!frame)
1506 return nullAtom();
1507
1508 return frame->tree().specifiedName();
1509}
1510
1511void LocalDOMWindow::setName(const AtomString& string)
1512{
1513 RefPtr frame = this->frame();
1514 if (!frame)
1515 return;
1516
1517 frame->tree().setSpecifiedName(string);
1518 frame->loader().client().frameNameChanged(string.string());
1519}
1520
1521void LocalDOMWindow::setStatus(const String& string)
1522{
1523 m_status = string;
1524}
1525
1526void LocalDOMWindow::disownOpener()
1527{
1528 if (RefPtr frame = this->frame())
1529 frame->disownOpener(Frame::NotifyUIProcess::Yes);
1530}
1531
1532String LocalDOMWindow::origin() const
1533{
1534 RefPtr document = this->document();
1535 return document ? document->securityOrigin().toString() : emptyString();
1536}
1537
1538SecurityOrigin* LocalDOMWindow::securityOrigin() const
1539{
1540 RefPtr document = this->document();
1541 return document ? &document->securityOrigin() : nullptr;
1542}
1543
1544Document* LocalDOMWindow::document() const
1545{
1546 return downcast<Document>(ContextDestructionObserver::scriptExecutionContext());
1547}
1548
1549void LocalDOMWindow::overrideTransientActivationDurationForTesting(std::optional<Seconds>&& override)
1550{
1551 transientActivationDurationOverrideForTesting() = WTF::move(override);
1552}
1553
1554// When the current high resolution time is greater than or equal to the last activation timestamp in W, and
1555// less than the last activation timestamp in W plus the transient activation duration, then W is said to
1556// have transient activation. (https://html.spec.whatwg.org/multipage/interaction.html#transient-activation)
1557bool LocalDOMWindow::hasTransientActivation() const
1558{
1559 auto now = MonotonicTime::now();
1560 return now >= m_lastActivationTimestamp && now < (m_lastActivationTimestamp + transientActivationDuration());
1561}
1562
1563// When the current high resolution time given W is greater than or equal to the last activation timestamp in W,
1564// W is said to have sticky activation. (https://html.spec.whatwg.org/multipage/interaction.html#sticky-activation)
1565bool LocalDOMWindow::hasStickyActivation() const
1566{
1567 auto now = MonotonicTime::now();
1568 return now >= m_lastActivationTimestamp;
1569}
1570
1571// When the last history-action activation timestamp of W is not equal to the last activation timestamp of W,
1572// then W is said to have history-action activation.
1573// (https://html.spec.whatwg.org/multipage/interaction.html#history-action-activation)
1574bool LocalDOMWindow::hasHistoryActionActivation() const
1575{
1576 return m_lastHistoryActionActivationTimestamp != m_lastActivationTimestamp;
1577}
1578
1579// https://html.spec.whatwg.org/multipage/interaction.html#consume-user-activation
1580bool LocalDOMWindow::consumeTransientActivation()
1581{
1582 if (!hasTransientActivation())
1583 return false;
1584
1585 RefPtr thisFrame = this->frame();
1586 for (auto* frame = thisFrame ? &thisFrame->tree().top() : nullptr; frame; frame = frame->tree().traverseNext()) {
1587 auto* localFrame = dynamicDowncast<LocalFrame>(frame);
1588 if (!localFrame)
1589 continue;
1590 if (auto* window = localFrame->window())
1591 window->consumeLastActivationIfNecessary();
1592 }
1593
1594 if (thisFrame && thisFrame->settings().siteIsolationEnabled())
1595 thisFrame->loader().client().didConsumeUserActivation();
1596
1597 return true;
1598}
1599
1600void LocalDOMWindow::consumeLastActivationIfNecessary()
1601{
1602 if (!m_lastActivationTimestamp.isInfinity())
1603 m_lastActivationTimestamp = -MonotonicTime::infinity();
1604}
1605
1606// https://html.spec.whatwg.org/multipage/interaction.html#consume-history-action-user-activation
1607bool LocalDOMWindow::consumeHistoryActionUserActivation()
1608{
1609 if (!hasHistoryActionActivation())
1610 return false;
1611
1612 for (auto* frame = this->frame() ? &this->frame()->tree().top() : nullptr; frame; frame = frame->tree().traverseNext()) {
1613 auto* localFrame = dynamicDowncast<LocalFrame>(frame);
1614 if (!localFrame)
1615 continue;
1616 if (auto* window = localFrame->window())
1617 window->m_lastHistoryActionActivationTimestamp = window->m_lastActivationTimestamp;
1618 }
1619
1620 return true;
1621}
1622
1623void LocalDOMWindow::updateLastUserClickEvent(OptionSet<PlatformEventModifier> modifiers)
1624{
1625 m_lastUserClickEvent = ClickEventData {
1626 MonotonicTime::now(),
1627 modifiers
1628 };
1629}
1630
1631std::optional<LocalDOMWindow::ClickEventData> LocalDOMWindow::consumeLastUserClickEvent()
1632{
1633 return std::exchange(m_lastUserClickEvent, std::nullopt);
1634}
1635
1636// https://html.spec.whatwg.org/multipage/interaction.html#activation-notification
1637void LocalDOMWindow::notifyActivated(MonotonicTime activationTime)
1638{
1639 setLastActivationTimestamp(activationTime);
1640 RefPtr frame = this->frame();
1641 if (!frame)
1642 return;
1643 if (frame->settings().closeWatcherEnabled())
1644 closeWatcherManager().notifyAboutUserActivation();
1645
1646 for (auto* ancestor = frame->tree().parent(); ancestor; ancestor = ancestor->tree().parent()) {
1647 auto* localAncestor = dynamicDowncast<LocalFrame>(ancestor);
1648 if (!localAncestor)
1649 continue;
1650 if (auto* window = localAncestor->window())
1651 window->setLastActivationTimestamp(activationTime);
1652 }
1653
1654 RefPtr securityOrigin = this->securityOrigin();
1655 if (!securityOrigin)
1656 return;
1657
1658 RefPtr<Frame> descendant = frame;
1659 while ((descendant = descendant->tree().traverseNext(frame.get()))) {
1660 RefPtr localDescendant = dynamicDowncast<LocalFrame>(descendant.get());
1661 if (!localDescendant)
1662 continue;
1663 RefPtr descendantWindow = localDescendant->window();
1664 if (!descendantWindow)
1665 continue;
1666
1667 RefPtr descendantSecurityOrigin = descendantWindow->securityOrigin();
1668 if (!descendantSecurityOrigin || !descendantSecurityOrigin->isSameOriginAs(*securityOrigin))
1669 continue;
1670
1671 descendantWindow->setLastActivationTimestamp(activationTime);
1672 }
1673
1674 if (frame->settings().siteIsolationEnabled())
1675 frame->loader().client().didNotifyUserActivation(activationTime);
1676}
1677
1678StyleMedia& LocalDOMWindow::styleMedia()
1679{
1680 if (!m_media)
1681 m_media = StyleMedia::create(*this);
1682 return *m_media;
1683}
1684
1685Ref<CSSStyleDeclaration> LocalDOMWindow::getComputedStyle(Element& element, const String& pseudoElt) const
1686{
1687 if (!pseudoElt.startsWith(':'))
1688 return CSSComputedStyleDeclaration::create(element, std::nullopt);
1689
1690 auto resolved = Style::resolveComputedPseudoElement(element, pseudoElt);
1691 if (!resolved.element)
1692 return CSSComputedStyleDeclaration::createEmpty(element);
1693 return CSSComputedStyleDeclaration::create(resolved.element.releaseNonNull(), resolved.identifier);
1694}
1695
1696RefPtr<CSSRuleList> LocalDOMWindow::getMatchedCSSRules(Element* element, const String& pseudoElement, bool authorOnly) const
1697{
1698 if (!isCurrentlyDisplayedInFrame())
1699 return nullptr;
1700
1701 Ref document = *this->document();
1702 auto pseudoElementIdentifier = CSSSelectorParser::parsePseudoElement(pseudoElement, CSSSelectorParserContext { document });
1703 // Reject new features, such as ::highlight(name) and ::file-selector-button.
1704 if (pseudoElementIdentifier && !pseudoElementIdentifier->nameOrPart.isNull())
1705 pseudoElementIdentifier = std::nullopt;
1706 if (!pseudoElementIdentifier && !pseudoElement.isEmpty())
1707 return nullptr;
1708
1709 document->styleScope().flushPendingUpdate();
1710
1711 unsigned rulesToInclude = Style::Resolver::AuthorCSSRules;
1712 if (!authorOnly)
1713 rulesToInclude |= Style::Resolver::UAAndUserCSSRules;
1714
1715 auto matchedRules = document->styleScope().resolver().pseudoStyleRulesForElement(element, pseudoElementIdentifier, rulesToInclude);
1716 if (matchedRules.isEmpty())
1717 return nullptr;
1718
1719 bool allowCrossOrigin = document->settings().crossOriginCheckInGetMatchedCSSRulesDisabled();
1720
1721 auto ruleList = StaticCSSRuleList::create();
1722 for (auto& rule : matchedRules) {
1723 if (!allowCrossOrigin && !rule->hasDocumentSecurityOrigin())
1724 continue;
1725 ruleList->rules().append(rule->createCSSOMWrapper());
1726 }
1727
1728 if (ruleList->rules().isEmpty())
1729 return nullptr;
1730
1731 return ruleList;
1732}
1733
1734RefPtr<WebKitPoint> LocalDOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const
1735{
1736 if (!node || !p)
1737 return nullptr;
1738
1739 RefPtr document = this->document();
1740 if (!document)
1741 return nullptr;
1742
1743 document->updateLayoutIgnorePendingStylesheets();
1744
1745 FloatPoint pagePoint(p->x(), p->y());
1746 pagePoint = node->convertToPage(pagePoint);
1747 return WebKitPoint::create(pagePoint.x(), pagePoint.y());
1748}
1749
1750RefPtr<WebKitPoint> LocalDOMWindow::webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const
1751{
1752 if (!node || !p)
1753 return nullptr;
1754
1755 RefPtr document = this->document();
1756 if (!document)
1757 return nullptr;
1758
1759 document->updateLayoutIgnorePendingStylesheets();
1760
1761 FloatPoint nodePoint(p->x(), p->y());
1762 nodePoint = node->convertFromPage(nodePoint);
1763 return WebKitPoint::create(nodePoint.x(), nodePoint.y());
1764}
1765
1766double LocalDOMWindow::devicePixelRatio() const
1767{
1768 RefPtr frame = this->frame();
1769 if (!frame)
1770 return 0.0;
1771
1772 RefPtr page = frame->page();
1773 if (!page)
1774 return 0.0;
1775
1776 // Page zoom applies to all frames synchronously, so include it in devicePixelRatio
1777 // for both main frame and iframes. frameScaleFactor() doesn't include page zoom
1778 // since page zoom is applied globally for rendering.
1779 auto frameScaleRatio = frame->frameScaleFactor() * frame->pageZoomFactor();
1780 return page->deviceScaleFactor() * frameScaleRatio;
1781}
1782
1783void LocalDOMWindow::scrollBy(double x, double y) const
1784{
1785 scrollBy(ScrollToOptions { { ScrollBehavior::Auto }, x, y });
1786}
1787
1788void LocalDOMWindow::scrollBy(const ScrollToOptions& options) const
1789{
1790 if (!isCurrentlyDisplayedInFrame())
1791 return;
1792
1793 protect(document())->updateLayoutIgnorePendingStylesheets();
1794
1795 RefPtr frame = this->frame();
1796 if (!frame)
1797 return;
1798
1799 RefPtr view = frame->view();
1800 if (!view)
1801 return;
1802
1803 ScrollToOptions scrollToOptions = normalizeNonFiniteCoordinatesOrFallBackTo(options, 0, 0);
1804 FloatSize originalDelta(scrollToOptions.left.value(), scrollToOptions.top.value());
1805 scrollToOptions.left.value() += view->mapFromLayoutToCSSUnits(view->contentsScrollPosition().x());
1806 scrollToOptions.top.value() += view->mapFromLayoutToCSSUnits(view->contentsScrollPosition().y());
1807 scrollTo(scrollToOptions, ScrollClamping::Clamped, ScrollSnapPointSelectionMethod::Directional, originalDelta);
1808}
1809
1810void LocalDOMWindow::scrollTo(double x, double y, ScrollClamping clamping) const
1811{
1812 scrollTo(ScrollToOptions { { ScrollBehavior::Auto }, x, y }, clamping);
1813}
1814
1815void LocalDOMWindow::scrollTo(const ScrollToOptions& options, ScrollClamping clamping, ScrollSnapPointSelectionMethod snapPointSelectionMethod, std::optional<FloatSize> originalScrollDelta) const
1816{
1817 if (!isCurrentlyDisplayedInFrame())
1818 return;
1819
1820 RefPtr view = frame()->view();
1821 if (!view)
1822 return;
1823
1824 ScrollToOptions scrollToOptions = normalizeNonFiniteCoordinatesOrFallBackTo(options,
1825 view->contentsScrollPosition().x(), view->contentsScrollPosition().y()
1826 );
1827
1828 // This is an optimization for the common case of scrolling to (0, 0) when the scroller is already at the origin.
1829 // If an animated scroll is in progress, this optimization is skipped to ensure that the animated scroll is really stopped.
1830 if (view->scrollAnimationStatus() == ScrollAnimationStatus::NotAnimating && !scrollToOptions.left.value() && !scrollToOptions.top.value() && view->contentsScrollPosition().isZero()) {
1831 LOG_WITH_STREAM(Scrolling, stream << "LocalDOMWindow::scrollTo bailing because going to 0,0")((void)0);
1832 return;
1833 }
1834
1835 view->cancelScheduledScrolls();
1836 protect(document())->updateLayoutIgnorePendingStylesheets(LayoutOptions::UpdateCompositingLayers);
1837
1838 IntPoint layoutPos(view->mapFromCSSToLayoutUnits(scrollToOptions.left.value()), view->mapFromCSSToLayoutUnits(scrollToOptions.top.value()));
1839
1840 // FIXME: Should we use document()->scrollingElement()?
1841 // See https://bugs.webkit.org/show_bug.cgi?id=205059
1842 auto animated = useSmoothScrolling(scrollToOptions.behavior, protect(document()->documentElement()).get()) ? ScrollIsAnimated::Yes : ScrollIsAnimated::No;
1843 auto scrollPositionChangeOptions = ScrollPositionChangeOptions::createProgrammaticWithOptions(clamping, animated, snapPointSelectionMethod, originalScrollDelta);
1844 view->setContentsScrollPosition(layoutPos, scrollPositionChangeOptions);
1845}
1846
1847bool LocalDOMWindow::allowedToChangeWindowGeometry() const
1848{
1849 auto* frame = this->frame();
1850 if (!frame)
1851 return false;
1852 if (!frame->page())
1853 return false;
1854 if (!frame->isMainFrame())
1855 return false;
1856 // Prevent web content from tricking the user into initiating a drag.
1857 if (frame->eventHandler().mousePressed())
1858 return false;
1859 return true;
1860}
1861
1862void LocalDOMWindow::moveBy(int x, int y) const
1863{
1864 if (!allowedToChangeWindowGeometry())
1865 return;
1866
1867 RefPtr page = frame()->page();
1868 auto fr = page->chrome().windowRect();
1869 auto update = fr;
1870 update.move(x, y);
1871 page->chrome().setWindowRect(adjustWindowRect(*page, update));
1872}
1873
1874void LocalDOMWindow::moveTo(int x, int y) const
1875{
1876 if (!allowedToChangeWindowGeometry())
1877 return;
1878
1879 RefPtr page = frame()->page();
1880 auto update = page->chrome().windowRect();
1881 RefPtr localMainFrame = page->localMainFrame();
1882 if (!localMainFrame)
1883 return;
1884
1885 update.setLocation(LayoutPoint(x, y));
1886 page->chrome().setWindowRect(adjustWindowRect(*page, update));
1887}
1888
1889void LocalDOMWindow::resizeBy(int x, int y) const
1890{
1891 if (!allowedToChangeWindowGeometry())
1892 return;
1893
1894 RefPtr page = frame()->page();
1895 auto fr = page->chrome().windowRect();
1896 auto dest = fr.size() + LayoutSize(x, y);
1897 LayoutRect update(fr.location(), dest);
1898 page->chrome().setWindowRect(adjustWindowRect(*page, update));
1899}
1900
1901void LocalDOMWindow::resizeTo(int width, int height) const
1902{
1903 if (!allowedToChangeWindowGeometry())
1904 return;
1905
1906 RefPtr page = frame()->page();
1907 auto fr = page->chrome().windowRect();
1908 auto dest = LayoutSize(width, height);
1909 LayoutRect update(fr.location(), dest);
1910 page->chrome().setWindowRect(adjustWindowRect(*page, update));
1911}
1912
1913ExceptionOr<int> LocalDOMWindow::setTimeout(std::unique_ptr<ScheduledAction> action, int timeout, FixedVector<JSC::Strong<JSC::Unknown>>&& arguments)
1914{
1915 RefPtr context = scriptExecutionContext();
1916 if (!context)
1917 return Exception { ExceptionCode::InvalidAccessError };
1918
1919 // FIXME: Should this check really happen here? Or should it happen when code is about to eval?
1920 if (action->type() == ScheduledAction::Type::Code) {
1921 if (!protect(context->contentSecurityPolicy())->allowEval(context->globalObject(), LogToConsole::Yes, action->code()))
1922 return 0;
1923 }
1924
1925 action->addArguments(WTF::move(arguments));
1926
1927 return DOMTimer::install(*context, WTF::move(action), Seconds::fromMilliseconds(timeout), DOMTimer::Type::SingleShot);
1928}
1929
1930void LocalDOMWindow::clearTimeout(int timeoutId)
1931{
1932 if (RefPtr context = scriptExecutionContext())
1933 DOMTimer::removeById(*context, timeoutId);
1934}
1935
1936ExceptionOr<int> LocalDOMWindow::setInterval(std::unique_ptr<ScheduledAction> action, int timeout, FixedVector<JSC::Strong<JSC::Unknown>>&& arguments)
1937{
1938 RefPtr context = scriptExecutionContext();
1939 if (!context)
1940 return Exception { ExceptionCode::InvalidAccessError };
1941
1942 // FIXME: Should this check really happen here? Or should it happen when code is about to eval?
1943 if (action->type() == ScheduledAction::Type::Code) {
1944 if (!protect(context->contentSecurityPolicy())->allowEval(context->globalObject(), LogToConsole::Yes, action->code()))
1945 return 0;
1946 }
1947
1948 action->addArguments(WTF::move(arguments));
1949
1950 return DOMTimer::install(*context, WTF::move(action), Seconds::fromMilliseconds(timeout), DOMTimer::Type::Repeating);
1951}
1952
1953void LocalDOMWindow::clearInterval(int timeoutId)
1954{
1955 if (RefPtr context = scriptExecutionContext())
1956 DOMTimer::removeById(*context, timeoutId);
1957}
1958
1959int LocalDOMWindow::requestAnimationFrame(Ref<RequestAnimationFrameCallback>&& callback)
1960{
1961 RefPtr document = this->document();
1962 return document ? document->requestAnimationFrame(WTF::move(callback)) : 0;
1963}
1964
1965int LocalDOMWindow::webkitRequestAnimationFrame(Ref<RequestAnimationFrameCallback>&& callback)
1966{
1967 static bool firstTime = true;
1968 if (firstTime && document()) {
1969 protect(document())->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, "webkitRequestAnimationFrame() is deprecated and will be removed. Please use requestAnimationFrame() instead."_s);
1970 firstTime = false;
1971 }
1972 return requestAnimationFrame(WTF::move(callback));
1973}
1974
1975void LocalDOMWindow::cancelAnimationFrame(int id)
1976{
1977 if (RefPtr document = this->document())
1978 document->cancelAnimationFrame(id);
1979}
1980
1981int LocalDOMWindow::requestIdleCallback(Ref<IdleRequestCallback>&& callback, const IdleRequestOptions& options)
1982{
1983 RefPtr document = this->document();
1984 return document ? document->requestIdleCallback(WTF::move(callback), Seconds::fromMilliseconds(options.timeout)) : 0;
1985}
1986
1987void LocalDOMWindow::cancelIdleCallback(int id)
1988{
1989 if (RefPtr document = this->document())
1990 document->cancelIdleCallback(id);
1991}
1992
1993void LocalDOMWindow::createImageBitmap(ImageBitmap::Source&& source, ImageBitmapOptions&& options, ImageBitmap::Promise&& promise)
1994{
1995 RefPtr document = this->document();
1996 if (!document) {
1997 promise.reject(ExceptionCode::InvalidStateError);
1998 return;
1999 }
2000 ImageBitmap::createPromise(*document, WTF::move(source), WTF::move(options), WTF::move(promise));
2001}
2002
2003void LocalDOMWindow::createImageBitmap(ImageBitmap::Source&& source, int sx, int sy, int sw, int sh, ImageBitmapOptions&& options, ImageBitmap::Promise&& promise)
2004{
2005 RefPtr document = this->document();
2006 if (!document) {
2007 promise.reject(ExceptionCode::InvalidStateError);
2008 return;
2009 }
2010 ImageBitmap::createPromise(*document, WTF::move(source), WTF::move(options), sx, sy, sw, sh, WTF::move(promise));
2011}
2012
2013bool LocalDOMWindow::isSecureContext() const
2014{
2015 RefPtr document = this->document();
2016 return document && document->isSecureContext();
2017}
2018
2019bool LocalDOMWindow::crossOriginIsolated() const
2020{
2021 auto* document = this->document();
2022 return document && document->crossOriginIsolated();
2023}
2024
2025// https://html.spec.whatwg.org/multipage/origin.html#dom-originagentcluster
2026bool LocalDOMWindow::originAgentCluster() const
2027{
2028 auto* document = this->document();
Local variable 'document' is unchecked and unsafe
2029 return document && document->originAgentCluster();
2030}
2031
2032static void didAddStorageEventListener(LocalDOMWindow& window)
2033{
2034 // Creating these WebCore::Storage objects informs the system that we'd like to receive
2035 // notifications about storage events that might be triggered in other processes. Rather
2036 // than subscribe to these notifications explicitly, we subscribe to them implicitly to
2037 // simplify the work done by the system.
2038 window.localStorage();
2039 window.sessionStorage();
2040}
2041
2042bool LocalDOMWindow::isSameSecurityOriginAsMainFrame() const
2043{
2044 RefPtr frame = this->frame();
2045 if (!frame || !frame->page() || !document())
2046 return false;
2047
2048 if (frame->isMainFrame())
2049 return true;
2050
2051 RefPtr localFrame = dynamicDowncast<LocalFrame>(frame->mainFrame());
2052 if (!localFrame)
2053 return false;
2054
2055 RefPtr mainFrameDocument = localFrame->document();
2056
2057 if (mainFrameDocument && protect(document()->securityOrigin())->isSameOriginDomain(protect(mainFrameDocument->securityOrigin())))
2058 return true;
2059
2060 return false;
2061}
2062
2063bool LocalDOMWindow::addEventListener(const AtomString& eventType, Ref<EventListener>&& listener, const AddEventListenerOptions& options)
2064{
2065 if (!EventTarget::addEventListener(eventType, WTF::move(listener), options))
2066 return false;
2067
2068 RefPtr document = this->document();
2069 auto& eventNames = WebCore::eventNames();
2070 auto typeInfo = eventNames.typeInfoForEvent(eventType);
2071 if (document) {
2072 const auto useTouchEventRegions = document->shouldUseTouchEventRegions();
2073 document->didAddEventListenersOfType(eventType, options.capture ? Document::IsCapture::Yes : Document::IsCapture::No);
2074 if (typeInfo.isInCategory(EventCategory::Wheel)) {
2075 document->didAddWheelEventHandler(*document);
2076 document->invalidateEventListenerRegions();
2077 } else if (isTouchRelatedEventType(typeInfo, *document)) {
2078 document->didAddTouchEventHandler(*document);
2079#if ENABLE(TOUCH_EVENT_REGIONS)(defined 0 && 0)
2080 if (useTouchEventRegions)
2081 document->invalidateEventListenerRegions();
2082#endif
2083 } else if (typeInfo.isInCategory(EventCategory::Gesture) && useTouchEventRegions) {
2084#if ENABLE(TOUCH_EVENT_REGIONS)(defined 0 && 0)
2085 document->didAddTouchEventHandler(*document);
2086 document->invalidateEventListenerRegions();
2087#endif
2088 }
2089 else if (eventType == eventNames.storageEvent)
2090 didAddStorageEventListener(*this);
2091 }
2092
2093 switch (typeInfo.type()) {
2094 case EventType::unload:
2095 addUnloadEventListener(this);
2096 break;
2097 case EventType::beforeunload:
2098 if (allowsBeforeUnloadListeners(this))
2099 addBeforeUnloadEventListener(this);
2100 break;
2101#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
2102 case EventType::scroll:
2103 incrementScrollEventListenersCount();
2104 break;
2105#endif
2106#if ENABLE(DEVICE_ORIENTATION)(defined 1 && 1)
2107 case EventType::deviceorientation:
2108 startListeningForDeviceOrientationIfNecessary();
2109 break;
2110 case EventType::devicemotion:
2111 startListeningForDeviceMotionIfNecessary();
2112 break;
2113#endif
2114 default:
2115#if ENABLE(IOS_TOUCH_EVENTS)(defined 0 && 0)
2116 if (isTouchRelatedEventType(typeInfo, *document))
2117 ++m_touchAndGestureEventListenerCount;
2118#endif
2119#if ENABLE(IOS_GESTURE_EVENTS)(defined 0 && 0)
2120 if (typeInfo.isInCategory(EventCategory::Gesture))
2121 ++m_touchAndGestureEventListenerCount;
2122#endif
2123#if ENABLE(GAMEPAD)(defined 1 && 1)
2124 if (typeInfo.isInCategory(EventCategory::Gamepad))
2125 incrementGamepadEventListenerCount();
2126#endif
2127 break;
2128 }
2129
2130 return true;
2131}
2132
2133#if ENABLE(DEVICE_ORIENTATION)(defined 1 && 1)
2134
2135DeviceOrientationController* LocalDOMWindow::deviceOrientationController() const
2136{
2137#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
2138 return document() ? &document()->deviceOrientationController() : nullptr;
2139#else
2140 return DeviceOrientationController::from(protect(page()).get());
2141#endif
2142}
2143
2144DeviceMotionController* LocalDOMWindow::deviceMotionController() const
2145{
2146#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
2147 return document() ? &document()->deviceMotionController() : nullptr;
2148#else
2149 return DeviceMotionController::from(protect(page()).get());
2150#endif
2151}
2152
2153bool LocalDOMWindow::isAllowedToUseDeviceMotionOrOrientation(String& message) const
2154{
2155 if (!frame() || !document() || !frame()->settings().deviceOrientationEventEnabled()) {
2156 message = "API is disabled"_s;
2157 return false;
2158 }
2159
2160 if (!isSecureContext()) {
2161 message = "Browsing context is not secure"_s;
2162 return false;
2163 }
2164
2165 return true;
2166}
2167
2168bool LocalDOMWindow::isAllowedToUseDeviceMotion(String& message) const
2169{
2170 if (!isAllowedToUseDeviceMotionOrOrientation(message))
2171 return false;
2172
2173 Ref document = *this->document();
2174 if (!PermissionsPolicy::isFeatureEnabled(PermissionsPolicy::Feature::Gyroscope, document, PermissionsPolicy::ShouldReportViolation::No)
2175 || !PermissionsPolicy::isFeatureEnabled(PermissionsPolicy::Feature::Accelerometer, document, PermissionsPolicy::ShouldReportViolation::No)) {
2176 message = "Third-party iframes are not allowed access to device motion unless explicitly allowed via Feature-Policy (gyroscope & accelerometer)"_s;
2177 return false;
2178 }
2179
2180 return true;
2181}
2182
2183bool LocalDOMWindow::isAllowedToUseDeviceOrientation(String& message) const
2184{
2185 if (!isAllowedToUseDeviceMotionOrOrientation(message))
2186 return false;
2187
2188 Ref document = *this->document();
2189 if (!PermissionsPolicy::isFeatureEnabled(PermissionsPolicy::Feature::Gyroscope, document, PermissionsPolicy::ShouldReportViolation::No)
2190 || !PermissionsPolicy::isFeatureEnabled(PermissionsPolicy::Feature::Accelerometer, document, PermissionsPolicy::ShouldReportViolation::No)
2191 || !PermissionsPolicy::isFeatureEnabled(PermissionsPolicy::Feature::Magnetometer, document, PermissionsPolicy::ShouldReportViolation::No)) {
2192 message = "Third-party iframes are not allowed access to device orientation unless explicitly allowed via Feature-Policy (gyroscope & accelerometer & magnetometer)"_s;
2193 return false;
2194 }
2195
2196 return true;
2197}
2198
2199bool LocalDOMWindow::hasPermissionToReceiveDeviceMotionOrOrientationEvents(String& message) const
2200{
2201 if (frame()->settings().deviceOrientationPermissionAPIEnabled()) {
2202 if (!page()) {
2203 message = "No browsing context"_s;
2204 return false;
2205 }
2206 auto accessState = page()->deviceOrientationAndMotionAccessController().accessState(protect(*this->document()));
2207 switch (accessState) {
2208 case DeviceOrientationOrMotionPermissionState::Denied:
2209 message = "Permission to use the API was denied"_s;
2210 return false;
2211 case DeviceOrientationOrMotionPermissionState::Prompt:
2212 message = "Permission to use the API was not yet requested"_s;
2213 return false;
2214 case DeviceOrientationOrMotionPermissionState::Granted:
2215 break;
2216 }
2217 }
2218
2219 return true;
2220}
2221
2222void LocalDOMWindow::startListeningForDeviceOrientationIfNecessary()
2223{
2224 if (!hasEventListeners(eventNames().deviceorientationEvent))
2225 return;
2226
2227 CheckedPtr deviceController = deviceOrientationController();
2228 if (!deviceController || deviceController->hasDeviceEventListener(*this))
2229 return;
2230
2231 String innerMessage;
2232 if (!isAllowedToUseDeviceOrientation(innerMessage) || !hasPermissionToReceiveDeviceMotionOrOrientationEvents(innerMessage)) {
2233 if (RefPtr document = this->document())
2234 document->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, makeString("No device orientation events will be fired, reason: "_s, innerMessage, '.'));
2235 return;
2236 }
2237
2238 deviceController->addDeviceEventListener(*this);
2239}
2240
2241void LocalDOMWindow::stopListeningForDeviceOrientationIfNecessary()
2242{
2243 if (hasEventListeners(eventNames().deviceorientationEvent))
2244 return;
2245
2246 if (CheckedPtr deviceController = deviceOrientationController())
2247 deviceController->removeDeviceEventListener(*this);
2248}
2249
2250void LocalDOMWindow::startListeningForDeviceMotionIfNecessary()
2251{
2252 if (!hasEventListeners(eventNames().devicemotionEvent))
2253 return;
2254
2255 CheckedPtr deviceController = deviceMotionController();
2256 if (!deviceController || deviceController->hasDeviceEventListener(*this))
2257 return;
2258
2259 String innerMessage;
2260 if (!isAllowedToUseDeviceMotion(innerMessage) || !hasPermissionToReceiveDeviceMotionOrOrientationEvents(innerMessage)) {
2261 failedToRegisterDeviceMotionEventListener();
2262 if (RefPtr document = this->document())
2263 document->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, makeString("No device motion events will be fired, reason: "_s, innerMessage, '.'));
2264 return;
2265 }
2266
2267 deviceController->addDeviceEventListener(*this);
2268}
2269
2270void LocalDOMWindow::stopListeningForDeviceMotionIfNecessary()
2271{
2272 if (hasEventListeners(eventNames().devicemotionEvent))
2273 return;
2274
2275 if (CheckedPtr deviceController = deviceMotionController())
2276 deviceController->removeDeviceEventListener(*this);
2277}
2278
2279void LocalDOMWindow::failedToRegisterDeviceMotionEventListener()
2280{
2281#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
2282 if (!isSameSecurityOriginAsMainFrame() || !isSecureContext())
2283 return;
2284
2285 // FIXME: This is a quirk for chase.com on iPad (<rdar://problem/48423023>).
2286 if (RegistrableDomain::uncheckedCreateFromRegistrableDomainString("chase.com"_s).matches(document()->url())) {
2287 // Fire a fake DeviceMotionEvent with acceleration data to unblock the site's login flow.
2288 protect(document())->postTask([](auto& context) {
2289 if (RefPtr window = downcast<Document>(context).window()) {
2290 auto acceleration = DeviceMotionData::Acceleration::create();
2291 window->dispatchEvent(DeviceMotionEvent::create(eventNames().devicemotionEvent, DeviceMotionData::create(acceleration.copyRef(), acceleration.copyRef(), DeviceMotionData::RotationRate::create(), std::nullopt).ptr()));
2292 }
2293 });
2294 }
2295#endif // PLATFORM(IOS_FAMILY)
2296}
2297
2298#endif // ENABLE(DEVICE_ORIENTATION)
2299
2300#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
2301
2302void LocalDOMWindow::incrementScrollEventListenersCount()
2303{
2304 RefPtr document = this->document();
2305 if (++m_scrollEventListenerCount == 1 && document->isTopDocument()) {
2306 if (RefPtr frame = this->frame(); frame && frame->page())
2307 protect(frame->page())->chrome().client().setNeedsScrollNotifications(*frame, true);
2308 }
2309}
2310
2311void LocalDOMWindow::decrementScrollEventListenersCount(unsigned count)
2312{
2313 ASSERT(count)((void)0);
2314 ASSERT(m_scrollEventListenerCount >= count)((void)0);
2315 RefPtr document = this->document();
2316 m_scrollEventListenerCount -= count;
2317 if (!m_scrollEventListenerCount && document->isTopDocument()) {
2318 if (RefPtr frame = this->frame(); frame && frame->page() && document->backForwardCacheState() == Document::NotInBackForwardCache)
2319 protect(frame->page())->chrome().client().setNeedsScrollNotifications(*frame, false);
2320 }
2321}
2322
2323#endif
2324
2325void LocalDOMWindow::resetAllGeolocationPermission()
2326{
2327 // FIXME: Can we remove the PLATFORM(IOS_FAMILY)-guard?
2328#if ENABLE(GEOLOCATION)(defined 1 && 1) && PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
2329 if (RefPtr navigator = m_navigator)
2330 NavigatorGeolocation::from(*navigator)->resetAllGeolocationPermission();
2331#endif
2332}
2333
2334bool LocalDOMWindow::removeEventListener(const AtomString& eventType, EventListener& listener, const EventListenerOptions& options)
2335{
2336 if (!EventTarget::removeEventListener(eventType, listener, options))
2337 return false;
2338
2339 RefPtr document = this->document();
2340 auto& eventNames = WebCore::eventNames();
2341 auto typeInfo = eventNames.typeInfoForEvent(eventType);
2342 if (document) {
2343 const auto useTouchEventRegions = document->shouldUseTouchEventRegions();
2344 document->didRemoveEventListenersOfType(eventType, options.capture ? Document::IsCapture::Yes : Document::IsCapture::No);
2345 if (typeInfo.isInCategory(EventCategory::Wheel)) {
2346 document->didRemoveWheelEventHandler(*document);
2347 document->invalidateEventListenerRegions();
2348 } else if (isTouchRelatedEventType(typeInfo, *document)) {
2349 document->didRemoveTouchEventHandler(*document);
2350#if ENABLE(TOUCH_EVENT_REGIONS)(defined 0 && 0)
2351 if (useTouchEventRegions)
2352 document->invalidateEventListenerRegions();
2353#endif
2354 } else if (typeInfo.isInCategory(EventCategory::Gesture) && useTouchEventRegions) {
2355#if ENABLE(TOUCH_EVENT_REGIONS)(defined 0 && 0)
2356 document->didRemoveTouchEventHandler(*document);
2357 document->invalidateEventListenerRegions();
2358#endif
2359 }
2360 }
2361
2362 switch (typeInfo.type()) {
2363 case EventType::unload:
2364 removeUnloadEventListener(this);
2365 break;
2366 case EventType::beforeunload:
2367 if (allowsBeforeUnloadListeners(this))
2368 removeBeforeUnloadEventListener(this);
2369 break;
2370#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
2371 case EventType::scroll:
2372 decrementScrollEventListenersCount();
2373 break;
2374#endif
2375#if ENABLE(DEVICE_ORIENTATION)(defined 1 && 1)
2376 case EventType::deviceorientation:
2377 stopListeningForDeviceOrientationIfNecessary();
2378 break;
2379 case EventType::devicemotion:
2380 stopListeningForDeviceMotionIfNecessary();
2381 break;
2382#endif
2383 default:
2384#if ENABLE(IOS_TOUCH_EVENTS)(defined 0 && 0)
2385 if (document && isTouchRelatedEventType(typeInfo, *document)) {
2386 ASSERT(m_touchAndGestureEventListenerCount > 0)((void)0);
2387 --m_touchAndGestureEventListenerCount;
2388 }
2389#endif
2390#if ENABLE(IOS_GESTURE_EVENTS)(defined 0 && 0)
2391 if (typeInfo.isInCategory(EventCategory::Gesture)) {
2392 ASSERT(m_touchAndGestureEventListenerCount > 0)((void)0);
2393 --m_touchAndGestureEventListenerCount;
2394 }
2395#endif
2396#if ENABLE(GAMEPAD)(defined 1 && 1)
2397 if (typeInfo.isInCategory(EventCategory::Gamepad))
2398 decrementGamepadEventListenerCount();
2399#endif
2400 break;
2401 }
2402
2403 return true;
2404}
2405
2406void LocalDOMWindow::languagesChanged()
2407{
2408 // https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-languages
2409 if (RefPtr document = this->document())
2410 document->queueTaskToDispatchEventOnWindow(*this, TaskSource::DOMManipulation, Event::create(eventNames().languagechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
2411}
2412
2413void LocalDOMWindow::dispatchLoadEvent()
2414{
2415 // If we did not protect it, the document loader and its timing subobject might get destroyed
2416 // as a side effect of what event handling code does.
2417 Ref protectedThis { *this };
2418 RefPtr document = this->document();
2419 RefPtr frame = this->frame();
2420 RefPtr protectedLoader = frame ? frame->loader().documentLoader() : nullptr;
2421 bool shouldMarkLoadEventTimes = protectedLoader && !protectedLoader->timing().loadEventStart();
2422
2423 if (shouldMarkLoadEventTimes) {
2424 auto now = MonotonicTime::now();
2425 protectedLoader->timing().setLoadEventStart(now);
2426 if (RefPtr navigationTiming = performance().navigationTiming())
2427 navigationTiming->documentLoadTiming().setLoadEventStart(now);
2428 WTFEmitSignpost(document.get(), NavigationAndPaintTiming, "loadEventBegin")do { if (true) [[unlikely]] do { if (WTFSignpostIndirectLoggingEnabled
) clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WTFSignpostLogHandle
()); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT); if (os_log_type_enabled
(_log_tmp, _type_tmp)) { __extension__({ clang diagnostic push
clang diagnostic ignored "-Wvla" clang diagnostic error "-Wformat"
_Static_assert(__builtin_constant_p("type=%d name=%d p=%" "lu"
" ts=%llu " "" "loadEventBegin"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG14"
) = "type=%d name=%d p=%" "lu" " ts=%llu " "" "loadEventBegin"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("type=%d name=%d p=%" "lu"
" ts=%llu " "" "loadEventBegin", WTFOSSignpostTypeEmitEvent,
WTFOSSignpostNameNavigationAndPaintTiming, reinterpret_cast<
uintptr_t>(((document.get()))), WTFCurrentContinuousTime(Seconds
()))]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "type=%d name=%d p=%"
"lu" " ts=%llu " "" "loadEventBegin", WTFOSSignpostTypeEmitEvent
, WTFOSSignpostNameNavigationAndPaintTiming, reinterpret_cast
<uintptr_t>(((document.get()))), WTFCurrentContinuousTime
(Seconds())), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; else do { RetainPtr<
os_log_t> wtfHandle = WTFSignpostLogHandle(); const void* wtfPointer
= (const void *)(((document.get()))); os_signpost_id_t wtfSignpostID
= wtfPointer ? os_signpost_id_make_with_pointer(wtfHandle.get
(), wtfPointer) : ((os_signpost_id_t)0xEEEEB0B5B2B2EEEE); clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" __extension__
({ os_log_t _log_tmp = (wtfHandle.get()); os_signpost_type_t _type_tmp
= (OS_SIGNPOST_EVENT); os_signpost_id_t _spid_tmp = (wtfSignpostID
); if (_spid_tmp != ((os_signpost_id_t)0) && _spid_tmp
!= ((os_signpost_id_t)~0) && os_signpost_enabled(_log_tmp
)) { __extension__({ clang diagnostic push clang diagnostic ignored
"-Wvla" clang diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("" "" "loadEventBegin" " %{signpost.description:event_time}llu"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG15"
) = "" "" "loadEventBegin" " %{signpost.description:event_time}llu"
; _Static_assert(__builtin_constant_p("NavigationAndPaintTiming"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_name_str[] __asm("LOS_LOG16"
) = "NavigationAndPaintTiming"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("" "" "loadEventBegin" " %{signpost.description:event_time}llu"
, WTFCurrentContinuousTime(Seconds()))]; (_os_signpost_emit_with_name_impl
)(&__dso_handle, _log_tmp, _type_tmp, _spid_tmp, _os_name_str
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "" "" "loadEventBegin" " %{signpost.description:event_time}llu"
, WTFCurrentContinuousTime(Seconds())), (uint32_t)sizeof(_os_fmt_buf
)) clang diagnostic pop ; }); } }); clang diagnostic pop } while
(0); } while (0); } while (0)
;
2429 }
2430
2431 dispatchEvent(Event::create(eventNames().loadEvent, Event::CanBubble::No, Event::IsCancelable::No), document.get());
2432
2433 if (shouldMarkLoadEventTimes) {
2434 auto now = MonotonicTime::now();
2435 protectedLoader->timing().setLoadEventEnd(now);
2436 performance().navigationFinished(now);
2437 WTFEmitSignpost(document.get(), NavigationAndPaintTiming, "loadEventEnd")do { if (true) [[unlikely]] do { if (WTFSignpostIndirectLoggingEnabled
) clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WTFSignpostLogHandle
()); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT); if (os_log_type_enabled
(_log_tmp, _type_tmp)) { __extension__({ clang diagnostic push
clang diagnostic ignored "-Wvla" clang diagnostic error "-Wformat"
_Static_assert(__builtin_constant_p("type=%d name=%d p=%" "lu"
" ts=%llu " "" "loadEventEnd"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG17"
) = "type=%d name=%d p=%" "lu" " ts=%llu " "" "loadEventEnd";
uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("type=%d name=%d p=%" "lu"
" ts=%llu " "" "loadEventEnd", WTFOSSignpostTypeEmitEvent, WTFOSSignpostNameNavigationAndPaintTiming
, reinterpret_cast<uintptr_t>(((document.get()))), WTFCurrentContinuousTime
(Seconds()))]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "type=%d name=%d p=%" "lu" " ts=%llu " "" "loadEventEnd", WTFOSSignpostTypeEmitEvent
, WTFOSSignpostNameNavigationAndPaintTiming, reinterpret_cast
<uintptr_t>(((document.get()))), WTFCurrentContinuousTime
(Seconds())), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; else do { RetainPtr<
os_log_t> wtfHandle = WTFSignpostLogHandle(); const void* wtfPointer
= (const void *)(((document.get()))); os_signpost_id_t wtfSignpostID
= wtfPointer ? os_signpost_id_make_with_pointer(wtfHandle.get
(), wtfPointer) : ((os_signpost_id_t)0xEEEEB0B5B2B2EEEE); clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" __extension__
({ os_log_t _log_tmp = (wtfHandle.get()); os_signpost_type_t _type_tmp
= (OS_SIGNPOST_EVENT); os_signpost_id_t _spid_tmp = (wtfSignpostID
); if (_spid_tmp != ((os_signpost_id_t)0) && _spid_tmp
!= ((os_signpost_id_t)~0) && os_signpost_enabled(_log_tmp
)) { __extension__({ clang diagnostic push clang diagnostic ignored
"-Wvla" clang diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("" "" "loadEventEnd" " %{signpost.description:event_time}llu"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG18"
) = "" "" "loadEventEnd" " %{signpost.description:event_time}llu"
; _Static_assert(__builtin_constant_p("NavigationAndPaintTiming"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_name_str[] __asm("LOS_LOG19"
) = "NavigationAndPaintTiming"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("" "" "loadEventEnd" " %{signpost.description:event_time}llu"
, WTFCurrentContinuousTime(Seconds()))]; (_os_signpost_emit_with_name_impl
)(&__dso_handle, _log_tmp, _type_tmp, _spid_tmp, _os_name_str
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "" "" "loadEventEnd" " %{signpost.description:event_time}llu"
, WTFCurrentContinuousTime(Seconds())), (uint32_t)sizeof(_os_fmt_buf
)) clang diagnostic pop ; }); } }); clang diagnostic pop } while
(0); } while (0); } while (0)
;
2438 WTFEndSignpost(document.get(), NavigationAndPaintTiming)do { if (true) [[unlikely]] do { if (WTFSignpostIndirectLoggingEnabled
) clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WTFSignpostLogHandle
()); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT); if (os_log_type_enabled
(_log_tmp, _type_tmp)) { __extension__({ clang diagnostic push
clang diagnostic ignored "-Wvla" clang diagnostic error "-Wformat"
_Static_assert(__builtin_constant_p("type=%d name=%d p=%" "lu"
" ts=%llu " ""), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG20"
) = "type=%d name=%d p=%" "lu" " ts=%llu " ""; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("type=%d name=%d p=%" "lu" " ts=%llu " "", WTFOSSignpostTypeEndInterval
, WTFOSSignpostNameNavigationAndPaintTiming, reinterpret_cast
<uintptr_t>(((document.get()))), WTFCurrentContinuousTime
(Seconds()))]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "type=%d name=%d p=%" "lu" " ts=%llu " "", WTFOSSignpostTypeEndInterval
, WTFOSSignpostNameNavigationAndPaintTiming, reinterpret_cast
<uintptr_t>(((document.get()))), WTFCurrentContinuousTime
(Seconds())), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; else do { RetainPtr<
os_log_t> wtfHandle = WTFSignpostLogHandle(); const void* wtfPointer
= (const void *)(((document.get()))); os_signpost_id_t wtfSignpostID
= wtfPointer ? os_signpost_id_make_with_pointer(wtfHandle.get
(), wtfPointer) : ((os_signpost_id_t)0xEEEEB0B5B2B2EEEE); clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" __extension__
({ os_log_t _log_tmp = (wtfHandle.get()); os_signpost_type_t _type_tmp
= (OS_SIGNPOST_INTERVAL_END); os_signpost_id_t _spid_tmp = (
wtfSignpostID); if (_spid_tmp != ((os_signpost_id_t)0) &&
_spid_tmp != ((os_signpost_id_t)~0) && os_signpost_enabled
(_log_tmp)) { __extension__({ clang diagnostic push clang diagnostic
ignored "-Wvla" clang diagnostic error "-Wformat" _Static_assert
(__builtin_constant_p("" "" " %{signpost.description:end_time}llu"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG21"
) = "" "" " %{signpost.description:end_time}llu"; _Static_assert
(__builtin_constant_p("NavigationAndPaintTiming"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_name_str[] __asm("LOS_LOG22"
) = "NavigationAndPaintTiming"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("" "" " %{signpost.description:end_time}llu", WTFCurrentContinuousTime
(Seconds()))]; (_os_signpost_emit_with_name_impl)(&__dso_handle
, _log_tmp, _type_tmp, _spid_tmp, _os_name_str, _os_fmt_str, (
uint8_t *)__builtin_os_log_format(_os_fmt_buf, "" "" " %{signpost.description:end_time}llu"
, WTFCurrentContinuousTime(Seconds())), (uint32_t)sizeof(_os_fmt_buf
)) clang diagnostic pop ; }); } }); clang diagnostic pop } while
(0); } while (0); } while (0)
;
2439 }
2440
2441 // Send a separate load event to the element that owns this frame.
2442 if (RefPtr frame = this->frame())
2443 frame->dispatchLoadEventToParent();
2444
2445 InspectorInstrumentation::loadEventFired(protect(this->frame()).get());
2446}
2447
2448void LocalDOMWindow::dispatchEvent(Event& event, EventTarget* target)
2449{
2450 // FIXME: It's confusing to have both the inherited EventTarget::dispatchEvent function
2451 // and this function, which does something nearly identical but subtly different if
2452 // called with a target of null. Most callers pass the document as the target, though.
2453 // Fixing this could allow us to remove the special case in DocumentEventQueue::dispatchEvent.
2454
2455 Ref protectedThis { *this };
2456
2457 if (target)
2458 event.setTarget(target);
2459 else
2460 event.setTarget(Ref { *this });
2461
2462 EventPath eventPath { *this };
2463 event.setCurrentTarget(this);
2464 event.setEventPhase(Event::AT_TARGET);
2465 event.resetBeforeDispatch();
2466 event.setEventPath(eventPath);
2467
2468 RefPtr<LocalFrame> protectedFrame;
2469 bool hasListenersForEvent = false;
2470 // FIXME: It doesn't seem right to have the inspector instrumentation here since not all
2471 // events dispatched to the window object are guaranteed to flow through this function.
2472 // But the instrumentation prevents us from calling EventDispatcher::dispatchEvent here.
2473 if (InspectorInstrumentation::hasFrontends()) [[unlikely]] {
2474 protectedFrame = this->frame();
2475 hasListenersForEvent = hasEventListeners(event.type());
2476 if (hasListenersForEvent)
2477 InspectorInstrumentation::willDispatchEventOnWindow(protectedFrame.get(), event);
2478 }
2479
2480 // FIXME: We should use EventDispatcher everywhere.
2481 fireEventListeners(event, EventInvokePhase::Capturing);
2482 fireEventListeners(event, EventInvokePhase::Bubbling);
2483
2484 if (hasListenersForEvent)
2485 InspectorInstrumentation::didDispatchEventOnWindow(protectedFrame.get(), event);
2486
2487 event.resetAfterDispatch();
2488}
2489
2490void LocalDOMWindow::removeAllEventListeners()
2491{
2492 EventTarget::removeAllEventListeners();
2493
2494#if ENABLE(DEVICE_ORIENTATION)(defined 1 && 1)
2495 stopListeningForDeviceOrientationIfNecessary();
2496 stopListeningForDeviceMotionIfNecessary();
2497#endif
2498
2499#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
2500 if (m_scrollEventListenerCount) {
2501 m_scrollEventListenerCount = 1;
2502 decrementScrollEventListenersCount();
2503 }
2504#endif
2505
2506#if ENABLE(IOS_TOUCH_EVENTS)(defined 0 && 0) || ENABLE(IOS_GESTURE_EVENTS)(defined 0 && 0)
2507 m_touchAndGestureEventListenerCount = 0;
2508#endif
2509
2510#if ENABLE(TOUCH_EVENTS)(defined 0 && 0)
2511 if (RefPtr<Document> document = this->document())
2512 document->didRemoveEventTargetNode(*document);
2513#endif
2514
2515 if (RefPtr performance = m_performance) {
2516 performance->removeAllEventListeners();
2517 performance->removeAllObservers();
2518 }
2519
2520 removeAllUnloadEventListeners(this);
2521 removeAllBeforeUnloadEventListeners(this);
2522}
2523
2524void LocalDOMWindow::captureEvents()
2525{
2526 // Not implemented.
2527}
2528
2529void LocalDOMWindow::releaseEvents()
2530{
2531 // Not implemented.
2532}
2533
2534void LocalDOMWindow::finishedLoading()
2535{
2536 if (m_shouldPrintWhenFinishedLoading) {
2537 m_shouldPrintWhenFinishedLoading = false;
2538 if (RefPtr loader = frame()->loader().activeDocumentLoader(); !loader || loader->mainDocumentError().isNull())
2539 print();
2540 }
2541}
2542
2543EventTimingInteractionID LocalDOMWindow::computeInteractionID(Event& event, EventType type)
2544{
2545 auto finalizePendingPointerDown = [this]() {
2546 auto interactionID = generateInteractionID();
2547 m_pointerMap = interactionID;
2548 m_pendingPointerDown->interactionID = interactionID;
2549 queueEventTimingCandidateForDispatch(*m_pendingPointerDown);
2550 m_pendingPointerDown.reset();
2551 return interactionID;
2552 };
2553
2554 switch (type) {
2555 case EventType::keyup: {
2556 RefPtr keyboardEvent = dynamicDowncast<KeyboardEvent>(&event);
2557 // Simulated keyboard inputs such as dictation are not KeyboardEvent:
2558 if (!keyboardEvent) [[unlikely]]
2559 return { };
2560
2561 if (keyboardEvent->isComposing())
2562 return { };
2563
2564 auto it = m_pendingKeyDowns.find(keyboardEvent->keyCode());
2565 if (it == m_pendingKeyDowns.end())
2566 return { };
2567
2568 auto interactionID = it->value.keyDown.interactionID.isUnassigned() ? generateInteractionID() : it->value.keyDown.interactionID;
2569 it->value.keyDown.interactionID = interactionID;
2570 queueEventTimingCandidateForDispatch(it->value.keyDown);
2571 if (it->value.keyPress) {
2572 it->value.keyPress->interactionID = interactionID;
2573 queueEventTimingCandidateForDispatch(*it->value.keyPress);
2574 }
2575 m_pendingKeyDowns.remove(it);
2576 keyboardEvent->setInteractionID(interactionID);
2577 return interactionID;
2578 }
2579 case EventType::compositionstart: {
2580 for (auto& pendingEntry : m_pendingKeyDowns) {
2581 queueEventTimingCandidateForDispatch(pendingEntry.value.keyDown);
2582 if (pendingEntry.value.keyPress)
2583 queueEventTimingCandidateForDispatch(*pendingEntry.value.keyPress);
2584 }
2585 m_pendingKeyDowns.clear();
2586 return { };
2587 }
2588 case EventType::input: {
2589 // Fails for events not related to text, such as checkbox toggling:
2590 RefPtr inputEvent = dynamicDowncast<InputEvent>(&event);
2591 if (!inputEvent)
2592 return { };
2593
2594 if (!inputEvent->isInputMethodComposing())
2595 return { };
2596
2597 return generateInteractionID();
2598 }
2599 case EventType::click: {
2600 auto clickEvent = downcast<MouseEvent>(&event);
2601 if (clickEvent->isSimulated()) {
2602 if (RefPtr keyboardEvent = dynamicDowncast<KeyboardEvent>(clickEvent->underlyingEvent())) {
2603 if (keyboardEvent->interactionID().isUnassigned())
2604 keyboardEvent->setInteractionID(generateInteractionID());
2605
2606 return keyboardEvent->interactionID();
2607 }
2608 }
2609
2610 if (m_pointerMap.isUnassigned())
2611 return { };
2612
2613 auto interactionID = m_pointerMap;
2614 m_pointerMap = { };
2615 return interactionID;
2616 }
2617 case EventType::pointerup: {
2618 if (!m_pendingPointerDown) {
2619 if (!m_contextMenuTriggered)
2620 return { };
2621
2622 m_contextMenuTriggered = false;
2623 return currentInteractionID();
2624 }
2625 return finalizePendingPointerDown();
2626 }
2627 case EventType::pointercancel: {
2628 if (m_pendingPointerDown) {
2629 // Cancelled pointerDowns are finalized without receiving an interactionID:
2630 queueEventTimingCandidateForDispatch(*m_pendingPointerDown);
2631 m_pendingPointerDown.reset();
2632 }
2633 return { };
2634 }
2635 case EventType::contextmenu: {
2636 if (!m_pendingPointerDown)
2637 return currentInteractionID();
2638
2639 m_contextMenuTriggered = true;
2640 return finalizePendingPointerDown();
2641 }
2642 default:
2643 return { };
2644 }
2645}
2646
2647EventTimingInteractionID LocalDOMWindow::currentInteractionID()
2648{
2649 return ensureUserInteractionValue();
2650}
2651
2652EventTimingInteractionID& LocalDOMWindow::ensureUserInteractionValue()
2653{
2654 // Should be initialized with a random number from 100 to 10000:
2655 if (m_userInteractionValue.isUnassigned()) [[unlikely]]
2656 m_userInteractionValue.value = 100 + WTF::cryptographicallyRandomNumber<uint64_t>() % 9901;
2657 return m_userInteractionValue;
2658}
2659
2660EventTimingInteractionID LocalDOMWindow::generateInteractionID()
2661{
2662 ++m_interactionCount;
2663 return generateInteractionIDWithoutIncreasingInteractionCount();
2664}
2665
2666EventTimingInteractionID LocalDOMWindow::generateInteractionIDWithoutIncreasingInteractionCount()
2667{
2668 // User interaction value should be increased by a small integer to
2669 // "discourage developers from considering it as a counter":
2670 ensureUserInteractionValue().value += 7;
2671 return ensureUserInteractionValue();
2672}
2673
2674void LocalDOMWindow::queueEventTimingCandidateForDispatch(PerformanceEventTimingCandidate& candidate)
2675{
2676 m_performanceEventTimingCandidates.append(candidate);
2677
2678 RefPtr document = this->document();
2679 if (!document)
2680 return;
2681
2682 RefPtr page { protect(document->page()) };
2683 if (!page)
2684 return;
2685
2686 page->scheduleRenderingUpdate(RenderingUpdateStep::EventTiming);
2687}
2688
2689PerformanceEventTimingCandidate LocalDOMWindow::initializeEventTiming(Event& event, EventType type)
2690{
2691 auto startTime = performance().relativeTimeFromTimeOriginInReducedResolutionSeconds(event.timeStamp());
2692 auto processingStart = performance().nowInReducedResolutionSeconds();
2693 LOG_WITH_STREAM(PerformanceTimeline, stream << "Initializing event timing entry (type=" << event.type() << "; tstamp=" << startTime << ") at t=" << processingStart)((void)0);
2694 if (startTime > processingStart)
2695 startTime = processingStart;
2696
2697 // Workaround for https://webkit.org/b/301443 firing keyup events with very old timestamps:
2698 if (type == EventType::input) {
2699 m_lastInputEventStartTime = std::max(startTime, m_lastInputEventStartTime);
2700 } else if (type == EventType::keyup && startTime < m_lastInputEventStartTime) {
2701 LOG_WITH_STREAM(PerformanceTimeline, stream << "Late keyup event received; refreshing timestamp: " << startTime << " -> " << m_lastInputEventStartTime)((void)0);
2702 startTime = m_lastInputEventStartTime;
2703 }
2704
2705 return PerformanceEventTimingCandidate {
2706 .type = type,
2707 .cancelable = event.cancelable(),
2708 .startTime = startTime,
2709 .processingStart = processingStart,
2710 .processingEnd = { },
2711 .duration = { },
2712 .target = { },
2713 .interactionID = computeInteractionID(event, type)
2714 };
2715}
2716
2717void LocalDOMWindow::markEndOfProcessingForEventTiming(PerformanceEventTimingCandidate& entry, const Event& event, EventType type)
2718{
2719 // Maps to "Finalize event timing" in the spec.
2720 auto processingEnd = performance().nowInReducedResolutionSeconds();
2721 entry.processingEnd = processingEnd;
2722 // Per the Event Timing spec, the target must be retargeted to the document scope.
2723 // Without this, when no event listeners are registered for a given event type,
2724 // the event target may be an un-retargeted node inside a user-agent shadow tree
2725 // (e.g., an internal node of <input>), leaking shadow DOM internals.
2726 if (RefPtr targetNode = dynamicDowncast<Node>(event.target()))
2727 entry.target = targetNode->document().retargetToScope(*targetNode).get();
2728 else
2729 entry.target = event.target();
2730
2731 switch (type) {
2732 case EventType::pointerdown: {
2733 if (m_pendingPointerDown) {
2734 queueEventTimingCandidateForDispatch(*m_pendingPointerDown);
2735 LOG_WITH_STREAM(PerformanceTimeline, stream << "Repeated pointerdown entries at t=" << processingEnd)((void)0);
2736 }
2737
2738 LOG_WITH_STREAM(PerformanceTimeline, stream << "Adding pending pointerdown at t=" << processingEnd)((void)0);
2739 m_pendingPointerDown = entry;
2740 m_contextMenuTriggered = false;
2741 return;
2742 }
2743 case EventType::keydown: {
2744 RefPtr keyboardEvent = dynamicDowncast<KeyboardEvent>(&event);
2745 // Simulated keyboard inputs such as dictation are not KeyboardEvent:
2746 if (!keyboardEvent) [[unlikely]] {
2747 queueEventTimingCandidateForDispatch(entry);
2748 return;
2749 }
2750 entry.interactionID = keyboardEvent->interactionID();
2751 auto keyCode = keyboardEvent->keyCode();
2752 // FIXME: checking for keyCode 229 (IME) is against the spec, but it's
2753 // required because of https://bugs.webkit.org/show_bug.cgi?id=165004 ,
2754 // which causes the last keypress of a composition to be issued after
2755 // compositionend, making .isComposing() not be true:
2756 if (keyCode == 229 || keyboardEvent->isComposing()) {
2757 queueEventTimingCandidateForDispatch(entry);
2758 return;
2759 }
2760 auto it = m_pendingKeyDowns.find(keyCode);
2761 if (it != m_pendingKeyDowns.end()) {
2762 it->value.keyDown.interactionID = generateInteractionIDWithoutIncreasingInteractionCount();
2763 queueEventTimingCandidateForDispatch(it->value.keyDown);
2764 if (it->value.keyPress) {
2765 it->value.keyPress->interactionID = it->value.keyDown.interactionID;
2766 queueEventTimingCandidateForDispatch(*it->value.keyPress);
2767 }
2768 it->value = { .keyDown = entry };
2769 return;
2770 }
2771 m_pendingKeyDowns.set(keyCode, PendingKeyDownState { .keyDown = entry });
2772 return;
2773 }
2774 case EventType::keypress: {
2775 RefPtr keyboardEvent = dynamicDowncast<KeyboardEvent>(&event);
2776 if (!keyboardEvent) [[unlikely]] {
2777 queueEventTimingCandidateForDispatch(entry);
2778 return;
2779 }
2780 auto keyCode = keyboardEvent->keyCodeForKeyDown();
2781 auto it = m_pendingKeyDowns.find(keyCode);
2782 if (it == m_pendingKeyDowns.end()) {
2783 queueEventTimingCandidateForDispatch(entry);
2784 return;
2785 }
2786 it->value.keyPress = entry;
2787 return;
2788 }
2789 default:
2790 queueEventTimingCandidateForDispatch(entry);
2791 }
2792}
2793
2794void LocalDOMWindow::finalizeAndQueueEventTimingEntries()
2795{
2796 // Maps to "Dispatch pending Event Timing entries" in the spec.
2797 auto renderingTime = performance().nowInReducedResolutionSeconds();
2798 if (m_pendingPointerDown && !m_pendingPointerDown->duration)
2799 m_pendingPointerDown->duration = std::max(renderingTime - m_pendingPointerDown->startTime, Seconds::fromMilliseconds(1));
2800
2801 for (auto& keydownEntry : m_pendingKeyDowns) {
2802 if (!keydownEntry.value.keyDown.duration)
2803 keydownEntry.value.keyDown.duration = std::max(renderingTime - keydownEntry.value.keyDown.startTime, Seconds::fromMilliseconds(1));
2804
2805 if (keydownEntry.value.keyPress && !keydownEntry.value.keyPress->duration)
2806 keydownEntry.value.keyPress->duration = std::max(renderingTime - keydownEntry.value.keyPress->startTime, Seconds::fromMilliseconds(1));
2807 }
2808
2809 if (m_performanceEventTimingCandidates.isEmpty())
2810 return;
2811
2812 LOG_WITH_STREAM(PerformanceTimeline, stream << "Dispatching " << m_performanceEventTimingCandidates.size() << " event timing entries at t=" << renderingTime)((void)0);
2813 for (auto& candidateEntry : borrow(m_performanceEventTimingCandidates).get()) {
2814 performance().countEvent(candidateEntry.type);
2815 if (!candidateEntry.duration)
2816 candidateEntry.duration = renderingTime - candidateEntry.startTime;
2817 performance().processEventEntry(candidateEntry);
2818 }
2819 m_performanceEventTimingCandidates.clear();
2820}
2821
2822void LocalDOMWindow::setLocation(LocalDOMWindow& activeWindow, const URL& completedURL, NavigationHistoryBehavior historyHandling, SetLocationLocking locking, CanNavigateState navigationState)
2823{
2824 if (!passesSetLocationSecurityChecks(activeWindow, completedURL, navigationState))
2825 return;
2826
2827 RefPtr activeDocument = activeWindow.document();
2828 if (!activeDocument)
2829 return;
2830 RefPtr frame = this->frame();
2831
2832 // Check the CSP of the embedder to determine if we allow execution of javascript: URLs via child frame navigation.
2833 if (completedURL.protocolIsJavaScript() && frameElement() && !protect(protect(frameElement()->document())->contentSecurityPolicy())->allowJavaScriptURLs(aboutBlankURL().string(), { }, completedURL.string(), protect(frameElement()).get()))
2834 return;
2835
2836 RefPtr localParent = dynamicDowncast<LocalFrame>(frame->tree().parent());
2837 // If the loader for activeWindow's frame (browsing context) has no outgoing referrer, set its outgoing referrer
2838 // to the URL of its parent frame's Document.
2839 if (RefPtr activeFrame = activeWindow.frame(); activeFrame && activeFrame->loader().outgoingReferrer().isEmpty() && localParent)
2840 activeFrame->loader().setOutgoingReferrer(protect(document())->encodingParseURL(localParent->document()->url().strippedForUseAsReferrer().string));
2841
2842 // We want a new history item if we are processing a user gesture.
2843 LockHistory lockHistory = (locking != SetLocationLocking::LockHistoryBasedOnGestureState || !UserGestureIndicator::processingUserGesture()) ? LockHistory::Yes : LockHistory::No;
2844 LockBackForwardList lockBackForwardList = (locking != SetLocationLocking::LockHistoryBasedOnGestureState) ? LockBackForwardList::Yes : LockBackForwardList::No;
2845 protect(frame->navigationScheduler())->scheduleLocationChange(*activeDocument, protect(activeDocument->securityOrigin()),
2846 // FIXME: What if activeDocument()->frame() is 0?
2847 completedURL, activeDocument->frame()->loader().outgoingReferrer(),
2848 lockHistory, lockBackForwardList,
2849 historyHandling);
2850}
2851
2852ExceptionOr<RefPtr<Frame>> LocalDOMWindow::createWindow(const String& urlString, const AtomString& frameName, const WindowFeatures& initialWindowFeatures, LocalDOMWindow& activeWindow, LocalFrame& firstFrame, LocalFrame& openerFrame, NOESCAPE[[clang::noescape]] const Function<void(LocalDOMWindow&)>& prepareDialogFunction)
2853{
2854 RefPtr activeFrame = activeWindow.frame();
2855 if (!activeFrame)
2856 return RefPtr<Frame> { nullptr };
2857
2858 RefPtr activeDocument = activeWindow.document();
2859 if (!activeDocument)
2860 return RefPtr<Frame> { nullptr };
2861
2862 URL completedURL = urlString.isEmpty() ? URL({ }, emptyString()) : protect(firstFrame.document())->encodingParseURL(urlString);
2863 if (!completedURL.isEmpty() && !completedURL.isValid())
2864 return Exception { ExceptionCode::SyntaxError };
2865
2866 WindowFeatures windowFeatures = initialWindowFeatures;
2867
2868 // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here.
2869 String referrer = windowFeatures.wantsNoReferrer() ? String() : SecurityPolicy::generateReferrerHeader(firstFrame.document()->referrerPolicy(), completedURL, firstFrame.loader().outgoingReferrerURL(), OriginAccessPatternsForWebProcess::singleton());
2870 auto initiatedByMainFrame = activeFrame->isMainFrame() ? InitiatedByMainFrame::Yes : InitiatedByMainFrame::Unknown;
2871
2872 ResourceRequest resourceRequest { URL { completedURL }, referrer };
2873 RefPtr openerDocumentLoader = openerFrame.document() ? openerFrame.document()->loader() : nullptr;
2874 if (openerDocumentLoader)
2875 resourceRequest.setIsAppInitiated(openerDocumentLoader->lastNavigationWasAppInitiated());
2876 FrameLoadRequest frameLoadRequest { *activeDocument, protect(activeDocument->securityOrigin()), WTF::move(resourceRequest), frameName, initiatedByMainFrame };
2877 frameLoadRequest.setShouldOpenExternalURLsPolicy(activeDocument->shouldOpenExternalURLsPolicyToPropagate());
2878
2879 // https://html.spec.whatwg.org/#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name (Step 8.2)
2880 if (openerFrame.document()->shouldForceNoOpenerBasedOnCOOP()) {
2881 frameLoadRequest.setFrameName(blankTargetFrameName());
2882 windowFeatures.noopener = true;
2883 }
2884
2885 RefPtr openerDocument = openerFrame.document();
2886 if (frameLoadRequest.resourceRequest().url().protocolIsBlob() && !protect(openerDocument->securityOrigin())->isSameOriginAs(protect(openerDocument->topOrigin()))) {
2887 frameLoadRequest.setFrameName(blankTargetFrameName());
2888 windowFeatures.noopener = true;
2889 }
2890 bool noopener = windowFeatures.wantsNoOpener();
2891
2892 auto [newFrame, created] = WebCore::createWindow(openerFrame, WTF::move(frameLoadRequest), WTF::move(windowFeatures));
2893 if (!newFrame)
2894 return RefPtr<Frame> { nullptr };
2895
2896 // https://html.spec.whatwg.org/#the-rules-for-choosing-a-navigable
2897 // Consume user activation when a new browsing context is created.
2898 if (created == CreatedNewPage::Yes)
2899 activeWindow.consumeTransientActivation();
2900
2901 if (!noopener) {
2902 ASSERT(!newFrame->opener() || newFrame->opener() == &openerFrame)((void)0);
2903 if (auto* page = newFrame->page())
2904 page->setOpenedByDOMWithOpener(true);
2905 }
2906
2907 if (created == CreatedNewPage::Yes) {
2908 if (RefPtr page = newFrame->page()) {
2909 page->setOpenedByDOM();
2910 if (openerDocument)
2911 page->setOpenedByScriptDomain(RegistrableDomain { openerDocument->currentSourceURL(ScriptExecutionContext::CallStackPosition::TopMost) });
2912 }
2913 }
2914
2915 RefPtr window = newFrame->window();
2916 if (window && window->isInsecureScriptAccess(activeWindow, completedURL))
2917 return noopener ? RefPtr<Frame> { nullptr } : newFrame;
2918
2919 RefPtr localNewFrame = dynamicDowncast<LocalFrame>(newFrame);
2920 if (prepareDialogFunction && localNewFrame)
2921 prepareDialogFunction(*protect(localNewFrame->document()->window()));
2922
2923 if (created == CreatedNewPage::Yes) {
2924 ResourceRequest resourceRequest { WTF::move(completedURL), referrer, ResourceRequestCachePolicy::UseProtocolCachePolicy };
2925 FrameLoader::addSameSiteInfoToRequestIfNeeded(resourceRequest, openerDocument.get());
2926 FrameLoadRequest frameLoadRequest { protect(activeWindow.document()).releaseNonNull(), protect(protect(activeWindow.document())->securityOrigin()), WTF::move(resourceRequest), selfTargetFrameName(), initiatedByMainFrame };
2927 frameLoadRequest.setShouldOpenExternalURLsPolicy(activeDocument->shouldOpenExternalURLsPolicyToPropagate());
2928 newFrame->changeLocation(WTF::move(frameLoadRequest));
2929 } else if (!urlString.isEmpty()) {
2930 LockHistory lockHistory = UserGestureIndicator::processingUserGesture() ? LockHistory::No : LockHistory::Yes;
2931 protect(newFrame->navigationScheduler())->scheduleLocationChange(*activeDocument, protect(activeDocument->securityOrigin()), completedURL, referrer, lockHistory, LockBackForwardList::No);
2932 }
2933
2934 // Navigating the new frame could result in it being detached from its page by a navigation policy delegate.
2935 if (!newFrame->page())
2936 return RefPtr<Frame> { nullptr };
2937
2938 return noopener ? RefPtr<Frame> { nullptr } : newFrame;
2939}
2940
2941#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
2942static bool shouldBypassPopupBlockerForQuirk(const Document* document, const String& urlString)
2943{
2944 if (RefPtr firstFrameDocument = document) {
2945 if (firstFrameDocument->quirks().shouldAllowPopupFromMicrosoftOfficeToOneDrive())
2946 return firstFrameDocument->quirks().needsPopupFromMicrosoftOfficeToOneDrive(firstFrameDocument->encodingParseURL(urlString));
2947 }
2948 return false;
2949}
2950#endif
2951
2952ExceptionOr<RefPtr<WindowProxy>> LocalDOMWindow::open(LocalDOMWindow& activeWindow, LocalDOMWindow& firstWindow, const String& urlStringToOpen, const AtomString& frameName, const String& windowFeaturesString)
2953{
2954 if (!isCurrentlyDisplayedInFrame())
2955 return RefPtr<WindowProxy> { nullptr };
2956
2957 RefPtr activeDocument = activeWindow.document();
2958 if (!activeDocument)
2959 return RefPtr<WindowProxy> { nullptr };
2960
2961 RefPtr firstFrame = firstWindow.frame();
2962 if (!firstFrame)
2963 return RefPtr<WindowProxy> { nullptr };
2964
2965 auto urlString = urlStringToOpen;
2966 if (activeDocument->quirks().shouldOpenAsAboutBlank(urlStringToOpen))
2967 urlString = "about:blank"_s;
2968
2969#if ENABLE(CONTENT_EXTENSIONS)(defined 1 && 1)
2970 RefPtr page = firstFrame->page();
2971 RefPtr firstFrameDocument = firstFrame->document();
2972 RefPtr userContentProvider = firstFrame->userContentProvider();
2973 RefPtr firstFrameDocumentLoader = firstFrameDocument ? firstFrameDocument->loader() : nullptr;
2974 if (firstFrameDocument && page && userContentProvider && firstFrameDocumentLoader) {
2975 auto results = userContentProvider->processContentRuleListsForLoad(*page, firstFrameDocument->encodingParseURL(urlString), ContentExtensions::ResourceType::Popup, *firstFrameDocumentLoader);
2976 if (results.shouldBlock())
2977 return RefPtr<WindowProxy> { nullptr };
2978 }
2979#endif
2980
2981 RefPtr frame = this->frame();
2982 if (!frame)
2983 return RefPtr<WindowProxy> { nullptr };
2984
2985 auto popupAllowed = firstWindow.allowPopUp();
2986#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
2987 popupAllowed |= shouldBypassPopupBlockerForQuirk(firstFrame->document(), urlString);
2988#endif
2989
2990 if (!popupAllowed) {
2991 // Because FrameTree::findFrameForNavigation() returns true for empty strings, we must check for empty frame names.
2992 // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
2993 if (frameName.isEmpty() || !frame->loader().findFrameForNavigation(frameName, activeDocument.get()))
2994 return RefPtr<WindowProxy> { nullptr };
2995 }
2996
2997 // Get the target frame for the special cases of _top and _parent.
2998 // In those cases, we schedule a location change right now and return early.
2999 RefPtr<Frame> targetFrame;
3000 if (isTopTargetFrameName(frameName))
3001 targetFrame = frame->tree().top();
3002 else if (isParentTargetFrameName(frameName)) {
3003 if (RefPtr parent = frame->tree().parent())
3004 targetFrame = parent;
3005 else
3006 targetFrame = frame;
3007 }
3008 if (targetFrame) {
3009 if (activeDocument->canNavigate(targetFrame.get()) != CanNavigateState::Able)
3010 return RefPtr<WindowProxy> { nullptr };
3011
3012 URL completedURL = protect(firstFrame->document())->encodingParseURL(urlString);
3013
3014 if (protect(targetFrame->window())->isInsecureScriptAccess(activeWindow, completedURL))
3015 return &targetFrame->windowProxy();
3016
3017 if (urlString.isEmpty())
3018 return &targetFrame->windowProxy();
3019
3020 // For whatever reason, Firefox uses the first window rather than the active window to
3021 // determine the outgoing referrer. We replicate that behavior here.
3022 LockHistory lockHistory = UserGestureIndicator::processingUserGesture() ? LockHistory::No : LockHistory::Yes;
3023 protect(targetFrame->navigationScheduler())->scheduleLocationChange(*activeDocument, protect(activeDocument->securityOrigin()), completedURL, firstFrame->loader().outgoingReferrer(),
3024 lockHistory, LockBackForwardList::No);
3025 return &targetFrame->windowProxy();
3026 }
3027
3028 auto newFrameOrException = createWindow(urlString, frameName, parseWindowFeatures(windowFeaturesString), activeWindow, *firstFrame, *frame);
3029 if (newFrameOrException.hasException())
3030 return newFrameOrException.releaseException();
3031
3032 auto newFrame = newFrameOrException.releaseReturnValue();
3033 return newFrame ? &newFrame->windowProxy() : nullptr;
3034}
3035
3036void LocalDOMWindow::showModalDialog(const String& urlString, const String& dialogFeaturesString, LocalDOMWindow& activeWindow, LocalDOMWindow& firstWindow, NOESCAPE[[clang::noescape]] const Function<void(LocalDOMWindow&)>& prepareDialogFunction)
3037{
3038 if (RefPtr document = this->document())
3039 document->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, "showModalDialog() is deprecated and will be removed. Please use the <dialog> element instead."_s);
3040
3041 if (!isCurrentlyDisplayedInFrame())
3042 return;
3043 if (!activeWindow.frame())
3044 return;
3045 RefPtr firstFrame = firstWindow.frame();
3046 if (!firstFrame)
3047 return;
3048
3049 RefPtr frame = this->frame();
3050 RefPtr page = frame->page();
3051 if (!page)
3052 return;
3053
3054 if (!page->arePromptsAllowed()) {
3055 printErrorMessage("Use of window.showModalDialog is not allowed while unloading a page."_s);
3056 return;
3057 }
3058
3059 if (!canShowModalDialog(*frame) || !firstWindow.allowPopUp())
3060 return;
3061
3062 auto dialogFrameOrException = createWindow(urlString, emptyAtom(), parseDialogFeatures(dialogFeaturesString, screenAvailableRect(protect(frame->view()).get())), activeWindow, *firstFrame, *frame, prepareDialogFunction);
3063 if (dialogFrameOrException.hasException())
3064 return;
3065 if (RefPtr dialogFrame = dialogFrameOrException.releaseReturnValue())
3066 dialogFrame->page()->chrome().runModal();
3067}
3068
3069void LocalDOMWindow::enableSuddenTermination()
3070{
3071 if (RefPtr page = this->page())
3072 page->chrome().enableSuddenTermination();
3073}
3074
3075void LocalDOMWindow::disableSuddenTermination()
3076{
3077 if (RefPtr page = this->page())
3078 page->chrome().disableSuddenTermination();
3079}
3080
3081LocalFrame* LocalDOMWindow::frame() const
3082{
3083 auto* document = this->document();
3084 return document ? document->frame() : nullptr;
3085}
3086
3087void LocalDOMWindow::eventListenersDidChange()
3088{
3089 if (m_localStorage || m_sessionStorage) {
3090 if (hasEventListeners(eventNames().storageEvent))
3091 windowsInterestedInStorageEvents().add(*this);
3092 else
3093 windowsInterestedInStorageEvents().remove(*this);
3094 }
3095}
3096
3097CookieStore& LocalDOMWindow::cookieStore()
3098{
3099 if (!m_cookieStore)
3100 m_cookieStore = CookieStore::create(protect(document()).get());
3101 return *m_cookieStore;
3102}
3103
3104CloseWatcherManager& LocalDOMWindow::closeWatcherManager()
3105{
3106 if (!m_closeWatcherManager)
3107 m_closeWatcherManager = adoptRef(*new CloseWatcherManager());
3108 return *m_closeWatcherManager;
3109}
3110
3111#if ENABLE(DECLARATIVE_WEB_PUSH)(defined 1 && 1)
3112PushManager& LocalDOMWindow::pushManager()
3113{
3114 if (!m_pushManager)
3115 lazyInitialize(m_pushManager, makeUniqueWithoutRefCountedCheck<PushManager>(*this));
3116 return *m_pushManager;
3117}
3118
3119static URL toScope(LocalDOMWindow& window)
3120{
3121 if (RefPtr frame = window.frame()) {
3122 if (RefPtr document = frame->document())
3123 return URL { document->url().protocolHostAndPort() };
3124 }
3125
3126 return { };
3127}
3128
3129void LocalDOMWindow::subscribeToPushService(const Vector<uint8_t>& applicationServerKey, DOMPromiseDeferred<IDLInterface<PushSubscription>>&& promise)
3130{
3131 LOG(Push, "LocalDOMWindow::subscribeToPushService")((void)0);
3132
3133 platformStrategies()->pushStrategy()->windowSubscribeToPushService(toScope(*this), applicationServerKey, [protectedThis = Ref { *this }, promise = WTF::move(promise)](auto&& result) mutable {
3134 LOG(Push, "LocalDOMWindow::subscribeToPushService completed")((void)0);
3135 if (result.hasException()) {
3136 promise.reject(result.releaseException());
3137 return;
3138 }
3139
3140 promise.resolve(PushSubscription::create(result.releaseReturnValue(), protectedThis.ptr()));
3141 });
3142}
3143
3144void LocalDOMWindow::unsubscribeFromPushService(std::optional<PushSubscriptionIdentifier> subscriptionIdentifier, DOMPromiseDeferred<IDLBoolean>&& promise)
3145{
3146 LOG(Push, "LocalDOMWindow::unsubscribeFromPushService")((void)0);
3147
3148 platformStrategies()->pushStrategy()->windowUnsubscribeFromPushService(toScope(*this), subscriptionIdentifier, [promise = WTF::move(promise)](auto&& result) mutable {
3149 LOG(Push, "LocalDOMWindow::unsubscribeFromPushService completed")((void)0);
3150 promise.settle(WTF::move(result));
3151 });
3152}
3153
3154void LocalDOMWindow::getPushSubscription(DOMPromiseDeferred<IDLNullable<IDLInterface<PushSubscription>>>&& promise)
3155{
3156 LOG(Push, "LocalDOMWindow::getPushSubscription")((void)0);
3157
3158 platformStrategies()->pushStrategy()->windowGetPushSubscription(toScope(*this), [protectedThis = Ref { *this }, promise = WTF::move(promise)](auto&& result) mutable {
3159 LOG(Push, "LocalDOMWindow::getPushSubscription completed")((void)0);
3160 if (result.hasException()) {
3161 promise.reject(result.releaseException());
3162 return;
3163 }
3164
3165 auto optionalPushSubscriptionData = result.releaseReturnValue();
3166 if (!optionalPushSubscriptionData) {
3167 promise.resolve(nullptr);
3168 return;
3169 }
3170
3171 promise.resolve(PushSubscription::create(WTF::move(*optionalPushSubscriptionData), protectedThis.ptr()).ptr());
3172 });
3173}
3174
3175void LocalDOMWindow::getPushPermissionState(DOMPromiseDeferred<IDLEnumeration<PushPermissionState>>&& promise)
3176{
3177 LOG(Push, "LocalDOMWindow::getPushPermissionState")((void)0);
3178
3179 platformStrategies()->pushStrategy()->windowGetPushPermissionState(toScope(*this), [promise = WTF::move(promise)](auto&& result) mutable {
3180 LOG(Push, "LocalDOMWindow::getPushPermissionState completed")((void)0);
3181 promise.settle(WTF::move(result));
3182 });
3183}
3184
3185#endif // #if ENABLE(DECLARATIVE_WEB_PUSH)
3186
3187} // namespace WebCore