Bug Summary

File:Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/testing/Internals.cpp
Warning:line 1192, column 23
Unsafe cast from base type 'Element' to derived type 'SVGImageElement'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-ios26.2.0-simulator -O3 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Internals.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/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.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/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1230.1 -fcoverage-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-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/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCoreTestSupport/normal/arm64/Internals-7f2b4baf2c486c5056addf0cd380ba2b.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCoreTestSupport.build/WebCoreTestSupport-generated-files.hmap -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCoreTestSupport.build/WebCoreTestSupport-project-headers.hmap -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/usr/include -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/System/Library/Frameworks -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/2862701673248763883/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 __clang_analyzer__ -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCoreTestSupport.build/WebCoreTestSupport-own-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCoreTestSupport.build/WebCoreTestSupport-all-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/include -I /usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/libxml2 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webm -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCoreTestSupport.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCoreTestSupport.build/DerivedSources/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCoreTestSupport.build/DerivedSources -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.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/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.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 -fsafe-buffer-usage-suggestions -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/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCoreTestSupport/normal/arm64/Internals-7f2b4baf2c486c5056addf0cd380ba2b.plist -x c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/testing/Internals.cpp
1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013-2026 Apple Inc. All rights reserved.
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 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "Internals.h"
29
30#include "AXCrossProcessSearch.h"
31#include "AXObjectCacheInlines.h"
32#include "AnimationTimeline.h"
33#include "AnimationTimelinesController.h"
34#include "AudioSession.h"
35#include "AudioTrackPrivateMediaStream.h"
36#include "Autofill.h"
37#include "BackForwardCache.h"
38#include "BackForwardController.h"
39#include "BitmapImage.h"
40#include "Blob.h"
41#include "BoundaryPointInlines.h"
42#include "CSSKeyframesRule.h"
43#include "CSSMediaRule.h"
44#include "CSSPropertyParser.h"
45#include "CSSPropertyParserConsumer+ColorInlines.h"
46#include "CSSSelectorParser.h"
47#include "CSSStyleRule.h"
48#include "CSSSupportsRule.h"
49#include "CacheStorageConnection.h"
50#include "CacheStorageProvider.h"
51#include "CachedImage.h"
52#include "CanvasBase.h"
53#include "CertificateInfo.h"
54#include "Chrome.h"
55#include "ChromeClient.h"
56#include "ClientOrigin.h"
57#include "ColorChooser.h"
58#include "ColorSerialization.h"
59#include "ComposedTreeIterator.h"
60#include "ContainerNodeInlines.h"
61#include "ContextDestructionObserverInlines.h"
62#include "CookieJar.h"
63#include "CrossOriginPreflightResultCache.h"
64#include "Cursor.h"
65#include "DOMAsyncIterator.h"
66#include "DOMPointReadOnly.h"
67#include "DOMRect.h"
68#include "DOMRectList.h"
69#include "DOMStringList.h"
70#include "DOMURL.h"
71#include "DeprecatedGlobalSettings.h"
72#include "DiagnosticLoggingClient.h"
73#include "DisabledAdaptations.h"
74#include "DisplayList.h"
75#include "DocumentFullscreen.h"
76#include "DocumentInlines.h"
77#include "DocumentLoader.h"
78#include "DocumentMarkerController.h"
79#include "DocumentMarkers.h"
80#include "DocumentPage.h"
81#include "DocumentQuirks.h"
82#include "DocumentResourceLoader.h"
83#include "DocumentTimeline.h"
84#include "DocumentView.h"
85#include "Editor.h"
86#include "Element.h"
87#include "ElementRareData.h"
88#include "EventHandler.h"
89#include "EventListener.h"
90#include "EventLoop.h"
91#include "EventNames.h"
92#include "EventTargetForTesting.h"
93#include "ExtendableEvent.h"
94#include "ExtensionStyleSheets.h"
95#include "FetchRequest.h"
96#include "FetchResponse.h"
97#include "File.h"
98#include "FileSystemHandle.h"
99#include "FloatQuad.h"
100#include "FontCache.h"
101#include "FormController.h"
102#include "FragmentDirectiveGenerator.h"
103#include "FrameInspectorController.h"
104#include "FrameLoader.h"
105#include "FrameMemoryMonitor.h"
106#include "FrameSnapshotting.h"
107#include "GCObservation.h"
108#include "GraphicsLayer.h"
109#include "HEVCUtilities.h"
110#include "HTMLAnchorElement.h"
111#include "HTMLAttachmentElement.h"
112#include "HTMLCanvasElement.h"
113#include "HTMLIFrameElement.h"
114#include "HTMLImageElement.h"
115#include "HTMLInputElement.h"
116#include "HTMLLinkElement.h"
117#include "HTMLNames.h"
118#include "HTMLPictureElement.h"
119#include "HTMLPlugInElement.h"
120#include "HTMLPreloadScanner.h"
121#include "HTMLSelectElement.h"
122#include "HTMLTextAreaElement.h"
123#include "HTMLVideoElement.h"
124#include "HighlightRegistry.h"
125#include "History.h"
126#include "HistoryController.h"
127#include "HistoryItem.h"
128#include "HitTestResult.h"
129#include "IDBRequest.h"
130#include "IDBTransaction.h"
131#include "ImageData.h"
132#include "ImageOverlay.h"
133#include "ImageOverlayController.h"
134#include "InlineIteratorLineBox.h"
135#include "InspectorBackendClient.h"
136#include "InspectorDebuggableType.h"
137#include "InspectorFrontendClientLocal.h"
138#include "InspectorOverlay.h"
139#include "InstrumentingAgents.h"
140#include "IntRect.h"
141#include "InternalSettings.h"
142#include "InternalsMapLike.h"
143#include "InternalsSetLike.h"
144#include "JSDOMPromiseDeferred.h"
145#include "JSFile.h"
146#include "JSInternals.h"
147#include "JSNode.h"
148#include "LegacySchemeRegistry.h"
149#include "LoaderStrategy.h"
150#include "LocalDOMWindow.h"
151#include "LocalFrame.h"
152#include "LocalFrameView.h"
153#include "LocalizedStrings.h"
154#include "Location.h"
155#include "MallocStatistics.h"
156#include "MediaControlsHost.h"
157#include "MediaDevices.h"
158#include "MediaKeySession.h"
159#include "MediaKeys.h"
160#include "MediaMetadata.h"
161#include "MediaPlayer.h"
162#include "MediaProducer.h"
163#include "MediaResourceLoader.h"
164#include "MediaSession.h"
165#include "MediaSessionActionDetails.h"
166#include "MediaStrategy.h"
167#include "MediaStreamTrack.h"
168#include "MediaUsageInfo.h"
169#include "MemoryCache.h"
170#include "MemoryInfo.h"
171#include "MemoryRelease.h"
172#include "MessagePort.h"
173#include "MockAudioDestinationCocoa.h"
174#include "MockLibWebRTCPeerConnection.h"
175#include "MockPageOverlay.h"
176#include "MockPageOverlayClient.h"
177#include "Navigation.h"
178#include "NavigatorBeacon.h"
179#include "NavigatorMediaDevices.h"
180#include "NetworkLoadInformation.h"
181#include "Page.h"
182#include "PageInspectorController.h"
183#include "PageOverlay.h"
184#include "PathUtilities.h"
185#include "PictureInPictureSupport.h"
186#include "PlatformKeyboardEvent.h"
187#include "PlatformMediaEngineConfigurationFactory.h"
188#include "PlatformMediaSession.h"
189#include "PlatformMediaSessionManager.h"
190#include "PlatformRenderTheme.h"
191#include "PlatformScreen.h"
192#include "PlatformStrategies.h"
193#include "PluginData.h"
194#include "PluginViewBase.h"
195#include "PrintContext.h"
196#include "PseudoElement.h"
197#include "PushSubscription.h"
198#include "PushSubscriptionData.h"
199#include "RTCController.h"
200#include "RTCNetworkManager.h"
201#include "RTCRtpSFrameTransform.h"
202#include "Range.h"
203#include "ReadableStream.h"
204#include "RenderEmbeddedObject.h"
205#include "RenderLayerBacking.h"
206#include "RenderLayerCompositor.h"
207#include "RenderLayerScrollableArea.h"
208#include "RenderListBox.h"
209#include "RenderObjectInlines.h"
210#include "RenderSearchField.h"
211#include "RenderTheme.h"
212#include "RenderTreeAsText.h"
213#include "RenderView.h"
214#include "RenderedDocumentMarker.h"
215#include "ResolvedStyle.h"
216#include "ResourceLoadObserver.h"
217#include "SMILTimeContainer.h"
218#include "SVGDocumentExtensions.h"
219#include "SVGImageElement.h"
220#include "SVGPathStringBuilder.h"
221#include "SVGSVGElement.h"
222#include "SWClientConnection.h"
223#include "ScriptController.h"
224#include "ScriptExecutionContextInlines.h"
225#include "ScriptedAnimationController.h"
226#include "ScrollTimeline.h"
227#include "ScrollToOptions.h"
228#include "ScrollbarsControllerMock.h"
229#include "ScrollingCoordinator.h"
230#include "ScrollingMomentumCalculator.h"
231#include "SecurityOrigin.h"
232#include "SelectorFilter.h"
233#include "SerializedScriptValue.h"
234#include "ServiceWorker.h"
235#include "ServiceWorkerProvider.h"
236#include "ServiceWorkerRegistration.h"
237#include "ServiceWorkerRegistrationData.h"
238#include "Settings.h"
239#include "ShadowRoot.h"
240#include "ShouldPartitionCookie.h"
241#include "SourceBuffer.h"
242#include "SpeechSynthesisUtterance.h"
243#include "SpellChecker.h"
244#include "StaticNodeList.h"
245#include "StorageNamespace.h"
246#include "StorageNamespaceProvider.h"
247#include "StreamTransferUtilities.h"
248#include "StringCallback.h"
249#include "StyleGridPosition.h"
250#include "StyleResolver.h"
251#include "StyleRule.h"
252#include "StyleScope.h"
253#include "StyleSheetContents.h"
254#include "SystemSoundManager.h"
255#include "TextIterator.h"
256#include "TextPainter.h"
257#include "TextPlaceholderElement.h"
258#include "TextRecognitionOptions.h"
259#include "ThreadableBlobRegistry.h"
260#include "TreeScopeInlines.h"
261#include "TypeConversions.h"
262#include "UserContentURLPattern.h"
263#include "UserGestureIndicator.h"
264#include "UserMediaController.h"
265#include "VideoConfiguration.h"
266#include "ViewportArguments.h"
267#include "ViewportConfiguration.h"
268#include "VoidCallback.h"
269#include "WebAnimation.h"
270#include "WebAnimationUtilities.h"
271#include "WebCodecsVideoDecoder.h"
272#include "WebCoreJSClientData.h"
273#include "WebCoreTestSupport.h"
274#include "WebRTCProvider.h"
275#include "WindowProxy.h"
276#include "WorkerThread.h"
277#include "WorkletGlobalScope.h"
278#include "WritableStream.h"
279#include "WritingDirection.h"
280#include "XMLHttpRequest.h"
281#include <JavaScriptCore/CodeBlock.h>
282#include <JavaScriptCore/FunctionExecutable.h>
283#include <JavaScriptCore/HeapInlines.h>
284#include <JavaScriptCore/HeapIterationScope.h>
285#include <JavaScriptCore/InspectorAgentBase.h>
286#include <JavaScriptCore/InspectorFrontendChannel.h>
287#include <JavaScriptCore/JSCInlines.h>
288#include <JavaScriptCore/JSCJSValue.h>
289#include <JavaScriptCore/JSCellInlines.h>
290#include <JavaScriptCore/MarkedSpaceInlines.h>
291#include <wtf/FileHandle.h>
292#include <wtf/FileSystem.h>
293#include <wtf/HexNumber.h>
294#include <wtf/JSONValues.h>
295#include <wtf/Language.h>
296#include <wtf/MemoryPressureHandler.h>
297#include <wtf/MonotonicTime.h>
298#include <wtf/NativePromise.h>
299#include <wtf/ProcessID.h>
300#include <wtf/RunLoop.h>
301#include <wtf/TZoneMallocInlines.h>
302#include <wtf/URLHelpers.h>
303#include <wtf/WeakPtr.h>
304#include <wtf/text/MakeString.h>
305#include <wtf/text/StringBuilder.h>
306#include <wtf/text/StringToIntegerConversion.h>
307
308#if USE(CG)(defined 1 && 1)
309#include "PDFDocumentImage.h"
310#endif
311
312#if ENABLE(MOUSE_CURSOR_SCALE)(defined 0 && 0)
313#include <wtf/dtoa.h>
314#endif
315
316#if ENABLE(LEGACY_ENCRYPTED_MEDIA)(defined 1 && 1)
317#include "LegacyCDM.h"
318#include "LegacyMockCDM.h"
319#endif
320
321#if ENABLE(ENCRYPTED_MEDIA)(defined 1 && 1)
322#include "MockCDMFactory.h"
323#endif
324
325#if ENABLE(VIDEO)(defined 1 && 1)
326#include "CaptionUserPreferences.h"
327#include "HTMLMediaElement.h"
328#include "MockCaptionDisplaySettingsClientCallback.h"
329#include "PageGroup.h"
330#include "TextTrack.h"
331#include "TextTrackCueGeneric.h"
332#include "TimeRanges.h"
333#include "VTTCue.h"
334#endif
335
336#if ENABLE(WEBGL)(defined 1 && 1)
337#include "WebGLRenderingContext.h"
338#endif
339
340#if ENABLE(SPEECH_SYNTHESIS)(defined 1 && 1)
341#include "LocalDOMWindowSpeechSynthesis.h"
342#include "PlatformSpeechSynthesizerMock.h"
343#include "SpeechSynthesis.h"
344#endif
345
346#if ENABLE(MEDIA_STREAM)(defined 1 && 1)
347#include "MediaStream.h"
348#include "MockRealtimeMediaSourceCenter.h"
349#include "VideoFrame.h"
350#endif
351
352#if ENABLE(MEDIA_RECORDER)(defined 1 && 1)
353#include "MediaRecorder.h"
354#include "MediaRecorderPrivateMock.h"
355#endif
356
357#if ENABLE(WEB_RTC)(defined 1 && 1)
358#include "RTCPeerConnection.h"
359#endif
360
361#if USE(LIBWEBRTC)(defined 1 && 1)
362#include "LibWebRTCProvider.h"
363#endif
364
365#if ENABLE(CONTENT_FILTERING)(defined 1 && 1)
366#include "MockContentFilterSettings.h"
367#endif
368
369#if ENABLE(WEB_AUDIO)(defined 1 && 1)
370#include "AudioContext.h"
371#include "WaveShaperDSPKernel.h"
372#endif
373
374#if ENABLE(WIRELESS_PLAYBACK_TARGET)(defined 1 && 1)
375#include "MediaPlaybackTargetMock.h"
376#endif
377
378#if ENABLE(POINTER_LOCK)(defined 1 && 1)
379#include "PointerLockController.h"
380#endif
381
382#if USE(QUICK_LOOK)(defined 1 && 1)
383#include "LegacyPreviewLoader.h"
384#include "MockPreviewLoaderClient.h"
385#endif
386
387#if ENABLE(APPLE_PAY)(defined 1 && 1)
388#include "MockPaymentCoordinator.h"
389#include "PaymentCoordinator.h"
390#endif
391
392#if ENABLE(WEB_CODECS)(defined 1 && 1)
393#include "JSWebCodecsVideoFrame.h"
394#endif
395
396#if ENABLE(WEBXR)(defined 0 && 0)
397#include "NavigatorWebXR.h"
398#include "WebXRSystem.h"
399#include "WebXRTest.h"
400#endif
401
402#if PLATFORM(MAC)(defined WTF_PLATFORM_MAC && WTF_PLATFORM_MAC)
403#include "GraphicsChecksMac.h"
404#include "ScrollbarsControllerMac.h"
405#endif
406
407#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
408#include "MediaSessionHelperIOS.h"
409#endif
410
411#if PLATFORM(COCOA)(defined 1 && 1)
412#include "FontCacheCoreText.h"
413#include "SystemBattery.h"
414#include "VP9UtilitiesCocoa.h"
415#include <pal/spi/cf/CoreTextSPI.h>
416#include <wtf/spi/darwin/SandboxSPI.h>
417#endif
418
419#if PLATFORM(WPE)(defined WTF_PLATFORM_WPE && WTF_PLATFORM_WPE)
420#include <wtf/glib/GResources.h>
421#endif
422
423#if ENABLE(MEDIA_SESSION_COORDINATOR)(defined ENABLE_MEDIA_SESSION_COORDINATOR && ENABLE_MEDIA_SESSION_COORDINATOR
)
424#include "MediaSessionCoordinator.h"
425#include "MockMediaSessionCoordinator.h"
426#include "NavigatorMediaSession.h"
427#endif
428
429#if ENABLE(MEDIA_SESSION)(defined 1 && 1) && USE(GLIB)(defined USE_GLIB && USE_GLIB)
430#include "MediaSessionManagerGLib.h"
431#endif
432
433#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
434#include "TextRecognitionResult.h"
435#endif
436
437#if ENABLE(MODEL_ELEMENT)(defined 1 && 1)
438#include "HTMLModelElement.h"
439#endif
440
441#if ENABLE(SERVICE_CONTROLS)(defined ENABLE_SERVICE_CONTROLS && ENABLE_SERVICE_CONTROLS
)
442#include "ImageControlsMac.h"
443#endif
444
445#if ENABLE(WIRELESS_PLAYBACK_MEDIA_PLAYER)(defined ENABLE_WIRELESS_PLAYBACK_MEDIA_PLAYER && ENABLE_WIRELESS_PLAYBACK_MEDIA_PLAYER
)
446#import "MediaDeviceRouteController.h"
447#import "MockMediaDeviceRouteController.h"
448#endif
449
450using JSC::CallData;
451using JSC::CodeBlock;
452using JSC::FunctionExecutable;
453using JSC::Identifier;
454using JSC::JSFunction;
455using JSC::JSGlobalObject;
456using JSC::JSObject;
457using JSC::JSValue;
458using JSC::MarkedArgumentBuffer;
459using JSC::PropertySlot;
460using JSC::ScriptExecutable;
461using JSC::StackVisitor;
462
463namespace WebCore {
464
465WTF_MAKE_TZONE_ALLOCATED_IMPL(Internals)::bmalloc::api::HeapRef Internals::s_heapRef; const TZoneSpecification
Internals::s_heapSpec = { &Internals::s_heapRef, TZoneSpecification
::encodeSize<Internals>(), TZoneSpecification::encodeAlignment
<Internals>(), TZoneSpecification::encodeCategory<Internals
>(), ::bmalloc::api::compactAllocationMode<Internals>
(), TZoneSpecification::encodeDescriptor<Internals>(), }
; void* Internals::operatorNewSlow(size_t size) { if constexpr
(::bmalloc::api::compactAllocationMode<Internals>() ==
CompactAllocationMode::Compact) return ::bmalloc::api::tzoneAllocateCompactSlow
(size, s_heapSpec); return ::bmalloc::api::tzoneAllocateNonCompactSlow
(size, s_heapSpec); } using __makeBtzoneMallocedInlineMacroSemicolonifier
__attribute__((unused)) = int
;
466
467using namespace Inspector;
468using namespace HTMLNames;
469
470class InspectorStubFrontend final : public InspectorFrontendClientLocal, public FrontendChannel {
471 WTF_MAKE_TZONE_ALLOCATED_INLINE(InspectorStubFrontend)public: public: using HeapRef = ::bmalloc::api::HeapRef; using
TZoneDescriptor = ::bmalloc::api::TZoneDescriptor; using TZoneMallocFallback
= ::bmalloc::api::TZoneMallocFallback; using CompactAllocationMode
= ::bmalloc::CompactAllocationMode; static constexpr bool usesTZoneHeap
() { return true; } static constexpr unsigned inheritedSizeClass
() { return ::bmalloc::TZone::sizeClass<InspectorStubFrontend
>(); } static constexpr unsigned inheritedAlignment() { return
::bmalloc::TZone::alignment<InspectorStubFrontend>(); }
__attribute__((always_inline)) inline void* operator new(size_t
, void* p) { return p; } __attribute__((always_inline)) inline
void* operator new[](size_t, void* p) { return p; } void* operator
new[](size_t size) = delete; void operator delete[](void* p)
= delete; __attribute__((always_inline)) inline void* operator
new(size_t, NotNullTag, void* location) { ((void)0); return location
; } void* operator new(size_t size) { static HeapRef s_heapRef
; static const TZoneSpecification s_heapSpec = { &s_heapRef
, TZoneSpecification::encodeSize<InspectorStubFrontend>
(), TZoneSpecification::encodeAlignment<InspectorStubFrontend
>(), TZoneSpecification::encodeCategory<InspectorStubFrontend
>(), ::bmalloc::api::compactAllocationMode<InspectorStubFrontend
>(), TZoneSpecification::encodeDescriptor<InspectorStubFrontend
>(), }; if (!s_heapRef || size != sizeof(InspectorStubFrontend
)) { [[unlikely]] if constexpr (::bmalloc::api::compactAllocationMode
<InspectorStubFrontend>() == CompactAllocationMode::Compact
) return ::bmalloc::api::tzoneAllocateCompactSlow(size, s_heapSpec
); return ::bmalloc::api::tzoneAllocateNonCompactSlow(size, s_heapSpec
); } ; if constexpr (::bmalloc::api::compactAllocationMode<
InspectorStubFrontend>() == CompactAllocationMode::Compact
) return ::bmalloc::api::tzoneAllocateCompact(s_heapRef); return
::bmalloc::api::tzoneAllocateNonCompact(s_heapRef); } __attribute__
((always_inline)) inline void operator delete(void* p) { ::bmalloc
::api::tzoneFree(p); } __attribute__((always_inline)) inline static
void freeAfterDestruction(void* p) { ::bmalloc::api::tzoneFree
(p); } using WTFIsFastMallocAllocated = int; private: using __makeBtzoneMallocedInlineMacroSemicolonifier
__attribute__((unused)) = int
;
472public:
473 InspectorStubFrontend(Page& inspectedPage, LocalFrame& mainFrame, RefPtr<LocalDOMWindow>&& frontendWindow);
474 virtual ~InspectorStubFrontend();
475
476private:
477 bool supportsDockSide(DockSide) final { return false; }
478 void attachWindow(DockSide) final { }
479 void detachWindow() final { }
480 void closeWindow() final;
481 void reopen() final { }
482 void bringToFront() final { }
483 void setForcedAppearance(InspectorFrontendClient::Appearance) final { }
484 String localizedStringsURL() const final { return String(); }
485 DebuggableType debuggableType() const final { return DebuggableType::WebPage; }
486 String targetPlatformName() const { return "Unknown"_s; }
487 String targetBuildVersion() const { return "Unknown"_s; }
488 String targetProductVersion() const { return "Unknown"_s; }
489 bool targetIsSimulator() const { return false; }
490 void inspectedURLChanged(const String&) final { }
491 void showCertificate(const CertificateInfo&) final { }
492 void setAttachedWindowHeight(unsigned) final { }
493 void setAttachedWindowWidth(unsigned) final { }
494 void setSheetRect(const FloatRect&) final { }
495
496 void sendMessageToFrontend(const String& message) final;
497 ConnectionType connectionType() const final { return ConnectionType::Local; }
498
499 RefPtr<LocalDOMWindow> m_frontendWindow;
500 WeakPtr<FrameInspectorController> m_mainFrameInspectorController;
501};
502
503InspectorStubFrontend::InspectorStubFrontend(Page& inspectedPage, LocalFrame& mainFrame, RefPtr<LocalDOMWindow>&& frontendWindow)
504 : InspectorFrontendClientLocal(&inspectedPage.inspectorController(), frontendWindow->document()->page(), makeUnique<InspectorFrontendClientLocal::Settings>(), InspectorFrontendClientLocal::DispatchBackendTarget::MainFrame)
505 , m_frontendWindow(frontendWindow.copyRef())
506 , m_mainFrameInspectorController(mainFrame.inspectorController())
507{
508 ASSERT_ARG(frontendWindow, frontendWindow)((void)0);
509
510 frontendPage()->inspectorController().setInspectorFrontendClient(this);
511 protect(inspectedPage.inspectorController())->connectFrontend(*this);
512 protect(mainFrame.inspectorController())->connectFrontend(*this);
513}
514
515InspectorStubFrontend::~InspectorStubFrontend()
516{
517 closeWindow();
518}
519
520void InspectorStubFrontend::closeWindow()
521{
522 if (!m_frontendWindow)
523 return;
524
525 frontendPage()->inspectorController().setInspectorFrontendClient(nullptr);
526 if (RefPtr controller = m_mainFrameInspectorController.get())
527 controller->disconnectFrontend(*this);
528 if (RefPtr page = inspectedPage())
529 protect(page->inspectorController())->disconnectFrontend(*this);
530
531 m_frontendWindow->close();
532 m_frontendWindow = nullptr;
533}
534
535void InspectorStubFrontend::sendMessageToFrontend(const String& message)
536{
537 frontendAPIDispatcher().dispatchMessageAsync(message);
538}
539
540static bool markerTypeFrom(const String& markerType, DocumentMarkerType& result)
541{
542 if (equalLettersIgnoringASCIICase(markerType, "spelling"_s))
543 result = DocumentMarkerType::Spelling;
544 else if (equalLettersIgnoringASCIICase(markerType, "grammar"_s))
545 result = DocumentMarkerType::Grammar;
546 else if (equalLettersIgnoringASCIICase(markerType, "textmatch"_s))
547 result = DocumentMarkerType::TextMatch;
548 else if (equalLettersIgnoringASCIICase(markerType, "replacement"_s))
549 result = DocumentMarkerType::Replacement;
550 else if (equalLettersIgnoringASCIICase(markerType, "correctionindicator"_s))
551 result = DocumentMarkerType::CorrectionIndicator;
552 else if (equalLettersIgnoringASCIICase(markerType, "rejectedcorrection"_s))
553 result = DocumentMarkerType::RejectedCorrection;
554 else if (equalLettersIgnoringASCIICase(markerType, "autocorrected"_s))
555 result = DocumentMarkerType::Autocorrected;
556 else if (equalLettersIgnoringASCIICase(markerType, "spellcheckingexemption"_s))
557 result = DocumentMarkerType::SpellCheckingExemption;
558 else if (equalLettersIgnoringASCIICase(markerType, "deletedautocorrection"_s))
559 result = DocumentMarkerType::DeletedAutocorrection;
560 else if (equalLettersIgnoringASCIICase(markerType, "dictationalternatives"_s))
561 result = DocumentMarkerType::DictationAlternatives;
562#if ENABLE(TELEPHONE_NUMBER_DETECTION)(defined 1 && 1)
563 else if (equalLettersIgnoringASCIICase(markerType, "telephonenumber"_s))
564 result = DocumentMarkerType::TelephoneNumber;
565#endif
566#if ENABLE(WRITING_TOOLS)(defined 1 && 1)
567 else if (equalLettersIgnoringASCIICase(markerType, "writingtoolstextsuggestion"_s))
568 result = DocumentMarkerType::WritingToolsTextSuggestion;
569#endif
570 else if (equalLettersIgnoringASCIICase(markerType, "transparentcontent"_s))
571 result = DocumentMarkerType::TransparentContent;
572 else if (equalLettersIgnoringASCIICase(markerType, "dictationstreamingopacity"_s))
573 result = DocumentMarkerType::DictationStreamingOpacity;
574 else
575 return false;
576
577 return true;
578}
579
580static bool markerTypesFrom(const String& markerType, OptionSet<DocumentMarkerType>& result)
581{
582 DocumentMarkerType singularResult;
583
584 if (markerType.isEmpty() || equalLettersIgnoringASCIICase(markerType, "all"_s))
585 result = DocumentMarker::allMarkers();
586 else if (markerTypeFrom(markerType, singularResult))
587 result = singularResult;
588 else
589 return false;
590
591 return true;
592}
593
594static RefPtr<PrintContext>& NODELETE[[clang::annotate_type("webkit.nodelete")]] printContextForTesting()
595{
596 static NeverDestroyed<RefPtr<PrintContext>> context;
597 return context;
598}
599
600Ref<Internals> Internals::create(Document& document)
601{
602 return adoptRef(*new Internals(document));
603}
604
605Internals::~Internals()
606{
607#if ENABLE(MEDIA_STREAM)(defined 1 && 1)
608 stopObservingRealtimeMediaSource();
609#endif
610#if ENABLE(MEDIA_SESSION)(defined 1 && 1) && ENABLE(WEB_CODECS)(defined 1 && 1)
611 if (m_artworkImagePromise)
612 m_artworkImagePromise->reject(Exception { ExceptionCode::InvalidStateError });
613#endif
614}
615
616void Internals::resetToConsistentState(Page& page)
617{
618 page.setPageScaleFactor(1, IntPoint(0, 0));
619 page.setPagination(Pagination());
620
621 page.setDefersLoading(false);
622 page.setResourceCachingDisabledByWebInspector(false);
623 page.setConsoleMessageListenerForTesting(nullptr);
624
625 RefPtr localMainFrame = page.localMainFrame();
626 if (!localMainFrame)
627 return;
628
629 localMainFrame->setTextZoomFactor(1.0f);
630
631 page.setCompositingPolicyOverride(WebCore::CompositingPolicy::Normal);
632
633 auto* mainFrameView = localMainFrame->view();
634 if (mainFrameView) {
635 page.setHeaderHeight(0);
636 page.setFooterHeight(0);
637 page.setObscuredContentInsets({ });
638#if ENABLE(BANNER_VIEW_OVERLAYS)(defined ENABLE_BANNER_VIEW_OVERLAYS && ENABLE_BANNER_VIEW_OVERLAYS
)
639 page.setHasBannerViewOverlay(false);
640#endif
641 mainFrameView->setUseFixedLayout(false);
642 mainFrameView->setFixedLayoutSize(IntSize());
643 mainFrameView->enableFixedWidthAutoSizeMode(false, { });
644
645 if (auto* backing = mainFrameView->tiledBacking())
646 backing->setTileSizeUpdateDelayDisabledForTesting(false);
647 }
648
649 if (RefPtr window = localMainFrame->window())
650 window->history().setTotalStateObjectPayloadLimitOverride(std::nullopt);
651
652 WTF::clearDefaultPortForProtocolMapForTesting();
653 overrideUserPreferredLanguages(Vector<String>());
654 WebCore::DeprecatedGlobalSettings::setUsesOverlayScrollbars(false);
655 if (!localMainFrame->editor().isContinuousSpellCheckingEnabled())
656 localMainFrame->editor().toggleContinuousSpellChecking();
657 if (localMainFrame->editor().isOverwriteModeEnabled())
658 localMainFrame->editor().toggleOverwriteModeEnabled();
659 localMainFrame->loader().clearTestingOverrides();
660
661 RefPtr sessionManager = page.mediaSessionManager();
662#if ENABLE(VIDEO)(defined 1 && 1)
663 page.group().ensureCaptionPreferences().setCaptionDisplayMode(CaptionUserPreferences::CaptionDisplayMode::ForcedOnly);
664 page.group().ensureCaptionPreferences().setCaptionsStyleSheetOverride(emptyString());
665 page.group().ensureCaptionPreferences().setPreferredLanguage(emptyString());
666
667 sessionManager->resetHaveEverRegisteredAsNowPlayingApplicationForTesting();
668 sessionManager->resetRestrictions();
669 sessionManager->resetSessionState();
670 sessionManager->setWillIgnoreSystemInterruptions(true);
671 sessionManager->applicationWillEnterForeground(false);
672 if (page.mediaPlaybackIsSuspended())
673 page.resumeAllMediaPlayback();
674#endif
675#if ENABLE(VIDEO)(defined 1 && 1) || ENABLE(WEB_AUDIO)(defined 1 && 1)
676 sessionManager->setIsPlayingToAutomotiveHeadUnit(false);
677#endif
678 AXObjectCache::setEnhancedUserInterfaceAccessibility(false);
679 AXObjectCache::disableAccessibilityForTesting();
680 WebCore::setShouldMockParentSearchResultsForTesting(false);
681 WebCore::setShouldMockChildFrameSearchResultsForTesting(false);
682#if ENABLE(ACCESSIBILITY_ISOLATED_TREE)(defined ENABLE_ACCESSIBILITY_ISOLATED_TREE && ENABLE_ACCESSIBILITY_ISOLATED_TREE
)
683 WebCoreTestSupport::notifyAccessibilityTestTeardown();
684#endif
685
686 MockPageOverlayClient::singleton().uninstallAllOverlays();
687
688#if ENABLE(CONTENT_FILTERING)(defined 1 && 1)
689 MockContentFilterSettings::reset();
690#endif
691
692#if ENABLE(WIRELESS_PLAYBACK_TARGET)(defined 1 && 1)
693 page.setMockMediaPlaybackTargetPickerEnabled(true);
694 page.setMockMediaPlaybackTargetPickerState(emptyString(), MediaPlaybackTargetMock::State::Unknown);
695#endif
696
697#if ENABLE(VIDEO)(defined 1 && 1)
698 MediaResourceLoader::recordResponsesForTesting();
699#endif
700
701 page.setShowAllPlugins(false);
702 page.setLowPowerModeEnabledOverrideForTesting(std::nullopt);
703 page.setAggressiveThermalMitigationEnabledForTesting(std::nullopt);
704 page.setOutsideViewportThrottlingEnabledForTesting(false);
705
706#if USE(QUICK_LOOK)(defined 1 && 1)
707 MockPreviewLoaderClient::singleton().setPassword(emptyString());
708 LegacyPreviewLoader::setClientForTesting(nullptr);
709#endif
710
711 printContextForTesting() = nullptr;
712
713 MemoryPressureHandler::singleton().endSimulatedMemoryWarning();
714 MemoryPressureHandler::singleton().endSimulatedMemoryPressure();
715
716#if ENABLE(WEB_RTC)(defined 1 && 1)
717 auto& rtcProvider = page.webRTCProvider();
718#if USE(LIBWEBRTC)(defined 1 && 1)
719 auto& webRTCProvider = downcast<LibWebRTCProvider>(rtcProvider);
720 WebCore::useRealRTCPeerConnectionFactory(webRTCProvider);
721 webRTCProvider.disableNonLocalhostConnections();
722 webRTCProvider.setVP9HardwareSupportForTesting({ });
723#endif
724 page.settings().setWebRTCEncryptionEnabled(true);
725 rtcProvider.setH265Support(true);
726 rtcProvider.setVP9Support(true, true);
727 rtcProvider.clearFactory();
728#if USE(GSTREAMER_WEBRTC)(defined USE_GSTREAMER_WEBRTC && USE_GSTREAMER_WEBRTC
)
729 page.settings().setPeerConnectionEnabled(true);
730#endif
731#endif
732
733 page.setFullscreenAutoHideDuration(0_s);
734 page.setFullscreenInsets({ });
735
736 PlatformMediaEngineConfigurationFactory::disableMock();
737
738#if ENABLE(ENCRYPTED_MEDIA)(defined 1 && 1)
739 MockCDMFactory::unregisterAllMockFactories();
740#endif
741
742#if ENABLE(MEDIA_STREAM)(defined 1 && 1)
743 page.settings().setInterruptAudioOnPageVisibilityChangeEnabled(false);
744#endif
745
746#if ENABLE(MEDIA_RECORDER)(defined 1 && 1)
747 WebCore::MediaRecorder::setCustomPrivateRecorderCreator(nullptr);
748#endif
749
750 CanvasBase::setMaxCanvasAreaForTesting(std::nullopt);
751 LocalDOMWindow::overrideTransientActivationDurationForTesting(std::nullopt);
752
753#if PLATFORM(IOS)(defined 1 && 1) || PLATFORM(VISION)(defined WTF_PLATFORM_VISION && WTF_PLATFORM_VISION)
754 WebCore::setContentSizeCategory(kCTFontContentSizeCategoryL);
755#endif
756
757#if ENABLE(MEDIA_SESSION)(defined 1 && 1) && USE(GLIB)(defined USE_GLIB && USE_GLIB)
758 MediaSessionManagerGLib* glibSessionManager = static_cast<MediaSessionManagerGLib*>(sessionManager.get());
759 glibSessionManager->setDBusNotificationsEnabled(false);
760#endif
761
762#if PLATFORM(COCOA)(defined 1 && 1)
763 setOverrideEnhanceTextLegibility(false);
764#endif
765
766 TextPainter::setForceUseGlyphDisplayListForTesting(false);
767
768#if USE(AUDIO_SESSION)(defined 1 && 1)
769 AudioSession::singleton().setCategoryOverride(AudioSessionCategory::None);
770 AudioSession::singleton().tryToSetActive(false);
771 AudioSession::singleton().endInterruptionForTesting();
772#endif
773
774#if ENABLE(DAMAGE_TRACKING)(defined ENABLE_DAMAGE_TRACKING && ENABLE_DAMAGE_TRACKING
)
775 page.chrome().client().resetDamageHistoryForTesting();
776#endif
777
778#if ENABLE(WIRELESS_PLAYBACK_MEDIA_PLAYER)(defined ENABLE_WIRELESS_PLAYBACK_MEDIA_PLAYER && ENABLE_WIRELESS_PLAYBACK_MEDIA_PLAYER
)
779 setMockMediaDeviceRouteControllerEnabled(false);
780#endif
781}
782
783Internals::Internals(Document& document)
784 : ContextDestructionObserver(&document)
785#if ENABLE(MEDIA_STREAM)(defined 1 && 1)
786 , m_orientationNotifier(0)
787#endif
788{
789#if ENABLE(WIRELESS_PLAYBACK_TARGET)(defined 1 && 1)
790 if (document.page())
791 document.page()->setMockMediaPlaybackTargetPickerEnabled(true);
792#endif
793
794#if ENABLE(VIDEO)(defined 1 && 1)
795 if (document.page())
796 m_testingModeToken = document.page()->group().ensureCaptionPreferences().createTestingModeToken().moveToUniquePtr();
797#endif
798
799 if (contextDocument() && contextDocument()->frame()) {
800 setAutomaticSpellingCorrectionEnabled(true);
801 setAutomaticQuoteSubstitutionEnabled(false);
802 setAutomaticDashSubstitutionEnabled(false);
803 setAutomaticLinkDetectionEnabled(false);
804 setAutomaticTextReplacementEnabled(true);
805 }
806
807#if ENABLE(APPLE_PAY)(defined 1 && 1)
808 auto* frame = document.frame();
809 if (frame && frame->page() && frame->isMainFrame()) {
810 auto mockPaymentCoordinator = MockPaymentCoordinator::create(*frame->page());
811 frame->page()->setPaymentCoordinator(PaymentCoordinator::create(WTF::move(mockPaymentCoordinator)));
812 }
813#endif
814
815#if PLATFORM(COCOA)(defined 1 && 1) && ENABLE(WEB_AUDIO)(defined 1 && 1)
816 AudioDestinationCocoa::createOverride = nullptr;
817#endif
818
819#if PLATFORM(COCOA)(defined 1 && 1)
820 SystemBatteryStatusTestingOverrides::singleton().resetOverridesToDefaultValues();
821#endif
822
823#if ENABLE(VP9)(defined 1 && 1) && PLATFORM(COCOA)(defined 1 && 1)
824 VP9TestingOverrides::singleton().resetOverridesToDefaultValues();
825#endif
826
827 Scrollbar::setShouldUseFixedPixelsPerLineStepForTesting(true);
828
829#if ENABLE(DAMAGE_TRACKING)(defined ENABLE_DAMAGE_TRACKING && ENABLE_DAMAGE_TRACKING
)
830 document.page()->chrome().client().resetDamageHistoryForTesting();
831#endif
832
833#if ENABLE(WIRELESS_PLAYBACK_MEDIA_PLAYER)(defined ENABLE_WIRELESS_PLAYBACK_MEDIA_PLAYER && ENABLE_WIRELESS_PLAYBACK_MEDIA_PLAYER
)
834 if (RefPtr mockMediaDeviceRouteController = m_mockMediaDeviceRouteController) {
835 m_mockMediaDeviceRouteController->setEnabled(false);
836 m_mockMediaDeviceRouteController = nullptr;
837 }
838#endif
839}
840
841Document* Internals::contextDocument() const
842{
843 return downcast<Document>(scriptExecutionContext());
844}
845
846LocalFrame* Internals::frame() const
847{
848 if (!contextDocument())
849 return nullptr;
850 return contextDocument()->frame();
851}
852
853InternalSettings* Internals::settings() const
854{
855 Document* document = contextDocument();
856 if (!document)
857 return nullptr;
858 Page* page = document->page();
859 if (!page)
860 return nullptr;
861 return InternalSettings::from(page);
862}
863
864unsigned Internals::inflightBeaconsCount() const
865{
866 auto* document = contextDocument();
867 if (!document)
868 return 0;
869
870 auto* window = document->window();
871 if (!window)
872 return 0;
873
874 auto* navigator = window->optionalNavigator();
875 if (!navigator)
876 return 0;
877
878 return NavigatorBeacon::from(*navigator)->inflightBeaconsCount();
879}
880
881unsigned Internals::workerThreadCount() const
882{
883 return WorkerThread::workerThreadCount();
884}
885
886ExceptionOr<bool> Internals::areSVGAnimationsPaused() const
887{
888 RefPtr document = contextDocument();
889 if (!document)
890 return Exception { ExceptionCode::InvalidAccessError, "No context document"_s };
891
892 if (!document->svgExtensionsIfExists())
893 return Exception { ExceptionCode::NotFoundError, "No SVG animations"_s };
894
895 return document->svgExtensions().areAnimationsPaused();
896}
897
898ExceptionOr<double> Internals::svgAnimationsInterval(SVGSVGElement& element) const
899{
900 RefPtr document = contextDocument();
901 if (!document)
902 return 0;
903
904 CheckedPtr svgExtensions = document->svgExtensionsIfExists();
905 if (!svgExtensions)
906 return 0;
907
908 if (svgExtensions->areAnimationsPaused())
909 return 0;
910
911 return element.timeContainer().animationFrameDelay().value();
912}
913
914Vector<Ref<SVGSVGElement>> Internals::allSVGSVGElements() const
915{
916 Vector<Ref<SVGSVGElement>> elements;
917 for (auto& checkedDocument : Document::allDocuments()) {
918 Ref document = checkedDocument.get();
919 if (CheckedPtr svgExtensions = document->svgExtensionsIfExists())
920 elements.appendVector(svgExtensions->allSVGSVGElements());
921 }
922 return elements;
923}
924
925String Internals::address(Node& node)
926{
927 return makeString("0x"_s, hex(reinterpret_cast<uintptr_t>(&node)));
928}
929
930bool Internals::nodeNeedsStyleRecalc(Node& node)
931{
932 return node.needsStyleRecalc();
933}
934
935static String styleValidityToToString(Style::Validity validity)
936{
937 switch (validity) {
938 case Style::Validity::Valid:
939 return "NoStyleChange"_s;
940 case Style::Validity::AnimationInvalid:
941 return "AnimationInvalid"_s;
942 case Style::Validity::InlineStyleInvalid:
943 return "InlineStyleInvalid"_s;
944 case Style::Validity::ElementInvalid:
945 return "InlineStyleChange"_s;
946 case Style::Validity::SubtreeInvalid:
947 return "FullStyleChange"_s;
948 }
949 ASSERT_NOT_REACHED()((void)0);
950 return emptyString();
951}
952
953String Internals::styleChangeType(Node& node)
954{
955 node.document().styleScope().flushPendingUpdate();
956
957 return styleValidityToToString(node.styleValidity());
958}
959
960String Internals::description(JSC::JSValue value)
961{
962 return ::toString(value);
963}
964
965void Internals::log(const String& value)
966{
967 WTFLogAlways("%s", value.utf8().data());
968}
969
970bool Internals::isPreloaded(const String& url)
971{
972 Document* document = contextDocument();
973 return document->cachedResourceLoader().isPreloaded(url);
974}
975
976bool Internals::isLoadingFromMemoryCache(const String& url)
977{
978 CachedResource* resource = resourceFromMemoryCache(url);
979 return resource && resource->status() == CachedResource::Cached;
980}
981
982CachedResource* Internals::resourceFromMemoryCache(const String& url)
983{
984 if (!contextDocument() || !contextDocument()->page())
985 return nullptr;
986
987 ResourceRequest request(contextDocument()->completeURL(url));
988 request.setDomainForCachePartition(contextDocument()->domainForCachePartition());
989
990 return MemoryCache::singleton().resourceForRequest(request, contextDocument()->page()->sessionID());
991}
992
993static String responseSourceToString(const ResourceResponse& response)
994{
995 if (response.isNull())
996 return "Null response"_s;
997 switch (response.source()) {
998 case ResourceResponse::Source::Unknown:
999 return "Unknown"_s;
1000 case ResourceResponse::Source::Network:
1001 return "Network"_s;
1002 case ResourceResponse::Source::ServiceWorker:
1003 return "Service worker"_s;
1004 case ResourceResponse::Source::DiskCache:
1005 return "Disk cache"_s;
1006 case ResourceResponse::Source::DiskCacheAfterValidation:
1007 return "Disk cache after validation"_s;
1008 case ResourceResponse::Source::MemoryCache:
1009 return "Memory cache"_s;
1010 case ResourceResponse::Source::MemoryCacheAfterValidation:
1011 return "Memory cache after validation"_s;
1012 case ResourceResponse::Source::LegacyApplicationCachePlaceholder:
1013 return "Application cache"_s;
1014 case ResourceResponse::Source::DOMCache:
1015 return "DOM cache"_s;
1016 case ResourceResponse::Source::InspectorOverride:
1017 return "Inspector override"_s;
1018 }
1019 ASSERT_NOT_REACHED()((void)0);
1020 return "Error"_s;
1021}
1022
1023String Internals::xhrResponseSource(XMLHttpRequest& request)
1024{
1025 return responseSourceToString(request.resourceResponse());
1026}
1027
1028String Internals::fetchResponseSource(FetchResponse& response)
1029{
1030 return responseSourceToString(response.resourceResponse());
1031}
1032
1033String Internals::blobInternalURL(const Blob& blob)
1034{
1035 return blob.url().string();
1036}
1037
1038void Internals::isBlobInternalURLRegistered(const String& url, DOMPromiseDeferred<IDLBoolean>&& promise)
1039{
1040 promise.resolve(!!ThreadableBlobRegistry::blobSize(URL { url }));
1041}
1042
1043bool Internals::isSharingStyleSheetContents(HTMLLinkElement& a, HTMLLinkElement& b)
1044{
1045 if (!a.sheet() || !b.sheet())
1046 return false;
1047 return &a.sheet()->contents() == &b.sheet()->contents();
1048}
1049
1050bool Internals::isStyleSheetLoadingSubresources(HTMLLinkElement& link)
1051{
1052 return link.sheet() && link.sheet()->contents().isLoadingSubresources();
1053}
1054
1055static ResourceRequestCachePolicy NODELETE[[clang::annotate_type("webkit.nodelete")]] toResourceRequestCachePolicy(Internals::CachePolicy policy)
1056{
1057 switch (policy) {
1058 case Internals::CachePolicy::UseProtocolCachePolicy:
1059 return ResourceRequestCachePolicy::UseProtocolCachePolicy;
1060 case Internals::CachePolicy::ReloadIgnoringCacheData:
1061 return ResourceRequestCachePolicy::ReloadIgnoringCacheData;
1062 case Internals::CachePolicy::ReturnCacheDataElseLoad:
1063 return ResourceRequestCachePolicy::ReturnCacheDataElseLoad;
1064 case Internals::CachePolicy::ReturnCacheDataDontLoad:
1065 return ResourceRequestCachePolicy::ReturnCacheDataDontLoad;
1066 }
1067 ASSERT_NOT_REACHED()((void)0);
1068 return ResourceRequestCachePolicy::UseProtocolCachePolicy;
1069}
1070
1071void Internals::setOverrideCachePolicy(CachePolicy policy)
1072{
1073 frame()->loader().setOverrideCachePolicyForTesting(toResourceRequestCachePolicy(policy));
1074}
1075
1076ExceptionOr<void> Internals::setCanShowModalDialogOverride(bool allow)
1077{
1078 if (!contextDocument() || !contextDocument()->window())
1079 return Exception { ExceptionCode::InvalidAccessError };
1080
1081 contextDocument()->window()->setCanShowModalDialogOverride(allow);
1082 return { };
1083}
1084
1085static ResourceLoadPriority NODELETE[[clang::annotate_type("webkit.nodelete")]] toResourceLoadPriority(Internals::ResourceLoadPriority priority)
1086{
1087 switch (priority) {
1088 case Internals::ResourceLoadPriority::ResourceLoadPriorityVeryLow:
1089 return ResourceLoadPriority::VeryLow;
1090 case Internals::ResourceLoadPriority::ResourceLoadPriorityLow:
1091 return ResourceLoadPriority::Low;
1092 case Internals::ResourceLoadPriority::ResourceLoadPriorityMedium:
1093 return ResourceLoadPriority::Medium;
1094 case Internals::ResourceLoadPriority::ResourceLoadPriorityHigh:
1095 return ResourceLoadPriority::High;
1096 case Internals::ResourceLoadPriority::ResourceLoadPriorityVeryHigh:
1097 return ResourceLoadPriority::VeryHigh;
1098 }
1099 ASSERT_NOT_REACHED()((void)0);
1100 return ResourceLoadPriority::Low;
1101}
1102
1103void Internals::setOverrideResourceLoadPriority(ResourceLoadPriority priority)
1104{
1105 frame()->loader().setOverrideResourceLoadPriorityForTesting(toResourceLoadPriority(priority));
1106}
1107
1108void Internals::setStrictRawResourceValidationPolicyDisabled(bool disabled)
1109{
1110 if (auto* localFrame = frame())
1111 localFrame->loader().setStrictRawResourceValidationPolicyDisabledForTesting(disabled);
1112}
1113
1114void Internals::setImmediateRendererDestructionEnabled(bool enabled)
1115{
1116 auto* document = contextDocument();
1117 if (!document || !document->view())
1118 return;
1119 document->view()->layoutContext().setImmediateRendererDestructionEnabledForTesting(enabled);
1120}
1121
1122static Internals::ResourceLoadPriority NODELETE[[clang::annotate_type("webkit.nodelete")]] toInternalsResourceLoadPriority(ResourceLoadPriority priority)
1123{
1124 switch (priority) {
1125 case ResourceLoadPriority::VeryLow:
1126 return Internals::ResourceLoadPriority::ResourceLoadPriorityVeryLow;
1127 case ResourceLoadPriority::Low:
1128 return Internals::ResourceLoadPriority::ResourceLoadPriorityLow;
1129 case ResourceLoadPriority::Medium:
1130 return Internals::ResourceLoadPriority::ResourceLoadPriorityMedium;
1131 case ResourceLoadPriority::High:
1132 return Internals::ResourceLoadPriority::ResourceLoadPriorityHigh;
1133 case ResourceLoadPriority::VeryHigh:
1134 return Internals::ResourceLoadPriority::ResourceLoadPriorityVeryHigh;
1135 }
1136 ASSERT_NOT_REACHED()((void)0);
1137 return Internals::ResourceLoadPriority::ResourceLoadPriorityLow;
1138}
1139
1140std::optional<Internals::ResourceLoadPriority> Internals::getResourcePriority(const String& url)
1141{
1142 auto* document = contextDocument();
1143 if (!document)
1144 return std::nullopt;
1145 auto* resource = document->cachedResourceLoader().cachedResource(url);
1146 if (!resource)
1147 resource = resourceFromMemoryCache(url);
1148 if (resource)
1149 return toInternalsResourceLoadPriority(resource->loadPriority());
1150 return std::nullopt;
1151}
1152
1153bool Internals::isFetchObjectContextStopped(const FetchObject& object)
1154{
1155 return switchOn(object, [](const auto& item) { return item->isContextStopped(); });
1156}
1157
1158void Internals::clearMemoryCache()
1159{
1160 MemoryCache::singleton().evictResources();
1161 CrossOriginPreflightResultCache::singleton().clear();
1162}
1163
1164void Internals::pruneMemoryCacheToSize(unsigned size)
1165{
1166 MemoryCache::singleton().pruneDeadResourcesToSize(size);
1167 MemoryCache::singleton().pruneLiveResourcesToSize(size, true);
1168}
1169
1170void Internals::destroyDecodedDataForAllImages()
1171{
1172 MemoryCache::singleton().destroyDecodedDataForAllImages();
1173}
1174
1175unsigned Internals::memoryCacheSize() const
1176{
1177 return MemoryCache::singleton().size();
1178}
1179
1180static Image* imageFromImageElement(HTMLImageElement& element)
1181{
1182 auto* cachedImage = element.cachedImage();
1183 return cachedImage ? cachedImage->image() : nullptr;
1184}
1185
1186static Image* imageFromElement(Element& element)
1187{
1188 CachedImage* cachedImage = nullptr;
1189 if (auto* htmlImage = dynamicDowncast<HTMLImageElement>(element))
1190 cachedImage = htmlImage->cachedImage();
1191 else if (element.isSVGElement() && element.localName() == "image"_s)
1192 cachedImage = static_cast<SVGImageElement&>(element).cachedImage();
Unsafe cast from base type 'Element' to derived type 'SVGImageElement'
1193 return cachedImage ? cachedImage->image() : nullptr;
1194}
1195
1196static BitmapImage* bitmapImageFromImageElement(HTMLImageElement& element)
1197{
1198 return dynamicDowncast<BitmapImage>(imageFromImageElement(element));
1199}
1200
1201#if USE(CG)(defined 1 && 1)
1202static PDFDocumentImage* pdfDocumentImageFromImageElement(HTMLImageElement& element)
1203{
1204 return dynamicDowncast<PDFDocumentImage>(imageFromImageElement(element));
1205}
1206#endif
1207
1208unsigned Internals::imageFrameIndex(Element& element)
1209{
1210 auto* bitmapImage = dynamicDowncast<BitmapImage>(imageFromElement(element));
1211 return bitmapImage ? bitmapImage->currentFrameIndex() : 0;
1212}
1213
1214unsigned Internals::imageFrameCount(HTMLImageElement& element)
1215{
1216 auto* bitmapImage = bitmapImageFromImageElement(element);
1217 return bitmapImage ? bitmapImage->frameCount() : 0;
1218}
1219
1220float Internals::imageFrameDurationAtIndex(HTMLImageElement& element, unsigned index)
1221{
1222 auto* bitmapImage = bitmapImageFromImageElement(element);
1223 return bitmapImage ? bitmapImage->frameDurationAtIndex(index).value() : 0;
1224}
1225
1226void Internals::setImageFrameDecodingDuration(HTMLImageElement& element, float duration)
1227{
1228 if (auto* bitmapImage = bitmapImageFromImageElement(element))
1229 bitmapImage->setMinimumDecodingDurationForTesting(Seconds { duration });
1230}
1231
1232void Internals::resetImageAnimation(HTMLImageElement& element)
1233{
1234 if (auto* image = imageFromImageElement(element))
1235 image->resetAnimation();
1236}
1237
1238bool Internals::isImageAnimating(Element& element)
1239{
1240 auto* image = imageFromElement(element);
1241 return image && (image->isAnimating() || image->animationPending());
1242}
1243
1244#if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL)(defined 1 && 1)
1245void Internals::setImageAnimationEnabled(bool enabled)
1246{
1247 if (auto* page = contextDocument() ? contextDocument()->page() : nullptr) {
1248 // We need to set this here to mimic the behavior of the AX preference changing
1249 Image::setSystemAllowsAnimationControls(!enabled);
1250 page->setImageAnimationEnabled(enabled);
1251 }
1252}
1253
1254void Internals::resumeImageAnimation(HTMLImageElement& element)
1255{
1256 element.setAllowsAnimation(true);
1257}
1258
1259void Internals::pauseImageAnimation(HTMLImageElement& element)
1260{
1261 element.setAllowsAnimation(false);
1262}
1263#endif // ENABLE(ACCESSIBILITY_ANIMATION_CONTROL)
1264
1265#if ENABLE(ACCESSIBILITY_NON_BLINKING_CURSOR)(defined 0 && 0)
1266void Internals::setPrefersNonBlinkingCursor(bool enabled)
1267{
1268 auto* document = contextDocument();
1269 if (RefPtr page = document ? document->page() : nullptr) {
1270 page->setPrefersNonBlinkingCursor(enabled);
1271 page->forEachDocument([&](auto& document) {
1272 document.selection().setPrefersNonBlinkingCursor(enabled);
1273 });
1274 }
1275}
1276#endif
1277
1278unsigned Internals::imagePendingDecodePromisesCountForTesting(HTMLImageElement& element)
1279{
1280 return element.pendingDecodePromisesCountForTesting();
1281}
1282
1283void Internals::setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement& element, bool enabled)
1284{
1285 if (auto* bitmapImage = bitmapImageFromImageElement(element))
1286 bitmapImage->setClearDecoderAfterAsyncFrameRequestForTesting(enabled);
1287}
1288
1289unsigned Internals::imageDecodeCount(HTMLImageElement& element)
1290{
1291 auto* bitmapImage = bitmapImageFromImageElement(element);
1292 return bitmapImage ? bitmapImage->decodeCountForTesting() : 0;
1293}
1294
1295unsigned Internals::imageBlankDrawCount(HTMLImageElement& element)
1296{
1297 auto* bitmapImage = bitmapImageFromImageElement(element);
1298 return bitmapImage ? bitmapImage->blankDrawCountForTesting() : 0;
1299}
1300
1301AtomString Internals::imageLastDecodingOptions(HTMLImageElement& element)
1302{
1303 auto* bitmapImage = bitmapImageFromImageElement(element);
1304 if (!bitmapImage)
1305 return { };
1306
1307 auto options = bitmapImage->currentFrameDecodingOptions();
1308 StringBuilder builder;
1309 builder.append("{ decodingMode : "_s,
1310 options.decodingMode() == DecodingMode::Asynchronous ? "Asynchronous"_s : "Synchronous"_s);
1311 if (auto sizeForDrawing = options.sizeForDrawing()) {
1312 builder.append(", sizeForDrawing : { "_s, sizeForDrawing->width(),
1313 ", "_s, sizeForDrawing->height(), " }"_s);
1314 }
1315 builder.append(" }"_s);
1316 return builder.toAtomString();
1317}
1318
1319unsigned Internals::imageCachedSubimageCreateCount(HTMLImageElement& element)
1320{
1321#if USE(CG)(defined 1 && 1)
1322 if (auto* pdfDocumentImage = pdfDocumentImageFromImageElement(element))
1323 return pdfDocumentImage->cachedSubimageCreateCountForTesting();
1324#else
1325 UNUSED_PARAM(element)(void)element;
1326#endif
1327 return 0;
1328}
1329
1330unsigned Internals::remoteImagesCountForTesting() const
1331{
1332 Document* document = contextDocument();
1333 if (!document || !document->page())
1334 return 0;
1335
1336 return document->page()->chrome().client().remoteImagesCountForTesting();
1337}
1338
1339void Internals::setAsyncDecodingEnabledForTesting(HTMLImageElement& element, bool enabled)
1340{
1341 if (auto* bitmapImage = bitmapImageFromImageElement(element))
1342 bitmapImage->setAsyncDecodingEnabledForTesting(enabled);
1343}
1344
1345void Internals::setForceUpdateImageDataEnabledForTesting(HTMLImageElement& element, bool enabled)
1346{
1347 if (auto* cachedImage = element.cachedImage())
1348 cachedImage->setForceUpdateImageDataEnabledForTesting(enabled);
1349}
1350
1351void Internals::setHasHDRContentForTesting(HTMLImageElement& element)
1352{
1353 if (auto* bitmapImage = bitmapImageFromImageElement(element))
1354 bitmapImage->setHasHDRContentForTesting();
1355}
1356
1357#if ENABLE(WEB_CODECS)(defined 1 && 1)
1358bool Internals::hasPendingActivity(const WebCodecsVideoDecoder& decoder) const
1359{
1360 return decoder.hasPendingActivity();
1361}
1362#endif
1363
1364void Internals::setGridMaxTracksLimit(unsigned maxTrackLimit)
1365{
1366 Style::GridPosition::setMaxPositionForTesting(maxTrackLimit);
1367}
1368
1369void Internals::clearBackForwardCache()
1370{
1371 BackForwardCache::singleton().pruneToSizeNow(0, PruningReason::None);
1372}
1373
1374unsigned Internals::backForwardCacheSize() const
1375{
1376 return BackForwardCache::singleton().pageCount();
1377}
1378
1379void Internals::preventDocumentFromEnteringBackForwardCache()
1380{
1381 if (auto* document = contextDocument())
1382 document->preventEnteringBackForwardCacheForTesting();
1383}
1384
1385void Internals::disableTileSizeUpdateDelay()
1386{
1387 Document* document = contextDocument();
1388 if (!document || !document->frame())
1389 return;
1390
1391 auto* view = document->frame()->view();
1392 if (!view)
1393 return;
1394
1395 if (auto* backing = view->tiledBacking())
1396 backing->setTileSizeUpdateDelayDisabledForTesting(true);
1397}
1398
1399void Internals::setSpeculativeTilingDelayDisabledForTesting(bool disabled)
1400{
1401 Document* document = contextDocument();
1402 if (!document || !document->frame())
1403 return;
1404
1405 if (auto* frameView = document->frame()->view())
1406 frameView->setSpeculativeTilingDelayDisabledForTesting(disabled);
1407}
1408
1409Node& Internals::treeScopeRootNode(Node& node)
1410{
1411 return node.treeScope().rootNode();
1412}
1413
1414Node* Internals::parentTreeScope(Node& node)
1415{
1416 const TreeScope* parentTreeScope = node.treeScope().parentTreeScope();
1417 return parentTreeScope ? &parentTreeScope->rootNode() : nullptr;
1418}
1419
1420ExceptionOr<unsigned> Internals::lastSpatialNavigationCandidateCount() const
1421{
1422 if (!contextDocument() || !contextDocument()->page())
1423 return Exception { ExceptionCode::InvalidAccessError };
1424
1425 return contextDocument()->page()->lastSpatialNavigationCandidateCount();
1426}
1427
1428bool Internals::animationWithIdExists(const String& id) const
1429{
1430 for (auto& animation : WebAnimation::instances()) {
1431 if (animation->id() == id)
1432 return true;
1433 }
1434 return false;
1435}
1436
1437unsigned Internals::numberOfActiveAnimations() const
1438{
1439 RefPtr localFrame = frame();
1440 return localFrame ? localFrame->document()->timeline().numberOfActiveAnimationsForTesting() : 0;
1441}
1442
1443ExceptionOr<bool> Internals::animationsAreSuspended() const
1444{
1445 Document* document = contextDocument();
1446 if (!document || !document->frame())
1447 return Exception { ExceptionCode::InvalidAccessError };
1448
1449 return document->ensureTimelinesController().animationsAreSuspended();
1450}
1451
1452double Internals::animationsInterval() const
1453{
1454 Document* document = contextDocument();
1455 if (!document)
1456 return INFINITY__builtin_huge_valf();
1457
1458 if (auto timeline = document->existingTimeline())
1459 return timeline->animationInterval().seconds();
1460 return INFINITY__builtin_huge_valf();
1461}
1462
1463ExceptionOr<void> Internals::suspendAnimations() const
1464{
1465 Document* document = contextDocument();
1466 if (!document || !document->frame())
1467 return Exception { ExceptionCode::InvalidAccessError };
1468
1469 document->ensureTimelinesController().suspendAnimations();
1470 for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
1471 auto* localFrame = dynamicDowncast<LocalFrame>(frame);
1472 if (!localFrame)
1473 continue;
1474 if (auto* document = localFrame->document())
1475 document->ensureTimelinesController().suspendAnimations();
1476 }
1477
1478 return { };
1479}
1480
1481ExceptionOr<void> Internals::resumeAnimations() const
1482{
1483 Document* document = contextDocument();
1484 if (!document || !document->frame())
1485 return Exception { ExceptionCode::InvalidAccessError };
1486
1487 document->ensureTimelinesController().resumeAnimations();
1488 for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
1489 auto* localFrame = dynamicDowncast<LocalFrame>(frame);
1490 if (!localFrame)
1491 continue;
1492 if (auto* document = localFrame->document())
1493 document->ensureTimelinesController().resumeAnimations();
1494 }
1495
1496 return { };
1497}
1498
1499uint64_t Internals::identifierForTimeline(AnimationTimeline& timeline) const
1500{
1501#if ENABLE(THREADED_ANIMATIONS)(defined 1 && 1)
1502 return timeline.acceleratedTimelineIdentifier().toRawValue();
1503#else
1504 UNUSED_PARAM(timeline)(void)timeline;
1505 return 0;
1506#endif
1507}
1508
1509Internals::ScrollingNodeID Internals::scrollingNodeIDForTimeline(AnimationTimeline& timeline) const
1510{
1511#if ENABLE(THREADED_ANIMATIONS)(defined 1 && 1)
1512 if (RefPtr scrollTimeline = dynamicDowncast<ScrollTimeline>(timeline)) {
1513 if (auto scrollingNodeID = scrollTimeline->scrollingNodeIDForTesting())
1514 return { scrollingNodeID->object().toUInt64(), scrollingNodeID->processIdentifier().toUInt64() };
1515 }
1516#else
1517 UNUSED_PARAM(timeline)(void)timeline;
1518#endif
1519 return { 0, 0 };
1520}
1521
1522Vector<Internals::AcceleratedAnimation> Internals::acceleratedAnimationsForElement(Element& element)
1523{
1524 CheckedPtr timelinesController = element.document().timelinesController();
1525 if (!timelinesController)
1526 return { };
1527
1528 Vector<Internals::AcceleratedAnimation> animations;
1529 for (const auto& acceleratedAnimation : timelinesController->acceleratedAnimationsForElement(element))
1530 animations.append({ acceleratedAnimation.property, acceleratedAnimation.speed, acceleratedAnimation.isThreaded, acceleratedAnimation.hasHighImpact });
1531 return animations;
1532}
1533
1534unsigned Internals::numberOfAnimationTimelineInvalidations() const
1535{
1536 RefPtr localFrame = frame();
1537 return localFrame ? localFrame->document()->timeline().numberOfAnimationTimelineInvalidationsForTesting() : 0;
1538}
1539
1540double Internals::timeToNextAnimationTick(WebAnimation& animation) const
1541{
1542 return secondsToWebAnimationsAPITime(animation.timeToNextTick());
1543}
1544
1545ExceptionOr<RefPtr<Element>> Internals::pseudoElement(Element& element, const String& pseudoId)
1546{
1547 if (pseudoId != "before"_s && pseudoId != "after"_s)
1548 return Exception { ExceptionCode::InvalidAccessError };
1549
1550 return pseudoId == "before"_s ? element.beforePseudoElement() : element.afterPseudoElement();
1551}
1552
1553double Internals::preferredRenderingUpdateInterval()
1554{
1555 auto* document = contextDocument();
1556 if (!document)
1557 return 0;
1558 auto* page = document->page();
1559 if (!page)
1560 return 0;
1561 return page->preferredRenderingUpdateInterval().milliseconds();
1562}
1563
1564ExceptionOr<String> Internals::elementRenderTreeAsText(Element& element)
1565{
1566 element.document().updateStyleIfNeeded();
1567
1568 String representation = externalRepresentation(&element);
1569 if (representation.isEmpty())
1570 return Exception { ExceptionCode::InvalidAccessError };
1571
1572 return representation;
1573}
1574
1575bool Internals::hasPausedImageAnimations(Element& element)
1576{
1577 return element.renderer() && element.renderer()->hasPausedImageAnimations();
1578}
1579
1580bool Internals::effectiveLangKnownToMatchDocumentElement(Element& element)
1581{
1582 return element.effectiveLangKnownToMatchDocumentElement();
1583}
1584
1585bool Internals::isFullyActive(Document& document)
1586{
1587 return document.isFullyActive();
1588}
1589
1590
1591bool Internals::isPaintingFrequently(Element& element)
1592{
1593 return element.renderer() && element.renderer()->enclosingLayer() && element.renderer()->enclosingLayer()->paintingFrequently();
1594}
1595
1596void Internals::incrementFrequentPaintCounter(Element& element)
1597{
1598 if (element.renderer() && element.renderer()->enclosingLayer())
1599 element.renderer()->enclosingLayer()->simulateFrequentPaint();
1600}
1601
1602void Internals::purgeFrontBuffer(Element& element)
1603{
1604 if (element.renderer()) {
1605 if (CheckedPtr layer = element.renderer()->enclosingLayer())
1606 layer->purgeFrontBufferForTesting();
1607 }
1608}
1609
1610void Internals::purgeBackBuffer(Element& element)
1611{
1612 if (element.renderer()) {
1613 if (CheckedPtr layer = element.renderer()->enclosingLayer())
1614 layer->purgeBackBufferForTesting();
1615 }
1616}
1617
1618void Internals::markFrontBufferVolatile(Element& element)
1619{
1620 if (element.renderer()) {
1621 if (CheckedPtr layer = element.renderer()->enclosingLayer())
1622 layer->markFrontBufferVolatileForTesting();
1623 }
1624}
1625
1626Ref<CSSComputedStyleDeclaration> Internals::computedStyleIncludingVisitedInfo(Element& element) const
1627{
1628 return CSSComputedStyleDeclaration::create(element, CSSComputedStyleDeclaration::AllowVisited::Yes);
1629}
1630
1631Node& Internals::ensureUserAgentShadowRoot(Element& host)
1632{
1633 return host.ensureUserAgentShadowRoot();
1634}
1635
1636Node* Internals::shadowRoot(Element& host)
1637{
1638 if (host.document().hasElementWithPendingUserAgentShadowTreeUpdate(host)) {
1639 host.updateUserAgentShadowTree();
1640 host.document().removeElementWithPendingUserAgentShadowTreeUpdate(host);
1641 }
1642 return host.shadowRoot();
1643}
1644
1645ExceptionOr<String> Internals::shadowRootType(const Node& root) const
1646{
1647 auto* shadowRoot = dynamicDowncast<ShadowRoot>(root);
1648 if (!shadowRoot)
1649 return Exception { ExceptionCode::InvalidAccessError };
1650
1651 switch (shadowRoot->mode()) {
1652 case ShadowRootMode::UserAgent:
1653 return "UserAgentShadowRoot"_str;
1654 case ShadowRootMode::Closed:
1655 return "ClosedShadowRoot"_str;
1656 case ShadowRootMode::Open:
1657 return "OpenShadowRoot"_str;
1658 default:
1659 ASSERT_NOT_REACHED()((void)0);
1660 return "Unknown"_str;
1661 }
1662}
1663
1664const AtomString& Internals::userAgentPart(Element& element)
1665{
1666 return element.userAgentPart();
1667}
1668
1669void Internals::setUserAgentPart(Element& element, const AtomString& part)
1670{
1671 return element.setUserAgentPart(part);
1672}
1673
1674ExceptionOr<bool> Internals::isTimerThrottled(int timeoutId)
1675{
1676 auto* timer = scriptExecutionContext()->findTimeout(timeoutId);
1677 if (!timer)
1678 return Exception { ExceptionCode::NotFoundError };
1679
1680 if (timer->intervalClampedToMinimum() > timer->m_originalInterval)
1681 return true;
1682
1683 constexpr MonotonicTime unalignedFireTime { };
1684 constexpr MonotonicTime alignmentForMaximallyNestedTimerToBeConsideredUnthrottled = unalignedFireTime + 2.0 * DOMTimer::minimumAlignmentForMaximallyNestedTimers();
1685 constexpr MonotonicTime alignmentForLowNestingTimerToBeConsideredUnthrottled = unalignedFireTime + 2.0 * DOMTimer::defaultAlignmentInterval();
1686
1687 MonotonicTime alignedFireTime = scriptExecutionContext()->alignedFireTime(timer->hasReachedMaxNestingLevel(), unalignedFireTime);
1688 if (timer->hasReachedMaxNestingLevel())
1689 return alignedFireTime > alignmentForMaximallyNestedTimerToBeConsideredUnthrottled;
1690 return alignedFireTime > alignmentForLowNestingTimerToBeConsideredUnthrottled;
1691}
1692
1693ExceptionOr<bool> Internals::isTimerAligned(int timeoutId)
1694{
1695 auto* timer = scriptExecutionContext()->findTimeout(timeoutId);
1696 if (!timer)
1697 return Exception { ExceptionCode::NotFoundError };
1698
1699 constexpr MonotonicTime unalignedFireTime { };
1700 MonotonicTime alignedFireTime = scriptExecutionContext()->alignedFireTime(timer->hasReachedMaxNestingLevel(), unalignedFireTime);
1701 return alignedFireTime != unalignedFireTime;
1702}
1703
1704String Internals::requestAnimationFrameThrottlingReasons() const
1705{
1706 auto* scriptedAnimationController = contextDocument()->scriptedAnimationController();
1707 if (!scriptedAnimationController)
1708 return String();
1709
1710 TextStream ts;
1711 ts << scriptedAnimationController->throttlingReasons();
1712 return ts.release();
1713}
1714
1715double Internals::requestAnimationFrameInterval() const
1716{
1717 auto* scriptedAnimationController = contextDocument()->scriptedAnimationController();
1718 if (!scriptedAnimationController)
1719 return INFINITY__builtin_huge_valf();
1720 return scriptedAnimationController->interval().value();
1721}
1722
1723bool Internals::scriptedAnimationsAreSuspended() const
1724{
1725 Document* document = contextDocument();
1726 if (!document || !document->page())
1727 return true;
1728
1729 return document->page()->scriptedAnimationsSuspended();
1730}
1731
1732bool Internals::areTimersThrottled() const
1733{
1734 return contextDocument()->isTimerThrottlingEnabled();
1735}
1736
1737void Internals::setEventThrottlingBehaviorOverride(std::optional<EventThrottlingBehavior> value)
1738{
1739 Document* document = contextDocument();
1740 if (!document || !document->page())
1741 return;
1742
1743 if (!value) {
1744 document->page()->setEventThrottlingBehaviorOverride(std::nullopt);
1745 return;
1746 }
1747
1748 switch (value.value()) {
1749 case Internals::EventThrottlingBehavior::Responsive:
1750 document->page()->setEventThrottlingBehaviorOverride(WebCore::EventThrottlingBehavior::Responsive);
1751 break;
1752 case Internals::EventThrottlingBehavior::Unresponsive:
1753 document->page()->setEventThrottlingBehaviorOverride(WebCore::EventThrottlingBehavior::Unresponsive);
1754 break;
1755 }
1756}
1757
1758std::optional<Internals::EventThrottlingBehavior> Internals::eventThrottlingBehaviorOverride() const
1759{
1760 Document* document = contextDocument();
1761 if (!document || !document->page())
1762 return std::nullopt;
1763
1764 auto behavior = document->page()->eventThrottlingBehaviorOverride();
1765 if (!behavior)
1766 return std::nullopt;
1767
1768 switch (behavior.value()) {
1769 case WebCore::EventThrottlingBehavior::Responsive:
1770 return Internals::EventThrottlingBehavior::Responsive;
1771 case WebCore::EventThrottlingBehavior::Unresponsive:
1772 return Internals::EventThrottlingBehavior::Unresponsive;
1773 }
1774
1775 return std::nullopt;
1776}
1777
1778String Internals::visiblePlaceholder(Element& element)
1779{
1780 element.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
1781
1782 if (auto* textFormControlElement = dynamicDowncast<HTMLTextFormControlElement>(element)) {
1783 if (!textFormControlElement->isPlaceholderVisible())
1784 return String();
1785 if (auto* placeholderElement = textFormControlElement->placeholderElement())
1786 return placeholderElement->textContent();
1787 }
1788
1789 return String();
1790}
1791
1792String Internals::anchorPrefetchEagerness(Element& element)
1793{
1794 if (auto* anchor = dynamicDowncast<HTMLAnchorElement>(element))
1795 return anchor->prefetchEagernessForTesting();
1796 return String();
1797}
1798
1799void Internals::setCanShowPlaceholder(Element& element, bool canShowPlaceholder)
1800{
1801 if (auto* textFormControlElement = dynamicDowncast<HTMLTextFormControlElement>(element))
1802 textFormControlElement->setCanShowPlaceholder(canShowPlaceholder);
1803}
1804
1805RefPtr<Element> Internals::insertTextPlaceholder(int width, int height)
1806{
1807 RefPtr localFrame = frame();
1808 return localFrame ? localFrame->editor().insertTextPlaceholder(IntSize { width, height }) : nullptr;
1809}
1810
1811void Internals::removeTextPlaceholder(Element& element)
1812{
1813 if (auto* placeholderElement = dynamicDowncast<TextPlaceholderElement>(element))
1814 frame()->editor().removeTextPlaceholder(*placeholderElement);
1815}
1816
1817void Internals::selectColorInColorChooser(HTMLInputElement& element, const String& colorValue)
1818{
1819 element.selectColor(colorValue);
1820}
1821
1822ExceptionOr<Vector<AtomString>> Internals::formControlStateOfPreviousHistoryItem()
1823{
1824 RefPtr mainItem = frame() ? frame()->loader().history().previousItem() : nullptr;
1825 if (!mainItem)
1826 return Exception { ExceptionCode::InvalidAccessError };
1827 auto frameID = frame()->frameID();
1828 if (mainItem->frameID() != frameID && !mainItem->childItemWithFrameID(frameID))
1829 return Exception { ExceptionCode::InvalidAccessError };
1830 return Vector<AtomString> { mainItem->frameID() == frameID ? mainItem->documentState() : mainItem->childItemWithFrameID(frameID)->documentState() };
1831}
1832
1833ExceptionOr<void> Internals::setFormControlStateOfPreviousHistoryItem(const Vector<AtomString>& state)
1834{
1835 RefPtr mainItem = frame() ? frame()->loader().history().previousItem() : nullptr;
1836 if (!mainItem)
1837 return Exception { ExceptionCode::InvalidAccessError };
1838 auto frameID = frame()->frameID();
1839 if (mainItem->frameID() == frameID)
1840 mainItem->setDocumentState(state);
1841 else if (HistoryItem* subItem = mainItem->childItemWithFrameID(frameID))
1842 subItem->setDocumentState(state);
1843 else
1844 return Exception { ExceptionCode::InvalidAccessError };
1845 return { };
1846}
1847
1848#if ENABLE(SPEECH_SYNTHESIS)(defined 1 && 1)
1849void Internals::simulateSpeechSynthesizerVoiceListChange()
1850{
1851 if (m_platformSpeechSynthesizer) {
1852 m_platformSpeechSynthesizer->setInitialVoiceListToEmpty(false);
1853 m_platformSpeechSynthesizer->initializeVoiceList();
1854 m_platformSpeechSynthesizer->client().voicesDidChange();
1855 return;
1856 }
1857
1858 RefPtr document = contextDocument();
1859 if (!document || !document->window())
1860 return;
1861
1862 if (RefPtr synthesis = LocalDOMWindowSpeechSynthesis::speechSynthesis(*document->window()))
1863 synthesis->simulateVoicesListChange();
1864}
1865
1866void Internals::enableMockSpeechSynthesizer()
1867{
1868 auto document = contextDocument();
1869 if (!document || !document->window())
1870 return;
1871 auto synthesis = LocalDOMWindowSpeechSynthesis::speechSynthesis(*document->window());
1872 if (!synthesis)
1873 return;
1874
1875 Ref mock = PlatformSpeechSynthesizerMock::create(*synthesis);
1876 m_platformSpeechSynthesizer = mock.copyRef();
1877 synthesis->setPlatformSynthesizer(WTF::move(mock));
1878}
1879
1880void Internals::enableMockSpeechSynthesizerForMediaElement(HTMLMediaElement& element)
1881{
1882 auto& synthesis = element.speechSynthesis();
1883 Ref mock = PlatformSpeechSynthesizerMock::create(synthesis);
1884
1885 m_platformSpeechSynthesizer = mock.copyRef();
1886 synthesis.setPlatformSynthesizer(WTF::move(mock));
1887}
1888
1889void Internals::setInitialVoiceListToEmpty()
1890{
1891 if (m_platformSpeechSynthesizer)
1892 m_platformSpeechSynthesizer->setInitialVoiceListToEmpty(true);
1893}
1894
1895ExceptionOr<void> Internals::setSpeechUtteranceDuration(double duration)
1896{
1897 if (!m_platformSpeechSynthesizer)
1898 return Exception { ExceptionCode::InvalidAccessError };
1899
1900 m_platformSpeechSynthesizer->setUtteranceDuration(Seconds(duration));
1901 return { };
1902}
1903
1904unsigned Internals::minimumExpectedVoiceCount()
1905{
1906 // https://webkit.org/b/250656
1907#if PLATFORM(MAC)(defined WTF_PLATFORM_MAC && WTF_PLATFORM_MAC)
1908 return 21;
1909#elif USE(GLIB)(defined USE_GLIB && USE_GLIB)
1910 return 4;
1911#else
1912 return 1;
1913#endif
1914}
1915
1916#endif
1917
1918#if ENABLE(WEB_RTC)(defined 1 && 1)
1919
1920void Internals::useMockRTCPeerConnectionFactory(const String& testCase)
1921{
1922 if (!WebRTCProvider::webRTCAvailable())
1923 return;
1924
1925#if USE(LIBWEBRTC)(defined 1 && 1)
1926 Document* document = contextDocument();
1927 auto* provider = (document && document->page()) ? &downcast<LibWebRTCProvider>(document->page()->webRTCProvider()) : nullptr;
1928 WebCore::useMockRTCPeerConnectionFactory(provider, testCase);
1929#else
1930 UNUSED_PARAM(testCase)(void)testCase;
1931#endif
1932}
1933
1934void Internals::setICECandidateFiltering(bool enabled)
1935{
1936 auto* page = contextDocument()->page();
1937 if (!page)
1938 return;
1939
1940 auto& rtcController = page->rtcController();
1941 if (enabled)
1942 rtcController.enableICECandidateFiltering();
1943 else
1944 rtcController.disableICECandidateFilteringForAllOrigins();
1945}
1946
1947void Internals::setEnumeratingAllNetworkInterfacesEnabled(bool enabled)
1948{
1949#if USE(LIBWEBRTC)(defined 1 && 1)
1950 Document* document = contextDocument();
1951 auto* page = document->page();
1952 if (!page)
1953 return;
1954 auto& rtcProvider = downcast<LibWebRTCProvider>(page->webRTCProvider());
1955 if (enabled)
1956 rtcProvider.enableEnumeratingAllNetworkInterfaces();
1957 else
1958 rtcProvider.disableEnumeratingAllNetworkInterfaces();
1959#else
1960 UNUSED_PARAM(enabled)(void)enabled;
1961#endif
1962}
1963
1964void Internals::stopPeerConnection(RTCPeerConnection& connection)
1965{
1966 ActiveDOMObject& object = connection;
1967 object.stop();
1968}
1969
1970void Internals::clearPeerConnectionFactory()
1971{
1972 if (auto* page = contextDocument()->page())
1973 page->webRTCProvider().clearFactory();
1974}
1975
1976void Internals::clearWebRTCCodecsConnection()
1977{
1978#if USE(LIBWEBRTC)(defined 1 && 1)
1979 if (auto* page = contextDocument()->page()) {
1980 auto& rtcProvider = downcast<LibWebRTCProvider>(page->webRTCProvider());
1981 rtcProvider.clearCodecsConnectionForTesting();
1982 }
1983#endif
1984}
1985
1986void Internals::applyRotationForOutgoingVideoSources(RTCPeerConnection& connection)
1987{
1988 connection.applyRotationForOutgoingVideoSources();
1989}
1990
1991void Internals::setWebRTCH265Support(bool value)
1992{
1993 if (auto* page = contextDocument()->page()) {
1994 page->webRTCProvider().setH265Support(value);
1995 page->webRTCProvider().clearFactory();
1996 }
1997}
1998
1999void Internals::setWebRTCVP9Support(bool supportVP9Profile0, bool supportVP9Profile2)
2000{
2001 if (auto* page = contextDocument()->page()) {
2002 page->webRTCProvider().setVP9Support(supportVP9Profile0, supportVP9Profile2);
2003 page->webRTCProvider().clearFactory();
2004 }
2005}
2006
2007void Internals::disableWebRTCHardwareVP9()
2008{
2009#if USE(LIBWEBRTC)(defined 1 && 1)
2010 if (auto* page = contextDocument()->page()) {
2011 auto& rtcProvider = downcast<LibWebRTCProvider>(page->webRTCProvider());
2012 rtcProvider.setVP9HardwareSupportForTesting(false);
2013 rtcProvider.clearFactory();
2014 }
2015#endif
2016}
2017
2018bool Internals::isSupportingVP9HardwareDecoder() const
2019{
2020#if USE(LIBWEBRTC)(defined 1 && 1)
2021 if (auto* page = contextDocument()->page()) {
2022 auto& rtcProvider = downcast<LibWebRTCProvider>(page->webRTCProvider());
2023 return rtcProvider.isSupportingVP9HardwareDecoder();
2024 }
2025#endif
2026 return false;
2027}
2028
2029void Internals::isVP9HardwareDecoderUsed(RTCPeerConnection& connection, DOMPromiseDeferred<IDLBoolean>&& promise)
2030{
2031 connection.gatherDecoderImplementationName([promise = WTF::move(promise)](auto&& name) mutable {
2032 promise.resolve(!name.contains("fallback from:"_s) && !name.contains("libvpx"_s));
2033 });
2034}
2035
2036void Internals::setSFrameCounter(RTCRtpSFrameTransform& transform, const String& counter)
2037{
2038 if (auto value = parseInteger<uint64_t>(counter))
2039 transform.setCounterForTesting(*value);
2040}
2041
2042uint64_t Internals::sframeCounter(const RTCRtpSFrameTransform& transform)
2043{
2044 return transform.counterForTesting();
2045}
2046
2047uint64_t Internals::sframeKeyId(const RTCRtpSFrameTransform& transform)
2048{
2049 return transform.keyIdForTesting();
2050}
2051
2052void Internals::setEnableWebRTCEncryption(bool value)
2053{
2054#if USE(LIBWEBRTC)(defined 1 && 1)
2055 if (auto* page = contextDocument()->page())
2056 page->settings().setWebRTCEncryptionEnabled(value);
2057#else
2058 UNUSED_PARAM(value)(void)value;
2059#endif
2060}
2061
2062bool Internals::hasPeerConnectionEnabledServiceClass(const RTCPeerConnection& connection)
2063{
2064 return protect(connection.backend())->shouldEnableServiceClass();
2065}
2066#endif // ENABLE(WEB_RTC)
2067
2068#if ENABLE(MEDIA_STREAM)(defined 1 && 1)
2069void Internals::setShouldInterruptAudioOnPageVisibilityChange(bool shouldInterrupt)
2070{
2071 Document* document = contextDocument();
2072 if (auto* page = document->page())
2073 page->settings().setInterruptAudioOnPageVisibilityChangeEnabled(shouldInterrupt);
2074}
2075#endif // ENABLE(MEDIA_STREAM)
2076
2077#if ENABLE(MEDIA_RECORDER)(defined 1 && 1)
2078static ExceptionOr<std::unique_ptr<MediaRecorderPrivate>> createRecorderMockSource(MediaStreamPrivate& stream, const MediaRecorderPrivateOptions&)
2079{
2080 return std::unique_ptr<MediaRecorderPrivate>(new MediaRecorderPrivateMock(stream));
2081}
2082
2083void Internals::setCustomPrivateRecorderCreator()
2084{
2085 WebCore::MediaRecorder::setCustomPrivateRecorderCreator(createRecorderMockSource);
2086}
2087#endif // ENABLE(MEDIA_RECORDER)
2088
2089ExceptionOr<Ref<DOMRect>> Internals::absoluteLineRectFromPoint(int x, int y)
2090{
2091 if (!contextDocument() || !contextDocument()->page())
2092 return Exception { ExceptionCode::InvalidAccessError };
2093
2094 auto& document = *contextDocument();
2095 if (!document.frame() || !document.view())
2096 return Exception { ExceptionCode::InvalidAccessError };
2097
2098 auto& frame = *document.frame();
2099 auto& view = *document.view();
2100 document.updateLayout(LayoutOptions::IgnorePendingStylesheets);
2101
2102 auto position = frame.visiblePositionForPoint(view.rootViewToContents(IntPoint { x, y }));
2103 return DOMRect::create(position.absoluteSelectionBoundsForLine());
2104}
2105
2106ExceptionOr<Ref<DOMRect>> Internals::absoluteCaretBounds()
2107{
2108 Document* document = contextDocument();
2109 if (!document || !document->frame())
2110 return Exception { ExceptionCode::InvalidAccessError };
2111
2112 return DOMRect::create(document->frame()->selection().absoluteCaretBounds());
2113}
2114
2115ExceptionOr<bool> Internals::isCaretVisible()
2116{
2117 RefPtr document = contextDocument();
2118 if (!document || !document->frame())
2119 return Exception { ExceptionCode::InvalidAccessError };
2120
2121 return document->frame()->selection().isCaretVisible();
2122}
2123
2124ExceptionOr<bool> Internals::isCaretBlinkingSuspended()
2125{
2126 auto* document = contextDocument();
2127 if (!document)
2128 return Exception { ExceptionCode::InvalidAccessError };
2129
2130 return isCaretBlinkingSuspended(*document);
2131}
2132
2133ExceptionOr<bool> Internals::isCaretBlinkingSuspended(Document& document)
2134{
2135 if (!document.frame())
2136 return Exception { ExceptionCode::InvalidAccessError };
2137
2138 return document.frame()->selection().isCaretBlinkingSuspended();
2139}
2140
2141Ref<DOMRect> Internals::boundingBox(Element& element)
2142{
2143 element.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
2144 auto renderer = element.renderer();
2145 if (!renderer)
2146 return DOMRect::create();
2147 return DOMRect::create(renderer->absoluteBoundingBoxRectIgnoringTransforms());
2148}
2149
2150ExceptionOr<unsigned> Internals::inspectorGridOverlayCount()
2151{
2152 Document* document = contextDocument();
2153 if (!document || !document->page())
2154 return Exception { ExceptionCode::InvalidAccessError };
2155
2156 return document->page()->inspectorController().gridOverlayCount();
2157}
2158
2159ExceptionOr<unsigned> Internals::inspectorFlexOverlayCount()
2160{
2161 Document* document = contextDocument();
2162 if (!document || !document->page())
2163 return Exception { ExceptionCode::InvalidAccessError };
2164
2165 return document->page()->inspectorController().flexOverlayCount();
2166}
2167
2168ExceptionOr<Ref<DOMRectList>> Internals::inspectorHighlightRects()
2169{
2170 Document* document = contextDocument();
2171 if (!document || !document->page())
2172 return Exception { ExceptionCode::InvalidAccessError };
2173
2174 InspectorOverlay::Highlight highlight;
2175 document->page()->inspectorController().getHighlight(highlight, InspectorOverlay::CoordinateSystem::View);
2176 return DOMRectList::create(highlight.quads);
2177}
2178
2179ExceptionOr<unsigned> Internals::inspectorPaintRectCount()
2180{
2181 auto document = contextDocument();
2182 if (!document || !document->page())
2183 return Exception { ExceptionCode::InvalidAccessError };
2184
2185 return document->page()->inspectorController().paintRectCount();
2186}
2187
2188ExceptionOr<unsigned> Internals::markerCountForNode(Node& node, const String& markerType)
2189{
2190 OptionSet<DocumentMarkerType> markerTypes;
2191 if (!markerTypesFrom(markerType, markerTypes))
2192 return Exception { ExceptionCode::SyntaxError };
2193
2194 node.document().editor().updateEditorUINowIfScheduled();
2195 return node.document().markers().markersFor(node, markerTypes).size();
2196}
2197
2198ExceptionOr<RenderedDocumentMarker*> Internals::markerAt(Node& node, const String& markerType, unsigned index)
2199{
2200 node.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
2201
2202 OptionSet<DocumentMarkerType> markerTypes;
2203 if (!markerTypesFrom(markerType, markerTypes))
2204 return Exception { ExceptionCode::SyntaxError };
2205
2206 node.document().editor().updateEditorUINowIfScheduled();
2207
2208 auto markers = node.document().markers().markersFor(node, markerTypes);
2209 if (markers.size() <= index)
2210 return nullptr;
2211 return markers[index].get();
2212}
2213
2214ExceptionOr<RefPtr<Range>> Internals::markerRangeForNode(Node& node, const String& markerType, unsigned index)
2215{
2216 auto result = markerAt(node, markerType, index);
2217 if (result.hasException())
2218 return result.releaseException();
2219 auto marker = result.releaseReturnValue();
2220 if (!marker)
2221 return nullptr;
2222 return { createLiveRange(makeSimpleRange(node, *marker)) };
2223}
2224
2225ExceptionOr<String> Internals::markerDescriptionForNode(Node& node, const String& markerType, unsigned index)
2226{
2227 auto result = markerAt(node, markerType, index);
2228 if (result.hasException())
2229 return result.releaseException();
2230 auto marker = result.releaseReturnValue();
2231 if (!marker)
2232 return String();
2233 return String { marker->description() };
2234}
2235
2236ExceptionOr<String> Internals::dumpMarkerRects(const String& markerTypeString)
2237{
2238 DocumentMarkerType markerType;
2239 if (!markerTypeFrom(markerTypeString, markerType))
2240 return Exception { ExceptionCode::SyntaxError };
2241
2242 contextDocument()->markers().updateRectsForInvalidatedMarkersOfType(markerType);
2243 auto rects = contextDocument()->markers().renderedRectsForMarkers(markerType);
2244
2245 // FIXME: Using fixed precision here for width because of test results that contain numbers with specific precision. Would be nice to update the test results and move to default formatting.
2246 StringBuilder rectString;
2247 rectString.append("marker rects: "_s);
2248 for (const auto& rect : rects)
2249 rectString.append('(', rect.x(), ", "_s, rect.y(), ", "_s, FormattedNumber::fixedPrecision(rect.width()), ", "_s, rect.height(), ") "_s);
2250 return String { rectString.toString() };
2251}
2252
2253ExceptionOr<void> Internals::setMarkedTextMatchesAreHighlighted(bool flag)
2254{
2255 Document* document = contextDocument();
2256 if (!document || !document->frame())
2257 return Exception { ExceptionCode::InvalidAccessError };
2258 document->editor().setMarkedTextMatchesAreHighlighted(flag);
2259 return { };
2260}
2261
2262ExceptionOr<RefPtr<ImageData>> Internals::snapshotNode(Node& node)
2263{
2264 RefPtr document = contextDocument();
2265 if (!document || !document->frame())
2266 return Exception { ExceptionCode::InvalidAccessError };
2267
2268 document->updateLayoutIgnorePendingStylesheets();
2269
2270 SnapshotOptions options { { SnapshotFlags::DraggableElement }, PixelFormat::BGRA8, DestinationColorSpace::SRGB() };
2271
2272 RefPtr imageBuffer = WebCore::snapshotNode(*document->frame(), node, WTF::move(options));
2273 if (!imageBuffer)
2274 return Exception { ExceptionCode::InvalidStateError, "Failed to create snapshot"_s };
2275
2276 auto size = imageBuffer->logicalSize();
2277 IntRect sourceRect(IntPoint(), imageBuffer->calculateBackendSize(size,
2278 document->frame()->page()->deviceScaleFactor()));
2279
2280 PixelBufferFormat destinationFormat {
2281 AlphaPremultiplication::Unpremultiplied,
2282 PixelFormat::RGBA8,
2283 DestinationColorSpace::SRGB()
2284 };
2285
2286 auto pixelBuffer = imageBuffer->getPixelBuffer(destinationFormat, sourceRect);
2287 if (!pixelBuffer)
2288 return Exception { ExceptionCode::InvalidStateError, "Failed to get pixel buffer"_s };
2289
2290 auto byteArrayPixelBuffer = dynamicDowncast<ByteArrayPixelBuffer>(pixelBuffer.get());
2291 if (!byteArrayPixelBuffer)
2292 return Exception { ExceptionCode::InvalidStateError, "Pixel buffer is not a ByteArrayPixelBuffer"_s };
2293
2294 RefPtr imageData = ImageData::create(WTF::move(byteArrayPixelBuffer));
2295 if (!imageData)
2296 return Exception { ExceptionCode::InvalidStateError, "Failed to create ImageData"_s };
2297
2298 return imageData;
2299}
2300
2301void Internals::invalidateFontCache()
2302{
2303 FontCache::invalidateAllFontCaches();
2304}
2305
2306ExceptionOr<void> Internals::setLowPowerModeEnabled(bool isEnabled)
2307{
2308 auto* document = contextDocument();
2309 if (!document)
2310 return Exception { ExceptionCode::InvalidAccessError };
2311 auto* page = document->page();
2312 if (!page)
2313 return Exception { ExceptionCode::InvalidAccessError };
2314
2315 page->setLowPowerModeEnabledOverrideForTesting(isEnabled);
2316 return { };
2317}
2318
2319ExceptionOr<void> Internals::setAggressiveThermalMitigationEnabled(bool isEnabled)
2320{
2321 auto* document = contextDocument();
2322 if (!document)
2323 return Exception { ExceptionCode::InvalidAccessError };
2324 auto* page = document->page();
2325 if (!page)
2326 return Exception { ExceptionCode::InvalidAccessError };
2327
2328 page->setAggressiveThermalMitigationEnabledForTesting(isEnabled);
2329 return { };
2330}
2331
2332ExceptionOr<void> Internals::setOutsideViewportThrottlingEnabled(bool isEnabled)
2333{
2334 auto* document = contextDocument();
2335 if (!document)
2336 return Exception { ExceptionCode::InvalidAccessError };
2337 auto* page = document->page();
2338 if (!page)
2339 return Exception { ExceptionCode::InvalidAccessError };
2340
2341 page->setOutsideViewportThrottlingEnabledForTesting(isEnabled);
2342 return { };
2343}
2344
2345ExceptionOr<void> Internals::setScrollViewPosition(int x, int y)
2346{
2347 Document* document = contextDocument();
2348 if (!document || !document->view())
2349 return Exception { ExceptionCode::InvalidAccessError };
2350
2351 auto& frameView = *document->view();
2352 auto oldClamping = frameView.scrollClamping();
2353 bool scrollbarsSuppressedOldValue = frameView.scrollbarsSuppressed();
2354
2355 frameView.setScrollClamping(ScrollClamping::Unclamped);
2356 frameView.setScrollbarsSuppressed(false);
2357 frameView.setScrollOffsetFromInternals({ x, y });
2358 frameView.setScrollbarsSuppressed(scrollbarsSuppressedOldValue);
2359 frameView.setScrollClamping(oldClamping);
2360
2361 return { };
2362}
2363
2364ExceptionOr<void> Internals::unconstrainedScrollTo(Element& element, double x, double y)
2365{
2366 Document* document = contextDocument();
2367 if (!document || !document->view())
2368 return Exception { ExceptionCode::InvalidAccessError };
2369
2370 element.scrollTo(ScrollToOptions { { ScrollBehavior::Auto }, x, y }, ScrollClamping::Unclamped);
2371
2372 auto& frameView = *document->view();
2373 frameView.setViewportConstrainedObjectsNeedLayout();
2374
2375 return { };
2376}
2377
2378ExceptionOr<void> Internals::scrollBySimulatingWheelEvent(Element& element, double deltaX, double deltaY)
2379{
2380 Document* document = contextDocument();
2381 if (!document || !document->view())
2382 return Exception { ExceptionCode::InvalidAccessError };
2383
2384 if (!element.renderBox())
2385 return Exception { ExceptionCode::InvalidAccessError };
2386
2387 RenderBox& box = *element.renderBox();
2388 ScrollableArea* scrollableArea;
2389
2390 if (&element == document->scrollingElementForAPI()) {
2391
2392 auto* localFrame = dynamicDowncast<LocalFrame>(box.frame().mainFrame());
2393 if (!localFrame)
2394 return Exception { ExceptionCode::InvalidAccessError };
2395
2396 auto* frameView = localFrame->view();
2397 if (!frameView || !frameView->isScrollable())
2398 return Exception { ExceptionCode::InvalidAccessError };
2399
2400 scrollableArea = frameView;
2401 } else {
2402 if (!box.canBeScrolledAndHasScrollableArea())
2403 return Exception { ExceptionCode::InvalidAccessError };
2404
2405 ASSERT(box.layer())((void)0);
2406 scrollableArea = box.layer()->scrollableArea();
2407 }
2408
2409 if (!scrollableArea)
2410 return Exception { ExceptionCode::InvalidAccessError };
2411
2412 auto scrollingNodeID = scrollableArea->scrollingNodeID();
2413 if (!scrollingNodeID)
2414 return Exception { ExceptionCode::InvalidAccessError };
2415
2416 auto page = document->page();
2417 if (!page)
2418 return Exception { ExceptionCode::InvalidAccessError };
2419
2420 RefPtr scrollingCoordinator = page->scrollingCoordinator();
2421 if (!scrollingCoordinator)
2422 return Exception { ExceptionCode::InvalidAccessError };
2423
2424 scrollingCoordinator->scrollBySimulatingWheelEventForTesting(*scrollingNodeID, FloatSize(deltaX, deltaY));
2425
2426 return { };
2427}
2428
2429ExceptionOr<Ref<DOMRect>> Internals::layoutViewportRect()
2430{
2431 Document* document = contextDocument();
2432 if (!document || !document->frame())
2433 return Exception { ExceptionCode::InvalidAccessError };
2434
2435 document->updateLayout(LayoutOptions::IgnorePendingStylesheets);
2436
2437 auto& frameView = *document->view();
2438 return DOMRect::create(frameView.layoutViewportRect());
2439}
2440
2441ExceptionOr<Ref<DOMRect>> Internals::visualViewportRect()
2442{
2443 Document* document = contextDocument();
2444 if (!document || !document->frame())
2445 return Exception { ExceptionCode::InvalidAccessError };
2446
2447 document->updateLayout(LayoutOptions::IgnorePendingStylesheets);
2448
2449 auto& frameView = *document->view();
2450 return DOMRect::create(frameView.visualViewportRect());
2451}
2452
2453ExceptionOr<void> Internals::setViewIsTransparent(bool transparent)
2454{
2455 Document* document = contextDocument();
2456 if (!document || !document->view())
2457 return Exception { ExceptionCode::InvalidAccessError };
2458
2459 document->view()->setTransparent(transparent);
2460 return { };
2461}
2462
2463ExceptionOr<String> Internals::viewBaseBackgroundColor()
2464{
2465 Document* document = contextDocument();
2466 if (!document || !document->view())
2467 return Exception { ExceptionCode::InvalidAccessError };
2468
2469 document->updateLayout(LayoutOptions::IgnorePendingStylesheets);
2470
2471 return serializationForCSS(document->view()->baseBackgroundColor());
2472}
2473
2474ExceptionOr<void> Internals::setViewBaseBackgroundColor(const String& colorValue)
2475{
2476 Document* document = contextDocument();
2477 if (!document || !document->view())
2478 return Exception { ExceptionCode::InvalidAccessError };
2479
2480 if (colorValue == "transparent"_s) {
2481 document->view()->setBaseBackgroundColor(Color::transparentBlack);
2482 return { };
2483 }
2484 if (colorValue == "white"_s) {
2485 document->view()->setBaseBackgroundColor(Color::white);
2486 return { };
2487 }
2488 return Exception { ExceptionCode::SyntaxError };
2489}
2490
2491ExceptionOr<void> Internals::setUnderPageBackgroundColorOverride(const String& colorValue)
2492{
2493 Document* document = contextDocument();
2494 if (!document || !document->page())
2495 return Exception { ExceptionCode::InvalidAccessError };
2496
2497 auto cssParserContext = document->cssParserContext();
2498 auto color = CSSPropertyParserHelpers::parseColorRaw(colorValue, cssParserContext, *document);
2499 if (!color.isValid())
2500 return Exception { ExceptionCode::SyntaxError };
2501
2502 document->page()->setUnderPageBackgroundColorOverride(WTF::move(color));
2503 return { };
2504}
2505
2506ExceptionOr<String> Internals::documentBackgroundColor()
2507{
2508 Document* document = contextDocument();
2509 if (!document || !document->view())
2510 return Exception { ExceptionCode::InvalidAccessError };
2511 return serializationForCSS(document->view()->documentBackgroundColor());
2512}
2513
2514ExceptionOr<void> Internals::setPagination(const String& mode, int gap, int pageLength)
2515{
2516 Document* document = contextDocument();
2517 if (!document || !document->page())
2518 return Exception { ExceptionCode::InvalidAccessError };
2519
2520 Pagination pagination;
2521 if (mode == "Unpaginated"_s)
2522 pagination.mode = Pagination::Mode::Unpaginated;
2523 else if (mode == "LeftToRightPaginated"_s)
2524 pagination.mode = Pagination::Mode::LeftToRightPaginated;
2525 else if (mode == "RightToLeftPaginated"_s)
2526 pagination.mode = Pagination::Mode::RightToLeftPaginated;
2527 else if (mode == "TopToBottomPaginated"_s)
2528 pagination.mode = Pagination::Mode::TopToBottomPaginated;
2529 else if (mode == "BottomToTopPaginated"_s)
2530 pagination.mode = Pagination::Mode::BottomToTopPaginated;
2531 else
2532 return Exception { ExceptionCode::SyntaxError };
2533
2534 pagination.gap = gap;
2535 pagination.pageLength = pageLength;
2536 document->page()->setPagination(pagination);
2537
2538 return { };
2539}
2540
2541ExceptionOr<uint64_t> Internals::lineIndexAfterPageBreak(Element& element)
2542{
2543 Document* document = contextDocument();
2544 if (!document || !document->frame())
2545 return Exception { ExceptionCode::InvalidAccessError };
2546
2547 element.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
2548
2549 if (!element.renderer() || !is<RenderBlockFlow>(element.renderer()))
2550 return Exception { ExceptionCode::NotFoundError };
2551 auto& blockFlow = downcast<RenderBlockFlow>(*element.renderer());
2552 if (!blockFlow.childrenInline())
2553 return Exception { ExceptionCode::NotFoundError };
2554
2555 size_t lineIndex = 0;
2556 for (auto lineBox = InlineIterator::firstLineBoxFor(blockFlow); lineBox; lineBox.traverseNext(), ++lineIndex) {
2557 if (lineBox->isFirstAfterPageBreak())
2558 return lineIndex;
2559 }
2560 return Exception { ExceptionCode::NotFoundError };
2561}
2562
2563ExceptionOr<String> Internals::configurationForViewport(float devicePixelRatio, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight)
2564{
2565 Document* document = contextDocument();
2566 if (!document || !document->page())
2567 return Exception { ExceptionCode::InvalidAccessError };
2568
2569 const int defaultLayoutWidthForNonMobilePages = 980;
2570
2571 ViewportArguments arguments = document->page()->viewportArguments();
2572 ViewportAttributes attributes = computeViewportAttributes(arguments, defaultLayoutWidthForNonMobilePages, deviceWidth, deviceHeight, devicePixelRatio, IntSize(availableWidth, availableHeight));
2573 restrictMinimumScaleFactorToViewportSize(attributes, IntSize(availableWidth, availableHeight), devicePixelRatio);
2574 restrictScaleFactorToInitialScaleIfNotUserScalable(attributes);
2575
2576 // FIXME: Using fixed precision here because of test results that contain numbers with specific precision. Would be nice to update the test results and move to default formatting.
2577 return makeString("viewport size "_s, FormattedNumber::fixedPrecision(attributes.layoutSize.width()), 'x', FormattedNumber::fixedPrecision(attributes.layoutSize.height()), " scale "_s, FormattedNumber::fixedPrecision(attributes.initialScale), " with limits ["_s, FormattedNumber::fixedPrecision(attributes.minimumScale), ", "_s, FormattedNumber::fixedPrecision(attributes.maximumScale), "] and userScalable "_s, (attributes.userScalable ? "true"_s : "false"_s));
2578}
2579
2580ExceptionOr<bool> Internals::wasLastChangeUserEdit(Element& textField)
2581{
2582 if (auto* input = dynamicDowncast<HTMLInputElement>(textField))
2583 return input->lastChangeWasUserEdit();
2584
2585 if (auto* textArea = dynamicDowncast<HTMLTextAreaElement>(textField))
2586 return textArea->lastChangeWasUserEdit();
2587
2588 return Exception { ExceptionCode::InvalidNodeTypeError };
2589}
2590
2591bool Internals::elementShouldAutoComplete(HTMLInputElement& element)
2592{
2593 return element.shouldAutocomplete();
2594}
2595
2596void Internals::setAutofilled(HTMLInputElement& element, bool enabled)
2597{
2598 element.setAutofilled(enabled);
2599}
2600
2601void Internals::setAutofilledAndViewable(HTMLInputElement& element, bool enabled)
2602{
2603 element.setAutofilledAndViewable(enabled);
2604}
2605
2606void Internals::setAutofilledAndObscured(HTMLInputElement& element, bool enabled)
2607{
2608 element.setAutofilledAndObscured(enabled);
2609}
2610
2611static AutoFillButtonType NODELETE[[clang::annotate_type("webkit.nodelete")]] toAutofillButtonType(Internals::AutoFillButtonType type)
2612{
2613 switch (type) {
2614 case Internals::AutoFillButtonType::None:
2615 return AutoFillButtonType::None;
2616 case Internals::AutoFillButtonType::Credentials:
2617 return AutoFillButtonType::Credentials;
2618 case Internals::AutoFillButtonType::Contacts:
2619 return AutoFillButtonType::Contacts;
2620 case Internals::AutoFillButtonType::StrongPassword:
2621 return AutoFillButtonType::StrongPassword;
2622 case Internals::AutoFillButtonType::CreditCard:
2623 return AutoFillButtonType::CreditCard;
2624 case Internals::AutoFillButtonType::Loading:
2625 return AutoFillButtonType::Loading;
2626 }
2627 ASSERT_NOT_REACHED()((void)0);
2628 return AutoFillButtonType::None;
2629}
2630
2631static Internals::AutoFillButtonType NODELETE[[clang::annotate_type("webkit.nodelete")]] toInternalsAutofillButtonType(AutoFillButtonType type)
2632{
2633 switch (type) {
2634 case AutoFillButtonType::None:
2635 return Internals::AutoFillButtonType::None;
2636 case AutoFillButtonType::Credentials:
2637 return Internals::AutoFillButtonType::Credentials;
2638 case AutoFillButtonType::Contacts:
2639 return Internals::AutoFillButtonType::Contacts;
2640 case AutoFillButtonType::StrongPassword:
2641 return Internals::AutoFillButtonType::StrongPassword;
2642 case AutoFillButtonType::CreditCard:
2643 return Internals::AutoFillButtonType::CreditCard;
2644 case AutoFillButtonType::Loading:
2645 return Internals::AutoFillButtonType::Loading;
2646 }
2647 ASSERT_NOT_REACHED()((void)0);
2648 return Internals::AutoFillButtonType::None;
2649}
2650
2651void Internals::setAutofillButtonType(HTMLInputElement& element, AutoFillButtonType type)
2652{
2653 element.setAutofillButtonType(toAutofillButtonType(type));
2654}
2655
2656auto Internals::autofillButtonType(const HTMLInputElement& element) -> AutoFillButtonType
2657{
2658 return toInternalsAutofillButtonType(element.autofillButtonType());
2659}
2660
2661auto Internals::lastAutofillButtonType(const HTMLInputElement& element) -> AutoFillButtonType
2662{
2663 return toInternalsAutofillButtonType(element.lastAutofillButtonType());
2664}
2665
2666Vector<String> Internals::recentSearches(const HTMLInputElement& element)
2667{
2668 if (!element.isSearchField())
2669 return { };
2670
2671 element.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
2672 auto* searchField = dynamicDowncast<RenderSearchField>(element.renderer());
2673 if (!searchField)
2674 return { };
2675
2676 Vector<String> result;
2677 for (auto search : searchField->recentSearches())
2678 result.append(search.string);
2679
2680 return result;
2681}
2682
2683ExceptionOr<void> Internals::scrollElementToRect(Element& element, int x, int y, int w, int h)
2684{
2685 auto* frameView = element.document().view();
2686 if (!frameView)
2687 return Exception { ExceptionCode::InvalidAccessError };
2688 frameView->scrollElementToRect(element, { x, y, w, h });
2689 return { };
2690}
2691
2692ExceptionOr<String> Internals::autofillFieldName(Element& element)
2693{
2694 if (auto* formControl = dynamicDowncast<HTMLFormControlElement>(element))
2695 return String { formControl->autofillData().fieldName };
2696
2697 return Exception { ExceptionCode::InvalidNodeTypeError };
2698
2699}
2700
2701ExceptionOr<void> Internals::invalidateControlTints()
2702{
2703 Document* document = contextDocument();
2704 if (!document || !document->view())
2705 return Exception { ExceptionCode::InvalidAccessError };
2706
2707 document->view()->invalidateControlTints();
2708 return { };
2709}
2710
2711RefPtr<Range> Internals::rangeFromLocationAndLength(Element& scope, unsigned rangeLocation, unsigned rangeLength)
2712{
2713 return createLiveRange(resolveCharacterRange(makeRangeSelectingNodeContents(scope), { rangeLocation, rangeLength }));
2714}
2715
2716unsigned Internals::locationFromRange(Element& scope, const Range& range)
2717{
2718 return clampTo<unsigned>(characterRange(makeBoundaryPointBeforeNodeContents(scope), makeSimpleRange(range)).location);
2719}
2720
2721unsigned Internals::lengthFromRange(Element& scope, const Range& range)
2722{
2723 return clampTo<unsigned>(characterRange(makeBoundaryPointBeforeNodeContents(scope), makeSimpleRange(range)).length);
2724}
2725
2726String Internals::rangeAsText(const Range& liveRange)
2727{
2728 auto range = makeSimpleRange(liveRange);
2729 range.start.document().updateLayout();
2730 return plainText(range);
2731}
2732
2733// FIXME: Move this to StringConcatenate.h.
2734static String join(Vector<String>&& strings)
2735{
2736 StringBuilder result;
2737 for (auto& string : strings)
2738 result.append(WTF::move(string));
2739 return result.toString();
2740}
2741
2742String Internals::rangeAsTextUsingBackwardsTextIterator(const Range& liveRange)
2743{
2744 auto range = makeSimpleRange(liveRange);
2745 range.start.document().updateLayout();
2746 Vector<String> strings;
2747 for (SimplifiedBackwardsTextIterator backwardsIterator(range); !backwardsIterator.atEnd(); backwardsIterator.advance())
2748 strings.append(backwardsIterator.text().toString());
2749 strings.reverse();
2750 return join(WTF::move(strings));
2751}
2752
2753Ref<Range> Internals::subrange(Range& liveRange, unsigned rangeLocation, unsigned rangeLength)
2754{
2755 auto range = makeSimpleRange(liveRange);
2756 range.start.document().updateLayout();
2757 return createLiveRange(resolveCharacterRange(range, { rangeLocation, rangeLength }));
2758}
2759
2760RefPtr<Range> Internals::rangeOfStringNearLocation(const Range& liveRange, const String& text, unsigned targetOffset)
2761{
2762 auto range = makeSimpleRange(liveRange);
2763 range.start.document().updateLayout();
2764 return createLiveRange(findClosestPlainText(range, text, { }, targetOffset));
2765}
2766
2767Vector<Internals::TextIteratorState> Internals::statesOfTextIterator(const Range& liveRange)
2768{
2769 auto simpleRange = makeSimpleRange(liveRange);
2770 simpleRange.start.document().updateLayout();
2771
2772 Vector<TextIteratorState> states;
2773 for (TextIterator it(simpleRange); !it.atEnd(); it.advance())
2774 states.append({ it.text().toString(), createLiveRange(it.range()) });
2775 return states;
2776}
2777
2778String Internals::textFragmentDirectiveForRange(const Range& range)
2779{
2780 auto simpleRange = makeSimpleRange(range);
2781 simpleRange.start.document().updateLayout();
2782 return FragmentDirectiveGenerator(simpleRange).urlWithFragment().string();
2783}
2784
2785#if !PLATFORM(MAC)(defined WTF_PLATFORM_MAC && WTF_PLATFORM_MAC)
2786ExceptionOr<RefPtr<Range>> Internals::rangeForDictionaryLookupAtLocation(int, int)
2787{
2788 return Exception { ExceptionCode::InvalidAccessError };
2789}
2790#endif
2791
2792ExceptionOr<void> Internals::setDelegatesScrolling(bool enabled)
2793{
2794 Document* document = contextDocument();
2795 // Delegate scrolling is valid only on mainframe's view.
2796 if (!document || !document->view() || !document->page() || &document->page()->mainFrame() != document->frame())
2797 return Exception { ExceptionCode::InvalidAccessError };
2798
2799 document->view()->setDelegatedScrollingMode(enabled ? DelegatedScrollingMode::DelegatedToNativeScrollView : DelegatedScrollingMode::NotDelegated);
2800 return { };
2801}
2802
2803ExceptionOr<uint64_t> Internals::lastSpellCheckRequestSequence()
2804{
2805 Document* document = contextDocument();
2806 if (!document || !document->frame())
2807 return Exception { ExceptionCode::InvalidAccessError };
2808
2809 auto lastRequestIdentifier = document->editor().spellChecker().lastRequestIdentifier();
2810 return lastRequestIdentifier ? lastRequestIdentifier->toUInt64() : 0;
2811}
2812
2813ExceptionOr<uint64_t> Internals::lastSpellCheckProcessedSequence()
2814{
2815 Document* document = contextDocument();
2816 if (!document || !document->frame())
2817 return Exception { ExceptionCode::InvalidAccessError };
2818
2819 auto lastProcessedIdentifier = document->editor().spellChecker().lastProcessedIdentifier();
2820 return lastProcessedIdentifier ? lastProcessedIdentifier->toUInt64() : 0;
2821}
2822
2823void Internals::advanceToNextMisspelling()
2824{
2825#if !PLATFORM(IOS_FAMILY)(defined 1 && 1)
2826 if (auto* document = contextDocument())
2827 document->editor().advanceToNextMisspelling();
2828#endif
2829}
2830
2831Vector<String> Internals::userPreferredLanguages() const
2832{
2833 return WTF::userPreferredLanguages(ShouldMinimizeLanguages::No);
2834}
2835
2836void Internals::setUserPreferredLanguages(const Vector<String>& languages)
2837{
2838 overrideUserPreferredLanguages(languages);
2839}
2840
2841Vector<String> Internals::userPreferredAudioCharacteristics() const
2842{
2843 Document* document = contextDocument();
2844 if (!document || !document->page())
2845 return Vector<String>();
2846#if ENABLE(VIDEO)(defined 1 && 1)
2847 return document->page()->group().ensureCaptionPreferences().preferredAudioCharacteristics();
2848#else
2849 return Vector<String>();
2850#endif
2851}
2852
2853void Internals::setUserPreferredAudioCharacteristic(const String& characteristic)
2854{
2855 Document* document = contextDocument();
2856 if (!document || !document->page())
2857 return;
2858#if ENABLE(VIDEO)(defined 1 && 1)
2859 document->page()->group().ensureCaptionPreferences().setPreferredAudioCharacteristic(characteristic);
2860#else
2861 UNUSED_PARAM(characteristic)(void)characteristic;
2862#endif
2863}
2864
2865ExceptionOr<unsigned> Internals::wheelEventHandlerCount()
2866{
2867 Document* document = contextDocument();
2868 if (!document)
2869 return Exception { ExceptionCode::InvalidAccessError };
2870
2871 return document->wheelEventHandlerCount();
2872}
2873
2874ExceptionOr<unsigned> Internals::touchEventHandlerCount()
2875{
2876 Document* document = contextDocument();
2877 if (!document)
2878 return Exception { ExceptionCode::InvalidAccessError };
2879
2880 return document->touchEventHandlerCount();
2881}
2882
2883ExceptionOr<Ref<DOMRectList>> Internals::touchEventRectsForEvent(const String& eventName)
2884{
2885 Document* document = contextDocument();
2886 if (!document || !document->page())
2887 return Exception { ExceptionCode::InvalidAccessError };
2888
2889 std::array<EventTrackingRegions::EventType, 4> touchEvents = { {
2890 EventTrackingRegions::EventType::Touchstart,
2891 EventTrackingRegions::EventType::Touchmove,
2892 EventTrackingRegions::EventType::Touchend,
2893 EventTrackingRegions::EventType::Touchforcechange,
2894 } };
2895
2896 std::optional<EventTrackingRegions::EventType> touchEvent;
2897 for (auto event : touchEvents) {
2898 if (eventName == EventTrackingRegions::eventName(event)) {
2899 touchEvent = event;
2900 break;
2901 }
2902 }
2903
2904 if (!touchEvent)
2905 return Exception { ExceptionCode::InvalidAccessError };
2906
2907 return document->page()->touchEventRectsForEventForTesting(touchEvent.value());
2908}
2909
2910ExceptionOr<Ref<DOMRectList>> Internals::passiveTouchEventListenerRects()
2911{
2912 Document* document = contextDocument();
2913 if (!document || !document->page())
2914 return Exception { ExceptionCode::InvalidAccessError };
2915
2916 return document->page()->passiveTouchEventListenerRectsForTesting();
2917}
2918
2919// FIXME: Remove the document argument. It is almost always the same as
2920// contextDocument(), with the exception of a few tests that pass a
2921// different document, and could just make the call through another Internals
2922// instance instead.
2923ExceptionOr<RefPtr<NodeList>> Internals::nodesFromRect(Document& document, int centerX, int centerY, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowUserAgentShadowContent, bool allowChildFrameContent) const
2924{
2925 if (!document.frame() || !document.frame()->view())
2926 return Exception { ExceptionCode::InvalidAccessError };
2927
2928 auto* frame = document.frame();
2929 auto* frameView = document.view();
2930 auto* renderView = document.renderView();
2931 if (!renderView)
2932 return nullptr;
2933
2934 document.updateLayout(LayoutOptions::IgnorePendingStylesheets);
2935
2936 float zoomFactor = frame->pageZoomFactor();
2937 LayoutPoint point(centerX * zoomFactor + frameView->scrollX(), centerY * zoomFactor + frameView->scrollY());
2938
2939 OptionSet<HitTestRequest::Type> hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::CollectMultipleElements };
2940 if (ignoreClipping)
2941 hitType.add(HitTestRequest::Type::IgnoreClipping);
2942 if (!allowUserAgentShadowContent)
2943 hitType.add(HitTestRequest::Type::DisallowUserAgentShadowContent);
2944 if (allowChildFrameContent)
2945 hitType.add(HitTestRequest::Type::AllowChildFrameContent);
2946
2947 HitTestRequest request(hitType);
2948
2949 auto hitTestResult = [&] {
2950 auto size = LayoutSize { leftPadding + rightPadding + 1, topPadding + bottomPadding + 1 };
2951 if (size.isEmpty())
2952 return HitTestResult { point };
2953 auto adjustedPosition = LayoutPoint { flooredIntPoint(point) } - LayoutSize { leftPadding, topPadding };
2954 return HitTestResult { LayoutRect { adjustedPosition, size } };
2955 }();
2956 // When ignoreClipping is false, this method returns null for coordinates outside of the viewport.
2957 if (!request.ignoreClipping() && !hitTestResult.hitTestLocation().intersects(LayoutRect { frameView->visibleContentRect() }))
2958 return nullptr;
2959
2960 document.hitTest(request, hitTestResult);
2961 auto matches = WTF::map(hitTestResult.listBasedTestResult(), [](const auto& node) { return node.copyRef(); });
2962 return RefPtr<NodeList> { StaticNodeList::create(WTF::move(matches)) };
2963}
2964
2965ExceptionOr<RefPtr<Node>> Internals::nodeFromPointIncludingChildFrames(Document& document, int x, int y) const
2966{
2967 if (!document.frame() || !document.frame()->view())
2968 return Exception { ExceptionCode::InvalidAccessError };
2969
2970 document.updateLayout(LayoutOptions::IgnorePendingStylesheets);
2971
2972 auto* localFrame = document.frame();
2973 if (!localFrame)
2974 return RefPtr<Node> { };
2975
2976 constexpr OptionSet<HitTestRequest::Type> hitType {
2977 HitTestRequest::Type::ReadOnly,
2978 HitTestRequest::Type::Active,
2979 HitTestRequest::Type::DisallowUserAgentShadowContent,
2980 HitTestRequest::Type::AllowChildFrameContent,
2981 };
2982 auto result = localFrame->eventHandler().hitTestResultAtPoint(IntPoint(x, y), hitType);
2983 return RefPtr<Node> { result.innerNode() };
2984}
2985
2986class GetCallerCodeBlockFunctor {
2987public:
2988 GetCallerCodeBlockFunctor()
2989 : m_iterations(0)
2990 , m_codeBlock(0)
2991 {
2992 }
2993
2994 IterationStatus NODELETE[[clang::annotate_type("webkit.nodelete")]] operator()(StackVisitor& visitor) const
2995 {
2996 ++m_iterations;
2997 if (m_iterations < 2)
2998 return IterationStatus::Continue;
2999
3000 m_codeBlock = visitor->codeBlock();
3001 return IterationStatus::Done;
3002 }
3003
3004 CodeBlock* NODELETE[[clang::annotate_type("webkit.nodelete")]] codeBlock() const { return m_codeBlock; }
3005
3006private:
3007 mutable int m_iterations;
3008 mutable CodeBlock* m_codeBlock;
3009};
3010
3011String Internals::parserMetaData(JSC::JSValue code)
3012{
3013 auto& vm = contextDocument()->vm();
3014 auto callFrame = vm.topCallFrame;
3015 auto* globalObject = callFrame->lexicalGlobalObject(vm);
3016
3017 ScriptExecutable* executable;
3018 if (!code || code.isNull() || code.isUndefined()) {
3019 GetCallerCodeBlockFunctor iter;
3020 StackVisitor::visit(callFrame, vm, iter);
3021 executable = iter.codeBlock()->ownerExecutable();
3022 } else if (code.isCallable())
3023 executable = downcast<JSFunction>(code.toObject(globalObject))->jsExecutable();
3024 else
3025 return String();
3026
3027 ASCIILiteral prefix;
3028 String functionName;
3029 ASCIILiteral suffix = ""_s;
3030
3031 if (auto* functionExecutable = dynamicDowncast<FunctionExecutable>(executable)) {
3032 prefix = "function \""_s;
3033 functionName = functionExecutable->ecmaName().string();
3034 suffix = "\""_s;
3035 } else if (executable->isEvalExecutable())
3036 prefix = "eval"_s;
3037 else if (executable->isModuleProgramExecutable())
3038 prefix = "module"_s;
3039 else if (executable->isProgramExecutable())
3040 prefix = "program"_s;
3041 else
3042 RELEASE_ASSERT_NOT_REACHED()do { WTF::isIntegralOrPointerType(); compilerFenceForCrash();
WTFCrashWithInfo(3042, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/testing/Internals.cpp"
, __PRETTY_FUNCTION__ ); } while (false)
;
3043
3044 return makeString(prefix, functionName, suffix, " { "_s,
3045 executable->firstLine(), ':', executable->startColumn(), " - "_s,
3046 executable->lastLine(), ':', executable->endColumn(), " }"_s);
3047}
3048
3049void Internals::updateEditorUINowIfScheduled()
3050{
3051 if (Document* document = contextDocument()) {
3052 if (LocalFrame* frame = document->frame())
3053 frame->editor().updateEditorUINowIfScheduled();
3054 }
3055}
3056
3057bool Internals::hasMarkerFor(DocumentMarkerType type, int from, int length)
3058{
3059 Document* document = contextDocument();
3060 if (!document || !document->frame())
3061 return false;
3062
3063 updateEditorUINowIfScheduled();
3064
3065 return document->editor().selectionStartHasMarkerFor(type, from, length);
3066}
3067
3068ExceptionOr<void> Internals::setMarkerFor(const String& markerTypeString, int from, int length, const String& data)
3069{
3070 DocumentMarkerType markerType;
3071 if (!markerTypeFrom(markerTypeString, markerType))
3072 return Exception { ExceptionCode::SyntaxError };
3073
3074 Document* document = contextDocument();
3075 if (!document || !document->frame())
3076 return { };
3077
3078 updateEditorUINowIfScheduled();
3079
3080 document->editor().selectionStartSetMarkerForTesting(markerType, from, length, data);
3081 return { };
3082}
3083
3084bool Internals::hasSpellingMarker(int from, int length)
3085{
3086 return hasMarkerFor(DocumentMarkerType::Spelling, from, length);
3087}
3088
3089bool Internals::hasGrammarMarker(int from, int length)
3090{
3091 return hasMarkerFor(DocumentMarkerType::Grammar, from, length);
3092}
3093
3094bool Internals::isAlternativeTextUIActive() const
3095{
3096 RefPtr document = contextDocument();
3097 if (!document || !document->frame())
3098 return false;
3099 return document->frame()->editor().isAlternativeTextUIActive();
3100}
3101
3102bool Internals::hasAutocorrectedMarker(int from, int length)
3103{
3104 return hasMarkerFor(DocumentMarkerType::Autocorrected, from, length);
3105}
3106
3107bool Internals::hasDictationAlternativesMarker(int from, int length)
3108{
3109 return hasMarkerFor(DocumentMarkerType::DictationAlternatives, from, length);
3110}
3111
3112bool Internals::hasCorrectionIndicatorMarker(int from, int length)
3113{
3114 return hasMarkerFor(DocumentMarkerType::CorrectionIndicator, from, length);
3115}
3116
3117#if ENABLE(WRITING_TOOLS)(defined 1 && 1)
3118bool Internals::hasWritingToolsTextSuggestionMarker(int from, int length)
3119{
3120 return hasMarkerFor(DocumentMarkerType::WritingToolsTextSuggestion, from, length);
3121}
3122#endif
3123
3124bool Internals::hasTransparentContentMarker(int from, int length)
3125{
3126 return hasMarkerFor(DocumentMarkerType::TransparentContent, from, length);
3127}
3128
3129bool Internals::hasDictationStreamingOpacityMarker(int from, int length)
3130{
3131 return hasMarkerFor(DocumentMarkerType::DictationStreamingOpacity, from, length);
3132}
3133
3134void Internals::setContinuousSpellCheckingEnabled(bool enabled)
3135{
3136 if (!contextDocument() || !contextDocument()->frame())
3137 return;
3138
3139 if (enabled != contextDocument()->editor().isContinuousSpellCheckingEnabled())
3140 contextDocument()->editor().toggleContinuousSpellChecking();
3141}
3142
3143void Internals::setAutomaticQuoteSubstitutionEnabled(bool enabled)
3144{
3145 if (!contextDocument() || !contextDocument()->frame())
3146 return;
3147
3148#if USE(AUTOMATIC_TEXT_REPLACEMENT)(defined USE_AUTOMATIC_TEXT_REPLACEMENT && USE_AUTOMATIC_TEXT_REPLACEMENT
)
3149 if (enabled != contextDocument()->editor().isAutomaticQuoteSubstitutionEnabled())
3150 contextDocument()->editor().toggleAutomaticQuoteSubstitution();
3151#else
3152 UNUSED_PARAM(enabled)(void)enabled;
3153#endif
3154}
3155
3156void Internals::setAutomaticLinkDetectionEnabled(bool enabled)
3157{
3158 if (!contextDocument() || !contextDocument()->frame())
3159 return;
3160
3161#if USE(AUTOMATIC_TEXT_REPLACEMENT)(defined USE_AUTOMATIC_TEXT_REPLACEMENT && USE_AUTOMATIC_TEXT_REPLACEMENT
)
3162 if (enabled != contextDocument()->editor().isAutomaticLinkDetectionEnabled())
3163 contextDocument()->editor().toggleAutomaticLinkDetection();
3164#else
3165 UNUSED_PARAM(enabled)(void)enabled;
3166#endif
3167}
3168
3169ExceptionOr<bool> Internals::testProcessIncomingSyncMessagesWhenWaitingForSyncReply()
3170{
3171 RefPtr document = contextDocument();
3172 if (!document || !document->page())
3173 return Exception { ExceptionCode::InvalidStateError };
3174 return document->page()->chrome().client().testProcessIncomingSyncMessagesWhenWaitingForSyncReply();
3175}
3176
3177void Internals::setAutomaticDashSubstitutionEnabled(bool enabled)
3178{
3179 if (!contextDocument() || !contextDocument()->frame())
3180 return;
3181
3182#if USE(AUTOMATIC_TEXT_REPLACEMENT)(defined USE_AUTOMATIC_TEXT_REPLACEMENT && USE_AUTOMATIC_TEXT_REPLACEMENT
)
3183 if (enabled != contextDocument()->editor().isAutomaticDashSubstitutionEnabled())
3184 contextDocument()->editor().toggleAutomaticDashSubstitution();
3185#else
3186 UNUSED_PARAM(enabled)(void)enabled;
3187#endif
3188}
3189
3190void Internals::setAutomaticTextReplacementEnabled(bool enabled)
3191{
3192 if (!contextDocument() || !contextDocument()->frame())
3193 return;
3194
3195#if USE(AUTOMATIC_TEXT_REPLACEMENT)(defined USE_AUTOMATIC_TEXT_REPLACEMENT && USE_AUTOMATIC_TEXT_REPLACEMENT
)
3196 if (enabled != contextDocument()->editor().isAutomaticTextReplacementEnabled())
3197 contextDocument()->editor().toggleAutomaticTextReplacement();
3198#else
3199 UNUSED_PARAM(enabled)(void)enabled;
3200#endif
3201}
3202
3203void Internals::setAutomaticSpellingCorrectionEnabled(bool enabled)
3204{
3205 if (!contextDocument() || !contextDocument()->frame())
3206 return;
3207
3208#if USE(AUTOMATIC_TEXT_REPLACEMENT)(defined USE_AUTOMATIC_TEXT_REPLACEMENT && USE_AUTOMATIC_TEXT_REPLACEMENT
)
3209 if (enabled != contextDocument()->editor().isAutomaticSpellingCorrectionEnabled())
3210 contextDocument()->editor().toggleAutomaticSpellingCorrection();
3211#else
3212 UNUSED_PARAM(enabled)(void)enabled;
3213#endif
3214}
3215
3216bool Internals::isSpellcheckDisabledExceptTextReplacement(const HTMLInputElement& element) const
3217{
3218 return element.isSpellcheckDisabledExceptTextReplacement();
3219}
3220
3221void Internals::handleAcceptedCandidate(const String& candidate, unsigned location, unsigned length)
3222{
3223 if (!contextDocument() || !contextDocument()->frame())
3224 return;
3225
3226 TextCheckingResult result;
3227 result.type = TextCheckingType::None;
3228 result.range = { location, length };
3229 result.replacement = candidate;
3230 contextDocument()->editor().handleAcceptedCandidate(result);
3231}
3232
3233void Internals::changeSelectionListType()
3234{
3235 if (RefPtr frame = this->frame())
3236 frame->editor().changeSelectionListType();
3237}
3238
3239void Internals::changeBackToReplacedString(const String& replacedString)
3240{
3241 if (RefPtr frame = this->frame())
3242 frame->editor().changeBackToReplacedString(replacedString);
3243}
3244
3245bool Internals::isOverwriteModeEnabled()
3246{
3247 Document* document = contextDocument();
3248 if (!document || !document->frame())
3249 return false;
3250
3251 return document->editor().isOverwriteModeEnabled();
3252}
3253
3254void Internals::toggleOverwriteModeEnabled()
3255{
3256 Document* document = contextDocument();
3257 if (!document || !document->frame())
3258 return;
3259
3260 document->editor().toggleOverwriteModeEnabled();
3261}
3262
3263static ExceptionOr<FindOptions> parseFindOptions(const Vector<String>& optionList)
3264{
3265 struct FlagListEntry {
3266 ASCIILiteral name;
3267 FindOption value;
3268 };
3269 static constexpr auto flagList = std::to_array<FlagListEntry>({
3270 { "CaseInsensitive"_s, FindOption::CaseInsensitive },
3271 { "AtWordStarts"_s, FindOption::AtWordStarts },
3272 { "TreatMedialCapitalAsWordStart"_s, FindOption::TreatMedialCapitalAsWordStart },
3273 { "Backwards"_s, FindOption::Backwards },
3274 { "WrapAround"_s, FindOption::WrapAround },
3275 { "StartInSelection"_s, FindOption::StartInSelection },
3276 { "DoNotRevealSelection"_s, FindOption::DoNotRevealSelection },
3277 { "AtWordEnds"_s, FindOption::AtWordEnds },
3278 { "DoNotTraverseFlatTree"_s, FindOption::DoNotTraverseFlatTree },
3279 });
3280 FindOptions result;
3281 for (auto& option : optionList) {
3282 bool found = false;
3283 for (auto& flag : flagList) {
3284 if (flag.name == option) {
3285 result.add(flag.value);
3286 found = true;
3287 break;
3288 }
3289 }
3290 if (!found)
3291 return Exception { ExceptionCode::SyntaxError };
3292 }
3293 return result;
3294}
3295
3296ExceptionOr<RefPtr<Range>> Internals::rangeOfString(const String& text, RefPtr<Range>&& referenceRange, const Vector<String>& findOptions)
3297{
3298 Document* document = contextDocument();
3299 if (!document || !document->frame())
3300 return Exception { ExceptionCode::InvalidAccessError };
3301
3302 auto parsedOptions = parseFindOptions(findOptions);
3303 if (parsedOptions.hasException())
3304 return parsedOptions.releaseException();
3305
3306 return createLiveRange(document->editor().rangeOfString(text, makeSimpleRange(referenceRange), parsedOptions.releaseReturnValue()));
3307}
3308
3309ExceptionOr<unsigned> Internals::countMatchesForText(const String& text, const Vector<String>& findOptions, const String& markMatches)
3310{
3311 Document* document = contextDocument();
3312 if (!document || !document->frame())
3313 return Exception { ExceptionCode::InvalidAccessError };
3314
3315 auto parsedOptions = parseFindOptions(findOptions);
3316 if (parsedOptions.hasException())
3317 return parsedOptions.releaseException();
3318
3319 bool mark = markMatches == "mark"_s;
3320 return document->editor().countMatchesForText(text, std::nullopt, parsedOptions.releaseReturnValue(), 1000, mark, nullptr);
3321}
3322
3323ExceptionOr<unsigned> Internals::countFindMatches(const String& text, const Vector<String>& findOptions)
3324{
3325 Document* document = contextDocument();
3326 if (!document || !document->page())
3327 return Exception { ExceptionCode::InvalidAccessError };
3328
3329 auto parsedOptions = parseFindOptions(findOptions);
3330 if (parsedOptions.hasException())
3331 return parsedOptions.releaseException();
3332
3333 return document->page()->countFindMatches(text, parsedOptions.releaseReturnValue(), 1000);
3334}
3335
3336unsigned Internals::numberOfIDBTransactions() const
3337{
3338 return IDBTransaction::numberOfIDBTransactions;
3339}
3340
3341unsigned Internals::numberOfLiveNodes() const
3342{
3343 unsigned nodeCount = 0;
3344 for (auto& document : Document::allDocuments())
3345 nodeCount += document->referencingNodeCount();
3346 return nodeCount;
3347}
3348
3349unsigned Internals::numberOfLiveDocuments() const
3350{
3351 return Document::allDocuments().size();
3352}
3353
3354unsigned Internals::referencingNodeCount(const Document& document) const
3355{
3356 return document.referencingNodeCount();
3357}
3358
3359ExceptionOr<void> Internals::executeOpportunisticallyScheduledTasks() const
3360{
3361 Document* document = contextDocument();
3362 if (!document || !document->page())
3363 return Exception { ExceptionCode::InvalidAccessError };
3364 document->page()->performOpportunisticallyScheduledTasks(MonotonicTime::now());
3365 return { };
3366}
3367
3368ExceptionOr<void> Internals::releaseMemoryNow() const
3369{
3370 WebCore::releaseMemory(Critical::Yes, Synchronous::Yes);
3371 return { };
3372}
3373
3374#if ENABLE(WEB_AUDIO)(defined 1 && 1)
3375uint64_t Internals::baseAudioContextIdentifier(const BaseAudioContext& context)
3376{
3377 return context.contextID();
3378}
3379
3380bool Internals::isBaseAudioContextAlive(uint64_t contextID)
3381{
3382 ASSERT(contextID)((void)0);
3383 return BaseAudioContext::isContextAlive(contextID);
3384}
3385#endif // ENABLE(WEB_AUDIO)
3386
3387unsigned Internals::numberOfIntersectionObservers(const Document& document) const
3388{
3389 return document.numberOfIntersectionObservers();
3390}
3391
3392unsigned Internals::numberOfResizeObservers(const Document& document) const
3393{
3394 return document.numberOfResizeObservers();
3395}
3396
3397String Internals::documentIdentifier(const Document& document) const
3398{
3399 return document.identifier().object().toString();
3400}
3401
3402ExceptionOr<bool> Internals::isDocumentAlive(const String& documentIdentifier) const
3403{
3404 auto uuid = WTF::UUID::parseVersion4(documentIdentifier);
3405 if (!uuid)
3406 return Exception { ExceptionCode::InvalidAccessError };
3407 return Document::allDocumentsMap().contains({ *uuid, Process::identifier() });
3408}
3409
3410uint64_t Internals::messagePortIdentifier(const MessagePort& port) const
3411{
3412 return port.identifier().portIdentifier.toUInt64();
3413}
3414
3415bool Internals::isMessagePortAlive(uint64_t messagePortIdentifier) const
3416{
3417 MessagePortIdentifier portIdentifier { Process::identifier(), AtomicObjectIdentifier<PortIdentifierType>(messagePortIdentifier) };
3418 return MessagePort::isMessagePortAliveForTesting(portIdentifier);
3419}
3420
3421uint64_t Internals::storageAreaMapCount() const
3422{
3423 auto* page = contextDocument() ? contextDocument()->page() : nullptr;
3424 if (!page)
3425 return 0;
3426
3427 return page->storageNamespaceProvider().localStorageNamespace(page->sessionID()).storageAreaMapCountForTesting();
3428}
3429
3430uint64_t Internals::elementIdentifier(Element& element) const
3431{
3432 return element.nodeIdentifier().toUInt64();
3433}
3434
3435bool Internals::isElementAlive(uint64_t elementIdentifier) const
3436{
3437 return Node::fromIdentifier(ObjectIdentifier<NodeIdentifierType>(elementIdentifier));
3438}
3439
3440uint64_t Internals::pageIdentifier(const Document& document) const
3441{
3442 return document.pageID() ? document.pageID()->toUInt64() : 0;
3443}
3444
3445bool Internals::isAnyWorkletGlobalScopeAlive() const
3446{
3447 return WorkletGlobalScope::numberOfWorkletGlobalScopes();
3448}
3449
3450String Internals::serviceWorkerClientInternalIdentifier(const Document& document) const
3451{
3452 return document.identifier().toString();
3453}
3454
3455RefPtr<WindowProxy> Internals::openDummyInspectorFrontend(const String& url)
3456{
3457 RefPtr document = contextDocument();
3458 if (!document || !document->page())
3459 return nullptr;
3460
3461 RefPtr inspectedPage = document->page();
3462 RefPtr localMainFrame = dynamicDowncast<LocalFrame>(inspectedPage->mainFrame());
3463 if (!localMainFrame)
3464 return nullptr;
3465
3466 RefPtr window = localMainFrame->document()->window();
3467 if (!window)
3468 return nullptr;
3469
3470#if PLATFORM(WPE)(defined WTF_PLATFORM_WPE && WTF_PLATFORM_WPE)
3471 WTF::registerInspectorResourceIfNeeded();
3472#endif
3473
3474 auto frontendWindowProxy = window->open(*window, *window, url, emptyAtom(), emptyString()).releaseReturnValue();
3475 m_inspectorFrontend = makeUnique<InspectorStubFrontend>(*inspectedPage, *localMainFrame, downcast<LocalDOMWindow>(frontendWindowProxy->window()));
3476 return frontendWindowProxy;
3477}
3478
3479void Internals::closeDummyInspectorFrontend()
3480{
3481 m_inspectorFrontend = nullptr;
3482}
3483
3484ExceptionOr<void> Internals::setInspectorIsUnderTest(bool isUnderTest)
3485{
3486 RefPtr document = contextDocument();
3487 if (!document || !document->page())
3488 return Exception { ExceptionCode::InvalidAccessError };
3489
3490 document->page()->inspectorController().setIsUnderTest(isUnderTest);
3491 return { };
3492}
3493
3494unsigned Internals::numberOfScrollableAreas()
3495{
3496 Document* document = contextDocument();
3497 if (!document || !document->frame())
3498 return 0;
3499
3500 unsigned count = 0;
3501 LocalFrame* frame = document->frame();
3502 if (frame->view()->scrollableAreas())
3503 count += frame->view()->scrollableAreas()->computeSize();
3504
3505 for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
3506 auto* localChild = dynamicDowncast<LocalFrame>(child);
3507 if (!localChild)
3508 continue;
3509 auto* frameView = localChild->view();
3510 if (!frameView)
3511 continue;
3512 if (frameView->scrollableAreas())
3513 count += frameView->scrollableAreas()->computeSize();
3514 }
3515
3516 return count;
3517}
3518
3519ExceptionOr<bool> Internals::isPageBoxVisible(int pageNumber)
3520{
3521 Document* document = contextDocument();
3522 if (!document)
3523 return Exception { ExceptionCode::InvalidAccessError };
3524
3525 return document->isPageBoxVisible(pageNumber);
3526}
3527
3528static OptionSet<LayerTreeAsTextOptions> NODELETE[[clang::annotate_type("webkit.nodelete")]] toLayerTreeAsTextOptions(unsigned short flags)
3529{
3530 OptionSet<LayerTreeAsTextOptions> layerTreeFlags;
3531 if (flags & Internals::LAYER_TREE_INCLUDES_VISIBLE_RECTS)
3532 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeVisibleRects);
3533 if (flags & Internals::LAYER_TREE_INCLUDES_TILE_CACHES)
3534 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeTileCaches);
3535 if (flags & Internals::LAYER_TREE_INCLUDES_REPAINT_RECTS)
3536 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeRepaintRects);
3537 if (flags & Internals::LAYER_TREE_INCLUDES_PAINTING_PHASES)
3538 layerTreeFlags.add(LayerTreeAsTextOptions::IncludePaintingPhases);
3539 if (flags & Internals::LAYER_TREE_INCLUDES_CONTENT_LAYERS)
3540 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeContentLayers);
3541 if (flags & Internals::LAYER_TREE_INCLUDES_ACCELERATES_DRAWING)
3542 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeAcceleratesDrawing);
3543 if (flags & Internals::LAYER_TREE_INCLUDES_CLIPPING)
3544 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeClipping);
3545 if (flags & Internals::LAYER_TREE_INCLUDES_BACKING_STORE_ATTACHED)
3546 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeBackingStoreAttached);
3547 if (flags & Internals::LAYER_TREE_INCLUDES_ROOT_LAYER_PROPERTIES)
3548 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeRootLayerProperties);
3549 if (flags & Internals::LAYER_TREE_INCLUDES_EVENT_REGION)
3550 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeEventRegion);
3551 if (flags & Internals::LAYER_TREE_INCLUDES_EXTENDED_COLOR)
3552 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeExtendedColor);
3553 if (flags & Internals::LAYER_TREE_INCLUDES_DEVICE_SCALE)
3554 layerTreeFlags.add(LayerTreeAsTextOptions::IncludeDeviceScale);
3555
3556 return layerTreeFlags;
3557}
3558
3559// FIXME: Remove the document argument. It is almost always the same as
3560// contextDocument(), with the exception of a few tests that pass a
3561// different document, and could just make the call through another Internals
3562// instance instead.
3563ExceptionOr<String> Internals::layerTreeAsText(Document& document, unsigned short flags) const
3564{
3565 if (!document.frame() || !document.frame()->contentRenderer())
3566 return Exception { ExceptionCode::InvalidAccessError };
3567 return document.frame()->contentRenderer()->compositor().layerTreeAsText(toLayerTreeAsTextOptions(flags));
3568}
3569
3570ExceptionOr<uint64_t> Internals::layerIDForElement(Element& element)
3571{
3572 Document* document = contextDocument();
3573 if (!document || !document->frame())
3574 return Exception { ExceptionCode::InvalidAccessError };
3575
3576 element.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
3577
3578 if (!element.renderer() || !element.renderer()->hasLayer())
3579 return Exception { ExceptionCode::NotFoundError };
3580
3581 auto& layerModelObject = downcast<RenderLayerModelObject>(*element.renderer());
3582 if (!layerModelObject.layer()->isComposited())
3583 return Exception { ExceptionCode::NotFoundError };
3584
3585 auto* backing = layerModelObject.layer()->backing();
3586 return backing->graphicsLayer()->primaryLayerID() ? backing->graphicsLayer()->primaryLayerID()->object().toUInt64() : 0;
3587}
3588
3589static ExceptionOr<uint64_t> getLayerID(GraphicsLayer* layer)
3590{
3591 if (!layer)
3592 return Exception { ExceptionCode::NotFoundError };
3593
3594 auto primaryLayerID = layer->primaryLayerID();
3595 if (!primaryLayerID)
3596 return Exception { ExceptionCode::NotFoundError };
3597
3598 return primaryLayerID ? primaryLayerID->object().toUInt64() : 0;
3599}
3600
3601ExceptionOr<uint64_t> Internals::horizontalScrollbarLayerID(Node* node) const
3602{
3603 auto areaOrException = scrollableAreaForNode(node);
3604 if (areaOrException.hasException())
3605 return areaOrException.releaseException();
3606
3607 return getLayerID(areaOrException.returnValue()->layerForHorizontalScrollbar());
3608}
3609
3610ExceptionOr<uint64_t> Internals::verticalScrollbarLayerID(Node* node) const
3611{
3612 auto areaOrException = scrollableAreaForNode(node);
3613 if (areaOrException.hasException())
3614 return areaOrException.releaseException();
3615
3616 return getLayerID(areaOrException.returnValue()->layerForVerticalScrollbar());
3617}
3618
3619ExceptionOr<Ref<DOMRect>> Internals::horizontalScrollbarFrameRect(Node* node) const
3620{
3621 auto areaOrException = scrollableAreaForNode(node);
3622 if (areaOrException.hasException())
3623 return areaOrException.releaseException();
3624
3625 if (auto* scrollbar = areaOrException.returnValue()->horizontalScrollbar())
3626 return DOMRect::create(scrollbar->frameRect());
3627
3628 return DOMRect::create();
3629}
3630
3631ExceptionOr<Ref<DOMRect>> Internals::verticalScrollbarFrameRect(Node* node) const
3632{
3633 auto areaOrException = scrollableAreaForNode(node);
3634 if (areaOrException.hasException())
3635 return areaOrException.releaseException();
3636
3637 if (auto* scrollbar = areaOrException.returnValue()->verticalScrollbar())
3638 return DOMRect::create(scrollbar->frameRect());
3639
3640 return DOMRect::create();
3641}
3642
3643ExceptionOr<Ref<DOMRect>> Internals::scrollCornerRect(Node* node) const
3644{
3645 auto areaOrException = scrollableAreaForNode(node);
3646 if (areaOrException.hasException())
3647 return areaOrException.releaseException();
3648
3649 return DOMRect::create(areaOrException.returnValue()->scrollCornerRect());
3650}
3651
3652ExceptionOr<Internals::ScrollingNodeID> Internals::scrollingNodeIDForNode(Node* node)
3653{
3654 auto areaOrException = scrollableAreaForNode(node);
3655 if (areaOrException.hasException())
3656 return areaOrException.releaseException();
3657
3658 auto scrollingNodeID = areaOrException.returnValue()->scrollingNodeID();
3659 if (!scrollingNodeID)
3660 return { { 0, 0 } };
3661 return { { scrollingNodeID->object().toUInt64(), scrollingNodeID->processIdentifier().toUInt64() } };
3662}
3663
3664ExceptionOr<unsigned> Internals::scrollableAreaWidth(Node& node)
3665{
3666 auto areaOrException = scrollableAreaForNode(&node);
3667 if (areaOrException.hasException())
3668 return areaOrException.releaseException();
3669 auto* scrollableArea = areaOrException.releaseReturnValue();
3670 return scrollableArea->contentsSize().width();
3671}
3672
3673static OptionSet<PlatformLayerTreeAsTextFlags> NODELETE[[clang::annotate_type("webkit.nodelete")]] toPlatformLayerTreeFlags(unsigned short flags)
3674{
3675 OptionSet<PlatformLayerTreeAsTextFlags> platformLayerTreeFlags = { };
3676 if (flags & Internals::PLATFORM_LAYER_TREE_DEBUG)
3677 platformLayerTreeFlags.add(PlatformLayerTreeAsTextFlags::Debug);
3678 if (flags & Internals::PLATFORM_LAYER_TREE_IGNORES_CHILDREN)
3679 platformLayerTreeFlags.add(PlatformLayerTreeAsTextFlags::IgnoreChildren);
3680 if (flags & Internals::PLATFORM_LAYER_TREE_INCLUDE_MODELS)
3681 platformLayerTreeFlags.add(PlatformLayerTreeAsTextFlags::IncludeModels);
3682 return platformLayerTreeFlags;
3683}
3684
3685ExceptionOr<String> Internals::platformLayerTreeAsText(Element& element, unsigned short flags) const
3686{
3687 Document& document = element.document();
3688 if (!document.frame() || !document.frame()->contentRenderer())
3689 return Exception { ExceptionCode::InvalidAccessError };
3690
3691 auto text = document.frame()->contentRenderer()->compositor().platformLayerTreeAsText(element, toPlatformLayerTreeFlags(flags));
3692 if (!text)
3693 return Exception { ExceptionCode::NotFoundError };
3694
3695 return String { text.value() };
3696}
3697
3698ExceptionOr<String> Internals::repaintRectsAsText() const
3699{
3700 Document* document = contextDocument();
3701 if (!document || !document->frame())
3702 return Exception { ExceptionCode::InvalidAccessError };
3703
3704 return document->frame()->trackedRepaintRectsAsText();
3705}
3706
3707ExceptionOr<ScrollableArea*> Internals::scrollableAreaForNode(Node* node) const
3708{
3709 if (!node)
3710 node = contextDocument();
3711
3712 if (!node)
3713 return Exception { ExceptionCode::InvalidAccessError };
3714
3715 Ref nodeRef { *node };
3716 nodeRef->document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
3717
3718 ScrollableArea* scrollableArea = nullptr;
3719 if (is<Document>(nodeRef)) {
3720 auto* frameView = downcast<Document>(nodeRef.get()).view();
3721 if (!frameView)
3722 return Exception { ExceptionCode::InvalidAccessError };
3723
3724 scrollableArea = frameView;
3725 } else if (node == nodeRef->document().scrollingElement()) {
3726 auto* frameView = nodeRef->document().view();
3727 if (!frameView)
3728 return Exception { ExceptionCode::InvalidAccessError };
3729
3730 scrollableArea = frameView;
3731 } else if (RefPtr element = dynamicDowncast<Element>(nodeRef)) {
3732 if (!element->renderBox())
3733 return Exception { ExceptionCode::InvalidAccessError };
3734
3735 auto& renderBox = *element->renderBox();
3736 if (auto* renderListBox = dynamicDowncast<RenderListBox>(renderBox))
3737 scrollableArea = renderListBox;
3738 else {
3739 ASSERT(renderBox.layer())((void)0);
3740 scrollableArea = renderBox.layer()->scrollableArea();
3741 }
3742 } else
3743 return Exception { ExceptionCode::InvalidNodeTypeError };
3744
3745 if (!scrollableArea)
3746 return Exception { ExceptionCode::InvalidNodeTypeError };
3747
3748 return scrollableArea;
3749}
3750
3751ExceptionOr<String> Internals::scrollbarOverlayStyle(Node* node) const
3752{
3753 auto areaOrException = scrollableAreaForNode(node);
3754 if (areaOrException.hasException())
3755 return areaOrException.releaseException();
3756
3757 auto* scrollableArea = areaOrException.releaseReturnValue();
3758 switch (scrollableArea->scrollbarOverlayStyle()) {
3759 case ScrollbarOverlayStyle::Default:
3760 return "default"_str;
3761 case ScrollbarOverlayStyle::Dark:
3762 return "dark"_str;
3763 case ScrollbarOverlayStyle::Light:
3764 return "light"_str;
3765 }
3766
3767 ASSERT_NOT_REACHED()((void)0);
3768 return "unknown"_str;
3769}
3770
3771ExceptionOr<bool> Internals::scrollbarUsingDarkAppearance(Node* node) const
3772{
3773 auto areaOrException = scrollableAreaForNode(node);
3774 if (areaOrException.hasException())
3775 return areaOrException.releaseException();
3776
3777 auto* scrollableArea = areaOrException.releaseReturnValue();
3778 return scrollableArea->useDarkAppearance();
3779}
3780
3781ExceptionOr<String> Internals::horizontalScrollbarState(Node* node) const
3782{
3783 auto areaOrException = scrollableAreaForNode(node);
3784 if (areaOrException.hasException())
3785 return areaOrException.releaseException();
3786
3787 auto* scrollableArea = areaOrException.releaseReturnValue();
3788 return scrollableArea->horizontalScrollbarStateForTesting();
3789}
3790
3791ExceptionOr<String> Internals::verticalScrollbarState(Node* node) const
3792{
3793 auto areaOrException = scrollableAreaForNode(node);
3794 if (areaOrException.hasException())
3795 return areaOrException.releaseException();
3796
3797 auto* scrollableArea = areaOrException.releaseReturnValue();
3798 return scrollableArea->verticalScrollbarStateForTesting();
3799}
3800
3801static String scrollbarsControllerTypeString(ScrollbarsController& controller)
3802{
3803#if PLATFORM(MAC)(defined WTF_PLATFORM_MAC && WTF_PLATFORM_MAC)
3804 if (is<ScrollbarsControllerMac>(controller))
3805 return "ScrollbarsControllerMac"_s;
3806#endif
3807 if (is<ScrollbarsControllerMock>(controller))
3808 return "ScrollbarsControllerMock"_s;
3809 return "RemoteScrollbarsController"_s;
3810}
3811
3812ExceptionOr<String> Internals::scrollbarsControllerTypeForNode(Node* node) const
3813{
3814 auto areaOrException = scrollableAreaForNode(node);
3815 if (areaOrException.hasException())
3816 return areaOrException.releaseException();
3817
3818 auto* scrollableArea = areaOrException.releaseReturnValue();
3819 return scrollbarsControllerTypeString(scrollableArea->scrollbarsController());
3820}
3821
3822ExceptionOr<String> Internals::scrollingStateTreeAsText() const
3823{
3824 Document* document = contextDocument();
3825 if (!document || !document->frame())
3826 return Exception { ExceptionCode::InvalidAccessError };
3827
3828 document->updateLayout(LayoutOptions::IgnorePendingStylesheets);
3829
3830 Page* page = document->page();
3831 if (!page)
3832 return String();
3833
3834 return page->scrollingStateTreeAsText();
3835}
3836
3837ExceptionOr<String> Internals::scrollingTreeAsText() const
3838{
3839 Document* document = contextDocument();
3840 if (!document || !document->frame())
3841 return Exception { ExceptionCode::InvalidAccessError };
3842
3843 document->updateLayout(LayoutOptions::IgnorePendingStylesheets);
3844
3845 auto page = document->page();
3846 if (!page)
3847 return String();
3848
3849 RefPtr scrollingCoordinator = page->scrollingCoordinator();
3850 if (!scrollingCoordinator)
3851 return String();
3852
3853 scrollingCoordinator->commitTreeStateIfNeeded();
3854 return scrollingCoordinator->scrollingTreeAsText();
3855}
3856
3857ExceptionOr<bool> Internals::haveScrollingTree() const
3858{
3859 auto* document = contextDocument();
3860 if (!document || !document->frame())
3861 return Exception { ExceptionCode::InvalidAccessError };
3862
3863 document->updateLayout(LayoutOptions::IgnorePendingStylesheets);
3864
3865 auto page = document->page();
3866 if (!page)
3867 return false;
3868
3869 RefPtr scrollingCoordinator = page->scrollingCoordinator();
3870 if (!scrollingCoordinator)
3871 return false;
3872
3873 return scrollingCoordinator->haveScrollingTree();
3874}
3875
3876ExceptionOr<String> Internals::synchronousScrollingReasons() const
3877{
3878 Document* document = contextDocument();
3879 if (!document || !document->frame())
3880 return Exception { ExceptionCode::InvalidAccessError };
3881
3882 Page* page = document->page();
3883 if (!page)
3884 return String();
3885
3886 return page->synchronousScrollingReasonsAsText();
3887}
3888
3889ExceptionOr<Ref<DOMRectList>> Internals::nonFastScrollableRects() const
3890{
3891 Document* document = contextDocument();
3892 if (!document || !document->frame())
3893 return Exception { ExceptionCode::InvalidAccessError };
3894
3895 Page* page = document->page();
3896 if (!page)
3897 return DOMRectList::create();
3898
3899 return page->nonFastScrollableRectsForTesting();
3900}
3901
3902double Internals::minimumShrinkToFitWidthWhenPreferringHorizontalScrolling() const
3903{
3904 return ViewportConfiguration::minimumShrinkToFitWidthWhenPreferringHorizontalScrolling;
3905}
3906
3907ExceptionOr<void> Internals::setElementUsesDisplayListDrawing(Element& element, bool usesDisplayListDrawing)
3908{
3909 Document* document = contextDocument();
3910 if (!document || !document->renderView())
3911 return Exception { ExceptionCode::InvalidAccessError };
3912
3913 element.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
3914
3915 if (!element.renderer())
3916 return Exception { ExceptionCode::InvalidAccessError };
3917
3918 if (!element.renderer()->hasLayer())
3919 return Exception { ExceptionCode::InvalidAccessError };
3920
3921 RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
3922 if (!layer->isComposited())
3923 return Exception { ExceptionCode::InvalidAccessError };
3924
3925 layer->backing()->setUsesDisplayListDrawing(usesDisplayListDrawing);
3926 return { };
3927}
3928
3929ExceptionOr<void> Internals::setElementTracksDisplayListReplay(Element& element, bool isTrackingReplay)
3930{
3931 Document* document = contextDocument();
3932 if (!document || !document->renderView())
3933 return Exception { ExceptionCode::InvalidAccessError };
3934
3935 element.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
3936
3937 if (!element.renderer())
3938 return Exception { ExceptionCode::InvalidAccessError };
3939
3940 if (!element.renderer()->hasLayer())
3941 return Exception { ExceptionCode::InvalidAccessError };
3942
3943 RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
3944 if (!layer->isComposited())
3945 return Exception { ExceptionCode::InvalidAccessError };
3946
3947 layer->backing()->setIsTrackingDisplayListReplay(isTrackingReplay);
3948 return { };
3949}
3950
3951static OptionSet<DisplayList::AsTextFlag> NODELETE[[clang::annotate_type("webkit.nodelete")]] toDisplayListFlags(unsigned short flags)
3952{
3953 OptionSet<DisplayList::AsTextFlag> displayListFlags;
3954 if (flags & Internals::DISPLAY_LIST_INCLUDE_PLATFORM_OPERATIONS)
3955 displayListFlags.add(DisplayList::AsTextFlag::IncludePlatformOperations);
3956 if (flags & Internals::DISPLAY_LIST_INCLUDE_RESOURCE_IDENTIFIERS)
3957 displayListFlags.add(DisplayList::AsTextFlag::IncludeResourceIdentifiers);
3958 return displayListFlags;
3959}
3960
3961ExceptionOr<String> Internals::displayListForElement(Element& element, unsigned short flags)
3962{
3963 Document* document = contextDocument();
3964 if (!document || !document->renderView())
3965 return Exception { ExceptionCode::InvalidAccessError };
3966
3967 element.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
3968
3969 if (!element.renderer())
3970 return Exception { ExceptionCode::InvalidAccessError };
3971
3972 if (!element.renderer()->hasLayer())
3973 return Exception { ExceptionCode::InvalidAccessError };
3974
3975 RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
3976 if (!layer->isComposited())
3977 return Exception { ExceptionCode::InvalidAccessError };
3978
3979 return layer->backing()->displayListAsText(toDisplayListFlags(flags));
3980}
3981
3982ExceptionOr<String> Internals::replayDisplayListForElement(Element& element, unsigned short flags)
3983{
3984 Document* document = contextDocument();
3985 if (!document || !document->renderView())
3986 return Exception { ExceptionCode::InvalidAccessError };
3987
3988 element.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
3989
3990 if (!element.renderer())
3991 return Exception { ExceptionCode::InvalidAccessError };
3992
3993 if (!element.renderer()->hasLayer())
3994 return Exception { ExceptionCode::InvalidAccessError };
3995
3996 RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
3997 if (!layer->isComposited())
3998 return Exception { ExceptionCode::InvalidAccessError };
3999
4000 return layer->backing()->replayDisplayListAsText(toDisplayListFlags(flags));
4001}
4002
4003void Internals::setForceUseGlyphDisplayListForTesting(bool enabled)
4004{
4005 TextPainter::setForceUseGlyphDisplayListForTesting(enabled);
4006}
4007
4008void Internals::clearGlyphDisplayListCacheForTesting()
4009{
4010 TextPainter::clearGlyphDisplayListCacheForTesting();
4011}
4012
4013ExceptionOr<String> Internals::cachedGlyphDisplayListsForTextNode(Node& node, unsigned short flags)
4014{
4015 Document* document = contextDocument();
4016 if (!document || !document->renderView())
4017 return Exception { ExceptionCode::InvalidAccessError };
4018
4019 RefPtr textNode = dynamicDowncast<Text>(node);
4020 if (!textNode)
4021 return Exception { ExceptionCode::InvalidAccessError };
4022
4023 textNode->document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
4024
4025 if (!textNode->renderer())
4026 return Exception { ExceptionCode::InvalidAccessError };
4027
4028 return TextPainter::cachedGlyphDisplayListsForTextNodeAsText(*textNode, toDisplayListFlags(flags));
4029}
4030
4031ExceptionOr<void> Internals::garbageCollectDocumentResources() const
4032{
4033 Document* document = contextDocument();
4034 if (!document)
4035 return Exception { ExceptionCode::InvalidAccessError };
4036 document->cachedResourceLoader().garbageCollectDocumentResources();
4037 return { };
4038}
4039
4040bool Internals::isUnderMemoryWarning()
4041{
4042 return MemoryPressureHandler::singleton().isUnderMemoryWarning();
4043}
4044
4045bool Internals::isUnderMemoryPressure()
4046{
4047 return MemoryPressureHandler::singleton().isUnderMemoryPressure();
4048}
4049
4050void Internals::beginSimulatedMemoryWarning()
4051{
4052 MemoryPressureHandler::singleton().beginSimulatedMemoryWarning();
4053}
4054
4055void Internals::endSimulatedMemoryWarning()
4056{
4057 MemoryPressureHandler::singleton().endSimulatedMemoryWarning();
4058}
4059
4060void Internals::beginSimulatedMemoryPressure()
4061{
4062 MemoryPressureHandler::singleton().beginSimulatedMemoryPressure();
4063}
4064
4065void Internals::endSimulatedMemoryPressure()
4066{
4067 MemoryPressureHandler::singleton().endSimulatedMemoryPressure();
4068}
4069
4070ExceptionOr<void> Internals::insertAuthorCSS(const String& css) const
4071{
4072 Document* document = contextDocument();
4073 if (!document)
4074 return Exception { ExceptionCode::InvalidAccessError };
4075
4076 auto parsedSheet = StyleSheetContents::create(*document);
4077 parsedSheet.get().setIsUserStyleSheet(false);
4078 parsedSheet.get().parseString(css);
4079 document->extensionStyleSheets().addAuthorStyleSheetForTesting(WTF::move(parsedSheet));
4080 return { };
4081}
4082
4083ExceptionOr<void> Internals::insertUserCSS(const String& css) const
4084{
4085 Document* document = contextDocument();
4086 if (!document)
4087 return Exception { ExceptionCode::InvalidAccessError };
4088
4089 auto parsedSheet = StyleSheetContents::create(*document);
4090 parsedSheet.get().setIsUserStyleSheet(true);
4091 parsedSheet.get().parseString(css);
4092 document->extensionStyleSheets().addUserStyleSheet(WTF::move(parsedSheet));
4093 return { };
4094}
4095
4096String Internals::counterValue(Element& element)
4097{
4098 return counterValueForElement(&element);
4099}
4100
4101int Internals::pageNumber(Element& element, float pageWidth, float pageHeight)
4102{
4103 return PrintContext::pageNumberForElement(&element, { pageWidth, pageHeight });
4104}
4105
4106Vector<String> Internals::shortcutIconURLs() const
4107{
4108 if (!frame())
4109 return { };
4110
4111 auto* documentLoader = frame()->loader().documentLoader();
4112 if (!documentLoader)
4113 return { };
4114
4115 Vector<String> result;
4116 for (auto& linkIcon : documentLoader->linkIcons())
4117 result.append(linkIcon.url.string());
4118
4119 return result;
4120}
4121
4122int Internals::numberOfPages(float pageWidth, float pageHeight)
4123{
4124 if (!frame())
4125 return -1;
4126
4127 return PrintContext::numberOfPages(*frame(), FloatSize(pageWidth, pageHeight));
4128}
4129
4130ExceptionOr<String> Internals::pageProperty(const String& propertyName, int pageNumber) const
4131{
4132 if (!frame())
4133 return Exception { ExceptionCode::InvalidAccessError };
4134
4135 return PrintContext::pageProperty(frame(), propertyName, pageNumber);
4136}
4137
4138ExceptionOr<String> Internals::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const
4139{
4140 if (!frame())
4141 return Exception { ExceptionCode::InvalidAccessError };
4142
4143 return PrintContext::pageSizeAndMarginsInPixels(frame(), pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft);
4144}
4145
4146ExceptionOr<float> Internals::pageScaleFactor() const
4147{
4148 Document* document = contextDocument();
4149 if (!document || !document->page())
4150 return Exception { ExceptionCode::InvalidAccessError };
4151
4152 return document->page()->pageScaleFactor();
4153}
4154
4155ExceptionOr<void> Internals::setPageZoomFactor(float zoomFactor)
4156{
4157 Document* document = contextDocument();
4158 if (!document || !document->frame())
4159 return Exception { ExceptionCode::InvalidAccessError };
4160
4161 document->frame()->setPageZoomFactor(zoomFactor);
4162 return { };
4163}
4164
4165ExceptionOr<void> Internals::setTextZoomFactor(float zoomFactor)
4166{
4167 Document* document = contextDocument();
4168 if (!document || !document->frame())
4169 return Exception { ExceptionCode::InvalidAccessError };
4170
4171 document->frame()->setTextZoomFactor(zoomFactor);
4172 return { };
4173}
4174
4175ExceptionOr<void> Internals::setUseFixedLayout(bool useFixedLayout)
4176{
4177 Document* document = contextDocument();
4178 if (!document || !document->view())
4179 return Exception { ExceptionCode::InvalidAccessError };
4180
4181 document->view()->setUseFixedLayout(useFixedLayout);
4182 return { };
4183}
4184
4185ExceptionOr<void> Internals::setFixedLayoutSize(int width, int height)
4186{
4187 Document* document = contextDocument();
4188 if (!document || !document->view())
4189 return Exception { ExceptionCode::InvalidAccessError };
4190
4191 document->view()->setFixedLayoutSize(IntSize(width, height));
4192 return { };
4193}
4194
4195ExceptionOr<void> Internals::setViewExposedRect(float x, float y, float width, float height)
4196{
4197 Document* document = contextDocument();
4198 if (!document || !document->view())
4199 return Exception { ExceptionCode::InvalidAccessError };
4200
4201 document->view()->setViewExposedRect(FloatRect(x, y, width, height));
4202 return { };
4203}
4204
4205void Internals::setPrinting(int width, int height)
4206{
4207 printContextForTesting() = PrintContext::create(frame());
4208 printContextForTesting()->begin(width, height);
4209}
4210
4211void Internals::setHeaderHeight(float height)
4212{
4213 Document* document = contextDocument();
4214 if (!document || !document->view())
4215 return;
4216
4217 document->page()->setHeaderHeight(height);
4218}
4219
4220void Internals::setFooterHeight(float height)
4221{
4222 Document* document = contextDocument();
4223 if (!document || !document->view())
4224 return;
4225
4226 document->page()->setFooterHeight(height);
4227}
4228
4229void Internals::setFullscreenInsets(FullscreenInsets insets)
4230{
4231 Page* page = contextDocument()->frame()->page();
4232 ASSERT(page)((void)0);
4233
4234 page->setFullscreenInsets(FloatBoxExtent(insets.top, insets.right, insets.bottom, insets.left));
4235}
4236
4237ExceptionOr<void> Internals::setFullscreenAutoHideDuration(double duration)
4238{
4239 RefPtr document = contextDocument();
4240 if (!document || !document->page())
4241 return Exception { ExceptionCode::InvalidStateError };
4242 protect(document->page())->setFullscreenAutoHideDuration(Seconds(duration));
4243 return { };
4244}
4245
4246void Internals::setScreenContentsFormatsForTesting(const Vector<Internals::ContentsFormat>& formats)
4247{
4248 OptionSet<WebCore::ContentsFormat> contentsFormats;
4249
4250 for (auto format : formats) {
4251 switch (format) {
4252 case Internals::ContentsFormat::RGBA8:
4253 contentsFormats.add(WebCore::ContentsFormat::RGBA8);
4254 break;
4255#if ENABLE(PIXEL_FORMAT_RGB10)(defined 0 && 0)
4256 case Internals::ContentsFormat::RGBA10:
4257 contentsFormats.add(WebCore::ContentsFormat::RGBA10);
4258 break;
4259#endif
4260#if ENABLE(PIXEL_FORMAT_RGBA16F)(defined 1 && 1)
4261 case Internals::ContentsFormat::RGBA16F:
4262 contentsFormats.add(WebCore::ContentsFormat::RGBA16F);
4263 break;
4264#endif
4265 }
4266 }
4267
4268#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
4269 WebCore::setScreenContentsFormatsForTesting(contentsFormats);
4270#else
4271 UNUSED_PARAM(contentsFormats)(void)contentsFormats;
4272#endif
4273}
4274
4275#if ENABLE(VIDEO)(defined 1 && 1)
4276bool Internals::isChangingPresentationMode(HTMLVideoElement& element) const
4277{
4278#if ENABLE(VIDEO_PRESENTATION_MODE)(defined 1 && 1)
4279 return element.isChangingPresentationMode();
4280#else
4281 UNUSED_PARAM(element)(void)element;
4282 return false;
4283#endif
4284}
4285#endif
4286
4287#if ENABLE(VIDEO_PRESENTATION_MODE)(defined 1 && 1)
4288void Internals::setMockVideoPresentationModeEnabled(bool enabled)
4289{
4290 Document* document = contextDocument();
4291 if (!document || !document->page())
4292 return;
4293
4294 document->page()->chrome().client().setMockVideoPresentationModeEnabled(enabled);
4295}
4296#endif
4297
4298void Internals::setCanvasNoiseInjectionSalt(HTMLCanvasElement& element, unsigned long long salt)
4299{
4300 element.setNoiseInjectionSalt(salt);
4301}
4302
4303bool Internals::doesCanvasHavePendingCanvasNoiseInjection(HTMLCanvasElement& element) const
4304{
4305 return element.havePendingCanvasNoiseInjection();
4306}
4307
4308void Internals::registerURLSchemeAsBypassingContentSecurityPolicy(const String& scheme)
4309{
4310 LegacySchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(scheme);
4311}
4312
4313void Internals::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(const String& scheme)
4314{
4315 LegacySchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(scheme);
4316}
4317
4318void Internals::registerDefaultPortForProtocol(unsigned short port, const String& protocol)
4319{
4320 registerDefaultPortForProtocolForTesting(port, protocol);
4321}
4322
4323Ref<MallocStatistics> Internals::mallocStatistics() const
4324{
4325 return MallocStatistics::create();
4326}
4327
4328Ref<TypeConversions> Internals::typeConversions() const
4329{
4330 return TypeConversions::create();
4331}
4332
4333Ref<MemoryInfo> Internals::memoryInfo() const
4334{
4335 return MemoryInfo::create();
4336}
4337
4338Vector<String> Internals::getReferencedFilePaths() const
4339{
4340 RefPtr localFrame = frame();
4341 if (!localFrame)
4342 return { };
4343 localFrame->loader().history().saveDocumentAndScrollState();
4344 return FormController::referencedFilePaths(localFrame->loader().history().currentItem()->documentState());
4345}
4346
4347ExceptionOr<void> Internals::startTrackingRepaints()
4348{
4349 Document* document = contextDocument();
4350 if (!document || !document->view())
4351 return Exception { ExceptionCode::InvalidAccessError };
4352
4353 document->view()->setTracksRepaints(true);
4354 return { };
4355}
4356
4357ExceptionOr<void> Internals::stopTrackingRepaints()
4358{
4359 Document* document = contextDocument();
4360 if (!document || !document->view())
4361 return Exception { ExceptionCode::InvalidAccessError };
4362
4363 document->view()->setTracksRepaints(false);
4364 return { };
4365}
4366
4367ExceptionOr<void> Internals::startTrackingLayerFlushes()
4368{
4369 Document* document = contextDocument();
4370 if (!document || !document->renderView())
4371 return Exception { ExceptionCode::InvalidAccessError };
4372
4373 document->renderView()->compositor().startTrackingLayerFlushes();
4374 return { };
4375}
4376
4377ExceptionOr<unsigned> Internals::layerFlushCount()
4378{
4379 Document* document = contextDocument();
4380 if (!document || !document->renderView())
4381 return Exception { ExceptionCode::InvalidAccessError };
4382
4383 return document->renderView()->compositor().layerFlushCount();
4384}
4385
4386ExceptionOr<void> Internals::startTrackingStyleRecalcs()
4387{
4388 Document* document = contextDocument();
4389 if (!document)
4390 return Exception { ExceptionCode::InvalidAccessError };
4391
4392 document->startTrackingStyleRecalcs();
4393 return { };
4394}
4395
4396ExceptionOr<unsigned> Internals::styleRecalcCount()
4397{
4398 Document* document = contextDocument();
4399 if (!document)
4400 return Exception { ExceptionCode::InvalidAccessError };
4401
4402 return document->styleRecalcCount();
4403}
4404
4405unsigned Internals::lastStyleUpdateSize() const
4406{
4407 Document* document = contextDocument();
4408 if (!document)
4409 return 0;
4410 return document->lastStyleUpdateSizeForTesting();
4411}
4412
4413unsigned Internals::styleInvalidationTraversalCount() const
4414{
4415 Document* document = contextDocument();
4416 if (!document)
4417 return 0;
4418 return document->styleInvalidationTraversalCountForTesting();
4419}
4420
4421void Internals::resetStyleInvalidationTraversalCount()
4422{
4423 if (Document* document = contextDocument())
4424 document->resetStyleInvalidationTraversalCountForTesting();
4425}
4426
4427ExceptionOr<void> Internals::startTrackingLayoutUpdates()
4428{
4429 Document* document = contextDocument();
4430 if (!document || !document->view())
4431 return Exception { ExceptionCode::InvalidAccessError };
4432
4433 document->view()->startTrackingLayoutUpdates();
4434 return { };
4435}
4436
4437ExceptionOr<unsigned> Internals::layoutUpdateCount()
4438{
4439 Document* document = contextDocument();
4440 if (!document || !document->view())
4441 return Exception { ExceptionCode::InvalidAccessError };
4442
4443 return document->view()->layoutUpdateCount();
4444}
4445
4446ExceptionOr<void> Internals::startTrackingRenderLayerPositionUpdates()
4447{
4448 Document* document = contextDocument();
4449 if (!document || !document->view())
4450 return Exception { ExceptionCode::InvalidAccessError };
4451
4452 document->view()->startTrackingRenderLayerPositionUpdates();
4453 return { };
4454}
4455
4456ExceptionOr<unsigned> Internals::renderLayerPositionUpdateCount()
4457{
4458 Document* document = contextDocument();
4459 if (!document || !document->view())
4460 return Exception { ExceptionCode::InvalidAccessError };
4461
4462 return document->view()->renderLayerPositionUpdateCount();
4463}
4464
4465ExceptionOr<void> Internals::startTrackingCompositingUpdates()
4466{
4467 Document* document = contextDocument();
4468 if (!document || !document->renderView())
4469 return Exception { ExceptionCode::InvalidAccessError };
4470
4471 document->renderView()->compositor().startTrackingCompositingUpdates();
4472 return { };
4473}
4474
4475ExceptionOr<unsigned> Internals::compositingUpdateCount()
4476{
4477 Document* document = contextDocument();
4478 if (!document || !document->renderView())
4479 return Exception { ExceptionCode::InvalidAccessError };
4480
4481 return document->renderView()->compositor().compositingUpdateCount();
4482}
4483
4484ExceptionOr<void> Internals::startTrackingRenderingUpdates()
4485{
4486 Document* document = contextDocument();
4487 if (!document || !document->page())
4488 return Exception { ExceptionCode::InvalidAccessError };
4489
4490 document->page()->startTrackingRenderingUpdates();
4491 return { };
4492}
4493
4494ExceptionOr<unsigned> Internals::renderingUpdateCount()
4495{
4496 Document* document = contextDocument();
4497 if (!document || !document->page())
4498 return Exception { ExceptionCode::InvalidAccessError };
4499
4500 return document->page()->renderingUpdateCount();
4501}
4502
4503ExceptionOr<std::optional<double>> Internals::timeToNextRenderingUpdate()
4504{
4505 Document* document = contextDocument();
4506 if (!document || !document->page())
4507 return Exception { ExceptionCode::InvalidAccessError };
4508
4509 if (auto timeToNextUpdate = document->page()->timeToNextRenderingUpdateForTesting())
4510 return timeToNextUpdate->milliseconds();
4511
4512 return { std::nullopt };
4513}
4514
4515ExceptionOr<void> Internals::setCompositingPolicyOverride(std::optional<CompositingPolicy> policyOverride)
4516{
4517 Document* document = contextDocument();
4518 if (!document || !document->page())
4519 return Exception { ExceptionCode::InvalidAccessError };
4520
4521 if (!policyOverride) {
4522 document->page()->setCompositingPolicyOverride(std::nullopt);
4523 return { };
4524 }
4525
4526 switch (policyOverride.value()) {
4527 case Internals::CompositingPolicy::Normal:
4528 document->page()->setCompositingPolicyOverride(WebCore::CompositingPolicy::Normal);
4529 break;
4530 case Internals::CompositingPolicy::Conservative:
4531 document->page()->setCompositingPolicyOverride(WebCore::CompositingPolicy::Conservative);
4532 break;
4533 }
4534
4535 return { };
4536}
4537
4538ExceptionOr<std::optional<Internals::CompositingPolicy>> Internals::compositingPolicyOverride() const
4539{
4540 Document* document = contextDocument();
4541 if (!document || !document->page())
4542 return Exception { ExceptionCode::InvalidAccessError };
4543
4544 auto policyOverride = document->page()->compositingPolicyOverride();
4545 if (!policyOverride)
4546 return { std::nullopt };
4547
4548 switch (policyOverride.value()) {
4549 case WebCore::CompositingPolicy::Normal:
4550 return { Internals::CompositingPolicy::Normal };
4551 case WebCore::CompositingPolicy::Conservative:
4552 return { Internals::CompositingPolicy::Conservative };
4553 }
4554
4555 return { Internals::CompositingPolicy::Normal };
4556}
4557
4558void Internals::updateLayoutAndStyleForAllFrames() const
4559{
4560 auto* document = contextDocument();
4561 if (!document || !document->view())
4562 return;
4563 document->view()->updateLayoutAndStyleIfNeededRecursive();
4564}
4565
4566ExceptionOr<void> Internals::updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node* node)
4567{
4568 Document* document;
4569 if (!node)
4570 document = contextDocument();
4571 else if (auto* documentNode = dynamicDowncast<Document>(*node))
4572 document = documentNode;
4573 else if (auto* iframe = dynamicDowncast<HTMLIFrameElement>(*node))
4574 document = iframe->contentDocument();
4575 else
4576 return Exception { ExceptionCode::TypeError };
4577
4578 document->updateLayout({ LayoutOptions::IgnorePendingStylesheets, LayoutOptions::RunPostLayoutTasksSynchronously });
4579 document->flushDeferredAXObjectCacheUpdate();
4580
4581 return { };
4582}
4583
4584#if !PLATFORM(IOS_FAMILY)(defined 1 && 1)
4585static ASCIILiteral cursorTypeToString(Cursor::Type cursorType)
4586{
4587 switch (cursorType) {
4588 case Cursor::Type::Pointer: return "Pointer"_s;
4589 case Cursor::Type::Cross: return "Cross"_s;
4590 case Cursor::Type::Hand: return "Hand"_s;
4591 case Cursor::Type::IBeam: return "IBeam"_s;
4592 case Cursor::Type::Wait: return "Wait"_s;
4593 case Cursor::Type::Help: return "Help"_s;
4594 case Cursor::Type::EastResize: return "EastResize"_s;
4595 case Cursor::Type::NorthResize: return "NorthResize"_s;
4596 case Cursor::Type::NorthEastResize: return "NorthEastResize"_s;
4597 case Cursor::Type::NorthWestResize: return "NorthWestResize"_s;
4598 case Cursor::Type::SouthResize: return "SouthResize"_s;
4599 case Cursor::Type::SouthEastResize: return "SouthEastResize"_s;
4600 case Cursor::Type::SouthWestResize: return "SouthWestResize"_s;
4601 case Cursor::Type::WestResize: return "WestResize"_s;
4602 case Cursor::Type::NorthSouthResize: return "NorthSouthResize"_s;
4603 case Cursor::Type::EastWestResize: return "EastWestResize"_s;
4604 case Cursor::Type::NorthEastSouthWestResize: return "NorthEastSouthWestResize"_s;
4605 case Cursor::Type::NorthWestSouthEastResize: return "NorthWestSouthEastResize"_s;
4606 case Cursor::Type::ColumnResize: return "ColumnResize"_s;
4607 case Cursor::Type::RowResize: return "RowResize"_s;
4608 case Cursor::Type::MiddlePanning: return "MiddlePanning"_s;
4609 case Cursor::Type::EastPanning: return "EastPanning"_s;
4610 case Cursor::Type::NorthPanning: return "NorthPanning"_s;
4611 case Cursor::Type::NorthEastPanning: return "NorthEastPanning"_s;
4612 case Cursor::Type::NorthWestPanning: return "NorthWestPanning"_s;
4613 case Cursor::Type::SouthPanning: return "SouthPanning"_s;
4614 case Cursor::Type::SouthEastPanning: return "SouthEastPanning"_s;
4615 case Cursor::Type::SouthWestPanning: return "SouthWestPanning"_s;
4616 case Cursor::Type::WestPanning: return "WestPanning"_s;
4617 case Cursor::Type::Move: return "Move"_s;
4618 case Cursor::Type::VerticalText: return "VerticalText"_s;
4619 case Cursor::Type::Cell: return "Cell"_s;
4620 case Cursor::Type::ContextMenu: return "ContextMenu"_s;
4621 case Cursor::Type::Alias: return "Alias"_s;
4622 case Cursor::Type::Progress: return "Progress"_s;
4623 case Cursor::Type::NoDrop: return "NoDrop"_s;
4624 case Cursor::Type::Copy: return "Copy"_s;
4625 case Cursor::Type::None: return "None"_s;
4626 case Cursor::Type::NotAllowed: return "NotAllowed"_s;
4627 case Cursor::Type::ZoomIn: return "ZoomIn"_s;
4628 case Cursor::Type::ZoomOut: return "ZoomOut"_s;
4629 case Cursor::Type::Grab: return "Grab"_s;
4630 case Cursor::Type::Grabbing: return "Grabbing"_s;
4631 case Cursor::Type::Custom: return "Custom"_s;
4632 case Cursor::Type::Invalid: break;
4633 }
4634
4635 ASSERT_NOT_REACHED()((void)0);
4636 return "UNKNOWN"_s;
4637}
4638#endif
4639
4640ExceptionOr<String> Internals::getCurrentCursorInfo()
4641{
4642 Document* document = contextDocument();
4643 if (!document || !document->frame())
4644 return Exception { ExceptionCode::InvalidAccessError };
4645
4646#if !PLATFORM(IOS_FAMILY)(defined 1 && 1)
4647 Cursor cursor = document->frame()->eventHandler().currentMouseCursor();
4648
4649 StringBuilder result;
4650 result.append("type="_s, cursorTypeToString(cursor.type()), " hotSpot="_s, cursor.hotSpot().x(), ',', cursor.hotSpot().y());
4651 if (cursor.image()) {
4652 FloatSize size = cursor.image()->size();
4653 result.append(" image="_s, size.width(), 'x', size.height());
4654 }
4655#if ENABLE(MOUSE_CURSOR_SCALE)(defined 0 && 0)
4656 if (cursor.imageScaleFactor() != 1)
4657 result.append(" scale="_s, cursor.imageScaleFactor());
4658#endif
4659 return String { result.toString() };
4660#else
4661 return "FAIL: Cursor details not available on this platform."_str;
4662#endif
4663}
4664
4665Ref<ArrayBuffer> Internals::serializeObject(const RefPtr<SerializedScriptValue>& value) const
4666{
4667 return ArrayBuffer::create(value->wireBytes());
4668}
4669
4670Ref<SerializedScriptValue> Internals::deserializeBuffer(ArrayBuffer& buffer) const
4671{
4672 return SerializedScriptValue::createFromWireBytes(buffer.toVector());
4673}
4674
4675bool Internals::isFromCurrentWorld(JSC::JSValue value) const
4676{
4677 if (!value.isObject())
4678 return true;
4679
4680 auto* realm = value.getObject()->realmMayBeNull();
4681 if (!realm)
4682 return false;
4683
4684 JSC::VM& vm = contextDocument()->vm();
4685 return &worldForDOMObject(*value.getObject()) == &currentWorld(*vm.topCallFrame->lexicalGlobalObject(vm));
4686}
4687
4688JSC::JSValue Internals::evaluateInWorldIgnoringException(const String& name, const String& source)
4689{
4690 auto* document = contextDocument();
4691 if (!document || !document->frame())
4692 return JSC::jsNull();
4693
4694 auto& scriptController = document->frame()->script();
4695 auto world = ScriptController::createWorld(name);
4696 return scriptController.executeScriptInWorldIgnoringException(world, source, JSC::SourceTaintedOrigin::Untainted);
4697}
4698
4699#if !PLATFORM(MAC)(defined WTF_PLATFORM_MAC && WTF_PLATFORM_MAC)
4700void Internals::setUsesOverlayScrollbars(bool enabled)
4701{
4702 WebCore::DeprecatedGlobalSettings::setUsesOverlayScrollbars(enabled);
4703}
4704#endif
4705
4706void Internals::forceAXObjectCacheUpdate() const
4707{
4708 if (RefPtr document = contextDocument()) {
4709 if (CheckedPtr cache = document->axObjectCache())
4710 cache->performDeferredCacheUpdate(ForceLayout::Yes);
4711 }
4712}
4713
4714void Internals::setShouldMockParentSearchResultsForTesting(bool enabled)
4715{
4716 WebCore::setShouldMockParentSearchResultsForTesting(enabled);
4717}
4718
4719void Internals::setShouldMockChildFrameSearchResultsForTesting(bool enabled)
4720{
4721 WebCore::setShouldMockChildFrameSearchResultsForTesting(enabled);
4722}
4723
4724void Internals::forceReload(bool endToEnd)
4725{
4726 OptionSet<ReloadOption> reloadOptions;
4727 if (endToEnd)
4728 reloadOptions.add(ReloadOption::FromOrigin);
4729
4730 if (RefPtr localFrame = frame())
4731 localFrame->loader().reload(reloadOptions);
4732}
4733
4734void Internals::reloadExpiredOnly()
4735{
4736 if (RefPtr localFrame = frame())
4737 localFrame->loader().reload(ReloadOption::ExpiredOnly);
4738}
4739
4740void Internals::enableFixedWidthAutoSizeMode(bool enabled, int width, int height)
4741{
4742 auto* document = contextDocument();
4743 if (!document || !document->view())
4744 return;
4745 document->view()->enableFixedWidthAutoSizeMode(enabled, { width, height });
4746}
4747
4748void Internals::enableSizeToContentAutoSizeMode(bool enabled, int width, int height)
4749{
4750 auto* document = contextDocument();
4751 if (!document || !document->view())
4752 return;
4753 document->view()->enableSizeToContentAutoSizeMode(enabled, { width, height });
4754}
4755
4756#if ENABLE(LEGACY_ENCRYPTED_MEDIA)(defined 1 && 1)
4757
4758void Internals::initializeMockCDM()
4759{
4760 LegacyCDM::registerCDMFactory([] (LegacyCDM& cdm) { return makeUniqueWithoutRefCountedCheck<LegacyMockCDM>(cdm); },
4761 LegacyMockCDM::supportsKeySystem, LegacyMockCDM::supportsKeySystemAndMimeType);
4762}
4763
4764#endif
4765
4766#if ENABLE(ENCRYPTED_MEDIA)(defined 1 && 1)
4767
4768Ref<MockCDMFactory> Internals::registerMockCDM()
4769{
4770 return MockCDMFactory::create();
4771}
4772
4773#endif
4774
4775String Internals::markerTextForListItem(Element& element)
4776{
4777 return WebCore::markerTextForListItem(&element);
4778}
4779
4780String Internals::toolTipFromElement(Element& element) const
4781{
4782 HitTestResult result;
4783 result.setInnerNode(&element);
4784 TextDirection direction;
4785 auto title = result.title(direction);
4786 return !title.isEmpty() ? title : result.innerTextIfTruncated(direction);
4787}
4788
4789String Internals::getImageSourceURL(Element& element)
4790{
4791 return element.imageSourceURL();
4792}
4793
4794#if ENABLE(VIDEO)(defined 1 && 1)
4795
4796unsigned Internals::mediaElementCount()
4797{
4798 Document* document = contextDocument();
4799 if (!document)
4800 return 0;
4801
4802 unsigned number = 0;
4803 for (auto& mediaElement : HTMLMediaElement::allMediaElements()) {
4804 if (&mediaElement->document() == document)
4805 ++number;
4806 }
4807
4808 return number;
4809}
4810
4811Vector<String> Internals::mediaResponseSources(HTMLMediaElement& media)
4812{
4813 auto* resourceLoader = media.lastMediaResourceLoaderForTesting();
4814 if (!resourceLoader)
4815 return { };
4816 Vector<String> result;
4817 auto responses = resourceLoader->responsesForTesting();
4818 for (auto& response : responses)
4819 result.append(responseSourceToString(response));
4820 return result;
4821}
4822
4823Vector<String> Internals::mediaResponseContentRanges(HTMLMediaElement& media)
4824{
4825 auto* resourceLoader = media.lastMediaResourceLoaderForTesting();
4826 if (!resourceLoader)
4827 return { };
4828 Vector<String> result;
4829 auto responses = resourceLoader->responsesForTesting();
4830 for (auto& response : responses)
4831 result.append(response.httpHeaderField(HTTPHeaderName::ContentRange));
4832 return result;
4833}
4834
4835void Internals::simulateAudioInterruption(HTMLMediaElement& element)
4836{
4837#if USE(GSTREAMER)(defined USE_GSTREAMER && USE_GSTREAMER)
4838 protect(element.player())->simulateAudioInterruption();
4839#else
4840 UNUSED_PARAM(element)(void)element;
4841#endif
4842}
4843
4844ExceptionOr<bool> Internals::mediaElementHasCharacteristic(HTMLMediaElement& element, const String& characteristic)
4845{
4846 if (equalLettersIgnoringASCIICase(characteristic, "audible"_s))
4847 return element.hasAudio();
4848 if (equalLettersIgnoringASCIICase(characteristic, "visual"_s))
4849 return element.hasVideo();
4850 if (equalLettersIgnoringASCIICase(characteristic, "legible"_s))
4851 return element.hasClosedCaptions();
4852
4853 return Exception { ExceptionCode::SyntaxError };
4854}
4855
4856void Internals::enterViewerMode(HTMLVideoElement& element)
4857{
4858 element.enterFullscreen(HTMLMediaElementEnums::VideoFullscreenModeInWindow);
4859}
4860
4861ExceptionOr<bool> Internals::mediaPlayerRenderingCanBeAccelerated(HTMLMediaElement& element)
4862{
4863 return element.mediaPlayerRenderingCanBeAccelerated();
4864}
4865
4866bool Internals::elementShouldBufferData(HTMLMediaElement& element)
4867{
4868 return element.bufferingPolicy() < MediaPlayer::BufferingPolicy::LimitReadAhead;
4869}
4870
4871String Internals::elementBufferingPolicy(HTMLMediaElement& element)
4872{
4873 switch (element.bufferingPolicy()) {
4874 case MediaPlayer::BufferingPolicy::Default:
4875 return "Default"_s;
4876 case MediaPlayer::BufferingPolicy::LimitReadAhead:
4877 return "LimitReadAhead"_s;
4878 case MediaPlayer::BufferingPolicy::MakeResourcesPurgeable:
4879 return "MakeResourcesPurgeable"_s;
4880 case MediaPlayer::BufferingPolicy::PurgeResources:
4881 return "PurgeResources"_s;
4882 }
4883
4884 ASSERT_NOT_REACHED()((void)0);
4885 return "UNKNOWN"_s;
4886}
4887
4888void Internals::setMediaElementBufferingPolicy(HTMLMediaElement& element, const String& policy)
4889{
4890 if (policy == "Default"_s) {
4891 element.setBufferingPolicy(MediaPlayer::BufferingPolicy::Default);
4892 return;
4893 }
4894 if (policy == "LimitReadAhead"_s) {
4895 element.setBufferingPolicy(MediaPlayer::BufferingPolicy::LimitReadAhead);
4896 return;
4897 }
4898 if (policy == "MakeResourcesPurgeable"_s) {
4899 element.setBufferingPolicy(MediaPlayer::BufferingPolicy::MakeResourcesPurgeable);
4900 return;
4901 }
4902 if (policy == "PurgeResources"_s) {
4903 element.setBufferingPolicy(MediaPlayer::BufferingPolicy::PurgeResources);
4904 return;
4905 }
4906 ASSERT_NOT_REACHED()((void)0);
4907}
4908
4909ExceptionOr<void> Internals::setOverridePreferredDynamicRangeMode(HTMLMediaElement& element, const String& modeString)
4910{
4911 DynamicRangeMode mode;
4912 if (modeString == "None"_s)
4913 mode = DynamicRangeMode::None;
4914 else if (modeString == "Standard"_s)
4915 mode = DynamicRangeMode::Standard;
4916 else if (modeString == "HLG"_s)
4917 mode = DynamicRangeMode::HLG;
4918 else if (modeString == "HDR10"_s)
4919 mode = DynamicRangeMode::HDR10;
4920 else if (modeString == "DolbyVisionPQ"_s)
4921 mode = DynamicRangeMode::DolbyVisionPQ;
4922 else
4923 return Exception { ExceptionCode::SyntaxError };
4924
4925 element.setOverridePreferredDynamicRangeMode(mode);
4926 return { };
4927}
4928
4929void Internals::enableGStreamerHolePunching(HTMLVideoElement& element)
4930{
4931#if USE(GSTREAMER)(defined USE_GSTREAMER && USE_GSTREAMER)
4932 element.enableGStreamerHolePunching();
4933#else
4934 UNUSED_PARAM(element)(void)element;
4935#endif
4936}
4937
4938double Internals::effectiveDynamicRangeLimitValue(const HTMLMediaElement& media)
4939{
4940 return media.computePlayerDynamicRangeLimit().value();
4941}
4942
4943#if ENABLE(FULLSCREEN_API)(defined 1 && 1)
4944bool Internals::isChildOfElementFullscreen(const HTMLMediaElement& media) const
4945{
4946 return media.isChildOfElementFullscreen();
4947}
4948#endif
4949
4950#endif
4951
4952ExceptionOr<double> Internals::getContextEffectiveDynamicRangeLimitValue(const HTMLCanvasElement& canvas)
4953{
4954 auto value = canvas.getContextEffectiveDynamicRangeLimitValue();
4955 if (value.has_value())
4956 return *value;
4957 return Exception { ExceptionCode::InvalidStateError };
4958}
4959
4960ExceptionOr<void> Internals::setPageShouldSuppressHDR(bool shouldSuppressHDR)
4961{
4962 Document* document = contextDocument();
4963 if (!document || !document->page())
4964 return Exception { ExceptionCode::InvalidAccessError };
4965
4966 document->page()->setShouldSuppressHDR(shouldSuppressHDR);
4967 return { };
4968}
4969
4970bool Internals::isSelectPopupVisible(HTMLSelectElement& element)
4971{
4972 element.document().updateLayout(LayoutOptions::IgnorePendingStylesheets);
4973
4974#if !PLATFORM(IOS_FAMILY)(defined 1 && 1)
4975 return element.popupIsVisible();
4976#else
4977 return false;
4978#endif
4979}
4980
4981ExceptionOr<String> Internals::captionsStyleSheetOverride()
4982{
4983 Document* document = contextDocument();
4984 if (!document || !document->page())
4985 return Exception { ExceptionCode::InvalidAccessError };
4986
4987#if ENABLE(VIDEO)(defined 1 && 1)
4988 return document->page()->group().ensureCaptionPreferences().captionsStyleSheetOverride();
4989#else
4990 return String { emptyString() };
4991#endif
4992}
4993
4994ExceptionOr<void> Internals::setCaptionsStyleSheetOverride(const String& override)
4995{
4996 Document* document = contextDocument();
4997 if (!document || !document->page())
4998 return Exception { ExceptionCode::InvalidAccessError };
4999
5000#if ENABLE(VIDEO)(defined 1 && 1)
5001 document->page()->group().ensureCaptionPreferences().setCaptionsStyleSheetOverride(override);
5002#else
5003 UNUSED_PARAM(override)(void)override;
5004#endif
5005 return { };
5006}
5007
5008ExceptionOr<void> Internals::setPrimaryAudioTrackLanguageOverride(const String& language)
5009{
5010 Document* document = contextDocument();
5011 if (!document || !document->page())
5012 return Exception { ExceptionCode::InvalidAccessError };
5013
5014#if ENABLE(VIDEO)(defined 1 && 1)
5015 document->page()->group().ensureCaptionPreferences().setPrimaryAudioTrackLanguageOverride(language);
5016#else
5017 UNUSED_PARAM(language)(void)language;
5018#endif
5019 return { };
5020}
5021
5022ExceptionOr<void> Internals::setPreferredAudioCharacteristicsForTesting(const Vector<String>& characteristics)
5023{
5024 Document* document = contextDocument();
5025 if (!document || !document->page())
5026 return Exception { ExceptionCode::InvalidAccessError };
5027
5028#if ENABLE(VIDEO)(defined 1 && 1)
5029 document->page()->group().ensureCaptionPreferences().setPreferredAudioCharacteristicsForTesting(characteristics);
5030#else
5031 UNUSED_PARAM(characteristics)(void)characteristics;
5032#endif
5033 return { };
5034}
5035
5036ExceptionOr<void> Internals::setCaptionDisplayMode(const String& mode)
5037{
5038 Document* document = contextDocument();
5039 if (!document || !document->page())
5040 return Exception { ExceptionCode::InvalidAccessError };
5041
5042#if ENABLE(VIDEO)(defined 1 && 1)
5043 auto& captionPreferences = document->page()->group().ensureCaptionPreferences();
5044
5045 if (equalLettersIgnoringASCIICase(mode, "automatic"_s))
5046 captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::CaptionDisplayMode::Automatic);
5047 else if (equalLettersIgnoringASCIICase(mode, "forcedonly"_s))
5048 captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::CaptionDisplayMode::ForcedOnly);
5049 else if (equalLettersIgnoringASCIICase(mode, "alwayson"_s))
5050 captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::CaptionDisplayMode::AlwaysOn);
5051 else if (equalLettersIgnoringASCIICase(mode, "manual"_s))
5052 captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::CaptionDisplayMode::Manual);
5053 else
5054 return Exception { ExceptionCode::SyntaxError };
5055#else
5056 UNUSED_PARAM(mode)(void)mode;
5057#endif
5058 return { };
5059}
5060
5061String Internals::captionDisplayMode() const
5062{
5063 Document* document = contextDocument();
5064 if (!document || !document->page())
5065 return emptyString();
5066
5067#if ENABLE(VIDEO)(defined 1 && 1)
5068 switch (document->page()->group().ensureCaptionPreferences().captionDisplayMode()) {
5069 case CaptionUserPreferences::CaptionDisplayMode::Automatic:
5070 return "automatic"_s;
5071 case CaptionUserPreferences::CaptionDisplayMode::ForcedOnly:
5072 return "forcedonly"_s;
5073 case CaptionUserPreferences::CaptionDisplayMode::AlwaysOn:
5074 return "alwayson"_s;
5075 case CaptionUserPreferences::CaptionDisplayMode::Manual:
5076 return "manual"_s;
5077 }
5078#endif
5079 return emptyString();
5080}
5081
5082#if ENABLE(VIDEO)(defined 1 && 1)
5083RefPtr<TextTrackCueGeneric> Internals::createGenericCue(double startTime, double endTime, String text)
5084{
5085 Document* document = contextDocument();
5086 if (!document || !document->page())
5087 return nullptr;
5088 return TextTrackCueGeneric::create(*document, MediaTime::createWithDouble(startTime), MediaTime::createWithDouble(endTime), text);
5089}
5090
5091ExceptionOr<String> Internals::textTrackBCP47Language(TextTrack& track)
5092{
5093 return String { track.validBCP47Language() };
5094}
5095
5096Ref<TimeRanges> Internals::createTimeRanges(Float32Array& startTimes, Float32Array& endTimes)
5097{
5098 ASSERT(startTimes.length() == endTimes.length())((void)0);
5099 Ref<TimeRanges> ranges = TimeRanges::create();
5100
5101 unsigned count = std::min(startTimes.length(), endTimes.length());
5102 for (unsigned i = 0; i < count; ++i)
5103 ranges->add(startTimes.item(i), endTimes.item(i));
5104 return ranges;
5105}
5106
5107double Internals::closestTimeToTimeRanges(double time, TimeRanges& ranges)
5108{
5109 return ranges.nearest(time);
5110}
5111
5112void Internals::showCaptionDisplaySettingsPreviewForMediaElement(HTMLMediaElement& element)
5113{
5114 element.showCaptionDisplaySettingsPreview();
5115}
5116
5117void Internals::hideCaptionDisplaySettingsPreviewForMediaElement(HTMLMediaElement& element)
5118{
5119 element.hideCaptionDisplaySettingsPreview();
5120}
5121
5122void Internals::setMockCaptionDisplaySettingsClientCallback(RefPtr<MockCaptionDisplaySettingsClientCallback>&& callback)
5123{
5124 if (m_mockCaptionDisplaySettingsClientCallback == callback)
5125 return;
5126
5127 m_mockCaptionDisplaySettingsClientCallback = WTF::move(callback);
5128
5129 auto frame = this->frame();
5130 if (!frame)
5131 return;
5132
5133 auto page = frame->page();
5134 if (!page)
5135 return;
5136
5137 page->clearCaptionDisplaySettingsClientForTesting();
5138 if (m_mockCaptionDisplaySettingsClientCallback)
5139 page->setCaptionDisplaySettingsClientForTesting(*m_mockCaptionDisplaySettingsClientCallback);
5140}
5141
5142MockCaptionDisplaySettingsClientCallback* Internals::mockCaptionDisplaySettingsClientCallback() const
5143{
5144 return m_mockCaptionDisplaySettingsClientCallback.get();
5145}
5146
5147RefPtr<MediaControlsHost> Internals::controlsHostForMediaElement(HTMLMediaElement& mediaElement)
5148{
5149 return mediaElement.mediaControlsHost();
5150}
5151#endif
5152
5153ExceptionOr<Ref<DOMRect>> Internals::selectionBounds()
5154{
5155 Document* document = contextDocument();
5156 if (!document || !document->frame())
5157 return Exception { ExceptionCode::InvalidAccessError };
5158
5159 return DOMRect::create(document->frame()->selection().selectionBounds());
5160}
5161
5162ExceptionOr<RefPtr<StaticRange>> Internals::selectedRange()
5163{
5164 RefPtr document = contextDocument();
5165 if (!document)
5166 return Exception { ExceptionCode::InvalidAccessError };
5167 auto range = contextDocument()->selection().selection().range();
5168 if (!range)
5169 return nullptr;
5170 return RefPtr { StaticRange::create(*range) };
5171}
5172
5173void Internals::setSelectionWithoutValidation(Ref<Node> baseNode, unsigned baseOffset, RefPtr<Node> extentNode, unsigned extentOffset)
5174{
5175 contextDocument()->frame()->selection().moveTo(
5176 VisiblePosition { makeDeprecatedLegacyPosition(baseNode.ptr(), baseOffset) },
5177 VisiblePosition { makeDeprecatedLegacyPosition(extentNode.get(), extentOffset) });
5178}
5179
5180void Internals::setSelectionFromNone()
5181{
5182 if (RefPtr localFrame = frame())
5183 localFrame->selection().setSelectionFromNone();
5184}
5185
5186#if ENABLE(MEDIA_SOURCE)(defined 1 && 1)
5187
5188void Internals::initializeMockMediaSource()
5189{
5190 RefPtr document = contextDocument();
5191 if (!document || (!document->settings().mediaSourceEnabled() && !document->settings().managedMediaSourceEnabled()))
5192 return;
5193
5194 platformStrategies()->mediaStrategy()->enableMockMediaSource();
5195}
5196
5197void Internals::setMaximumSourceBufferSize(SourceBuffer& buffer, uint64_t maximumSize, DOMPromiseDeferred<void>&& promise)
5198{
5199 buffer.setMaximumSourceBufferSize(maximumSize)->whenSettled(RunLoop::currentSingleton(), [promise = WTF::move(promise)]() mutable {
5200 promise.resolve();
5201 });
5202}
5203
5204void Internals::bufferedSamplesForTrackId(SourceBuffer& buffer, const AtomString& trackId, BufferedSamplesPromise&& promise)
5205{
5206 buffer.bufferedSamplesForTrackId(parseInteger<uint64_t>(trackId).value_or(0))->whenSettled(RunLoop::currentSingleton(), [promise = WTF::move(promise)](auto&& samples) mutable {
5207 if (!samples) {
5208 promise.reject(Exception { ExceptionCode::OperationError, makeString("Error "_s, samples.error()) });
5209 return;
5210 }
5211 promise.resolve(WTF::move(*samples));
5212 });
5213}
5214
5215void Internals::enqueuedSamplesForTrackID(SourceBuffer& buffer, const AtomString& trackID, BufferedSamplesPromise&& promise)
5216{
5217 buffer.enqueuedSamplesForTrackID(parseInteger<uint64_t>(trackID).value_or(0))->whenSettled(RunLoop::currentSingleton(), [promise = WTF::move(promise)](auto&& samples) mutable {
5218 if (!samples) {
5219 promise.reject(Exception { ExceptionCode::OperationError, makeString("Error "_s, samples.error()) });
5220 return;
5221 }
5222 promise.resolve(WTF::move(*samples));
5223 });
5224}
5225
5226double Internals::minimumUpcomingPresentationTimeForTrackID(SourceBuffer& buffer, const AtomString& trackID)
5227{
5228 return buffer.minimumUpcomingPresentationTimeForTrackID(parseInteger<TrackID>(trackID).value_or(0)).toDouble();
5229}
5230
5231void Internals::setShouldGenerateTimestamps(SourceBuffer& buffer, bool flag)
5232{
5233 buffer.setShouldGenerateTimestamps(flag);
5234}
5235
5236void Internals::setMaximumQueueDepthForTrackID(SourceBuffer& buffer, const AtomString& trackID, size_t maxQueueDepth)
5237{
5238 buffer.setMaximumQueueDepthForTrackID(parseInteger<TrackID>(trackID).value_or(0), maxQueueDepth);
5239}
5240
5241size_t Internals::evictableSize(SourceBuffer& buffer)
5242{
5243 return buffer.evictableSize();
5244}
5245
5246#endif
5247
5248void Internals::enableMockMediaCapabilities()
5249{
5250 PlatformMediaEngineConfigurationFactory::enableMock();
5251}
5252
5253#if ENABLE(VIDEO)(defined 1 && 1)
5254
5255ExceptionOr<void> Internals::beginMediaSessionInterruption(const String& interruptionString)
5256{
5257 RefPtr manager = sessionManager();
5258 if (!manager)
5259 return Exception { ExceptionCode::InvalidAccessError };
5260
5261 PlatformMediaSession::InterruptionType interruption = PlatformMediaSession::InterruptionType::SystemInterruption;
5262
5263 if (equalLettersIgnoringASCIICase(interruptionString, "system"_s))
5264 interruption = PlatformMediaSession::InterruptionType::SystemInterruption;
5265 else if (equalLettersIgnoringASCIICase(interruptionString, "systemsleep"_s))
5266 interruption = PlatformMediaSession::InterruptionType::SystemSleep;
5267 else if (equalLettersIgnoringASCIICase(interruptionString, "enteringbackground"_s))
5268 interruption = PlatformMediaSession::InterruptionType::EnteringBackground;
5269 else if (equalLettersIgnoringASCIICase(interruptionString, "suspendedunderlock"_s))
5270 interruption = PlatformMediaSession::InterruptionType::SuspendedUnderLock;
5271 else
5272 return Exception { ExceptionCode::InvalidAccessError };
5273
5274 manager->beginInterruption(interruption);
5275 return { };
5276}
5277
5278void Internals::endMediaSessionInterruption(const String& flagsString)
5279{
5280 PlatformMediaSession::EndInterruptionFlags flags = PlatformMediaSession::EndInterruptionFlags::NoFlags;
5281
5282 if (equalLettersIgnoringASCIICase(flagsString, "mayresumeplaying"_s))
5283 flags = PlatformMediaSession::EndInterruptionFlags::MayResumePlaying;
5284
5285 if (RefPtr manager = sessionManager())
5286 manager->endInterruption(flags);
5287}
5288
5289void Internals::applicationWillBecomeInactive()
5290{
5291 if (RefPtr manager = sessionManager())
5292 manager->applicationWillBecomeInactive();
5293}
5294
5295void Internals::applicationDidBecomeActive()
5296{
5297 if (RefPtr manager = sessionManager())
5298 manager->applicationDidBecomeActive();
5299}
5300
5301void Internals::applicationWillEnterForeground(bool suspendedUnderLock) const
5302{
5303 if (RefPtr manager = sessionManager())
5304 manager->applicationWillEnterForeground(suspendedUnderLock);
5305}
5306
5307void Internals::applicationDidEnterBackground(bool suspendedUnderLock) const
5308{
5309 if (RefPtr manager = sessionManager())
5310 manager->applicationDidEnterBackground(suspendedUnderLock);
5311}
5312
5313static PlatformMediaSession::MediaType mediaTypeFromString(const String& mediaTypeString)
5314{
5315 if (equalLettersIgnoringASCIICase(mediaTypeString, "video"_s))
5316 return PlatformMediaSession::MediaType::Video;
5317 if (equalLettersIgnoringASCIICase(mediaTypeString, "audio"_s))
5318 return PlatformMediaSession::MediaType::Audio;
5319 if (equalLettersIgnoringASCIICase(mediaTypeString, "videoaudio"_s))
5320 return PlatformMediaSession::MediaType::VideoAudio;
5321 if (equalLettersIgnoringASCIICase(mediaTypeString, "webaudio"_s))
5322 return PlatformMediaSession::MediaType::WebAudio;
5323
5324 return PlatformMediaSession::MediaType::None;
5325}
5326
5327ExceptionOr<void> Internals::setMediaSessionRestrictions(const String& mediaTypeString, StringView restrictionsString)
5328{
5329 auto mediaType = mediaTypeFromString(mediaTypeString);
5330 if (mediaType == PlatformMediaSession::MediaType::None)
5331 return Exception { ExceptionCode::InvalidAccessError };
5332
5333 RefPtr manager = sessionManager();
5334 if (!manager)
5335 return Exception { ExceptionCode::InvalidAccessError };
5336
5337 auto restrictions = manager->restrictions(mediaType);
5338 manager->removeRestriction(mediaType, restrictions);
5339
5340 restrictions = MediaSessionRestriction::NoRestrictions;
5341
5342 for (StringView restrictionString : restrictionsString.split(',')) {
5343 if (equalLettersIgnoringASCIICase(restrictionString, "concurrentplaybacknotpermitted"_s))
5344 restrictions |= MediaSessionRestriction::ConcurrentPlaybackNotPermitted;
5345 if (equalLettersIgnoringASCIICase(restrictionString, "backgroundprocessplaybackrestricted"_s))
5346 restrictions |= MediaSessionRestriction::BackgroundProcessPlaybackRestricted;
5347 if (equalLettersIgnoringASCIICase(restrictionString, "backgroundtabplaybackrestricted"_s))
5348 restrictions |= MediaSessionRestriction::BackgroundTabPlaybackRestricted;
5349 if (equalLettersIgnoringASCIICase(restrictionString, "interruptedplaybacknotpermitted"_s))
5350 restrictions |= MediaSessionRestriction::InterruptedPlaybackNotPermitted;
5351 if (equalLettersIgnoringASCIICase(restrictionString, "inactiveprocessplaybackrestricted"_s))
5352 restrictions |= MediaSessionRestriction::InactiveProcessPlaybackRestricted;
5353 if (equalLettersIgnoringASCIICase(restrictionString, "suspendedunderlockplaybackrestricted"_s))
5354 restrictions |= MediaSessionRestriction::SuspendedUnderLockPlaybackRestricted;
5355 }
5356 manager->addRestriction(mediaType, restrictions);
5357 return { };
5358}
5359
5360ExceptionOr<String> Internals::mediaSessionRestrictions(const String& mediaTypeString) const
5361{
5362 PlatformMediaSession::MediaType mediaType = mediaTypeFromString(mediaTypeString);
5363 if (mediaType == PlatformMediaSession::MediaType::None)
5364 return Exception { ExceptionCode::InvalidAccessError };
5365
5366 RefPtr manager = sessionManager();
5367 if (!manager)
5368 return Exception { ExceptionCode::InvalidAccessError };
5369
5370 auto restrictions = manager->restrictions(mediaType);
5371 if (restrictions == MediaSessionRestriction::NoRestrictions)
5372 return String();
5373
5374 StringBuilder builder;
5375 if (restrictions & MediaSessionRestriction::ConcurrentPlaybackNotPermitted)
5376 builder.append("concurrentplaybacknotpermitted"_s);
5377 if (restrictions & MediaSessionRestriction::BackgroundProcessPlaybackRestricted) {
5378 if (!builder.isEmpty())
5379 builder.append(',');
5380 builder.append("backgroundprocessplaybackrestricted"_s);
5381 }
5382 if (restrictions & MediaSessionRestriction::BackgroundTabPlaybackRestricted) {
5383 if (!builder.isEmpty())
5384 builder.append(',');
5385 builder.append("backgroundtabplaybackrestricted"_s);
5386 }
5387 if (restrictions & MediaSessionRestriction::InterruptedPlaybackNotPermitted) {
5388 if (!builder.isEmpty())
5389 builder.append(',');
5390 builder.append("interruptedplaybacknotpermitted"_s);
5391 }
5392 return String { builder.toString() };
5393}
5394
5395void Internals::setMediaElementRestrictions(HTMLMediaElement& element, StringView restrictionsString)
5396{
5397 MediaElementSession::BehaviorRestrictions restrictions = element.mediaSession().behaviorRestrictions();
5398 element.mediaSession().removeBehaviorRestriction(restrictions);
5399
5400 restrictions = MediaElementSession::NoRestrictions;
5401
5402 for (StringView restrictionString : restrictionsString.split(',')) {
5403 if (equalLettersIgnoringASCIICase(restrictionString, "norestrictions"_s))
5404 restrictions |= MediaElementSession::NoRestrictions;
5405 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforload"_s))
5406 restrictions |= MediaElementSession::RequireUserGestureForLoad;
5407 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforvideoratechange"_s))
5408 restrictions |= MediaElementSession::RequireUserGestureForVideoRateChange;
5409 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforfullscreen"_s))
5410 restrictions |= MediaElementSession::RequireUserGestureForFullscreen;
5411 if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsenttoloadmedia"_s))
5412 restrictions |= MediaElementSession::RequirePageConsentToLoadMedia;
5413 if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsenttoresumemedia"_s))
5414 restrictions |= MediaElementSession::RequirePageConsentToResumeMedia;
5415#if ENABLE(WIRELESS_PLAYBACK_TARGET)(defined 1 && 1)
5416 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergesturetoshowplaybacktargetpicker"_s))
5417 restrictions |= MediaElementSession::RequireUserGestureToShowPlaybackTargetPicker;
5418 if (equalLettersIgnoringASCIICase(restrictionString, "wirelessvideoplaybackdisabled"_s))
5419 restrictions |= MediaElementSession::WirelessVideoPlaybackDisabled;
5420#endif
5421 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforaudioratechange"_s))
5422 restrictions |= MediaElementSession::RequireUserGestureForAudioRateChange;
5423 if (equalLettersIgnoringASCIICase(restrictionString, "autopreloadingnotpermitted"_s))
5424 restrictions |= MediaElementSession::AutoPreloadingNotPermitted;
5425 if (equalLettersIgnoringASCIICase(restrictionString, "invisibleautoplaynotpermitted"_s))
5426 restrictions |= MediaElementSession::InvisibleAutoplayNotPermitted;
5427 if (equalLettersIgnoringASCIICase(restrictionString, "overrideusergesturerequirementformaincontent"_s))
5428 restrictions |= MediaElementSession::OverrideUserGestureRequirementForMainContent;
5429 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergesturetocontrolcontrolsmanager"_s))
5430 restrictions |= MediaElementSession::RequireUserGestureToControlControlsManager;
5431 if (equalLettersIgnoringASCIICase(restrictionString, "requireplaybackTocontrolcontrolsmanager"_s))
5432 restrictions |= MediaElementSession::RequirePlaybackToControlControlsManager;
5433 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforvideoduetolowpowermode"_s))
5434 restrictions |= MediaElementSession::RequireUserGestureForVideoDueToLowPowerMode;
5435 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforvideoduetoaggressivethermalmitigation"_s))
5436 restrictions |= MediaElementSession::RequireUserGestureForVideoDueToAggressiveThermalMitigation;
5437 if (equalLettersIgnoringASCIICase(restrictionString, "requirepagevisibilitytoplayaudio"_s))
5438 restrictions |= MediaElementSession::RequirePageVisibilityToPlayAudio;
5439#if ENABLE(REQUIRES_PAGE_VISIBILITY_FOR_NOW_PLAYING)(defined ENABLE_REQUIRES_PAGE_VISIBILITY_FOR_NOW_PLAYING &&
ENABLE_REQUIRES_PAGE_VISIBILITY_FOR_NOW_PLAYING)
5440 if (equalLettersIgnoringASCIICase(restrictionString, "requirepagevisibilityforvideotobenowplaying"_s))
5441 restrictions |= MediaElementSession::RequirePageVisibilityForVideoToBeNowPlaying;
5442#endif
5443 }
5444 element.mediaSession().addBehaviorRestriction(restrictions);
5445}
5446
5447ExceptionOr<void> Internals::postRemoteControlCommand(const String& commandString, float argument)
5448{
5449 RefPtr manager = sessionManager();
5450 if (!manager)
5451 return Exception { ExceptionCode::InvalidAccessError };
5452
5453 PlatformMediaSession::RemoteControlCommandType command;
5454 PlatformMediaSession::RemoteCommandArgument parameter { argument, { } };
5455
5456 if (equalLettersIgnoringASCIICase(commandString, "play"_s))
5457 command = PlatformMediaSession::RemoteControlCommandType::PlayCommand;
5458 else if (equalLettersIgnoringASCIICase(commandString, "pause"_s))
5459 command = PlatformMediaSession::RemoteControlCommandType::PauseCommand;
5460 else if (equalLettersIgnoringASCIICase(commandString, "stop"_s))
5461 command = PlatformMediaSession::RemoteControlCommandType::StopCommand;
5462 else if (equalLettersIgnoringASCIICase(commandString, "toggleplaypause"_s))
5463 command = PlatformMediaSession::RemoteControlCommandType::TogglePlayPauseCommand;
5464 else if (equalLettersIgnoringASCIICase(commandString, "beginseekingbackward"_s))
5465 command = PlatformMediaSession::RemoteControlCommandType::BeginSeekingBackwardCommand;
5466 else if (equalLettersIgnoringASCIICase(commandString, "endseekingbackward"_s))
5467 command = PlatformMediaSession::RemoteControlCommandType::EndSeekingBackwardCommand;
5468 else if (equalLettersIgnoringASCIICase(commandString, "beginseekingforward"_s))
5469 command = PlatformMediaSession::RemoteControlCommandType::BeginSeekingForwardCommand;
5470 else if (equalLettersIgnoringASCIICase(commandString, "endseekingforward"_s))
5471 command = PlatformMediaSession::RemoteControlCommandType::EndSeekingForwardCommand;
5472 else if (equalLettersIgnoringASCIICase(commandString, "seektoplaybackposition"_s))
5473 command = PlatformMediaSession::RemoteControlCommandType::SeekToPlaybackPositionCommand;
5474 else if (equalLettersIgnoringASCIICase(commandString, "beginscrubbing"_s))
5475 command = PlatformMediaSession::RemoteControlCommandType::BeginScrubbingCommand;
5476 else if (equalLettersIgnoringASCIICase(commandString, "endscrubbing"_s))
5477 command = PlatformMediaSession::RemoteControlCommandType::EndScrubbingCommand;
5478 else
5479 return Exception { ExceptionCode::InvalidAccessError };
5480
5481 manager->processDidReceiveRemoteControlCommand(command, parameter);
5482 return { };
5483}
5484
5485void Internals::activeAudioRouteDidChange(bool shouldPause)
5486{
5487#if PLATFORM(IOS)(defined 1 && 1) || PLATFORM(VISION)(defined WTF_PLATFORM_VISION && WTF_PLATFORM_VISION)
5488 MediaSessionHelper::sharedHelper().activeAudioRouteDidChange(shouldPause ? MediaSessionHelperClient::ShouldPause::Yes : MediaSessionHelperClient::ShouldPause::No);
5489#else
5490 UNUSED_PARAM(shouldPause)(void)shouldPause;
5491#endif
5492}
5493
5494bool Internals::elementIsBlockingDisplaySleep(const HTMLMediaElement& element) const
5495{
5496 return element.isDisablingSleep();
5497}
5498
5499bool Internals::isPlayerVisibleInViewport(const HTMLMediaElement& element) const
5500{
5501 auto* player = element.player();
5502 return player && player->viewportVisibility() == HTMLMediaElement::ViewportVisibility::VisibleInViewport;
5503}
5504
5505bool Internals::isPlayerMuted(const HTMLMediaElement& element) const
5506{
5507 RefPtr player = element.player();
5508 return player && player->muted();
5509}
5510
5511bool Internals::isPlayerPaused(const HTMLMediaElement& element) const
5512{
5513 RefPtr player = element.player();
5514 return player && player->paused();
5515}
5516
5517void Internals::forceStereoDecoding(HTMLMediaElement& element)
5518{
5519 element.forceStereoDecoding();
5520}
5521
5522void Internals::beginAudioSessionInterruption()
5523{
5524#if USE(AUDIO_SESSION)(defined 1 && 1)
5525 AudioSession::singleton().beginInterruptionForTesting();
5526#endif
5527}
5528
5529
5530void Internals::endAudioSessionInterruption()
5531{
5532#if USE(AUDIO_SESSION)(defined 1 && 1)
5533 AudioSession::singleton().endInterruptionForTesting();
5534#endif
5535}
5536
5537void Internals::clearAudioSessionInterruptionFlag()
5538{
5539#if USE(AUDIO_SESSION)(defined 1 && 1)
5540 AudioSession::singleton().clearInterruptionFlagForTesting();
5541#endif
5542}
5543
5544void Internals::suspendAllMediaBuffering()
5545{
5546 auto frame = this->frame();
5547 if (!frame)
5548 return;
5549
5550 auto page = frame->page();
5551 if (!page)
5552 return;
5553
5554 page->suspendAllMediaBuffering();
5555}
5556
5557void Internals::suspendAllMediaPlayback()
5558{
5559 auto frame = this->frame();
5560 if (!frame)
5561 return;
5562
5563 auto page = frame->page();
5564 if (!page)
5565 return;
5566
5567 page->suspendAllMediaPlayback();
5568}
5569
5570void Internals::resumeAllMediaPlayback()
5571{
5572 auto frame = this->frame();
5573 if (!frame)
5574 return;
5575
5576 auto page = frame->page();
5577 if (!page)
5578 return;
5579
5580 page->resumeAllMediaPlayback();
5581}
5582
5583#endif // ENABLE(VIDEO)
5584
5585#if ENABLE(WEB_AUDIO)(defined 1 && 1)
5586void Internals::setAudioContextRestrictions(AudioContext& context, StringView restrictionsString)
5587{
5588 auto restrictions = context.behaviorRestrictions();
5589 context.removeBehaviorRestriction(restrictions);
5590
5591 restrictions = { };
5592
5593 for (StringView restrictionString : restrictionsString.split(',')) {
5594 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforaudiostart"_s))
5595 restrictions.add(AudioContext::BehaviorRestrictionFlags::RequireUserGestureForAudioStartRestriction);
5596 if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsentforaudiostart"_s))
5597 restrictions.add(AudioContext::BehaviorRestrictionFlags::RequirePageConsentForAudioStartRestriction);
5598 }
5599 context.addBehaviorRestriction(restrictions);
5600}
5601
5602Vector<float> Internals::waveShaperProcessCurveWithData(Vector<float> source, Vector<float> curve)
5603{
5604 Vector<float> destination(FillWith { }, source.size(), 0.0f);
5605 WaveShaperDSPKernel::processCurveWithData(std::span { source }, std::span { destination }, std::span { curve });
5606 return destination;
5607}
5608
5609void Internals::useMockAudioDestinationCocoa()
5610{
5611#if PLATFORM(COCOA)(defined 1 && 1)
5612 AudioDestinationCocoa::createOverride = MockAudioDestinationCocoa::create;
5613#endif
5614}
5615#endif
5616
5617void Internals::simulateSystemSleep() const
5618{
5619#if ENABLE(VIDEO)(defined 1 && 1)
5620 if (RefPtr manager = sessionManager())
5621 manager->processSystemWillSleep();
5622#endif
5623}
5624
5625void Internals::simulateSystemWake() const
5626{
5627#if ENABLE(VIDEO)(defined 1 && 1)
5628 if (RefPtr manager = sessionManager())
5629 manager->processSystemDidWake();
5630#endif
5631}
5632
5633std::optional<Internals::NowPlayingMetadata> Internals::nowPlayingMetadata() const
5634{
5635 RefPtr manager = sessionManager();
5636 if (!manager)
5637 return std::nullopt;
5638
5639 if (auto nowPlayingInfo = manager->nowPlayingInfo()) {
5640 return { {
5641 nowPlayingInfo->metadata.title,
5642 nowPlayingInfo->metadata.artist,
5643 nowPlayingInfo->metadata.album,
5644 nowPlayingInfo->metadata.sourceApplicationIdentifier,
5645 nowPlayingInfo->metadata.artwork ? std::optional { NowPlayingInfoArtwork {
5646 nowPlayingInfo->metadata.artwork->src,
5647 nowPlayingInfo->metadata.artwork->mimeType
5648 } } : std::nullopt,
5649 } };
5650 }
5651
5652 return std::nullopt;
5653}
5654
5655ExceptionOr<Internals::NowPlayingState> Internals::nowPlayingState() const
5656{
5657#if ENABLE(VIDEO)(defined 1 && 1)
5658 RefPtr manager = sessionManager();
5659 if (!manager)
5660 return Exception { ExceptionCode::InvalidAccessError };
5661
5662 auto lastUpdatedNowPlayingInfoUniqueIdentifier = manager->lastUpdatedNowPlayingInfoUniqueIdentifier();
5663 return { { manager->lastUpdatedNowPlayingTitle(),
5664 manager->lastUpdatedNowPlayingDuration(),
5665 manager->lastUpdatedNowPlayingElapsedTime(),
5666 lastUpdatedNowPlayingInfoUniqueIdentifier ? lastUpdatedNowPlayingInfoUniqueIdentifier->toUInt64() : 0,
5667 manager->hasActiveNowPlayingSession(),
5668 manager->registeredAsNowPlayingApplication(),
5669 manager->haveEverRegisteredAsNowPlayingApplication()
5670 } };
5671#else
5672 return Exception { ExceptionCode::InvalidAccessError };
5673#endif
5674}
5675
5676void Internals::setNowPlayingUpdateInterval(double interval)
5677{
5678 if (RefPtr manager = sessionManager())
5679 manager->setNowPlayingUpdateInterval(interval);
5680}
5681
5682ExceptionOr<double> Internals::nowPlayingUpdateInterval() const
5683{
5684 RefPtr manager = sessionManager();
5685 if (!manager)
5686 return Exception { ExceptionCode::InvalidAccessError };
5687
5688 return manager->nowPlayingUpdateInterval();
5689}
5690
5691
5692#if ENABLE(VIDEO)(defined 1 && 1)
5693RefPtr<HTMLMediaElement> Internals::bestMediaElementForRemoteControls(Internals::PlaybackControlsPurpose purpose)
5694{
5695 RefPtr document = contextDocument();
5696 if (!document || !document->page())
5697 return nullptr;
5698
5699 return protect(document->page())->bestMediaElementForRemoteControls(purpose, document.get());
5700}
5701
5702Internals::MediaSessionState Internals::mediaSessionState(HTMLMediaElement& element)
5703{
5704 return static_cast<Internals::MediaSessionState>(element.mediaSession().state());
5705}
5706#endif
5707
5708ExceptionOr<Internals::MediaUsageState> Internals::mediaUsageState(HTMLMediaElement& element) const
5709{
5710#if ENABLE(VIDEO)(defined 1 && 1)
5711 element.mediaSession().updateMediaUsageIfChanged();
5712 auto info = element.mediaSession().mediaUsageInfo();
5713 if (!info)
5714 return Exception { ExceptionCode::NotSupportedError };
5715
5716 return { { info.value().mediaURL.string(),
5717 info.value().isPlaying,
5718 info.value().canShowControlsManager,
5719 info.value().canShowNowPlayingControls,
5720 info.value().isSuspended,
5721 info.value().isInActiveDocument,
5722 info.value().isFullscreen,
5723 info.value().isMuted,
5724 info.value().isMediaDocumentInMainFrame,
5725 info.value().isVideo,
5726 info.value().isAudio,
5727 info.value().hasVideo,
5728 info.value().hasAudio,
5729 info.value().hasRenderer,
5730 info.value().audioElementWithUserGesture,
5731 info.value().userHasPlayedAudioBefore,
5732 info.value().isElementRectMostlyInMainFrame,
5733 info.value().playbackPermitted,
5734 info.value().pageMediaPlaybackSuspended,
5735 info.value().isMediaDocumentAndNotOwnerElement,
5736 info.value().pageExplicitlyAllowsElementToAutoplayInline,
5737 info.value().requiresFullscreenForVideoPlaybackAndFullscreenNotPermitted,
5738 info.value().isVideoAndRequiresUserGestureForVideoRateChange,
5739 info.value().isAudioAndRequiresUserGestureForAudioRateChange,
5740 info.value().isVideoAndRequiresUserGestureForVideoDueToLowPowerMode,
5741 info.value().isVideoAndRequiresUserGestureForVideoDueToAggressiveThermalMitigation,
5742 info.value().noUserGestureRequired,
5743 info.value().requiresPlaybackAndIsNotPlaying,
5744 info.value().hasEverNotifiedAboutPlaying,
5745 info.value().outsideOfFullscreen,
5746 info.value().isLargeEnoughForMainContent,
5747 } };
5748
5749#else
5750 UNUSED_PARAM(element)(void)element;
5751 return Exception { ExceptionCode::InvalidAccessError };
5752#endif
5753}
5754
5755ExceptionOr<bool> Internals::elementShouldDisplayPosterImage(HTMLVideoElement& element) const
5756{
5757#if ENABLE(VIDEO)(defined 1 && 1)
5758 return element.shouldDisplayPosterImage();
5759#else
5760 UNUSED_PARAM(element)(void)element;
5761 return Exception { ExceptionCode::InvalidAccessError };
5762#endif
5763}
5764
5765#if ENABLE(VIDEO)(defined 1 && 1)
5766size_t Internals::mediaElementCount() const
5767{
5768 return HTMLMediaElement::allMediaElements().size();
5769}
5770
5771void Internals::setMediaElementVolumeLocked(HTMLMediaElement& element, bool volumeLocked)
5772{
5773 element.setVolumeLocked(volumeLocked);
5774}
5775
5776#if ENABLE(SPEECH_SYNTHESIS)(defined 1 && 1)
5777SpeechSynthesisUtterance* Internals::speechSynthesisUtteranceForCue(const VTTCue& cue)
5778{
5779 return cue.speechUtterance();
5780}
5781
5782ExceptionOr<RefPtr<VTTCue>> Internals::mediaElementCurrentlySpokenCue(HTMLMediaElement& element)
5783{
5784 RefPtr cue = dynamicDowncast<VTTCue>(element.cueBeingSpoken());
5785 ASSERT(cue)((void)0);
5786 if (!cue)
5787 return Exception { ExceptionCode::InvalidAccessError };
5788
5789 return cue;
5790}
5791#endif
5792
5793bool Internals::elementIsActiveNowPlayingSession(HTMLMediaElement& element) const
5794{
5795 return element.isActiveNowPlayingSession();
5796}
5797
5798#endif // ENABLE(VIDEO)
5799
5800#if ENABLE(WIRELESS_PLAYBACK_TARGET)(defined 1 && 1)
5801void Internals::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
5802{
5803 auto frame = this->frame();
5804 if (!frame || !frame->page())
5805 return;
5806
5807 frame->page()->setMockMediaPlaybackTargetPickerEnabled(enabled);
5808}
5809
5810ExceptionOr<void> Internals::setMockMediaPlaybackTargetPickerState(const String& deviceName, const String& deviceState)
5811{
5812 auto frame = this->frame();
5813 if (!frame || !frame->page())
5814 return Exception { ExceptionCode::InvalidAccessError };
5815
5816 MediaPlaybackTargetMock::State state = MediaPlaybackTargetMock::State::Unknown;
5817
5818 if (equalLettersIgnoringASCIICase(deviceState, "deviceavailable"_s))
5819 state = MediaPlaybackTargetMock::State::OutputDeviceAvailable;
5820 else if (equalLettersIgnoringASCIICase(deviceState, "deviceunavailable"_s))
5821 state = MediaPlaybackTargetMock::State::OutputDeviceUnavailable;
5822 else if (equalLettersIgnoringASCIICase(deviceState, "unknown"_s))
5823 state = MediaPlaybackTargetMock::State::Unknown;
5824 else
5825 return Exception { ExceptionCode::InvalidAccessError };
5826
5827 frame->page()->setMockMediaPlaybackTargetPickerState(deviceName, state);
5828 return { };
5829}
5830
5831void Internals::mockMediaPlaybackTargetPickerDismissPopup()
5832{
5833 auto frame = this->frame();
5834 if (!frame || !frame->page())
5835 return;
5836
5837 frame->page()->mockMediaPlaybackTargetPickerDismissPopup();
5838}
5839#endif
5840
5841bool Internals::isMonitoringWirelessRoutes() const
5842{
5843#if ENABLE(VIDEO)(defined 1 && 1)
5844 if (RefPtr manager = sessionManager())
5845 return manager->isMonitoringWirelessTargets();
5846#endif
5847
5848 return false;
5849}
5850
5851ExceptionOr<Ref<MockPageOverlay>> Internals::installMockPageOverlay(PageOverlayType type)
5852{
5853 Document* document = contextDocument();
5854 if (!document || !document->page())
5855 return Exception { ExceptionCode::InvalidAccessError };
5856
5857 return MockPageOverlayClient::singleton().installOverlay(*document->page(), type == PageOverlayType::View ? PageOverlay::OverlayType::View : PageOverlay::OverlayType::Document);
5858}
5859
5860ExceptionOr<String> Internals::pageOverlayLayerTreeAsText(unsigned short flags) const
5861{
5862 Document* document = contextDocument();
5863 if (!document || !document->page())
5864 return Exception { ExceptionCode::InvalidAccessError };
5865
5866 document->updateLayout(LayoutOptions::IgnorePendingStylesheets);
5867
5868 return MockPageOverlayClient::singleton().layerTreeAsText(*document->page(), toLayerTreeAsTextOptions(flags));
5869}
5870
5871void Internals::setPageMuted(StringView statesString)
5872{
5873 Document* document = contextDocument();
5874 if (!document)
5875 return;
5876
5877 WebCore::MediaProducerMutedStateFlags state;
5878 for (StringView stateString : statesString.split(',')) {
5879 if (equalLettersIgnoringASCIICase(stateString, "audio"_s))
5880 state.add(MediaProducerMutedState::AudioIsMuted);
5881 if (equalLettersIgnoringASCIICase(stateString, "capturedevices"_s))
5882 state.add(MediaProducer::AudioAndVideoCaptureIsMuted);
5883 if (equalLettersIgnoringASCIICase(stateString, "screencapture"_s))
5884 state.add(MediaProducerMutedState::ScreenCaptureIsMuted);
5885 }
5886
5887 if (Page* page = document->page())
5888 page->setMuted(state);
5889}
5890
5891String Internals::pageMediaState()
5892{
5893 Document* document = contextDocument();
5894 if (!document || !document->page())
5895 return emptyString();
5896
5897 auto state = document->page()->mediaState();
5898 StringBuilder string;
5899 if (state.containsAny(MediaProducerMediaState::IsPlayingAudio))
5900 string.append("IsPlayingAudio,"_s);
5901 if (state.containsAny(MediaProducerMediaState::IsPlayingVideo))
5902 string.append("IsPlayingVideo,"_s);
5903 if (state.containsAny(MediaProducerMediaState::IsPlayingToExternalDevice))
5904 string.append("IsPlayingToExternalDevice,"_s);
5905 if (state.containsAny(MediaProducerMediaState::RequiresPlaybackTargetMonitoring))
5906 string.append("RequiresPlaybackTargetMonitoring,"_s);
5907 if (state.containsAny(MediaProducerMediaState::ExternalDeviceAutoPlayCandidate))
5908 string.append("ExternalDeviceAutoPlayCandidate,"_s);
5909 if (state.containsAny(MediaProducerMediaState::DidPlayToEnd))
5910 string.append("DidPlayToEnd,"_s);
5911 if (state.containsAny(MediaProducerMediaState::IsSourceElementPlaying))
5912 string.append("IsSourceElementPlaying,"_s);
5913
5914 if (state.containsAny(MediaProducerMediaState::IsNextTrackControlEnabled))
5915 string.append("IsNextTrackControlEnabled,"_s);
5916 if (state.containsAny(MediaProducerMediaState::IsPreviousTrackControlEnabled))
5917 string.append("IsPreviousTrackControlEnabled,"_s);
5918
5919 if (state.containsAny(MediaProducerMediaState::HasPlaybackTargetAvailabilityListener))
5920 string.append("HasPlaybackTargetAvailabilityListener,"_s);
5921 if (state.containsAny(MediaProducerMediaState::HasAudioOrVideo))
5922 string.append("HasAudioOrVideo,"_s);
5923
5924 if (state.containsAny(MediaProducerMediaState::HasActiveAudioCaptureDevice))
5925 string.append("HasActiveAudioCaptureDevice,"_s);
5926 if (state.containsAny(MediaProducerMediaState::HasMutedAudioCaptureDevice))
5927 string.append("HasMutedAudioCaptureDevice,"_s);
5928 if (state.containsAny(MediaProducerMediaState::HasInterruptedAudioCaptureDevice))
5929 string.append("HasInterruptedAudioCaptureDevice,"_s);
5930
5931 if (state.containsAny(MediaProducerMediaState::HasActiveVideoCaptureDevice))
5932 string.append("HasActiveVideoCaptureDevice,"_s);
5933 if (state.containsAny(MediaProducerMediaState::HasMutedVideoCaptureDevice))
5934 string.append("HasMutedVideoCaptureDevice,"_s);
5935 if (state.containsAny(MediaProducerMediaState::HasInterruptedVideoCaptureDevice))
5936 string.append("HasInterruptedVideoCaptureDevice,"_s);
5937
5938 if (state.containsAny(MediaProducerMediaState::HasUserInteractedWithMediaElement))
5939 string.append("HasUserInteractedWithMediaElement,"_s);
5940
5941 if (state.containsAny(MediaProducerMediaState::HasActiveScreenCaptureDevice))
5942 string.append("HasActiveScreenCaptureDevice,"_s);
5943 if (state.containsAny(MediaProducerMediaState::HasMutedScreenCaptureDevice))
5944 string.append("HasMutedScreenCaptureDevice,"_s);
5945
5946 if (state.containsAny(MediaProducerMediaState::HasActiveWindowCaptureDevice))
5947 string.append("HasActiveWindowCaptureDevice,"_s);
5948 if (state.containsAny(MediaProducerMediaState::HasMutedWindowCaptureDevice))
5949 string.append("HasMutedWindowCaptureDevice,"_s);
5950 if (state.containsAny(MediaProducerMediaState::HasInterruptedWindowCaptureDevice))
5951 string.append("HasInterruptedWindowCaptureDevice,"_s);
5952
5953 if (state.containsAny(MediaProducerMediaState::HasActiveSystemAudioCaptureDevice))
5954 string.append("HasActiveSystemAudioCaptureDevice,"_s);
5955 if (state.containsAny(MediaProducerMediaState::HasMutedSystemAudioCaptureDevice))
5956 string.append("HasMutedSystemAudioCaptureDevice,"_s);
5957 if (state.containsAny(MediaProducerMediaState::HasInterruptedSystemAudioCaptureDevice))
5958 string.append("HasInterruptedSystemAudioCaptureDevice,"_s);
5959
5960 if (string.isEmpty())
5961 string.append("IsNotPlaying"_s);
5962 else
5963 string.shrink(string.length() - 1);
5964
5965 return string.toString();
5966}
5967
5968void Internals::setPageDefersLoading(bool defersLoading)
5969{
5970 Document* document = contextDocument();
5971 if (!document)
5972 return;
5973 if (Page* page = document->page())
5974 page->setDefersLoading(defersLoading);
5975}
5976
5977ExceptionOr<bool> Internals::pageDefersLoading()
5978{
5979 Document* document = contextDocument();
5980 if (!document || !document->page())
5981 return Exception { ExceptionCode::InvalidAccessError };
5982 return document->page()->defersLoading();
5983}
5984
5985void Internals::grantUniversalAccess()
5986{
5987 if (auto* document = contextDocument())
5988 document->securityOrigin().grantUniversalAccess();
5989}
5990
5991void Internals::disableCORSForURL(const String& url)
5992{
5993 if (auto* page = contextDocument() ? contextDocument()->page() : nullptr)
5994 page->addCORSDisablingPatternForTesting(UserContentURLPattern { url });
5995}
5996
5997RefPtr<File> Internals::createFile(const String& path)
5998{
5999 Document* document = contextDocument();
6000 if (!document)
6001 return nullptr;
6002
6003 URL url = document->completeURL(path);
6004 if (!url.protocolIsFile())
6005 return nullptr;
6006
6007 if (auto* page = document->page())
6008 page->chrome().client().registerBlobPathForTesting(url.fileSystemPath(), [] () { });
6009
6010 return File::create(document, url.fileSystemPath());
6011}
6012void Internals::asyncCreateFile(const String& path, DOMPromiseDeferred<IDLInterface<File>>&& promise)
6013{
6014 Document* document = contextDocument();
6015 if (!document) {
6016 promise.reject(ExceptionCode::InvalidStateError);
6017 return;
6018 }
6019
6020 URL url = document->completeURL(path);
6021 if (!url.protocolIsFile()) {
6022 promise.reject(ExceptionCode::InvalidStateError);
6023 return;
6024 }
6025
6026 if (auto* page = document->page()) {
6027 auto fileSystemPath = url.fileSystemPath();
6028 page->chrome().client().registerBlobPathForTesting(fileSystemPath, [promise = WTF::move(promise), weakDocument = WeakPtr { *document }, url = WTF::move(url)] () mutable {
6029 if (!weakDocument) {
6030 promise.reject(ExceptionCode::InvalidStateError);
6031 return;
6032 }
6033 promise.resolve(File::create(weakDocument.get(), url.fileSystemPath()));
6034 });
6035 } else
6036 promise.reject(ExceptionCode::InvalidStateError);
6037}
6038
6039
6040String Internals::createTemporaryFile(const String& name, const String& contents)
6041{
6042 if (name.isEmpty())
6043 return nullString();
6044
6045 auto [path, file] = FileSystem::openTemporaryFile(makeString("WebCoreTesting-"_s, name));
6046 if (!file)
6047 return nullString();
6048
6049 file.write(byteCast<uint8_t>(contents.utf8().span()));
6050 return path;
6051}
6052
6053void Internals::queueMicroTask(int testNumber)
6054{
6055 Document* document = contextDocument();
6056 if (!document)
6057 return;
6058
6059 ScriptExecutionContext* context = document;
6060 auto& eventLoop = context->eventLoop();
6061 eventLoop.queueMicrotask(document->vm(), [document = Ref { *document }, testNumber]() {
6062 document->addConsoleMessage(MessageSource::JS, MessageLevel::Debug, makeString("MicroTask #"_s, testNumber, " has run."_s));
6063 });
6064}
6065
6066#if ENABLE(CONTENT_FILTERING)(defined 1 && 1)
6067
6068MockContentFilterSettings& Internals::mockContentFilterSettings()
6069{
6070 return MockContentFilterSettings::singleton();
6071}
6072
6073#endif
6074
6075static void serializeOffset(StringBuilder& builder, const SnapOffset<LayoutUnit>& snapOffset)
6076{
6077 builder.append(snapOffset.offset.toUnsigned());
6078 if (snapOffset.stop == ScrollSnapStop::Always)
6079 builder.append(" (always)"_s);
6080}
6081
6082static void serializeOffsets(StringBuilder& builder, const Vector<SnapOffset<LayoutUnit>>& snapOffsets)
6083{
6084 builder.append("{ "_s, interleave(snapOffsets, serializeOffset, ", "_s), " }"_s);
6085}
6086
6087void Internals::setPlatformMomentumScrollingPredictionEnabled(bool enabled)
6088{
6089 ScrollingMomentumCalculator::setPlatformMomentumScrollingPredictionEnabled(enabled);
6090}
6091
6092ExceptionOr<String> Internals::scrollSnapOffsets(Element& element)
6093{
6094 auto areaOrException = scrollableAreaForNode(&element);
6095 if (areaOrException.hasException())
6096 return areaOrException.releaseException();
6097
6098 auto* scrollableArea = areaOrException.releaseReturnValue();
6099 if (!scrollableArea)
6100 return Exception { ExceptionCode::InvalidAccessError };
6101
6102 auto* offsetInfo = scrollableArea->snapOffsetsInfo();
6103 StringBuilder result;
6104 if (offsetInfo && !offsetInfo->horizontalSnapOffsets.isEmpty()) {
6105 result.append("horizontal = "_s);
6106 serializeOffsets(result, offsetInfo->horizontalSnapOffsets);
6107 }
6108
6109 if (offsetInfo && !offsetInfo->verticalSnapOffsets.isEmpty()) {
6110 if (result.length())
6111 result.append(", "_s);
6112 result.append("vertical = "_s);
6113 serializeOffsets(result, offsetInfo->verticalSnapOffsets);
6114 }
6115
6116 return String { result.toString() };
6117}
6118
6119ExceptionOr<bool> Internals::isScrollSnapInProgress(Element& element)
6120{
6121 auto areaOrException = scrollableAreaForNode(&element);
6122 if (areaOrException.hasException())
6123 return areaOrException.releaseException();
6124
6125 auto* scrollableArea = areaOrException.releaseReturnValue();
6126 if (!scrollableArea)
6127 return Exception { ExceptionCode::InvalidAccessError };
6128
6129 return scrollableArea->isScrollSnapInProgress();
6130}
6131
6132bool Internals::testPreloaderSettingViewport()
6133{
6134 return testPreloadScannerViewportSupport(contextDocument());
6135}
6136
6137ExceptionOr<String> Internals::pathStringWithShrinkWrappedRects(const Vector<double>& rectComponents, double radius)
6138{
6139 if (rectComponents.size() % 4)
6140 return Exception { ExceptionCode::InvalidAccessError };
6141
6142 Vector<FloatRect> rects;
6143 for (unsigned i = 0; i < rectComponents.size(); i += 4)
6144 rects.append(FloatRect(rectComponents[i], rectComponents[i + 1], rectComponents[i + 2], rectComponents[i + 3]));
6145
6146 SVGPathStringBuilder builder;
6147 PathUtilities::pathWithShrinkWrappedRects(rects, radius).applyElements([&builder](const PathElement& element) {
6148 switch (element.type) {
6149 case PathElement::Type::MoveToPoint:
6150 builder.moveTo(element.points[0], false, AbsoluteCoordinates);
6151 return;
6152 case PathElement::Type::AddLineToPoint:
6153 builder.lineTo(element.points[0], AbsoluteCoordinates);
6154 return;
6155 case PathElement::Type::AddQuadCurveToPoint:
6156 builder.curveToQuadratic(element.points[0], element.points[1], AbsoluteCoordinates);
6157 return;
6158 case PathElement::Type::AddCurveToPoint:
6159 builder.curveToCubic(element.points[0], element.points[1], element.points[2], AbsoluteCoordinates);
6160 return;
6161 case PathElement::Type::CloseSubpath:
6162 builder.closePath();
6163 return;
6164 }
6165 ASSERT_NOT_REACHED()((void)0);
6166 });
6167 return builder.result();
6168}
6169
6170void Internals::systemBeep()
6171{
6172 SystemSoundManager::singleton().systemBeep();
6173}
6174
6175#if ENABLE(VIDEO)(defined 1 && 1)
6176
6177void Internals::setMediaControlsMaximumRightContainerButtonCountOverride(HTMLMediaElement& mediaElement, size_t count)
6178{
6179 mediaElement.setMediaControlsMaximumRightContainerButtonCountOverride(count);
6180}
6181
6182void Internals::setMediaControlsHidePlaybackRates(HTMLMediaElement& mediaElement, bool hidePlaybackRates)
6183{
6184 mediaElement.setMediaControlsHidePlaybackRates(hidePlaybackRates);
6185}
6186
6187#endif // ENABLE(VIDEO)
6188
6189void Internals::setPageMediaVolume(float volume)
6190{
6191 Document* document = contextDocument();
6192 if (!document)
6193 return;
6194
6195 Page* page = document->page();
6196 if (!page)
6197 return;
6198
6199 page->setMediaVolume(volume);
6200}
6201
6202float Internals::pageMediaVolume()
6203{
6204 Document* document = contextDocument();
6205 if (!document)
6206 return 0;
6207
6208 Page* page = document->page();
6209 if (!page)
6210 return 0;
6211
6212 return page->mediaVolume();
6213}
6214
6215#if ENABLE(BANNER_VIEW_OVERLAYS)(defined ENABLE_BANNER_VIEW_OVERLAYS && ENABLE_BANNER_VIEW_OVERLAYS
)
6216void Internals::setPageHasBannerViewOverlayForTesting(bool hasBannerViewOverlay)
6217{
6218 RefPtr document = contextDocument();
6219 if (!document)
6220 return;
6221
6222 RefPtr page = document->page();
6223 if (!page)
6224 return;
6225
6226 page->setHasBannerViewOverlay(hasBannerViewOverlay);
6227}
6228#endif
6229
6230#if !PLATFORM(COCOA)(defined 1 && 1)
6231
6232String Internals::userVisibleString(const DOMURL& url)
6233{
6234 return WTF::URLHelpers::userVisibleURL(url.href().string().utf8());
6235}
6236
6237#endif
6238
6239void Internals::setShowAllPlugins(bool show)
6240{
6241 Document* document = contextDocument();
6242 if (!document)
6243 return;
6244
6245 Page* page = document->page();
6246 if (!page)
6247 return;
6248
6249 page->setShowAllPlugins(show);
6250}
6251
6252bool Internals::isReadableStreamDisturbed(ReadableStream& stream)
6253{
6254 return stream.isDisturbed();
6255}
6256
6257void Internals::observeReadableStreamLifetime(ReadableStream& stream)
6258{
6259 m_observedLiveReadableStreams.add(stream);
6260}
6261
6262unsigned Internals::observedLiveReadableStreamCount()
6263{
6264 return m_observedLiveReadableStreams.computeSize();
6265}
6266
6267JSValue Internals::cloneArrayBuffer(JSC::JSGlobalObject& lexicalGlobalObject, JSValue buffer, JSValue srcByteOffset, JSValue srcLength)
6268{
6269 auto& vm = lexicalGlobalObject.vm();
6270 const Identifier& privateName = builtinNames(vm).cloneArrayBufferPrivateName();
6271 JSValue value;
6272 PropertySlot propertySlot(value, PropertySlot::InternalMethodType::Get);
6273 lexicalGlobalObject.methodTable()->getOwnPropertySlot(&lexicalGlobalObject, &lexicalGlobalObject, privateName, propertySlot);
6274 value = propertySlot.getValue(&lexicalGlobalObject, privateName);
6275 ASSERT(value.isCallable())((void)0);
6276
6277 JSObject* function = value.getObject();
6278 auto callData = JSC::getCallData(function);
6279 ASSERT(callData.type != JSC::CallData::Type::None)((void)0);
6280 MarkedArgumentBuffer arguments;
6281 arguments.append(buffer);
6282 arguments.append(srcByteOffset);
6283 arguments.append(srcLength);
6284 ASSERT(!arguments.hasOverflowed())((void)0);
6285
6286 return JSC::call(&lexicalGlobalObject, function, callData, JSC::jsUndefined(), arguments);
6287}
6288
6289String Internals::resourceLoadStatisticsForURL(const DOMURL& url)
6290{
6291 return ResourceLoadObserver::singleton().statisticsForURL(url.href());
6292}
6293
6294void Internals::setTrackingPreventionEnabled(bool enable)
6295{
6296 DeprecatedGlobalSettings::setTrackingPreventionEnabled(enable);
6297}
6298
6299String Internals::composedTreeAsText(Node& node)
6300{
6301 if (!is<ContainerNode>(node))
6302 return emptyString();
6303 return WebCore::composedTreeAsText(downcast<ContainerNode>(node));
6304}
6305
6306String Internals::composedTreeAsTextFromNode(Node& root, Node& startNode)
6307{
6308 if (!is<ContainerNode>(root))
6309 return emptyString();
6310 return WebCore::composedTreeAsTextFromNode(downcast<ContainerNode>(root), startNode);
6311}
6312
6313bool Internals::isProcessingUserGesture()
6314{
6315 return UserGestureIndicator::processingUserGesture();
6316}
6317
6318void Internals::withUserGesture(Ref<VoidCallback>&& callback)
6319{
6320 UserGestureIndicator gestureIndicator(IsProcessingUserGesture::Yes, contextDocument());
6321 callback->invoke();
6322}
6323
6324void Internals::withoutUserGesture(Ref<VoidCallback>&& callback)
6325{
6326 UserGestureIndicator gestureIndicator(IsProcessingUserGesture::No, contextDocument());
6327 callback->invoke();
6328}
6329
6330bool Internals::userIsInteracting()
6331{
6332 if (auto* document = contextDocument()) {
6333 if (auto* page = document->page())
6334 return page->chrome().client().userIsInteracting();
6335 }
6336 return false;
6337}
6338
6339bool Internals::hasTransientActivation()
6340{
6341 if (auto* document = contextDocument()) {
6342 if (auto* window = document->window())
6343 return window->hasTransientActivation();
6344 }
6345 return false;
6346}
6347
6348bool Internals::consumeTransientActivation()
6349{
6350 if (auto* document = contextDocument()) {
6351 if (auto* window = document->window())
6352 return window->consumeTransientActivation();
6353 }
6354 return false;
6355}
6356
6357double Internals::lastHandledUserGestureTimestamp()
6358{
6359 Document* document = contextDocument();
6360 if (!document)
6361 return 0;
6362
6363 return document->lastHandledUserGestureTimestamp().secondsSinceEpoch().value();
6364}
6365
6366bool Internals::hasHistoryActionActivation()
6367{
6368 if (auto* document = contextDocument()) {
6369 if (auto* window = document->window())
6370 return window->hasHistoryActionActivation();
6371 }
6372 return false;
6373}
6374
6375bool Internals::consumeHistoryActionUserActivation()
6376{
6377 if (auto* document = contextDocument()) {
6378 if (auto* window = document->window())
6379 return window->consumeHistoryActionUserActivation();
6380 }
6381 return false;
6382}
6383
6384RefPtr<GCObservation> Internals::observeGC(JSC::JSValue value)
6385{
6386 if (!value.isObject())
6387 return nullptr;
6388 return GCObservation::create(asObject(value));
6389}
6390
6391void Internals::setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection)
6392{
6393 Document* document = contextDocument();
6394 if (!document)
6395 return;
6396
6397 Page* page = document->page();
6398 if (!page)
6399 return;
6400
6401 page->setUserInterfaceLayoutDirection(userInterfaceLayoutDirection == UserInterfaceLayoutDirection::LTR ? WebCore::UserInterfaceLayoutDirection::LTR : WebCore::UserInterfaceLayoutDirection::RTL);
6402}
6403
6404#if !PLATFORM(COCOA)(defined 1 && 1)
6405
6406bool Internals::userPrefersReducedMotion() const
6407{
6408 return false;
6409}
6410
6411bool Internals::userPrefersContrast() const
6412{
6413 return false;
6414}
6415
6416#if ENABLE(VIDEO)(defined 1 && 1)
6417double Internals::privatePlayerVolume(const HTMLMediaElement&)
6418{
6419 return 0;
6420}
6421
6422bool Internals::privatePlayerMuted(const HTMLMediaElement&)
6423{
6424 return false;
6425}
6426#endif
6427
6428RefPtr<SharedBuffer> Internals::pngDataForTesting()
6429{
6430 return nullptr;
6431}
6432
6433#endif // !PLATFORM(COCOA)
6434
6435#if ENABLE(VIDEO)(defined 1 && 1)
6436bool Internals::isMediaElementHidden(const HTMLMediaElement& media)
6437{
6438 return media.elementIsHidden();
6439}
6440
6441double Internals::elementEffectivePlaybackRate(const HTMLMediaElement& media)
6442{
6443 return media.effectivePlaybackRate();
6444}
6445
6446double Internals::privatePlayerCurrentTime(HTMLMediaElement& media)
6447{
6448 return media.mediaPlayerCurrentTime();
6449}
6450
6451#endif
6452
6453ExceptionOr<void> Internals::setIsPlayingToBluetoothOverride(std::optional<bool> isPlaying)
6454{
6455#if ENABLE(ROUTING_ARBITRATION)(defined ENABLE_ROUTING_ARBITRATION && ENABLE_ROUTING_ARBITRATION
)
6456 AudioSession::singleton().setIsPlayingToBluetoothOverride(isPlaying);
6457 return { };
6458#else
6459 UNUSED_PARAM(isPlaying)(void)isPlaying;
6460 return Exception { ExceptionCode::NotSupportedError };
6461#endif
6462}
6463
6464void Internals::reportBacktrace()
6465{
6466 WTFReportBacktrace();
6467}
6468
6469void Internals::setBaseWritingDirection(BaseWritingDirection direction)
6470{
6471 if (auto* document = contextDocument()) {
6472 if (auto* frame = document->frame()) {
6473 switch (direction) {
6474 case BaseWritingDirection::Ltr:
6475 frame->editor().setBaseWritingDirection(WritingDirection::LeftToRight);
6476 break;
6477 case BaseWritingDirection::Rtl:
6478 frame->editor().setBaseWritingDirection(WritingDirection::RightToLeft);
6479 break;
6480 case BaseWritingDirection::Natural:
6481 frame->editor().setBaseWritingDirection(WritingDirection::Natural);
6482 break;
6483 }
6484 }
6485 }
6486}
6487
6488#if ENABLE(POINTER_LOCK)(defined 1 && 1)
6489bool Internals::pageHasPendingPointerLock() const
6490{
6491 Document* document = contextDocument();
6492 if (!document)
6493 return false;
6494
6495 Page* page = document->page();
6496 if (!page)
6497 return false;
6498
6499 return page->pointerLockController().lockPending();
6500}
6501
6502bool Internals::pageHasPointerLock() const
6503{
6504 Document* document = contextDocument();
6505 if (!document)
6506 return false;
6507
6508 Page* page = document->page();
6509 if (!page)
6510 return false;
6511
6512 auto& controller = page->pointerLockController();
6513 return controller.element() && !controller.lockPending();
6514}
6515#endif
6516
6517void Internals::markContextAsInsecure()
6518{
6519 auto* document = contextDocument();
6520 if (!document)
6521 return;
6522
6523 document->securityOrigin().setIsPotentiallyTrustworthy(false);
6524}
6525
6526void Internals::postTask(Ref<VoidCallback>&& callback)
6527{
6528 auto* document = contextDocument();
6529 if (!document) {
6530 callback->invoke();
6531 return;
6532 }
6533
6534 document->postTask([callback = WTF::move(callback)](ScriptExecutionContext&) {
6535 callback->invoke();
6536 });
6537}
6538
6539static std::optional<TaskSource> taskSourceFromString(const String& taskSourceName)
6540{
6541 if (taskSourceName == "DOMManipulation"_s)
6542 return TaskSource::DOMManipulation;
6543 return std::nullopt;
6544}
6545
6546ExceptionOr<void> Internals::queueTask(ScriptExecutionContext& context, const String& taskSourceName, Ref<VoidCallback>&& callback)
6547{
6548 auto source = taskSourceFromString(taskSourceName);
6549 if (!source)
6550 return Exception { ExceptionCode::NotSupportedError };
6551
6552 context.eventLoop().queueTask(*source, [callback = WTF::move(callback)] {
6553 callback->invoke();
6554 });
6555
6556 return { };
6557}
6558
6559ExceptionOr<void> Internals::queueTaskToQueueMicrotask(Document& document, const String& taskSourceName, Ref<VoidCallback>&& callback)
6560{
6561 auto source = taskSourceFromString(taskSourceName);
6562 if (!source)
6563 return Exception { ExceptionCode::NotSupportedError };
6564
6565 ScriptExecutionContext& context = document; // This avoids unnecessarily exporting Document::eventLoop.
6566 context.eventLoop().queueTask(*source, [movedCallback = WTF::move(callback), protectedDocument = Ref { document }]() mutable {
6567 ScriptExecutionContext& context = protectedDocument.get();
6568 context.eventLoop().queueMicrotask(context.vm(), [callback = WTF::move(movedCallback)] {
6569 callback->invoke();
6570 });
6571 });
6572
6573 return { };
6574}
6575
6576ExceptionOr<bool> Internals::hasSameEventLoopAs(WindowProxy& proxy)
6577{
6578 RefPtr<ScriptExecutionContext> context = contextDocument();
6579 if (!context || !proxy.frame())
6580 return Exception { ExceptionCode::InvalidStateError };
6581
6582 auto* proxyFrame = dynamicDowncast<LocalFrame>(*proxy.frame());
6583 if (!proxyFrame)
6584 return false;
6585 RefPtr<ScriptExecutionContext> proxyContext = proxyFrame->document();
6586 if (!proxyContext)
6587 return Exception { ExceptionCode::InvalidStateError };
6588
6589 return context->eventLoop().hasSameEventLoopAs(proxyContext->eventLoop());
6590}
6591
6592Vector<String> Internals::accessKeyModifiers() const
6593{
6594 Vector<String> accessKeyModifierStrings;
6595
6596 for (auto modifier : EventHandler::accessKeyModifiers()) {
6597 switch (modifier) {
6598 case PlatformEvent::Modifier::AltKey:
6599 accessKeyModifierStrings.append("altKey"_s);
6600 break;
6601 case PlatformEvent::Modifier::ControlKey:
6602 accessKeyModifierStrings.append("ctrlKey"_s);
6603 break;
6604 case PlatformEvent::Modifier::MetaKey:
6605 accessKeyModifierStrings.append("metaKey"_s);
6606 break;
6607 case PlatformEvent::Modifier::ShiftKey:
6608 accessKeyModifierStrings.append("shiftKey"_s);
6609 break;
6610 case PlatformEvent::Modifier::CapsLockKey:
6611 accessKeyModifierStrings.append("capsLockKey"_s);
6612 break;
6613 case PlatformEvent::Modifier::AltGraphKey:
6614 ASSERT_NOT_REACHED()((void)0); // AltGraph is only for DOM API.
6615 break;
6616 }
6617 }
6618
6619 return accessKeyModifierStrings;
6620}
6621
6622void Internals::setQuickLookPassword(const String& password)
6623{
6624#if PLATFORM(IOS_FAMILY)(defined 1 && 1) && USE(QUICK_LOOK)(defined 1 && 1)
6625 auto& quickLookHandleClient = MockPreviewLoaderClient::singleton();
6626 LegacyPreviewLoader::setClientForTesting(&quickLookHandleClient);
6627 quickLookHandleClient.setPassword(password);
6628#else
6629 UNUSED_PARAM(password)(void)password;
6630#endif
6631}
6632
6633void Internals::setAsRunningUserScripts(Document& document)
6634{
6635 if (RefPtr page = document.page())
6636 page->setHasInjectedUserScript();
6637}
6638
6639#if ENABLE(WEBGL)(defined 1 && 1)
6640void Internals::simulateEventForWebGLContext(SimulatedWebGLContextEvent event, WebGLRenderingContextBase& context)
6641{
6642 WebGLRenderingContext::SimulatedEventForTesting contextEvent;
6643 switch (event) {
6644 case SimulatedWebGLContextEvent::GPUStatusFailure:
6645 contextEvent = WebGLRenderingContext::SimulatedEventForTesting::GPUStatusFailure;
6646 break;
6647 case SimulatedWebGLContextEvent::Timeout:
6648 contextEvent = WebGLRenderingContext::SimulatedEventForTesting::Timeout;
6649 break;
6650 default:
6651 ASSERT_NOT_REACHED()((void)0);
6652 return;
6653 }
6654 context.simulateEventForTesting(contextEvent);
6655}
6656
6657Internals::RequestedGPU Internals::requestedGPU(WebGLRenderingContextBase& context)
6658{
6659 switch (context.creationAttributes().powerPreference) {
6660 case WebGLPowerPreference::Default:
6661 return RequestedGPU::Default;
6662 case WebGLPowerPreference::LowPower:
6663 return RequestedGPU::LowPower;
6664 case WebGLPowerPreference::HighPerformance:
6665 return RequestedGPU::HighPerformance;
6666 }
6667 ASSERT_NOT_REACHED()((void)0);
6668 return RequestedGPU::Default;
6669
6670}
6671#endif
6672
6673void Internals::setPageVisibility(bool isVisible)
6674{
6675 updatePageActivityState(ActivityState::IsVisible, isVisible);
6676}
6677
6678void Internals::setPageIsFocused(bool isFocused)
6679{
6680 updatePageActivityState(ActivityState::IsFocused, isFocused);
6681}
6682
6683void Internals::setPageIsFocusedAndActive(bool isFocusedAndActive)
6684{
6685 updatePageActivityState({ ActivityState::IsFocused, ActivityState::WindowIsActive }, isFocusedAndActive);
6686}
6687
6688void Internals::setPageIsInWindow(bool isInWindow)
6689{
6690 updatePageActivityState(ActivityState::IsInWindow, isInWindow);
6691}
6692
6693void Internals::updatePageActivityState(OptionSet<ActivityState> statesToChange, bool newValue)
6694{
6695 auto* page = contextDocument() ? contextDocument()->page() : nullptr;
6696 if (!page)
6697 return;
6698 auto state = page->activityState();
6699
6700 if (!newValue)
6701 state.remove(statesToChange);
6702 else
6703 state.add(statesToChange);
6704
6705 page->setActivityState(state);
6706}
6707
6708bool Internals::isPageActive() const
6709{
6710 auto* document = contextDocument();
6711 if (!document || !document->page())
6712 return false;
6713 auto& page = *document->page();
6714 return page.activityState().contains(ActivityState::WindowIsActive);
6715}
6716
6717#if ENABLE(MEDIA_STREAM)(defined 1 && 1)
6718void Internals::setMockAudioTrackChannelNumber(MediaStreamTrack& track, unsigned short channelNumber)
6719{
6720 if (auto* source = dynamicDowncast<MockRealtimeAudioSource>(track.source()))
6721 source->setChannelCount(channelNumber);
6722}
6723
6724void Internals::setCameraMediaStreamTrackOrientation(MediaStreamTrack& track, int orientation)
6725{
6726 auto& source = track.source();
6727 if (!source.isCaptureSource())
6728 return;
6729 m_orientationNotifier.orientationChanged(orientation);
6730 source.monitorOrientation(m_orientationNotifier);
6731}
6732
6733void Internals::stopObservingRealtimeMediaSource()
6734{
6735 if (!m_trackSource)
6736 return;
6737
6738 switch (m_trackSource->type()) {
6739 case RealtimeMediaSource::Type::Audio:
6740 m_trackSource->removeAudioSampleObserver(*this);
6741 break;
6742 case RealtimeMediaSource::Type::Video:
6743 m_trackSource->removeVideoFrameObserver(*this);
6744 break;
6745 }
6746 m_trackSource->removeObserver(*this);
6747
6748 m_trackSource = nullptr;
6749 m_trackAudioSampleCount = 0;
6750 m_trackVideoSampleCount = 0;
6751}
6752
6753void Internals::observeMediaStreamTrack(MediaStreamTrack& track)
6754{
6755 stopObservingRealtimeMediaSource();
6756
6757 m_trackVideoRotation = -1;
6758 m_trackSource = track.source();
6759 m_trackSource->addObserver(*this);
6760 switch (m_trackSource->type()) {
6761 case RealtimeMediaSource::Type::Audio:
6762 m_trackSource->addAudioSampleObserver(*this);
6763 break;
6764 case RealtimeMediaSource::Type::Video:
6765 m_trackSource->addVideoFrameObserver(*this);
6766 break;
6767 }
6768}
6769
6770void Internals::mediaStreamTrackVideoFrameRotation(DOMPromiseDeferred<IDLShort>&& promise)
6771{
6772 promise.resolve(m_trackVideoRotation);
6773}
6774
6775void Internals::videoFrameAvailable(VideoFrame& videoFrame, VideoFrameTimeMetadata)
6776{
6777 callOnMainThread([this, weakThis = WeakPtr { *this }, videoFrame = Ref { videoFrame }] {
6778 if (!weakThis)
6779 return;
6780 m_trackVideoSampleCount++;
6781 m_trackVideoRotation = static_cast<int>(videoFrame->rotation());
6782 });
6783}
6784
6785void Internals::delayMediaStreamTrackSamples(MediaStreamTrack& track, float delay)
6786{
6787 track.source().delaySamples(Seconds { delay });
6788}
6789
6790void Internals::setMediaStreamTrackMuted(MediaStreamTrack& track, bool muted)
6791{
6792 track.source().setMuted(muted);
6793}
6794
6795void Internals::removeMediaStreamTrack(MediaStream& stream, MediaStreamTrack& track)
6796{
6797 stream.allowEventTracksForTesting();
6798 stream.privateStream().removeTrack(track.privateTrack());
6799}
6800
6801void Internals::simulateMediaStreamTrackCaptureSourceFailure(MediaStreamTrack& track)
6802{
6803 track.source().captureFailed();
6804}
6805
6806void Internals::setMediaStreamTrackIdentifier(MediaStreamTrack& track, String&& id)
6807{
6808 track.setIdForTesting(WTF::move(id));
6809}
6810
6811void Internals::setMediaStreamSourceInterrupted(MediaStreamTrack& track, bool interrupted)
6812{
6813 track.source().setInterruptedForTesting(interrupted);
6814}
6815
6816const String& Internals::mediaStreamTrackPersistentId(const MediaStreamTrack& track)
6817{
6818 return track.source().persistentID();
6819}
6820
6821size_t Internals::audioCaptureSourceCount() const
6822{
6823 if (RefPtr manager = sessionManager())
6824 return manager->audioCaptureSourceCount();
6825
6826 return false;
6827}
6828
6829bool Internals::supportsMultiMicrophoneCaptureWithoutEchoCancellation() const
6830{
6831#if PLATFORM(MAC)(defined WTF_PLATFORM_MAC && WTF_PLATFORM_MAC)
6832 return true;
6833#else
6834 return false;
6835#endif
6836}
6837
6838bool Internals::isMediaStreamSourceInterrupted(MediaStreamTrack& track) const
6839{
6840 return track.source().interrupted();
6841}
6842
6843bool Internals::isMediaStreamSourceEnded(MediaStreamTrack& track) const
6844{
6845 return track.source().isEnded();
6846}
6847
6848bool Internals::isMockRealtimeMediaSourceCenterEnabled()
6849{
6850 return MockRealtimeMediaSourceCenter::mockRealtimeMediaSourceCenterEnabled();
6851}
6852
6853bool Internals::shouldAudioTrackPlay(const AudioTrack& track)
6854{
6855 auto* audioTrack = dynamicDowncast<AudioTrackPrivateMediaStream>(track.privateTrack());
6856 return audioTrack && audioTrack->shouldPlay();
6857}
6858#endif // ENABLE(MEDIA_STREAM)
6859
6860#if ENABLE(WEB_RTC)(defined 1 && 1)
6861String Internals::rtcNetworkInterfaceName() const
6862{
6863 RefPtr document = contextDocument();
6864 RefPtr rtcNetworkManager = document ? document->rtcNetworkManager() : nullptr;
6865 if (!rtcNetworkManager)
6866 return { };
6867
6868 return rtcNetworkManager->interfaceNameForTesting();
6869}
6870#endif // ENABLE(WEB_RTC)
6871
6872bool Internals::isHardwareVP9DecoderExpected()
6873{
6874#if PLATFORM(IOS_FAMILY_SIMULATOR)(defined 1 && 1)
6875 return false;
6876#elif PLATFORM(IOS_FAMILY)(defined 1 && 1)
6877 return true;
6878#elif PLATFORM(MAC)(defined WTF_PLATFORM_MAC && WTF_PLATFORM_MAC) && CPU(ARM64)(defined 1 && 1)
6879 return true;
6880#else
6881 return false;
6882#endif
6883}
6884
6885bool Internals::supportsAudioSession() const
6886{
6887#if USE(AUDIO_SESSION)(defined 1 && 1)
6888 return true;
6889#else
6890 return false;
6891#endif
6892}
6893
6894auto Internals::audioSessionCategory() const -> AudioSessionCategory
6895{
6896#if USE(AUDIO_SESSION)(defined 1 && 1)
6897 return AudioSession::singleton().category();
6898#else
6899 return AudioSessionCategory::None;
6900#endif
6901}
6902
6903auto Internals::audioSessionMode() const -> AudioSessionMode
6904{
6905#if USE(AUDIO_SESSION)(defined 1 && 1)
6906 return AudioSession::singleton().mode();
6907#else
6908 return AudioSessionMode::Default;
6909#endif
6910}
6911
6912auto Internals::routeSharingPolicy() const -> RouteSharingPolicy
6913{
6914#if USE(AUDIO_SESSION)(defined 1 && 1)
6915 return AudioSession::singleton().routeSharingPolicy();
6916#else
6917 return RouteSharingPolicy::Default;
6918#endif
6919}
6920
6921#if ENABLE(VIDEO)(defined 1 && 1)
6922auto Internals::categoryAtMostRecentPlayback(HTMLMediaElement& element) const -> AudioSessionCategory
6923{
6924#if USE(AUDIO_SESSION)(defined 1 && 1)
6925 return element.categoryAtMostRecentPlayback();
6926#else
6927 UNUSED_PARAM(element)(void)element;
6928 return AudioSessionCategory::None;
6929#endif
6930}
6931
6932auto Internals::modeAtMostRecentPlayback(HTMLMediaElement& element) const -> AudioSessionMode
6933{
6934#if USE(AUDIO_SESSION)(defined 1 && 1)
6935 WTFLogAlways("Internals::modeAtMostRecentPlayback");
6936 return element.modeAtMostRecentPlayback();
6937#else
6938 UNUSED_PARAM(element)(void)element;
6939 return AudioSessionMode::Default;
6940#endif
6941}
6942#endif
6943
6944double Internals::preferredAudioBufferSize() const
6945{
6946#if USE(AUDIO_SESSION)(defined 1 && 1)
6947 return AudioSession::singleton().preferredBufferSize();
6948#endif
6949 return 0;
6950}
6951
6952double Internals::currentAudioBufferSize() const
6953{
6954#if USE(AUDIO_SESSION)(defined 1 && 1)
6955 return AudioSession::singleton().bufferSize();
6956#endif
6957 return 0;
6958}
6959
6960
6961bool Internals::audioSessionActive() const
6962{
6963#if USE(AUDIO_SESSION)(defined 1 && 1)
6964 return AudioSession::singleton().isActive();
6965#endif
6966 return false;
6967}
6968
6969void Internals::storeRegistrationsOnDisk(DOMPromiseDeferred<void>&& promise)
6970{
6971 if (!contextDocument())
6972 return;
6973
6974 auto& connection = ServiceWorkerProvider::singleton().serviceWorkerConnection();
6975 connection.storeRegistrationsOnDiskForTesting([promise = WTF::move(promise)]() mutable {
6976 promise.resolve();
6977 });
6978}
6979
6980void Internals::sendH2Ping(String url, DOMPromiseDeferred<IDLDouble>&& promise)
6981{
6982 auto* document = contextDocument();
6983 if (!document) {
6984 promise.reject(ExceptionCode::InvalidStateError);
6985 return;
6986 }
6987
6988 auto* frame = document->frame();
6989 if (!frame) {
6990 promise.reject(ExceptionCode::InvalidStateError);
6991 return;
6992 }
6993
6994 frame->loader().client().sendH2Ping(URL { url }, [promise = WTF::move(promise)] (Expected<Seconds, ResourceError>&& result) mutable {
6995 if (result.has_value())
6996 promise.resolve(result.value().value());
6997 else
6998 promise.reject(ExceptionCode::InvalidStateError);
6999 });
7000}
7001
7002void Internals::clearCacheStorageMemoryRepresentation(DOMPromiseDeferred<void>&& promise)
7003{
7004 RefPtr document = contextDocument();
7005 if (!document)
7006 return;
7007
7008 if (!m_cacheStorageConnection) {
7009 if (RefPtr page = document->page())
7010 m_cacheStorageConnection = page->cacheStorageProvider().createCacheStorageConnection();
7011 if (!m_cacheStorageConnection)
7012 return;
7013 }
7014
7015 document->enqueueTaskWhenSettled(m_cacheStorageConnection->clearMemoryRepresentation(ClientOrigin { document->topOrigin().data(), document->securityOrigin().data() }), TaskSource::DOMManipulation, [promise = WTF::move(promise)] (auto&&) mutable {
7016 promise.resolve();
7017 });
7018}
7019
7020void Internals::cacheStorageEngineRepresentation(DOMPromiseDeferred<IDLDOMString>&& promise)
7021{
7022 RefPtr document = contextDocument();
7023 if (!document)
7024 return;
7025
7026 if (!m_cacheStorageConnection) {
7027 if (RefPtr page = document->page())
7028 m_cacheStorageConnection = page->cacheStorageProvider().createCacheStorageConnection();
7029 if (!m_cacheStorageConnection)
7030 return;
7031 }
7032 document->enqueueTaskWhenSettled(m_cacheStorageConnection->engineRepresentation(), TaskSource::DOMManipulation, [promise = WTF::move(promise)](auto&& result) mutable {
7033 if (!result) {
7034 promise.reject(Exception { ExceptionCode::InvalidStateError, "internal error"_s });
7035 return;
7036 }
7037 promise.resolve(WTF::move(result.value()));
7038 });
7039}
7040
7041void Internals::updateQuotaBasedOnSpaceUsage()
7042{
7043 auto* document = contextDocument();
7044 if (!document)
7045 return;
7046
7047 if (!m_cacheStorageConnection) {
7048 if (auto* page = contextDocument()->page())
7049 m_cacheStorageConnection = page->cacheStorageProvider().createCacheStorageConnection();
7050 if (!m_cacheStorageConnection)
7051 return;
7052 }
7053
7054 m_cacheStorageConnection->updateQuotaBasedOnSpaceUsage(ClientOrigin { document->topOrigin().data(), document->securityOrigin().data() });
7055}
7056
7057void Internals::setConsoleMessageListener(RefPtr<StringCallback>&& listener)
7058{
7059 if (!contextDocument())
7060 return;
7061
7062 if (RefPtr page = contextDocument()->page())
7063 page->setConsoleMessageListenerForTesting(WTF::move(listener));
7064}
7065
7066void Internals::setResponseSizeWithPadding(FetchResponse& response, uint64_t size)
7067{
7068 response.setBodySizeWithPadding(size);
7069}
7070
7071uint64_t Internals::responseSizeWithPadding(FetchResponse& response) const
7072{
7073 return response.bodySizeWithPadding();
7074}
7075
7076const String& Internals::responseNetworkLoadMetricsProtocol(const FetchResponse& response)
7077{
7078 return response.networkLoadMetrics().protocol;
7079}
7080
7081void Internals::hasServiceWorkerRegistration(const String& clientURL, HasRegistrationPromise&& promise)
7082{
7083 if (!contextDocument())
7084 return;
7085
7086 URL parsedURL = contextDocument()->completeURL(clientURL);
7087
7088 return ServiceWorkerProvider::singleton().serviceWorkerConnection().matchRegistration(SecurityOriginData { contextDocument()->topOrigin().data() }, parsedURL, [promise = WTF::move(promise)] (auto&& result) mutable {
7089 promise.resolve(!!result);
7090 });
7091}
7092
7093void Internals::terminateServiceWorker(ServiceWorker& worker, DOMPromiseDeferred<void>&& promise)
7094{
7095 ServiceWorkerProvider::singleton().terminateWorkerForTesting(worker.identifier(), [promise = WTF::move(promise)]() mutable {
7096 promise.resolve();
7097 });
7098}
7099
7100void Internals::whenServiceWorkerIsTerminated(ServiceWorker& worker, DOMPromiseDeferred<void>&& promise)
7101{
7102 return ServiceWorkerProvider::singleton().serviceWorkerConnection().whenServiceWorkerIsTerminatedForTesting(worker.identifier(), [promise = WTF::move(promise)]() mutable {
7103 promise.resolve();
7104 });
7105}
7106
7107void Internals::terminateWebContentProcess()
7108{
7109 exit(0);
7110}
7111
7112#if ENABLE(APPLE_PAY)(defined 1 && 1)
7113ExceptionOr<Ref<MockPaymentCoordinator>> Internals::mockPaymentCoordinator(Document& document)
7114{
7115 auto* page = document.page();
7116 if (!page)
7117 return Exception { ExceptionCode::InvalidAccessError };
7118
7119 Ref mockPaymentCoordinator = downcast<MockPaymentCoordinator>(page->paymentCoordinator().client());
7120 return mockPaymentCoordinator;
7121}
7122#endif
7123
7124Internals::ImageOverlayLine::~ImageOverlayLine() = default;
7125Internals::ImageOverlayText::~ImageOverlayText() = default;
7126Internals::ImageOverlayBlock::~ImageOverlayBlock() = default;
7127Internals::ImageOverlayDataDetector::~ImageOverlayDataDetector() = default;
7128
7129#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
7130
7131template<typename T>
7132static FloatQuad NODELETE[[clang::annotate_type("webkit.nodelete")]] getQuad(const T& overlayTextOrLine)
7133{
7134 return {
7135 FloatPoint(overlayTextOrLine.topLeft->x(), overlayTextOrLine.topLeft->y()),
7136 FloatPoint(overlayTextOrLine.topRight->x(), overlayTextOrLine.topRight->y()),
7137 FloatPoint(overlayTextOrLine.bottomRight->x(), overlayTextOrLine.bottomRight->y()),
7138 FloatPoint(overlayTextOrLine.bottomLeft->x(), overlayTextOrLine.bottomLeft->y()),
7139 };
7140}
7141
7142static TextRecognitionLineData makeDataForLine(const Internals::ImageOverlayLine& line)
7143{
7144 return {
7145 getQuad<Internals::ImageOverlayLine>(line),
7146 line.children.map([](auto& textChild) -> TextRecognitionWordData {
7147 return { textChild.text, getQuad(textChild), textChild.hasLeadingWhitespace };
7148 }),
7149 line.hasTrailingNewline,
7150 line.isVertical
7151 };
7152}
7153
7154void Internals::requestTextRecognition(Element& element, Ref<VoidCallback>&& callback)
7155{
7156 auto page = contextDocument()->page();
7157 if (!page)
7158 callback->invoke();
7159
7160 page->chrome().client().requestTextRecognition(element, { }, [callback = WTF::move(callback)] (auto&&) {
7161 callback->invoke();
7162 });
7163}
7164
7165RefPtr<Element> Internals::textRecognitionCandidate() const
7166{
7167 if (RefPtr frame = contextDocument()->frame())
7168 return frame->eventHandler().textRecognitionCandidateElement();
7169
7170 return nullptr;
7171}
7172
7173#endif // ENABLE(IMAGE_ANALYSIS)
7174
7175void Internals::installImageOverlay(Element& element, Vector<ImageOverlayLine>&& lines, Vector<ImageOverlayBlock>&& blocks, Vector<ImageOverlayDataDetector>&& dataDetectors)
7176{
7177 if (!is<HTMLElement>(element))
7178 return;
7179
7180#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
7181 ImageOverlay::updateWithTextRecognitionResult(downcast<HTMLElement>(element), TextRecognitionResult {
7182 lines.map([] (auto& line) -> TextRecognitionLineData {
7183 return makeDataForLine(line);
7184 })
7185#if ENABLE(DATA_DETECTION)(defined 1 && 1)
7186 , dataDetectors.map([](auto& dataDetector) -> TextRecognitionDataDetector {
7187 return { fakeDataDetectorResultForTesting(), { getQuad(dataDetector) } };
7188 })
7189#endif // ENABLE(DATA_DETECTION)
7190 , blocks.map([] (auto& block) {
7191 return TextRecognitionBlockData { block.text, getQuad(block) };
7192 })
7193#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
7194 , TextRecognitionResult::extractAttributedString(fakeImageAnalysisResultForTesting(lines).get())
7195#endif
7196 });
7197#else
7198 UNUSED_PARAM(blocks)(void)blocks;
7199 UNUSED_PARAM(dataDetectors)(void)dataDetectors;
7200 UNUSED_PARAM(lines)(void)lines;
7201#endif
7202}
7203
7204bool Internals::hasActiveDataDetectorHighlight() const
7205{
7206#if ENABLE(DATA_DETECTION)(defined 1 && 1) && ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
7207 RefPtr document = contextDocument();
7208 if (!document || !document->page())
7209 return false;
7210 if (auto* controller = document->page()->imageOverlayControllerIfExists())
7211 return controller->hasActiveDataDetectorHighlightForTesting();
7212#endif
7213 return false;
7214}
7215
7216bool Internals::isSystemPreviewLink(Element& element) const
7217{
7218#if USE(SYSTEM_PREVIEW)(defined 1 && 1)
7219 auto* anchor = dynamicDowncast<HTMLAnchorElement>(element);
7220 return anchor && anchor->isSystemPreviewLink();
7221#else
7222 UNUSED_PARAM(element)(void)element;
7223 return false;
7224#endif
7225}
7226
7227bool Internals::isSystemPreviewImage(Element& element) const
7228{
7229#if USE(SYSTEM_PREVIEW)(defined 1 && 1)
7230 if (auto* image = dynamicDowncast<HTMLImageElement>(element))
7231 return image->isSystemPreviewImage();
7232 if (auto* picture = dynamicDowncast<HTMLPictureElement>(element))
7233 return picture->isSystemPreviewImage();
7234 return false;
7235#else
7236 UNUSED_PARAM(element)(void)element;
7237 return false;
7238#endif
7239}
7240
7241bool Internals::usingAppleInternalSDK() const
7242{
7243#if USE(APPLE_INTERNAL_SDK)(defined USE_APPLE_INTERNAL_SDK && USE_APPLE_INTERNAL_SDK
)
7244 return true;
7245#else
7246 return false;
7247#endif
7248}
7249
7250bool Internals::usingGStreamer() const
7251{
7252#if USE(GSTREAMER)(defined USE_GSTREAMER && USE_GSTREAMER)
7253 return true;
7254#else
7255 return false;
7256#endif
7257}
7258
7259void Internals::setCaptureExtraNetworkLoadMetricsEnabled(bool value)
7260{
7261 platformStrategies()->loaderStrategy()->setCaptureExtraNetworkLoadMetricsEnabled(value);
7262}
7263
7264String Internals::ongoingLoadsDescriptions() const
7265{
7266 StringBuilder builder;
7267 builder.append('[');
7268 bool isStarting = true;
7269 for (auto& identifier : platformStrategies()->loaderStrategy()->ongoingLoads()) {
7270 if (isStarting)
7271 isStarting = false;
7272 else
7273 builder.append(',');
7274
7275 builder.append('[');
7276
7277 for (auto& info : platformStrategies()->loaderStrategy()->intermediateLoadInformationFromResourceLoadIdentifier(identifier))
7278 builder.append('[', (int)info.type, ",\""_s, info.request.url().string(), "\",\""_s, info.request.httpMethod(), "\","_s, info.response.httpStatusCode(), ']');
7279
7280 builder.append(']');
7281 }
7282 builder.append(']');
7283 return builder.toString();
7284}
7285
7286void Internals::reloadWithoutContentExtensions()
7287{
7288 if (auto* frame = this->frame())
7289 frame->loader().reload(ReloadOption::DisableContentBlockers);
7290}
7291
7292void Internals::disableContentExtensionsChecks()
7293{
7294 auto* frame = this->frame();
7295 auto* loader = frame ? frame->loader().documentLoader() : nullptr;
7296 if (loader)
7297 loader->setContentExtensionEnablement({ ContentExtensionDefaultEnablement::Disabled, { } });
7298}
7299
7300size_t Internals::pluginCount()
7301{
7302 if (!contextDocument() || !contextDocument()->page())
7303 return 0;
7304
7305 return contextDocument()->page()->pluginData().webVisiblePlugins().size();
7306}
7307
7308static std::optional<ScrollPosition> scrollPositionForPlugin(Element& element)
7309{
7310 auto* pluginElement = dynamicDowncast<HTMLPlugInElement>(element);
7311 if (auto* pluginViewBase = pluginElement ? pluginElement->pluginWidget() : nullptr)
7312 return pluginViewBase->scrollPositionForTesting();
7313 return std::nullopt;
7314}
7315
7316ExceptionOr<unsigned> Internals::pluginScrollPositionX(Element& element)
7317{
7318 if (std::optional scrollPosition = scrollPositionForPlugin(element))
7319 return scrollPosition->x();
7320 return Exception { ExceptionCode::InvalidAccessError };
7321}
7322
7323ExceptionOr<unsigned> Internals::pluginScrollPositionY(Element& element)
7324{
7325 if (std::optional scrollPosition = scrollPositionForPlugin(element))
7326 return scrollPosition->y();
7327 return Exception { ExceptionCode::InvalidAccessError };
7328}
7329
7330void Internals::notifyResourceLoadObserver()
7331{
7332 ResourceLoadObserver::singleton().updateCentralStatisticsStore([] { });
7333}
7334
7335unsigned Internals::primaryScreenDisplayID()
7336{
7337#if PLATFORM(COCOA)(defined 1 && 1)
7338 return WebCore::primaryScreenDisplayID();
7339#else
7340 return 0;
7341#endif
7342}
7343
7344bool Internals::capsLockIsOn()
7345{
7346 return WebCore::PlatformKeyboardEvent::currentCapsLockState();
7347}
7348
7349auto Internals::parseHEVCCodecParameters(StringView string) -> std::optional<HEVCParameterSet>
7350{
7351 return WebCore::parseHEVCCodecParameters(string);
7352}
7353
7354String Internals::createHEVCCodecParametersString(const HEVCParameterSet& parameters)
7355{
7356 return WebCore::createHEVCCodecParametersString(parameters);
7357}
7358
7359auto Internals::parseDoViCodecParameters(StringView string) -> std::optional<DoViParameterSet>
7360{
7361 auto parseResult = WebCore::parseDoViCodecParameters(string);
7362 if (!parseResult)
7363 return std::nullopt;
7364 DoViParameterSet convertedResult;
7365 switch (parseResult->codec) {
7366 case DoViParameters::Codec::AVC1:
7367 convertedResult.codecName = "avc1"_s;
7368 break;
7369 case DoViParameters::Codec::AVC3:
7370 convertedResult.codecName = "avc3"_s;
7371 break;
7372 case DoViParameters::Codec::HEV1:
7373 convertedResult.codecName = "hev1"_s;
7374 break;
7375 case DoViParameters::Codec::HVC1:
7376 convertedResult.codecName = "hvc1"_s;
7377 break;
7378 }
7379 convertedResult.bitstreamProfileID = parseResult->bitstreamProfileID;
7380 convertedResult.bitstreamLevelID = parseResult->bitstreamLevelID;
7381 return convertedResult;
7382}
7383
7384String Internals::createDoViCodecParametersString(const DoViParameterSet& parameterSet)
7385{
7386 DoViParameters::Codec codec;
7387 if (parameterSet.codecName == "avc1"_s)
7388 codec = DoViParameters::Codec::AVC1;
7389 else if (parameterSet.codecName == "avc3"_s)
7390 codec = DoViParameters::Codec::AVC3;
7391 else if (parameterSet.codecName == "hev1"_s)
7392 codec = DoViParameters::Codec::HEV1;
7393 else if (parameterSet.codecName == "hvc1"_s)
7394 codec = DoViParameters::Codec::HVC1;
7395 else
7396 return emptyString();
7397
7398 return WebCore::createDoViCodecParametersString({ codec, parameterSet.bitstreamProfileID, parameterSet.bitstreamLevelID });
7399}
7400
7401std::optional<VPCodecConfigurationRecord> Internals::parseVPCodecParameters(StringView string)
7402{
7403 return WebCore::parseVPCodecParameters(string);
7404}
7405
7406std::optional<AV1CodecConfigurationRecord> Internals::parseAV1CodecParameters(const String& parameters)
7407{
7408 return WebCore::parseAV1CodecParameters(parameters);
7409}
7410
7411String Internals::createAV1CodecParametersString(const AV1CodecConfigurationRecord& configuration)
7412{
7413 return WebCore::createAV1CodecParametersString(configuration);
7414}
7415
7416bool Internals::validateAV1PerLevelConstraints(const String& parameters, VideoConfiguration&& configuration)
7417{
7418 if (auto record = WebCore::parseAV1CodecParameters(parameters))
7419 return WebCore::validateAV1PerLevelConstraints(*record, toPlatform(WTF::move(configuration)));
7420 return false;
7421}
7422
7423bool Internals::validateAV1ConfigurationRecord(const String& parameters)
7424{
7425 if (auto record = WebCore::parseAV1CodecParameters(parameters))
7426 return WebCore::validateAV1ConfigurationRecord(*record);
7427 return false;
7428}
7429
7430void Internals::setCookie(CookieData&& cookieData)
7431{
7432 auto* document = contextDocument();
7433 if (!document)
7434 return;
7435
7436 auto* page = document->page();
7437 if (!page)
7438 return;
7439
7440 page->cookieJar().setRawCookie(*document, CookieData::toCookie(WTF::move(cookieData)), ShouldPartitionCookie::No);
7441}
7442
7443auto Internals::getCookies() const -> Vector<CookieData>
7444{
7445 auto* document = contextDocument();
7446 if (!document)
7447 return { };
7448
7449 auto* page = document->page();
7450 if (!page)
7451 return { };
7452
7453 Vector<Cookie> cookies;
7454 page->cookieJar().getRawCookies(*document, document->cookieURL(), cookies);
7455 return WTF::map(cookies, [](auto& cookie) {
7456 return CookieData::fromCookie(cookie);
7457 });
7458}
7459
7460static Internals::WebDriverCookieData createWebDriverCookieData(Cookie cookie)
7461{
7462 Internals::WebDriverCookieData data;
7463 data.name = cookie.name;
7464 data.value = cookie.value;
7465 data.path = cookie.path;
7466 data.domain = cookie.domain;
7467 data.secure = cookie.secure;
7468 data.httpOnly = cookie.httpOnly;
7469 data.expiry = cookie.expires ? std::make_optional(*cookie.expires / 1000) : std::nullopt;
7470
7471 // Due to how CFNetwork handles host-only cookies, we may need to prepend a '.' to the domain when
7472 // setting a cookie (see CookieStore::set). So we must strip this '.' when returning the cookie.
7473 if (data.domain.startsWith('.'))
7474 data.domain = data.domain.substring(1, data.domain.length() - 1);
7475
7476 switch (cookie.sameSite) {
7477 case Cookie::SameSitePolicy::Strict:
7478 data.sameSite = "Strict"_s;
7479 break;
7480 case Cookie::SameSitePolicy::Lax:
7481 data.sameSite = "Lax"_s;
7482 break;
7483 case Cookie::SameSitePolicy::None:
7484 data.sameSite = "None"_s;
7485 break;
7486 }
7487
7488 return data;
7489}
7490
7491auto Internals::webDriverGetCookies(Document& document) const -> Vector<WebDriverCookieData>
7492{
7493 auto* page = document.page();
7494 if (!page)
7495 return { };
7496
7497 Vector<Cookie> cookies;
7498 page->cookieJar().getRawCookies(document, document.cookieURL(), cookies);
7499 return WTF::map(cookies, [](auto& cookie) {
7500 return createWebDriverCookieData(cookie);
7501 });
7502}
7503
7504void Internals::setAlwaysAllowLocalWebarchive(bool alwaysAllowLocalWebarchive)
7505{
7506 auto* localFrame = frame();
7507 if (!localFrame)
7508 return;
7509 localFrame->loader().setAlwaysAllowLocalWebarchive(alwaysAllowLocalWebarchive);
7510}
7511
7512void Internals::processWillSuspend()
7513{
7514#if ENABLE(VIDEO)(defined 1 && 1) || ENABLE(WEB_AUDIO)(defined 1 && 1)
7515 if (RefPtr manager = sessionManager())
7516 manager->processWillSuspend();
7517#endif
7518}
7519
7520void Internals::processDidResume()
7521{
7522#if ENABLE(VIDEO)(defined 1 && 1) || ENABLE(WEB_AUDIO)(defined 1 && 1)
7523 if (RefPtr manager = sessionManager())
7524 manager->processDidResume();
7525#endif
7526}
7527
7528void Internals::testDictionaryLogging()
7529{
7530 auto* document = contextDocument();
7531 if (!document)
7532 return;
7533
7534 auto* page = document->page();
7535 if (!page)
7536 return;
7537
7538 DiagnosticLoggingClient::ValueDictionary dictionary;
7539 dictionary.set("stringKey"_s, String("stringValue"_s));
7540 dictionary.set("uint64Key"_s, std::numeric_limits<uint64_t>::max());
7541 dictionary.set("int64Key"_s, std::numeric_limits<int64_t>::min());
7542 dictionary.set("boolKey"_s, true);
7543 dictionary.set("doubleKey"_s, 2.7182818284590452353602874);
7544
7545 page->diagnosticLoggingClient().logDiagnosticMessageWithValueDictionary("testMessage"_s, "testDescription"_s, dictionary, ShouldSample::No);
7546}
7547
7548void Internals::setMaximumIntervalForUserGestureForwardingForFetch(double interval)
7549{
7550 UserGestureToken::setMaximumIntervalForUserGestureForwardingForFetchForTesting(Seconds(interval));
7551}
7552
7553void Internals::setTransientActivationDuration(double seconds)
7554{
7555 LocalDOMWindow::overrideTransientActivationDurationForTesting(Seconds { seconds });
7556}
7557
7558void Internals::setIsPlayingToAutomotiveHeadUnit(bool isPlaying)
7559{
7560#if ENABLE(VIDEO)(defined 1 && 1) || ENABLE(WEB_AUDIO)(defined 1 && 1)
7561 if (RefPtr manager = sessionManager())
7562 manager->setIsPlayingToAutomotiveHeadUnit(isPlaying);
7563#else
7564 UNUSED_PARAM(isPlaying)(void)isPlaying;
7565#endif
7566}
7567
7568String Internals::highlightPseudoElementColor(const AtomString& highlightName, Element& element)
7569{
7570 element.document().updateStyleIfNeeded();
7571
7572 auto& styleResolver = element.document().styleScope().resolver();
7573 auto* parentStyle = element.computedStyle();
7574 if (!parentStyle)
7575 return { };
7576
7577 auto resolvedStyle = styleResolver.styleForPseudoElement(element, { PseudoElementType::Highlight, highlightName }, { parentStyle });
7578 if (!resolvedStyle)
7579 return { };
7580
7581 return serializationForCSS(resolvedStyle->style->color());
7582}
7583
7584Internals::TextIndicatorInfo Internals::textIndicatorForRange(const Range& range, TextIndicatorOptions options)
7585{
7586 auto indicator = TextIndicator::createWithRange(makeSimpleRange(range), options.coreOptions(), TextIndicatorPresentationTransition::None);
7587 auto data = indicator->data();
7588 return {
7589 DOMRect::create(data.textBoundingRectInRootViewCoordinates),
7590 DOMRectList::create(data.textRectsInBoundingRectCoordinates)
7591 };
7592}
7593
7594void Internals::addPrefetchLoadEventListener(HTMLLinkElement& link, RefPtr<EventListener>&& listener)
7595{
7596 if (link.document().settings().linkPrefetchEnabled() && equalLettersIgnoringASCIICase(link.rel(), "prefetch"_s)) {
7597 link.allowPrefetchLoadAndErrorForTesting();
7598 link.addEventListener(eventNames().loadEvent, listener.releaseNonNull());
7599 }
7600}
7601
7602#if ENABLE(WEB_AUTHN)(defined 1 && 1)
7603void Internals::setMockWebAuthenticationConfiguration(const MockWebAuthenticationConfiguration& configuration)
7604{
7605 auto* document = contextDocument();
7606 if (!document)
7607 return;
7608 auto* page = document->page();
7609 if (!page)
7610 return;
7611 page->chrome().client().setMockWebAuthenticationConfiguration(configuration);
7612}
7613#endif
7614
7615void Internals::setMaxCanvasArea(unsigned size)
7616{
7617 CanvasBase::setMaxCanvasAreaForTesting(size);
7618}
7619
7620int Internals::processIdentifier() const
7621{
7622 return getCurrentProcessID();
7623}
7624
7625Ref<InternalsMapLike> Internals::createInternalsMapLike()
7626{
7627 return InternalsMapLike::create();
7628}
7629
7630Ref<InternalsSetLike> Internals::createInternalsSetLike()
7631{
7632 return InternalsSetLike::create();
7633}
7634
7635bool Internals::hasSandboxMachLookupAccessToGlobalName(const String& process, const String& service)
7636{
7637#if PLATFORM(COCOA)(defined 1 && 1)
7638 pid_t pid;
7639 if (process == "com.apple.WebKit.WebContent"_s)
7640 pid = getpid();
7641 else
7642 RELEASE_ASSERT_NOT_REACHED()do { WTF::isIntegralOrPointerType(); compilerFenceForCrash();
WTFCrashWithInfo(7642, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/testing/Internals.cpp"
, __PRETTY_FUNCTION__ ); } while (false)
;
7643
7644 return !sandbox_check(pid, "mach-lookup", static_cast<enum sandbox_filter_type>(SANDBOX_FILTER_GLOBAL_NAME | SANDBOX_CHECK_NO_REPORT), service.utf8().data());
7645#else
7646 UNUSED_PARAM(process)(void)process;
7647 UNUSED_PARAM(service)(void)service;
7648 return false;
7649#endif
7650}
7651
7652bool Internals::hasSandboxMachLookupAccessToXPCServiceName(const String& process, const String& service)
7653{
7654#if PLATFORM(COCOA)(defined 1 && 1)
7655 pid_t pid;
7656 if (process == "com.apple.WebKit.WebContent"_s)
7657 pid = getpid();
7658 else
7659 RELEASE_ASSERT_NOT_REACHED()do { WTF::isIntegralOrPointerType(); compilerFenceForCrash();
WTFCrashWithInfo(7659, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/testing/Internals.cpp"
, __PRETTY_FUNCTION__ ); } while (false)
;
7660
7661 return !sandbox_check(pid, "mach-lookup", static_cast<enum sandbox_filter_type>(SANDBOX_FILTER_XPC_SERVICE_NAME | SANDBOX_CHECK_NO_REPORT), service.utf8().data());
7662#else
7663 UNUSED_PARAM(process)(void)process;
7664 UNUSED_PARAM(service)(void)service;
7665 return false;
7666#endif
7667}
7668
7669bool Internals::hasSandboxUnixSyscallAccess(const String& process, unsigned syscall) const
7670{
7671#if PLATFORM(COCOA)(defined 1 && 1)
7672 RELEASE_ASSERT(process == "com.apple.WebKit.WebContent"_s)do { if (__builtin_expect(!!(!(process == "com.apple.WebKit.WebContent"_s
)), 0)) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7672, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/testing/Internals.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
7673 auto pid = getpid();
7674 return !sandbox_check(pid, "syscall-unix", static_cast<enum sandbox_filter_type>(SANDBOX_FILTER_SYSCALL_NUMBER | SANDBOX_CHECK_NO_REPORT), syscall);
7675#else
7676 UNUSED_PARAM(process)(void)process;
7677 UNUSED_PARAM(syscall)(void)syscall;
7678 return false;
7679#endif
7680}
7681
7682String Internals::windowLocationHost(DOMWindow& window)
7683{
7684 return window.location().host();
7685}
7686
7687void Internals::setNavigationRateLimiterParameters(DOMWindow& window, unsigned maxNavigations, double windowDurationSeconds)
7688{
7689 if (RefPtr localWindow = dynamicDowncast<LocalDOMWindow>(window))
7690 localWindow->navigation().rateLimiterForTesting().setParametersForTesting(maxNavigations, Seconds(windowDurationSeconds));
7691}
7692
7693void Internals::resetNavigationRateLimiter(DOMWindow& window)
7694{
7695 if (RefPtr localWindow = dynamicDowncast<LocalDOMWindow>(window))
7696 localWindow->navigation().rateLimiterForTesting().resetForTesting();
7697}
7698
7699ExceptionOr<String> Internals::systemColorForCSSValue(const String& cssValue, bool useDarkModeAppearance, bool useElevatedUserInterfaceLevel)
7700{
7701 CSSValueID id = cssValueKeywordID(cssValue);
7702 if (!CSS::isSystemColorKeyword(id))
7703 return Exception { ExceptionCode::InvalidAccessError };
7704
7705 OptionSet<StyleColorOptions> options;
7706 if (useDarkModeAppearance)
7707 options.add(StyleColorOptions::UseDarkAppearance);
7708 if (useElevatedUserInterfaceLevel)
7709 options.add(StyleColorOptions::UseElevatedUserInterfaceLevel);
7710
7711 return serializationForCSS(RenderTheme::singleton().systemColor(id, options));
7712}
7713
7714bool Internals::systemHasBattery() const
7715{
7716#if PLATFORM(COCOA)(defined 1 && 1)
7717 return WebCore::systemHasBattery();
7718#else
7719 return false;
7720#endif
7721}
7722
7723void Internals::setSystemHasBatteryForTesting(bool hasBattery)
7724{
7725#if PLATFORM(COCOA)(defined 1 && 1)
7726 SystemBatteryStatusTestingOverrides::singleton().setHasBattery(hasBattery);
7727#else
7728 UNUSED_PARAM(hasBattery)(void)hasBattery;
7729#endif
7730}
7731
7732void Internals::setSystemHasACForTesting(bool hasAC)
7733{
7734#if PLATFORM(COCOA)(defined 1 && 1)
7735 SystemBatteryStatusTestingOverrides::singleton().setHasAC(hasAC);
7736#else
7737 UNUSED_PARAM(hasAC)(void)hasAC;
7738#endif
7739}
7740
7741void Internals::setHardwareVP9DecoderDisabledForTesting(bool disabled)
7742{
7743#if ENABLE(VP9)(defined 1 && 1) && PLATFORM(COCOA)(defined 1 && 1)
7744 VP9TestingOverrides::singleton().setHardwareDecoderDisabled(disabled);
7745#else
7746 UNUSED_PARAM(disabled)(void)disabled;
7747#endif
7748}
7749
7750void Internals::setVP9DecoderDisabledForTesting(bool disabled)
7751{
7752#if ENABLE(VP9)(defined 1 && 1) && PLATFORM(COCOA)(defined 1 && 1)
7753 VP9TestingOverrides::singleton().setVP9DecoderDisabled(disabled);
7754#else
7755 UNUSED_PARAM(disabled)(void)disabled;
7756#endif
7757}
7758
7759void Internals::setVP9ScreenSizeAndScaleForTesting(double width, double height, double scale)
7760{
7761#if ENABLE(VP9)(defined 1 && 1) && PLATFORM(COCOA)(defined 1 && 1)
7762 VP9TestingOverrides::singleton().setVP9ScreenSizeAndScale(ScreenDataOverrides { width, height, scale });
7763#else
7764 UNUSED_PARAM(width)(void)width;
7765 UNUSED_PARAM(height)(void)height;
7766 UNUSED_PARAM(scale)(void)scale;
7767#endif
7768}
7769
7770int Internals::readPreferenceInteger(const String& domain, const String& key)
7771{
7772#if PLATFORM(COCOA)(defined 1 && 1)
7773 Boolean keyExistsAndHasValidFormat = false;
7774 return CFPreferencesGetAppIntegerValue(key.createCFString().get(), domain.createCFString().get(), &keyExistsAndHasValidFormat);
7775#else
7776 UNUSED_PARAM(domain)(void)domain;
7777 UNUSED_PARAM(key)(void)key;
7778 return -1;
7779#endif
7780}
7781
7782#if !PLATFORM(COCOA)(defined 1 && 1)
7783String Internals::encodedPreferenceValue(const String&, const String&)
7784{
7785 return emptyString();
7786}
7787
7788bool Internals::isRemoteUIAppForAccessibility()
7789{
7790 return false;
7791}
7792
7793bool Internals::hasSandboxIOKitOpenAccessToClass(const String& process, const String& ioKitClass)
7794{
7795 UNUSED_PARAM(process)(void)process;
7796 UNUSED_PARAM(ioKitClass)(void)ioKitClass;
7797 return false;
7798}
7799#endif
7800
7801#if ENABLE(APP_HIGHLIGHTS)(defined 1 && 1)
7802Vector<String> Internals::appHighlightContextMenuItemTitles() const
7803{
7804 return {{
7805 contextMenuItemTagAddHighlightToCurrentQuickNote(),
7806 contextMenuItemTagAddHighlightToNewQuickNote(),
7807 }};
7808}
7809
7810unsigned Internals::numberOfAppHighlights()
7811{
7812 Document* document = contextDocument();
7813 if (!document)
7814 return 0;
7815 auto appHighlightRegistry = document->appHighlightRegistryIfExists();
7816 if (!appHighlightRegistry)
7817 return 0;
7818 unsigned numHighlights = 0;
7819 for (auto& highlight : appHighlightRegistry->map())
7820 numHighlights += highlight.value->highlightRanges().size();
7821 return numHighlights;
7822}
7823#endif
7824
7825Vector<Ref<AbstractRange>> Internals::textExtractionHighlightRanges() const
7826{
7827 RefPtr document = contextDocument();
7828 if (!document)
7829 return { };
7830
7831 RefPtr registry = document->textExtractionHighlightRegistryIfExists();
7832 if (!registry)
7833 return { };
7834
7835 return flatMap(copyToVector(registry->map().values()), [](auto&& highlight) {
7836 return highlight->highlightRanges().map([](auto& range) {
7837 return Ref { range->range() };
7838 });
7839 });
7840}
7841
7842bool Internals::supportsPictureInPicture()
7843{
7844 return WebCore::supportsPictureInPicture();
7845}
7846
7847String Internals::focusRingColor()
7848{
7849 return serializationForCSS(RenderTheme::singleton().focusRingColor(StyleColorOptions::UseSystemAppearance));
7850}
7851
7852double Internals::switchAnimationVisuallyOnDuration() const
7853{
7854 return RenderTheme::singleton().switchAnimationVisuallyOnDuration().seconds();
7855}
7856
7857ExceptionOr<unsigned> Internals::createSleepDisabler(const String& reason, bool display)
7858{
7859 auto* document = contextDocument();
7860 if (!document || !document->pageID())
7861 return Exception { ExceptionCode::InvalidAccessError };
7862
7863 static unsigned lastUsedIdentifier = 0;
7864 auto sleepDisabler = makeUnique<WebCore::SleepDisabler>(reason, display ? PAL::SleepDisabler::Type::Display : PAL::SleepDisabler::Type::System, *document->pageID());
7865 m_sleepDisablers.add(++lastUsedIdentifier, WTF::move(sleepDisabler));
7866 return lastUsedIdentifier;
7867}
7868
7869bool Internals::destroySleepDisabler(unsigned identifier)
7870{
7871 return m_sleepDisablers.remove(identifier);
7872}
7873
7874#if ENABLE(WEBXR)(defined 0 && 0)
7875
7876ExceptionOr<Ref<WebXRTest>> Internals::xrTest()
7877{
7878 auto* document = contextDocument();
7879 if (!document || !document->window() || !document->settings().webXREnabled())
7880 return Exception { ExceptionCode::InvalidAccessError };
7881
7882 if (!m_xrTest) {
7883 auto* navigator = contextDocument()->window()->optionalNavigator();
7884 if (!navigator)
7885 return Exception { ExceptionCode::InvalidAccessError };
7886
7887 m_xrTest = WebXRTest::create(NavigatorWebXR::xr(*navigator));
7888 }
7889 return Ref<WebXRTest> { *m_xrTest };
7890}
7891
7892#endif
7893
7894#if ENABLE(ENCRYPTED_MEDIA)(defined 1 && 1)
7895unsigned Internals::mediaKeysInternalInstanceObjectRefCount(const MediaKeys& mediaKeys) const
7896{
7897 return mediaKeys.internalInstanceObjectRefCount();
7898}
7899
7900unsigned Internals::mediaKeySessionInternalInstanceSessionObjectRefCount(const MediaKeySession& mediaKeySession) const
7901{
7902 return mediaKeySession.internalInstanceSessionObjectRefCount();
7903}
7904#endif
7905
7906void Internals::setContentSizeCategory(Internals::ContentSizeCategory category)
7907{
7908#if PLATFORM(IOS)(defined 1 && 1) || PLATFORM(VISION)(defined WTF_PLATFORM_VISION && WTF_PLATFORM_VISION)
7909 CFStringRef ctCategory = nilnullptr;
7910 switch (category) {
7911 case Internals::ContentSizeCategory::L:
7912 ctCategory = kCTFontContentSizeCategoryL;
7913 break;
7914 case Internals::ContentSizeCategory::XXXL:
7915 ctCategory = kCTFontContentSizeCategoryXXXL;
7916 break;
7917 }
7918 WebCore::setContentSizeCategory(ctCategory);
7919 Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment();
7920#else
7921 UNUSED_PARAM(category)(void)category;
7922#endif
7923}
7924
7925#if ENABLE(ATTACHMENT_ELEMENT)(defined 1 && 1)
7926#if ENABLE(SERVICE_CONTROLS)(defined ENABLE_SERVICE_CONTROLS && ENABLE_SERVICE_CONTROLS
)
7927bool Internals::hasImageControls(const HTMLImageElement& element) const
7928{
7929 return ImageControlsMac::hasImageControls(element);
7930}
7931#endif // ENABLE(SERVICE_CONTROLS)
7932
7933String Internals::attachmentElementShadowUserAgentStyleSheet() const
7934{
7935 return HTMLAttachmentElement::shadowUserAgentStyleSheetText();
7936}
7937#endif // ENABLE(ATTACHMENT_ELEMENT)
7938
7939#if ENABLE(MEDIA_SESSION)(defined 1 && 1)
7940ExceptionOr<double> Internals::currentMediaSessionPosition(const MediaSession& session)
7941{
7942 if (auto currentPosition = session.currentPosition())
7943 return *currentPosition;
7944 return Exception { ExceptionCode::InvalidStateError };
7945}
7946
7947ExceptionOr<void> Internals::sendMediaSessionAction(MediaSession& session, const MediaSessionActionDetails& actionDetails)
7948{
7949 if (session.callActionHandler(actionDetails))
7950 return { };
7951
7952 return Exception { ExceptionCode::InvalidStateError };
7953}
7954
7955#if ENABLE(WEB_CODECS)(defined 1 && 1)
7956void Internals::loadArtworkImage(String&& url, ArtworkImagePromise&& promise)
7957{
7958 if (!contextDocument()) {
7959 promise.reject(Exception { ExceptionCode::InvalidStateError, "No document."_s });
7960 return;
7961 }
7962 if (m_artworkImagePromise) {
7963 promise.reject(Exception { ExceptionCode::InvalidStateError, "Another download is currently pending."_s });
7964 return;
7965 }
7966 m_artworkImagePromise = makeUnique<ArtworkImagePromise>(WTF::move(promise));
7967 m_artworkLoader = ArtworkImageLoader::create(*contextDocument(), url, [weakThis = WeakPtr { *this }](Image* image) {
7968 RefPtr protectedThis = weakThis.get();
7969 if (!protectedThis)
7970 return;
7971
7972 RefPtr document = protectedThis->contextDocument();
7973 if (!document)
7974 return;
7975
7976 auto promise = std::exchange(protectedThis->m_artworkImagePromise, { });
7977 RefPtr nativeImage = image ? image->nativeImage() : nullptr;
7978 if (!nativeImage) {
7979 promise->reject(Exception { ExceptionCode::InvalidAccessError, "No image retrieved."_s });
7980 return;
7981 }
7982 promise->settle(WebCodecsVideoFrame::create(*document, *nativeImage));
7983 });
7984 m_artworkLoader->requestImageResource();
7985}
7986#endif
7987
7988ExceptionOr<Vector<String>> Internals::platformSupportedCommands() const
7989{
7990 RefPtr manager = sessionManager();
7991 if (!manager || !contextDocument())
7992 return Exception { ExceptionCode::InvalidAccessError };
7993
7994 auto commands = manager->supportedCommands();
7995 Vector<String> commandStrings;
7996 for (auto command : commands)
7997 commandStrings.append(convertEnumerationToString(command));
7998
7999 return commandStrings;
8000}
8001
8002#endif
8003
8004#if ENABLE(MEDIA_SESSION_COORDINATOR)(defined ENABLE_MEDIA_SESSION_COORDINATOR && ENABLE_MEDIA_SESSION_COORDINATOR
)
8005ExceptionOr<void> Internals::registerMockMediaSessionCoordinator(ScriptExecutionContext& context, Ref<StringCallback>&& listener)
8006{
8007 if (m_mockMediaSessionCoordinator)
8008 return { };
8009
8010 auto* document = contextDocument();
8011 if (!document || !document->window())
8012 return Exception { ExceptionCode::InvalidAccessError };
8013
8014 if (!document->settings().mediaSessionCoordinatorEnabled())
8015 return Exception { ExceptionCode::InvalidAccessError };
8016
8017 auto& session = NavigatorMediaSession::mediaSession(document->window()->navigator());
8018 auto mock = MockMediaSessionCoordinator::create(context, WTF::move(listener));
8019 m_mockMediaSessionCoordinator = mock.ptr();
8020 session.coordinator().setMediaSessionCoordinatorPrivate(WTF::move(mock));
8021
8022 return { };
8023}
8024
8025ExceptionOr<void> Internals::setMockMediaSessionCoordinatorCommandsShouldFail(bool shouldFail)
8026{
8027 if (!m_mockMediaSessionCoordinator)
8028 return Exception { ExceptionCode::InvalidStateError };
8029
8030 m_mockMediaSessionCoordinator->setCommandsShouldFail(shouldFail);
8031 return { };
8032}
8033#endif // ENABLE(MEDIA_SESSION)
8034
8035constexpr ASCIILiteral string(std::partial_ordering ordering)
8036{
8037 if (is_lt(ordering))
8038 return "less"_s;
8039 if (is_gt(ordering))
8040 return "greater"_s;
8041 if (is_eq(ordering))
8042 return "equivalent"_s;
8043 return "unordered"_s;
8044}
8045
8046constexpr TreeType NODELETE[[clang::annotate_type("webkit.nodelete")]] convertType(Internals::TreeType type)
8047{
8048 switch (type) {
8049 case Internals::Tree:
8050 return Tree;
8051 case Internals::ShadowIncludingTree:
8052 return ShadowIncludingTree;
8053 case Internals::ComposedTree:
8054 return ComposedTree;
8055 case Internals::ComposedTreeIncludingPseudoElements:
8056 return ComposedTreeIncludingPseudoElements;
8057 }
8058 ASSERT_NOT_REACHED()((void)0);
8059 return Tree;
8060}
8061
8062String Internals::treeOrder(Node& a, Node& b, TreeType type)
8063{
8064 return string(treeOrderForTesting(convertType(type), a, b));
8065}
8066
8067String Internals::treeOrderBoundaryPoints(Node& containerA, unsigned offsetA, Node& containerB, unsigned offsetB, TreeType type)
8068{
8069 return string(treeOrderForTesting(convertType(type), BoundaryPoint( containerA, offsetA ), BoundaryPoint(containerB, offsetB)));
8070}
8071
8072bool Internals::rangeContainsNode(const AbstractRange& range, Node& node, TreeType type)
8073{
8074 return contains(convertType(type), makeSimpleRange(range), node);
8075}
8076
8077bool Internals::rangeContainsBoundaryPoint(const AbstractRange& range, Node& container, unsigned offset, TreeType type)
8078{
8079 return contains(convertType(type), makeSimpleRange(range), { container, offset });
8080}
8081
8082bool Internals::rangeContainsRange(const AbstractRange& outerRange, const AbstractRange& innerRange, TreeType type)
8083{
8084 return contains(convertType(type), makeSimpleRange(outerRange), makeSimpleRange(innerRange));
8085}
8086
8087bool Internals::rangeIntersectsNode(const AbstractRange& range, Node& node, TreeType type)
8088{
8089 return intersectsForTesting(convertType(type), makeSimpleRange(range), node);
8090}
8091
8092bool Internals::rangeIntersectsRange(const AbstractRange& a, const AbstractRange& b, TreeType type)
8093{
8094 return intersectsForTesting(convertType(type), makeSimpleRange(a), makeSimpleRange(b));
8095}
8096
8097String Internals::dumpStyleResolvers()
8098{
8099 auto* document = contextDocument();
8100 if (!document || !document->window())
8101 return { };
8102
8103 document->updateStyleIfNeeded();
8104
8105 unsigned currentIdentifier = 0;
8106 HashMap<Style::Resolver*, unsigned> resolverIdentifiers;
8107
8108 StringBuilder result;
8109
8110 auto dumpResolver = [&](auto name, auto& resolver) {
8111 auto identifier = resolverIdentifiers.ensure(&resolver, [&] {
8112 return currentIdentifier++;
8113 }).iterator->value;
8114
8115 result.append('(', name, ' ', "(identifier="_s, identifier, ") (author rule count="_s,
8116 resolver.ruleSets().authorStyle().ruleCount(), "))\n"_s);
8117 };
8118
8119 dumpResolver("document resolver"_s, document->styleScope().resolver());
8120
8121 for (auto& shadowRoot : document->inDocumentShadowRoots()) {
8122 auto name = shadowRoot.mode() == ShadowRootMode::UserAgent ? "shadow root resolver (user agent)"_s : "shadow root resolver (author)"_s;
8123 dumpResolver(name, const_cast<ShadowRoot&>(shadowRoot).styleScope().resolver());
8124 }
8125
8126 return result.toString();
8127}
8128
8129ExceptionOr<void> Internals::setDocumentAutoplayPolicy(Document& document, Internals::AutoplayPolicy policy)
8130{
8131 static_assert(static_cast<uint8_t>(WebCore::AutoplayPolicy::Default) == static_cast<uint8_t>(Internals::AutoplayPolicy::Default), "Internals::Default != WebCore::Default");
8132 static_assert(static_cast<uint8_t>(WebCore::AutoplayPolicy::Allow) == static_cast<uint8_t>(Internals::AutoplayPolicy::Allow), "Internals::Allow != WebCore::Allow");
8133 static_assert(static_cast<uint8_t>(WebCore::AutoplayPolicy::AllowWithoutSound) == static_cast<uint8_t>(Internals::AutoplayPolicy::AllowWithoutSound), "Internals::AllowWithoutSound != WebCore::AllowWithoutSound");
8134 static_assert(static_cast<uint8_t>(WebCore::AutoplayPolicy::Deny) == static_cast<uint8_t>(Internals::AutoplayPolicy::Deny), "Internals::Deny != WebCore::Deny");
8135
8136 auto* loader = document.loader();
8137 if (!loader)
8138 return Exception { ExceptionCode::InvalidStateError };
8139
8140 loader->setAutoplayPolicy(static_cast<WebCore::AutoplayPolicy>(policy));
8141
8142 return { };
8143}
8144
8145void Internals::retainTextIteratorForDocumentContent()
8146{
8147 auto* document = contextDocument();
8148 if (!document)
8149 return;
8150
8151 auto range = makeRangeSelectingNodeContents(*document);
8152 m_textIterator = makeUnique<TextIterator>(range);
8153}
8154
8155RefPtr<PushSubscription> Internals::createPushSubscription(const String& endpoint, std::optional<EpochTimeStamp> expirationTime, const ArrayBuffer& serverVAPIDPublicKey, const ArrayBuffer& clientECDHPublicKey, const ArrayBuffer& auth)
8156{
8157 return PushSubscription::create(PushSubscriptionData { std::nullopt, { endpoint }, expirationTime, serverVAPIDPublicKey.toVector(), clientECDHPublicKey.toVector(), auth.toVector() });
8158}
8159
8160bool Internals::hasSleepDisabler() const
8161{
8162 auto* document = contextDocument();
8163 return document && document->hasSleepDisabler();
8164}
8165
8166void Internals::acceptTypedArrays(Int32Array&)
8167{
8168 // Do nothing.
8169}
8170
8171Internals::SelectorFilterHashCounts Internals::selectorFilterHashCounts(const String& selector)
8172{
8173 auto selectorList = CSSSelectorParser::parseSelectorList(selector, CSSParserContext(*contextDocument()));
8174 if (!selectorList)
8175 return { };
8176
8177 auto hashes = SelectorFilter::collectHashesForTesting(selectorList->first());
8178
8179 return { hashes.ids.size(), hashes.classes.size(), hashes.tags.size(), hashes.attributes.size() };
8180}
8181
8182// This produces statistics for every JS wrapper (including duplicate JS wrappers for the same dom node).
8183JSC::JSValue Internals::dumpJSNodeStatistics()
8184{
8185 auto* document = contextDocument();
8186 if (!document)
8187 return JSC::jsNull();
8188
8189 auto& vm = document->vm();
8190 auto* globalObject = vm.topCallFrame->lexicalGlobalObject(vm);
8191
8192 vm.heap.collectNow(JSC::Sync, JSC::CollectionScope::Full);
8193
8194 struct Entry {
8195 size_t connected { 0 };
8196 size_t count { 0 };
8197 };
8198 HashMap<String, Entry> stats;
8199 Entry totals;
8200
8201 {
8202 JSC::HeapIterationScope iterationScope(vm.heap);
8203 vm.heap.objectSpace().forEachLiveCell(iterationScope, [&](JSC::HeapCell* heapCell, JSC::HeapCell::Kind kind) {
8204 if (!isJSCellKind(kind))
8205 return IterationStatus::Continue;
8206 SUPPRESS_MEMORY_UNSAFE_CAST[[clang::suppress]] auto* jsNode = dynamicDowncast<JSNode>(static_cast<JSC::JSCell*>(heapCell));
8207 if (!jsNode)
8208 return IterationStatus::Continue;
8209
8210 auto& node = jsNode->wrapped();
8211 String nodeName;
8212 if (node.isElementNode())
8213 nodeName = downcast<Element>(node).tagName();
8214 else
8215 nodeName = node.localName();
8216 bool connected = node.isConnected();
8217
8218 if (!nodeName)
8219 return IterationStatus::Continue;
8220
8221 auto& entry = stats.add(WTF::move(nodeName), Entry { }).iterator->value;
8222 ++entry.count;
8223 ++totals.count;
8224 if (connected) {
8225 ++entry.connected;
8226 ++totals.connected;
8227 }
8228
8229 return IterationStatus::Continue;
8230 });
8231 }
8232
8233 auto* result = JSC::constructEmptyObject(globalObject);
8234 auto makeEntry = [&](const Entry& e) {
8235 auto* obj = JSC::constructEmptyObject(globalObject);
8236 obj->putDirect(vm, JSC::Identifier::fromString(vm, "connected"_s), JSC::jsNumber(e.connected));
8237 obj->putDirect(vm, JSC::Identifier::fromString(vm, "count"_s), JSC::jsNumber(e.count));
8238 return obj;
8239 };
8240 result->putDirect(vm, JSC::Identifier::fromString(vm, "nodes"_s), makeEntry(totals));
8241 for (auto& [key, entry] : stats)
8242 result->putDirect(vm, JSC::Identifier::fromString(vm, key), makeEntry(entry));
8243
8244 return result;
8245}
8246
8247bool Internals::isVisuallyNonEmpty() const
8248{
8249 auto* document = contextDocument();
8250 if (!document || !document->frame())
8251 return false;
8252
8253 auto* frameView = document->frame()->view();
8254 return frameView && frameView->isVisuallyNonEmpty();
8255}
8256
8257bool Internals::isUsingUISideCompositing() const
8258{
8259 auto* document = contextDocument();
8260 if (!document)
8261 return false;
8262 auto* page = document->page();
8263 if (!page)
8264 return false;
8265 return page->chrome().client().isUsingUISideCompositing();
8266}
8267
8268AccessibilityObject* Internals::axObjectForElement(Element& element) const
8269{
8270 auto* document = contextDocument();
8271 if (!document)
8272 return nullptr;
8273 WebCore::AXObjectCache::enableAccessibility();
8274
8275 if (CheckedPtr cache = document->axObjectCache()) {
8276 cache->performDeferredCacheUpdate(ForceLayout::No);
8277 return cache->exportedGetOrCreate(element);
8278 }
8279 return nullptr;
8280}
8281
8282String Internals::getComputedLabel(Element& element) const
8283{
8284 // Force a layout. If we don't, and this request has come in before the render tree was built,
8285 // the accessibility object for this element will not be created (because it doesn't yet have its renderer).
8286 updateLayoutAndStyleForAllFrames();
8287
8288 RefPtr axObject = axObjectForElement(element);
8289 return axObject ? axObject->computedLabel() : ""_s;
8290}
8291
8292String Internals::getComputedRole(Element& element) const
8293{
8294 updateLayoutAndStyleForAllFrames();
8295
8296 RefPtr axObject = axObjectForElement(element);
8297 return axObject ? axObject->computedRoleString() : ""_s;
8298}
8299
8300void Internals::setHistoryTotalStateObjectPayloadLimitOverride(uint32_t limit)
8301{
8302 RefPtr window = contextDocument() ? contextDocument()->window() : nullptr;
8303 if (!window)
8304 return;
8305 window->history().setTotalStateObjectPayloadLimitOverride(limit);
8306}
8307
8308void Internals::setPDFDisplayModeForTesting(Element& element, const String& displayMode) const
8309{
8310 RefPtr pluginElement = dynamicDowncast<HTMLPlugInElement>(element);
8311 if (!pluginElement)
8312 return;
8313
8314 RefPtr pluginViewBase = pluginElement->pluginWidget();
8315 if (!pluginViewBase)
8316 return;
8317
8318 pluginViewBase->setPDFDisplayModeForTesting(displayMode);
8319}
8320
8321void Internals::unlockPDFDocumentForTesting(Element& element, const String& password) const
8322{
8323 RefPtr pluginElement = dynamicDowncast<HTMLPlugInElement>(element);
8324 if (!pluginElement)
8325 return;
8326
8327 RefPtr pluginViewBase = pluginElement->pluginWidget();
8328 if (!pluginViewBase)
8329 return;
8330
8331 pluginViewBase->unlockPDFDocumentForTesting(password);
8332}
8333
8334bool Internals::sendEditingCommandToPDFForTesting(Element& element, const String& commandName, const String& argument) const
8335{
8336 RefPtr pluginElement = dynamicDowncast<HTMLPlugInElement>(element);
8337 if (!pluginElement)
8338 return false;
8339
8340 RefPtr pluginViewBase = pluginElement->pluginWidget();
8341 if (!pluginViewBase)
8342 return false;
8343
8344 return pluginViewBase->sendEditingCommandToPDFForTesting(commandName, argument);
8345}
8346
8347Vector<Internals::PDFAnnotationRect> Internals::pdfAnnotationRectsForTesting(Element& element) const
8348{
8349 Vector<PDFAnnotationRect> annotationRects;
8350 if (RefPtr pluginElement = dynamicDowncast<HTMLPlugInElement>(element)) {
8351 if (RefPtr pluginViewBase = pluginElement ? pluginElement->pluginWidget() : nullptr) {
8352 for (auto& annotationRect : pluginViewBase->pdfAnnotationRectsForTesting())
8353 annotationRects.append({ annotationRect.x(), annotationRect.y(), annotationRect.width(), annotationRect.height() });
8354 }
8355 }
8356 return annotationRects;
8357}
8358
8359void Internals::setPDFTextAnnotationValueForTesting(Element& element, unsigned pageIndex, unsigned annotationIndex, const String& value)
8360{
8361 RefPtr pluginElement = dynamicDowncast<HTMLPlugInElement>(element);
8362 if (!pluginElement)
8363 return;
8364
8365 RefPtr pluginView = pluginElement->pluginWidget();
8366 if (!pluginView)
8367 return;
8368
8369 pluginView->setPDFTextAnnotationValueForTesting(pageIndex, annotationIndex, value);
8370}
8371
8372void Internals::registerPDFTest(Ref<VoidCallback>&& callback, Element& element)
8373{
8374 RefPtr pluginElement = dynamicDowncast<HTMLPlugInElement>(element);
8375 if (!pluginElement)
8376 return;
8377
8378 if (RefPtr pluginViewBase = pluginElement->pluginWidget())
8379 pluginViewBase->registerPDFTestCallback(WTF::move(callback));
8380}
8381
8382String Internals::defaultSpatialTrackingLabel() const
8383{
8384#if HAVE(SPATIAL_TRACKING_LABEL)(defined HAVE_SPATIAL_TRACKING_LABEL && HAVE_SPATIAL_TRACKING_LABEL
)
8385 auto* document = contextDocument();
8386 if (!document)
8387 return nullString();
8388 if (RefPtr page = document->page())
8389 return page->defaultSpatialTrackingLabel();
8390#endif
8391 return nullString();
8392}
8393
8394#if ENABLE(VIDEO)(defined 1 && 1)
8395bool Internals::isEffectivelyMuted(const HTMLMediaElement& element)
8396{
8397 return element.effectiveMuted();
8398}
8399
8400Ref<EventTarget> Internals::addInternalEventTarget(HTMLMediaElement& element)
8401{
8402 return EventTargetForTesting::create(element.document(), element);
8403}
8404#endif
8405
8406std::optional<RenderingMode> Internals::getEffectiveRenderingModeOfNewlyCreatedAcceleratedImageBuffer()
8407{
8408 RefPtr document = contextDocument();
8409 if (!document || !document->page())
8410 return std::nullopt;
8411
8412 if (RefPtr imageBuffer = ImageBuffer::create({ 100, 100 }, RenderingMode::Accelerated, RenderingPurpose::DOM, 1, DestinationColorSpace::SRGB(), PixelFormat::BGRA8, &document->page()->chrome())) {
8413 imageBuffer->ensureBackendCreated();
8414 if (imageBuffer->hasBackend())
8415 return imageBuffer->renderingMode();
8416 }
8417 return std::nullopt;
8418}
8419
8420void Internals::getImageBufferResourceLimits(ImageBufferResourceLimitsPromise&& promise)
8421{
8422 RefPtr document = contextDocument();
8423 if (!document || !document->page()) {
8424 promise.reject(Exception { ExceptionCode::InvalidStateError });
8425 return;
8426 }
8427
8428 document->page()->chrome().client().getImageBufferResourceLimitsForTesting([promise = WTF::move(promise)](auto&& limits) mutable {
8429 if (!limits) {
8430 promise.reject(Exception { ExceptionCode::InvalidStateError });
8431 return;
8432 }
8433 promise.resolve(*limits);
8434 });
8435}
8436
8437void Internals::setResourceCachingDisabledByWebInspector(bool disabled)
8438{
8439 auto* document = contextDocument();
8440 if (!document || !document->page())
8441 return;
8442
8443 document->page()->setResourceCachingDisabledByWebInspector(disabled);
8444}
8445
8446ExceptionOr<void> Internals::lowerAllFrameMemoryMonitorLimits()
8447{
8448 RefPtr document = contextDocument();
8449
8450 if (!document || !document->frame())
8451 return Exception { ExceptionCode::InvalidAccessError };
8452
8453
8454 document->frameMemoryMonitor().lowerAllMemoryLimitsForTesting();
8455 return { };
8456}
8457
8458void Internals::setTopDocumentURLForQuirks(const String& urlString)
8459{
8460 RefPtr document = contextDocument();
8461 if (!document || !document->page())
8462 return;
8463
8464 protect(document->page())->settings().setNeedsSiteSpecificQuirks(true);
8465 document->quirks().setTopDocumentURLForTesting(URL { urlString });
8466}
8467
8468#if ENABLE(CONTENT_EXTENSIONS)(defined 1 && 1)
8469void Internals::setResourceMonitorNetworkUsageThreshold(size_t threshold, double randomness)
8470{
8471 ResourceMonitorChecker::singleton().setNetworkUsageThreshold(threshold, randomness);
8472}
8473
8474bool Internals::shouldSkipResourceMonitorThrottling() const
8475{
8476 if (auto* document = contextDocument())
8477 return document->shouldSkipResourceMonitorThrottling();
8478
8479 return false;
8480}
8481
8482void Internals::setShouldSkipResourceMonitorThrottling(bool flag)
8483{
8484 if (auto* document = contextDocument())
8485 document->setShouldSkipResourceMonitorThrottling(flag);
8486}
8487#endif
8488
8489#if ENABLE(DAMAGE_TRACKING)(defined ENABLE_DAMAGE_TRACKING && ENABLE_DAMAGE_TRACKING
)
8490ExceptionOr<Vector<Internals::FrameDamage>> Internals::getFrameDamageHistory() const
8491{
8492 RefPtr document = contextDocument();
8493 if (!document || !document->page())
8494 return Exception { ExceptionCode::NotSupportedError };
8495
8496 Vector<Internals::FrameDamage> damageDetails;
8497 unsigned sequenceId = 0;
8498 document->page()->chrome().client().foreachRegionInDamageHistoryForTesting([&](const auto& region) {
8499 const auto& regionBounds = region.bounds();
8500 damageDetails.append(FrameDamage {
8501 .sequenceId = sequenceId++,
8502 .bounds = DOMRectReadOnly::create(regionBounds.x(), regionBounds.y(), regionBounds.width(), regionBounds.height()),
8503 .rects = region.rects().map([](const IntRect& rect) -> Ref<DOMRectReadOnly> {
8504 return DOMRectReadOnly::create(rect.x(), rect.y(), rect.width(), rect.height());
8505 }),
8506 });
8507 });
8508
8509 return damageDetails;
8510}
8511#endif
8512
8513RefPtr<MediaSessionManagerInterface> Internals::sessionManager() const
8514{
8515 RefPtr document = contextDocument();
8516 if (!document)
8517 return nullptr;
8518
8519 RefPtr page = document->page();
8520 if (!page)
8521 return nullptr;
8522
8523 return page->mediaSessionManager();
8524}
8525
8526bool Internals::hasMediaSessionManager() const
8527{
8528 auto* document = contextDocument();
8529 if (!document)
8530 return false;
8531
8532 auto* page = document->page();
8533 if (!page)
8534 return false;
8535
8536 return !!page->mediaSessionManagerIfExists();
8537}
8538
8539size_t Internals::fileConnectionHandleCount(const FileSystemHandle& handle) const
8540{
8541 return handle.connectionHandleCount();
8542}
8543
8544static void storeNextResults(DOMAsyncIterator& iterator, Vector<JSC::Strong<JSC::Unknown>>&& results, Internals::IteratorResultPromise&& promise)
8545{
8546 iterator.callNext([iterator = Ref { iterator }, results = WTF::move(results), promise = WTF::move(promise)](auto* globalObject, bool isOK, JSC::JSValue value) mutable {
8547 if (!globalObject) {
8548 promise.reject(Exception { ExceptionCode::InvalidStateError });
8549 return;
8550 }
8551
8552 if (!isOK) {
8553 promise.rejectWithCallback([value](auto&) {
8554 return value;
8555 });
8556 return;
8557 }
8558
8559 Ref vm = globalObject->vm();
8560 results.append({ vm.get(), value });
8561
8562 auto scope = DECLARE_THROW_SCOPE(vm)JSC::ThrowScope((vm));
8563 auto done = value.get(globalObject, vm->propertyNames->done);
8564 if (scope.exception()) {
8565 promise.reject(Exception { ExceptionCode::ExistingExceptionError });
8566 return;
8567 }
8568
8569 if (done.toBoolean(globalObject)) {
8570 promise.resolve(WTF::move(results));
8571 return;
8572 }
8573
8574 storeNextResults(iterator.get(), WTF::move(results), WTF::move(promise));
8575 });
8576
8577}
8578
8579void Internals::testAsyncIterator(JSDOMGlobalObject& globalObject, JSC::JSValue value, IteratorResultPromise&& promise)
8580{
8581 auto domIteratorOrException = DOMAsyncIterator::create(globalObject, value);
8582 if (domIteratorOrException.hasException()) {
8583 promise.reject(domIteratorOrException.releaseException());
8584 return;
8585 }
8586
8587 Vector<JSC::Strong<JSC::Unknown>> results;
8588 Ref domIterator = domIteratorOrException.releaseReturnValue();
8589 storeNextResults(domIterator.get(), WTF::move(results), WTF::move(promise));
8590}
8591
8592ExceptionOr<Ref<ReadableStream>> Internals::readableStreamFromMessagePort(JSDOMGlobalObject& globalObject, MessagePort& port)
8593{
8594 return setupCrossRealmTransformReadable(globalObject, port);
8595}
8596
8597ExceptionOr<Ref<WritableStream>> Internals::writableStreamFromMessagePort(JSDOMGlobalObject& globalObject, MessagePort& port)
8598{
8599 return setupCrossRealmTransformWritable(globalObject, port);
8600}
8601
8602#if ENABLE(MODEL_ELEMENT)(defined 1 && 1)
8603void Internals::disableModelLoadDelaysForTesting()
8604{
8605 auto* document = contextDocument();
8606 if (!document || !document->page())
8607 return;
8608
8609 document->page()->disableModelLoadDelaysForTesting();
8610}
8611
8612String Internals::modelElementState(HTMLModelElement& element)
8613{
8614 return element.modelElementStateForTesting();
8615}
8616
8617bool Internals::isModelElementIntersectingViewport(HTMLModelElement& element)
8618{
8619 return element.isIntersectingViewport();
8620}
8621#endif
8622
8623// FIXME: Implement this method for iOS.
8624ExceptionOr<void> Internals::copyImageAtLocation(int x, int y)
8625{
8626#if !PLATFORM(IOS_FAMILY)(defined 1 && 1)
8627 RefPtr document = contextDocument();
8628 if (!document || !document->frame())
8629 return Exception { ExceptionCode::InvalidAccessError };
8630
8631 document->updateLayout(LayoutOptions::IgnorePendingStylesheets);
8632
8633 constexpr OptionSet<HitTestRequest::Type> hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowChildFrameContent };
8634
8635 RefPtr localFrame = dynamicDowncast<LocalFrame>(document->frame()->mainFrame());
8636 if (!localFrame)
8637 return Exception { ExceptionCode::InvalidAccessError };
8638
8639 auto hitTestResult = localFrame->eventHandler().hitTestResultAtPoint(IntPoint(x, y), hitType);
8640 protect(localFrame->editor())->copyImage(hitTestResult);
8641#endif
8642 UNUSED_PARAM(x)(void)x;
8643 UNUSED_PARAM(y)(void)y;
8644 return { };
8645}
8646
8647#if ENABLE(WIRELESS_PLAYBACK_MEDIA_PLAYER)(defined ENABLE_WIRELESS_PLAYBACK_MEDIA_PLAYER && ENABLE_WIRELESS_PLAYBACK_MEDIA_PLAYER
)
8648MockMediaDeviceRouteController& Internals::mockMediaDeviceRouteController()
8649{
8650 if (!m_mockMediaDeviceRouteController)
8651 m_mockMediaDeviceRouteController = MockMediaDeviceRouteController::create();
8652 return *m_mockMediaDeviceRouteController;
8653}
8654#endif
8655
8656} // namespace WebCore