1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013-2019 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 "AXObjectCache.h"
31#include "ActiveDOMCallbackMicrotask.h"
32#include "ActivityState.h"
33#include "AnimationTimeline.h"
34#include "ApplicationCacheStorage.h"
35#include "AudioSession.h"
36#include "Autofill.h"
37#include "BackForwardController.h"
38#include "BitmapImage.h"
39#include "CSSAnimationController.h"
40#include "CSSKeyframesRule.h"
41#include "CSSMediaRule.h"
42#include "CSSStyleRule.h"
43#include "CSSSupportsRule.h"
44#include "CacheStorageConnection.h"
45#include "CacheStorageProvider.h"
46#include "CachedImage.h"
47#include "CachedResourceLoader.h"
48#include "CertificateInfo.h"
49#include "Chrome.h"
50#include "ChromeClient.h"
51#include "ClientOrigin.h"
52#include "ComposedTreeIterator.h"
53#include "CookieJar.h"
54#include "Cursor.h"
55#include "DOMRect.h"
56#include "DOMRectList.h"
57#include "DOMStringList.h"
58#include "DOMWindow.h"
59#include "DeprecatedGlobalSettings.h"
60#include "DiagnosticLoggingClient.h"
61#include "DisabledAdaptations.h"
62#include "DisplayList.h"
63#include "Document.h"
64#include "DocumentLoader.h"
65#include "DocumentMarkerController.h"
66#include "DocumentTimeline.h"
67#include "Editor.h"
68#include "Element.h"
69#include "EventHandler.h"
70#include "ExtendableEvent.h"
71#include "ExtensionStyleSheets.h"
72#include "FetchResponse.h"
73#include "File.h"
74#include "FontCache.h"
75#include "FormController.h"
76#include "Frame.h"
77#include "FrameLoader.h"
78#include "FrameView.h"
79#include "FullscreenManager.h"
80#include "GCObservation.h"
81#include "GridPosition.h"
82#include "HEVCUtilities.h"
83#include "HTMLAnchorElement.h"
84#include "HTMLCanvasElement.h"
85#include "HTMLIFrameElement.h"
86#include "HTMLImageElement.h"
87#include "HTMLInputElement.h"
88#include "HTMLLinkElement.h"
89#include "HTMLNames.h"
90#include "HTMLPictureElement.h"
91#include "HTMLPlugInElement.h"
92#include "HTMLPreloadScanner.h"
93#include "HTMLSelectElement.h"
94#include "HTMLTextAreaElement.h"
95#include "HTMLVideoElement.h"
96#include "HistoryController.h"
97#include "HistoryItem.h"
98#include "HitTestResult.h"
99#include "IDBRequest.h"
100#include "IDBTransaction.h"
101#include "InspectorClient.h"
102#include "InspectorController.h"
103#include "InspectorFrontendClientLocal.h"
104#include "InspectorOverlay.h"
105#include "InstrumentingAgents.h"
106#include "IntRect.h"
107#include "InternalSettings.h"
108#include "JSImageData.h"
109#include "LibWebRTCProvider.h"
110#include "LoaderStrategy.h"
111#include "MallocStatistics.h"
112#include "MediaDevices.h"
113#include "MediaEngineConfigurationFactory.h"
114#include "MediaPlayer.h"
115#include "MediaProducer.h"
116#include "MediaResourceLoader.h"
117#include "MediaStreamTrack.h"
118#include "MemoryCache.h"
119#include "MemoryInfo.h"
120#include "MockLibWebRTCPeerConnection.h"
121#include "MockPageOverlay.h"
122#include "MockPageOverlayClient.h"
123#include "NavigatorMediaDevices.h"
124#include "NetworkLoadInformation.h"
125#include "Page.h"
126#include "PageCache.h"
127#include "PageOverlay.h"
128#include "PathUtilities.h"
129#include "PlatformKeyboardEvent.h"
130#include "PlatformMediaSessionManager.h"
131#include "PlatformScreen.h"
132#include "PlatformStrategies.h"
133#include "PluginData.h"
134#include "PrintContext.h"
135#include "PseudoElement.h"
136#include "Range.h"
137#include "ReadableStream.h"
138#include "RenderEmbeddedObject.h"
139#include "RenderLayerBacking.h"
140#include "RenderLayerCompositor.h"
141#include "RenderMenuList.h"
142#include "RenderTreeAsText.h"
143#include "RenderView.h"
144#include "RenderedDocumentMarker.h"
145#include "ResourceLoadObserver.h"
146#include "RuntimeEnabledFeatures.h"
147#include "SMILTimeContainer.h"
148#include "SVGDocumentExtensions.h"
149#include "SVGPathStringBuilder.h"
150#include "SVGSVGElement.h"
151#include "SWClientConnection.h"
152#include "SchemeRegistry.h"
153#include "ScriptedAnimationController.h"
154#include "ScrollingCoordinator.h"
155#include "ScrollingMomentumCalculator.h"
156#include "SecurityOrigin.h"
157#include "SerializedScriptValue.h"
158#include "ServiceWorker.h"
159#include "ServiceWorkerProvider.h"
160#include "ServiceWorkerRegistrationData.h"
161#include "Settings.h"
162#include "ShadowRoot.h"
163#include "SourceBuffer.h"
164#include "SpellChecker.h"
165#include "StaticNodeList.h"
166#include "StringCallback.h"
167#include "StyleRule.h"
168#include "StyleScope.h"
169#include "StyleSheetContents.h"
170#include "TextIterator.h"
171#include "TreeScope.h"
172#include "TypeConversions.h"
173#include "UserGestureIndicator.h"
174#include "UserMediaController.h"
175#include "ViewportArguments.h"
176#include "VoidCallback.h"
177#include "WebCoreJSClientData.h"
178#include "WindowProxy.h"
179#include "WorkerThread.h"
180#include "WorkletGlobalScope.h"
181#include "WritingDirection.h"
182#include "XMLHttpRequest.h"
183#include <JavaScriptCore/CodeBlock.h>
184#include <JavaScriptCore/InspectorAgentBase.h>
185#include <JavaScriptCore/InspectorFrontendChannel.h>
186#include <JavaScriptCore/JSCInlines.h>
187#include <JavaScriptCore/JSCJSValue.h>
188#include <wtf/HexNumber.h>
189#include <wtf/JSONValues.h>
190#include <wtf/Language.h>
191#include <wtf/MemoryPressureHandler.h>
192#include <wtf/MonotonicTime.h>
193#include <wtf/URLHelpers.h>
194#include <wtf/text/StringBuilder.h>
195#include <wtf/text/StringConcatenateNumbers.h>
196
197#if USE(CG)
198#include "PDFDocumentImage.h"
199#endif
200
201#if ENABLE(INPUT_TYPE_COLOR)
202#include "ColorChooser.h"
203#endif
204
205#if ENABLE(MOUSE_CURSOR_SCALE)
206#include <wtf/dtoa.h>
207#endif
208
209#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
210#include "LegacyCDM.h"
211#include "LegacyMockCDM.h"
212#endif
213
214#if ENABLE(ENCRYPTED_MEDIA)
215#include "MockCDMFactory.h"
216#endif
217
218#if ENABLE(VIDEO_TRACK)
219#include "CaptionUserPreferences.h"
220#include "PageGroup.h"
221#include "TextTrackCueGeneric.h"
222#endif
223
224#if ENABLE(VIDEO)
225#include "HTMLMediaElement.h"
226#include "TimeRanges.h"
227#endif
228
229#if ENABLE(WEBGL)
230#include "WebGLRenderingContext.h"
231#endif
232
233#if ENABLE(SPEECH_SYNTHESIS)
234#include "DOMWindowSpeechSynthesis.h"
235#include "PlatformSpeechSynthesizerMock.h"
236#include "SpeechSynthesis.h"
237#endif
238
239#if ENABLE(MEDIA_STREAM)
240#include "MediaRecorder.h"
241#include "MediaRecorderPrivateMock.h"
242#include "MediaStream.h"
243#include "MockRealtimeMediaSourceCenter.h"
244#endif
245
246#if ENABLE(WEB_RTC)
247#include "RTCPeerConnection.h"
248#endif
249
250#if ENABLE(MEDIA_SOURCE)
251#include "MockMediaPlayerMediaSource.h"
252#endif
253
254#if ENABLE(CONTENT_FILTERING)
255#include "MockContentFilterSettings.h"
256#endif
257
258#if ENABLE(WEB_AUDIO)
259#include "AudioContext.h"
260#endif
261
262#if ENABLE(MEDIA_SESSION)
263#include "MediaSession.h"
264#include "MediaSessionManager.h"
265#endif
266
267#if ENABLE(WIRELESS_PLAYBACK_TARGET)
268#include "MediaPlaybackTargetContext.h"
269#endif
270
271#if ENABLE(POINTER_LOCK)
272#include "PointerLockController.h"
273#endif
274
275#if USE(QUICK_LOOK)
276#include "MockPreviewLoaderClient.h"
277#include "PreviewLoader.h"
278#endif
279
280#if ENABLE(APPLE_PAY)
281#include "MockPaymentCoordinator.h"
282#include "PaymentCoordinator.h"
283#endif
284
285#if PLATFORM(MAC) && USE(LIBWEBRTC)
286#include <webrtc/sdk/WebKit/VideoProcessingSoftLink.h>
287#endif
288
289#if PLATFORM(MAC)
290#include "GraphicsContext3DManager.h"
291#endif
292
293using JSC::CallData;
294using JSC::CallType;
295using JSC::CodeBlock;
296using JSC::FunctionExecutable;
297using JSC::Identifier;
298using JSC::JSFunction;
299using JSC::JSGlobalObject;
300using JSC::JSObject;
301using JSC::JSValue;
302using JSC::MarkedArgumentBuffer;
303using JSC::PropertySlot;
304using JSC::ScriptExecutable;
305using JSC::StackVisitor;
306
307
308namespace WebCore {
309using namespace Inspector;
310
311using namespace HTMLNames;
312
313class InspectorStubFrontend final : public InspectorFrontendClientLocal, public FrontendChannel {
314public:
315 InspectorStubFrontend(Page& inspectedPage, RefPtr<DOMWindow>&& frontendWindow);
316 virtual ~InspectorStubFrontend();
317
318private:
319 void attachWindow(DockSide) final { }
320 void detachWindow() final { }
321 void closeWindow() final;
322 void reopen() final { }
323 void bringToFront() final { }
324 String localizedStringsURL() final { return String(); }
325 void inspectedURLChanged(const String&) final { }
326 void showCertificate(const CertificateInfo&) final { }
327 void setAttachedWindowHeight(unsigned) final { }
328 void setAttachedWindowWidth(unsigned) final { }
329 void setSheetRect(const FloatRect&) final { }
330
331 void sendMessageToFrontend(const String& message) final;
332 ConnectionType connectionType() const final { return ConnectionType::Local; }
333
334 Page* frontendPage() const
335 {
336 if (!m_frontendWindow || !m_frontendWindow->document())
337 return nullptr;
338
339 return m_frontendWindow->document()->page();
340 }
341
342 RefPtr<DOMWindow> m_frontendWindow;
343 InspectorController& m_frontendController;
344};
345
346InspectorStubFrontend::InspectorStubFrontend(Page& inspectedPage, RefPtr<DOMWindow>&& frontendWindow)
347 : InspectorFrontendClientLocal(&inspectedPage.inspectorController(), frontendWindow->document()->page(), std::make_unique<InspectorFrontendClientLocal::Settings>())
348 , m_frontendWindow(frontendWindow.copyRef())
349 , m_frontendController(frontendPage()->inspectorController())
350{
351 ASSERT_ARG(frontendWindow, frontendWindow);
352
353 m_frontendController.setInspectorFrontendClient(this);
354 inspectedPage.inspectorController().connectFrontend(*this);
355}
356
357InspectorStubFrontend::~InspectorStubFrontend()
358{
359 closeWindow();
360}
361
362void InspectorStubFrontend::closeWindow()
363{
364 if (!m_frontendWindow)
365 return;
366
367 m_frontendController.setInspectorFrontendClient(nullptr);
368 inspectedPage()->inspectorController().disconnectFrontend(*this);
369
370 m_frontendWindow->close();
371 m_frontendWindow = nullptr;
372}
373
374void InspectorStubFrontend::sendMessageToFrontend(const String& message)
375{
376 ASSERT_ARG(message, !message.isEmpty());
377
378 InspectorClient::doDispatchMessageOnFrontendPage(frontendPage(), message);
379}
380
381static bool markerTypeFrom(const String& markerType, DocumentMarker::MarkerType& result)
382{
383 if (equalLettersIgnoringASCIICase(markerType, "spelling"))
384 result = DocumentMarker::Spelling;
385 else if (equalLettersIgnoringASCIICase(markerType, "grammar"))
386 result = DocumentMarker::Grammar;
387 else if (equalLettersIgnoringASCIICase(markerType, "textmatch"))
388 result = DocumentMarker::TextMatch;
389 else if (equalLettersIgnoringASCIICase(markerType, "replacement"))
390 result = DocumentMarker::Replacement;
391 else if (equalLettersIgnoringASCIICase(markerType, "correctionindicator"))
392 result = DocumentMarker::CorrectionIndicator;
393 else if (equalLettersIgnoringASCIICase(markerType, "rejectedcorrection"))
394 result = DocumentMarker::RejectedCorrection;
395 else if (equalLettersIgnoringASCIICase(markerType, "autocorrected"))
396 result = DocumentMarker::Autocorrected;
397 else if (equalLettersIgnoringASCIICase(markerType, "spellcheckingexemption"))
398 result = DocumentMarker::SpellCheckingExemption;
399 else if (equalLettersIgnoringASCIICase(markerType, "deletedautocorrection"))
400 result = DocumentMarker::DeletedAutocorrection;
401 else if (equalLettersIgnoringASCIICase(markerType, "dictationalternatives"))
402 result = DocumentMarker::DictationAlternatives;
403#if ENABLE(TELEPHONE_NUMBER_DETECTION)
404 else if (equalLettersIgnoringASCIICase(markerType, "telephonenumber"))
405 result = DocumentMarker::TelephoneNumber;
406#endif
407 else
408 return false;
409
410 return true;
411}
412
413static bool markerTypesFrom(const String& markerType, OptionSet<DocumentMarker::MarkerType>& result)
414{
415 DocumentMarker::MarkerType singularResult;
416
417 if (markerType.isEmpty() || equalLettersIgnoringASCIICase(markerType, "all"))
418 result = DocumentMarker::allMarkers();
419 else if (markerTypeFrom(markerType, singularResult))
420 result = singularResult;
421 else
422 return false;
423
424 return true;
425}
426
427static std::unique_ptr<PrintContext>& printContextForTesting()
428{
429 static NeverDestroyed<std::unique_ptr<PrintContext>> context;
430 return context;
431}
432
433const char* Internals::internalsId = "internals";
434
435Ref<Internals> Internals::create(Document& document)
436{
437 return adoptRef(*new Internals(document));
438}
439
440Internals::~Internals()
441{
442#if ENABLE(MEDIA_STREAM)
443 if (m_track)
444 m_track->source().removeObserver(*this);
445#endif
446}
447
448void Internals::resetToConsistentState(Page& page)
449{
450 page.setPageScaleFactor(1, IntPoint(0, 0));
451 page.setPagination(Pagination());
452 page.setPaginationLineGridEnabled(false);
453
454 page.setDefersLoading(false);
455
456 page.mainFrame().setTextZoomFactor(1.0f);
457
458 page.setCompositingPolicyOverride(WebCore::CompositingPolicy::Normal);
459
460 FrameView* mainFrameView = page.mainFrame().view();
461 if (mainFrameView) {
462 page.setHeaderHeight(0);
463 page.setFooterHeight(0);
464 page.setTopContentInset(0);
465 mainFrameView->setUseFixedLayout(false);
466 mainFrameView->setFixedLayoutSize(IntSize());
467 mainFrameView->enableAutoSizeMode(false, { });
468#if USE(COORDINATED_GRAPHICS)
469 mainFrameView->setFixedVisibleContentRect(IntRect());
470#endif
471 if (auto* backing = mainFrameView->tiledBacking())
472 backing->setTileSizeUpdateDelayDisabledForTesting(false);
473 }
474
475 WTF::clearDefaultPortForProtocolMapForTesting();
476 overrideUserPreferredLanguages(Vector<String>());
477 WebCore::DeprecatedGlobalSettings::setUsesOverlayScrollbars(false);
478 WebCore::DeprecatedGlobalSettings::setUsesMockScrollAnimator(false);
479#if ENABLE(VIDEO_TRACK)
480 page.group().captionPreferences().setTestingMode(true);
481 page.group().captionPreferences().setCaptionsStyleSheetOverride(emptyString());
482 page.group().captionPreferences().setTestingMode(false);
483#endif
484 if (!page.mainFrame().editor().isContinuousSpellCheckingEnabled())
485 page.mainFrame().editor().toggleContinuousSpellChecking();
486 if (page.mainFrame().editor().isOverwriteModeEnabled())
487 page.mainFrame().editor().toggleOverwriteModeEnabled();
488 page.mainFrame().loader().clearTestingOverrides();
489 page.applicationCacheStorage().setDefaultOriginQuota(ApplicationCacheStorage::noQuota());
490#if ENABLE(VIDEO)
491 PlatformMediaSessionManager::sharedManager().resetRestrictions();
492 PlatformMediaSessionManager::sharedManager().setWillIgnoreSystemInterruptions(true);
493#endif
494#if HAVE(ACCESSIBILITY)
495 AXObjectCache::setEnhancedUserInterfaceAccessibility(false);
496 AXObjectCache::disableAccessibility();
497#endif
498
499 MockPageOverlayClient::singleton().uninstallAllOverlays();
500
501#if ENABLE(CONTENT_FILTERING)
502 MockContentFilterSettings::reset();
503#endif
504
505#if ENABLE(WIRELESS_PLAYBACK_TARGET)
506 page.setMockMediaPlaybackTargetPickerEnabled(true);
507 page.setMockMediaPlaybackTargetPickerState(emptyString(), MediaPlaybackTargetContext::Unknown);
508#endif
509
510 page.setShowAllPlugins(false);
511 page.setLowPowerModeEnabledOverrideForTesting(WTF::nullopt);
512
513#if USE(QUICK_LOOK)
514 MockPreviewLoaderClient::singleton().setPassword("");
515 PreviewLoader::setClientForTesting(nullptr);
516#endif
517
518 printContextForTesting() = nullptr;
519
520#if USE(LIBWEBRTC)
521 auto& rtcProvider = page.libWebRTCProvider();
522 WebCore::useRealRTCPeerConnectionFactory(rtcProvider);
523 rtcProvider.disableNonLocalhostConnections();
524 RuntimeEnabledFeatures::sharedFeatures().setWebRTCVP8CodecEnabled(true);
525#endif
526
527 page.settings().setStorageAccessAPIEnabled(false);
528 page.setFullscreenAutoHideDuration(0_s);
529 page.setFullscreenInsets({ });
530 page.setFullscreenControlsHidden(false);
531
532 MediaEngineConfigurationFactory::disableMock();
533}
534
535Internals::Internals(Document& document)
536 : ContextDestructionObserver(&document)
537#if ENABLE(MEDIA_STREAM)
538 , m_orientationNotifier(0)
539#endif
540{
541#if ENABLE(VIDEO_TRACK)
542 if (document.page())
543 document.page()->group().captionPreferences().setTestingMode(true);
544#endif
545
546#if ENABLE(MEDIA_STREAM)
547 setMockMediaCaptureDevicesEnabled(true);
548 setMediaCaptureRequiresSecureConnection(false);
549#endif
550
551#if ENABLE(WIRELESS_PLAYBACK_TARGET)
552 if (document.page())
553 document.page()->setMockMediaPlaybackTargetPickerEnabled(true);
554#endif
555
556 if (contextDocument() && contextDocument()->frame()) {
557 setAutomaticSpellingCorrectionEnabled(true);
558 setAutomaticQuoteSubstitutionEnabled(false);
559 setAutomaticDashSubstitutionEnabled(false);
560 setAutomaticLinkDetectionEnabled(false);
561 setAutomaticTextReplacementEnabled(true);
562 }
563
564 setConsoleMessageListener(nullptr);
565
566#if ENABLE(APPLE_PAY)
567 auto* frame = document.frame();
568 if (frame && frame->page() && frame->isMainFrame()) {
569 auto mockPaymentCoordinator = new MockPaymentCoordinator(*frame->page());
570 frame->page()->setPaymentCoordinator(std::make_unique<PaymentCoordinator>(*mockPaymentCoordinator));
571 }
572#endif
573}
574
575Document* Internals::contextDocument() const
576{
577 return downcast<Document>(scriptExecutionContext());
578}
579
580Frame* Internals::frame() const
581{
582 if (!contextDocument())
583 return nullptr;
584 return contextDocument()->frame();
585}
586
587InternalSettings* Internals::settings() const
588{
589 Document* document = contextDocument();
590 if (!document)
591 return nullptr;
592 Page* page = document->page();
593 if (!page)
594 return nullptr;
595 return InternalSettings::from(page);
596}
597
598unsigned Internals::workerThreadCount() const
599{
600 return WorkerThread::workerThreadCount();
601}
602
603ExceptionOr<bool> Internals::areSVGAnimationsPaused() const
604{
605 auto* document = contextDocument();
606 if (!document)
607 return Exception { InvalidAccessError, "No context document"_s };
608
609 if (!document->svgExtensions())
610 return Exception { NotFoundError, "No SVG animations"_s };
611
612 return document->accessSVGExtensions().areAnimationsPaused();
613}
614
615ExceptionOr<double> Internals::svgAnimationsInterval(SVGSVGElement& element) const
616{
617 auto* document = contextDocument();
618 if (!document)
619 return 0;
620
621 if (!document->svgExtensions())
622 return 0;
623
624 if (document->accessSVGExtensions().areAnimationsPaused())
625 return 0;
626
627 return element.timeContainer().animationFrameDelay().value();
628}
629
630String Internals::address(Node& node)
631{
632 return makeString("0x", hex(reinterpret_cast<uintptr_t>(&node)));
633}
634
635bool Internals::nodeNeedsStyleRecalc(Node& node)
636{
637 return node.needsStyleRecalc();
638}
639
640static String styleValidityToToString(Style::Validity validity)
641{
642 switch (validity) {
643 case Style::Validity::Valid:
644 return "NoStyleChange";
645 case Style::Validity::ElementInvalid:
646 return "InlineStyleChange";
647 case Style::Validity::SubtreeInvalid:
648 return "FullStyleChange";
649 case Style::Validity::SubtreeAndRenderersInvalid:
650 return "ReconstructRenderTree";
651 }
652 ASSERT_NOT_REACHED();
653 return "";
654}
655
656String Internals::styleChangeType(Node& node)
657{
658 node.document().styleScope().flushPendingUpdate();
659
660 return styleValidityToToString(node.styleValidity());
661}
662
663String Internals::description(JSC::JSValue value)
664{
665 return toString(value);
666}
667
668bool Internals::isPreloaded(const String& url)
669{
670 Document* document = contextDocument();
671 return document->cachedResourceLoader().isPreloaded(url);
672}
673
674bool Internals::isLoadingFromMemoryCache(const String& url)
675{
676 if (!contextDocument() || !contextDocument()->page())
677 return false;
678
679 ResourceRequest request(contextDocument()->completeURL(url));
680 request.setDomainForCachePartition(contextDocument()->domainForCachePartition());
681
682 CachedResource* resource = MemoryCache::singleton().resourceForRequest(request, contextDocument()->page()->sessionID());
683 return resource && resource->status() == CachedResource::Cached;
684}
685
686static String responseSourceToString(const ResourceResponse& response)
687{
688 if (response.isNull())
689 return "Null response";
690 switch (response.source()) {
691 case ResourceResponse::Source::Unknown:
692 return "Unknown";
693 case ResourceResponse::Source::Network:
694 return "Network";
695 case ResourceResponse::Source::ServiceWorker:
696 return "Service worker";
697 case ResourceResponse::Source::DiskCache:
698 return "Disk cache";
699 case ResourceResponse::Source::DiskCacheAfterValidation:
700 return "Disk cache after validation";
701 case ResourceResponse::Source::MemoryCache:
702 return "Memory cache";
703 case ResourceResponse::Source::MemoryCacheAfterValidation:
704 return "Memory cache after validation";
705 case ResourceResponse::Source::ApplicationCache:
706 return "Application cache";
707 }
708 ASSERT_NOT_REACHED();
709 return "Error";
710}
711
712String Internals::xhrResponseSource(XMLHttpRequest& request)
713{
714 return responseSourceToString(request.resourceResponse());
715}
716
717String Internals::fetchResponseSource(FetchResponse& response)
718{
719 return responseSourceToString(response.resourceResponse());
720}
721
722bool Internals::isSharingStyleSheetContents(HTMLLinkElement& a, HTMLLinkElement& b)
723{
724 if (!a.sheet() || !b.sheet())
725 return false;
726 return &a.sheet()->contents() == &b.sheet()->contents();
727}
728
729bool Internals::isStyleSheetLoadingSubresources(HTMLLinkElement& link)
730{
731 return link.sheet() && link.sheet()->contents().isLoadingSubresources();
732}
733
734static ResourceRequestCachePolicy toResourceRequestCachePolicy(Internals::CachePolicy policy)
735{
736 switch (policy) {
737 case Internals::CachePolicy::UseProtocolCachePolicy:
738 return ResourceRequestCachePolicy::UseProtocolCachePolicy;
739 case Internals::CachePolicy::ReloadIgnoringCacheData:
740 return ResourceRequestCachePolicy::ReloadIgnoringCacheData;
741 case Internals::CachePolicy::ReturnCacheDataElseLoad:
742 return ResourceRequestCachePolicy::ReturnCacheDataElseLoad;
743 case Internals::CachePolicy::ReturnCacheDataDontLoad:
744 return ResourceRequestCachePolicy::ReturnCacheDataDontLoad;
745 }
746 ASSERT_NOT_REACHED();
747 return ResourceRequestCachePolicy::UseProtocolCachePolicy;
748}
749
750void Internals::setOverrideCachePolicy(CachePolicy policy)
751{
752 frame()->loader().setOverrideCachePolicyForTesting(toResourceRequestCachePolicy(policy));
753}
754
755ExceptionOr<void> Internals::setCanShowModalDialogOverride(bool allow)
756{
757 if (!contextDocument() || !contextDocument()->domWindow())
758 return Exception { InvalidAccessError };
759
760 contextDocument()->domWindow()->setCanShowModalDialogOverride(allow);
761 return { };
762}
763
764static ResourceLoadPriority toResourceLoadPriority(Internals::ResourceLoadPriority priority)
765{
766 switch (priority) {
767 case Internals::ResourceLoadPriority::ResourceLoadPriorityVeryLow:
768 return ResourceLoadPriority::VeryLow;
769 case Internals::ResourceLoadPriority::ResourceLoadPriorityLow:
770 return ResourceLoadPriority::Low;
771 case Internals::ResourceLoadPriority::ResourceLoadPriorityMedium:
772 return ResourceLoadPriority::Medium;
773 case Internals::ResourceLoadPriority::ResourceLoadPriorityHigh:
774 return ResourceLoadPriority::High;
775 case Internals::ResourceLoadPriority::ResourceLoadPriorityVeryHigh:
776 return ResourceLoadPriority::VeryHigh;
777 }
778 ASSERT_NOT_REACHED();
779 return ResourceLoadPriority::Low;
780}
781
782void Internals::setOverrideResourceLoadPriority(ResourceLoadPriority priority)
783{
784 frame()->loader().setOverrideResourceLoadPriorityForTesting(toResourceLoadPriority(priority));
785}
786
787void Internals::setStrictRawResourceValidationPolicyDisabled(bool disabled)
788{
789 frame()->loader().setStrictRawResourceValidationPolicyDisabledForTesting(disabled);
790}
791
792void Internals::clearMemoryCache()
793{
794 MemoryCache::singleton().evictResources();
795}
796
797void Internals::pruneMemoryCacheToSize(unsigned size)
798{
799 MemoryCache::singleton().pruneDeadResourcesToSize(size);
800 MemoryCache::singleton().pruneLiveResourcesToSize(size, true);
801}
802
803void Internals::destroyDecodedDataForAllImages()
804{
805 MemoryCache::singleton().destroyDecodedDataForAllImages();
806}
807
808unsigned Internals::memoryCacheSize() const
809{
810 return MemoryCache::singleton().size();
811}
812
813static Image* imageFromImageElement(HTMLImageElement& element)
814{
815 auto* cachedImage = element.cachedImage();
816 return cachedImage ? cachedImage->image() : nullptr;
817}
818
819static BitmapImage* bitmapImageFromImageElement(HTMLImageElement& element)
820{
821 auto* image = imageFromImageElement(element);
822 return image && is<BitmapImage>(image) ? &downcast<BitmapImage>(*image) : nullptr;
823}
824
825#if USE(CG)
826static PDFDocumentImage* pdfDocumentImageFromImageElement(HTMLImageElement& element)
827{
828 auto* image = imageFromImageElement(element);
829 return image && is<PDFDocumentImage>(image) ? &downcast<PDFDocumentImage>(*image) : nullptr;
830}
831#endif
832
833unsigned Internals::imageFrameIndex(HTMLImageElement& element)
834{
835 auto* bitmapImage = bitmapImageFromImageElement(element);
836 return bitmapImage ? bitmapImage->currentFrame() : 0;
837}
838
839unsigned Internals::imageFrameCount(HTMLImageElement& element)
840{
841 auto* bitmapImage = bitmapImageFromImageElement(element);
842 return bitmapImage ? bitmapImage->frameCount() : 0;
843}
844
845float Internals::imageFrameDurationAtIndex(HTMLImageElement& element, unsigned index)
846{
847 auto* bitmapImage = bitmapImageFromImageElement(element);
848 return bitmapImage ? bitmapImage->frameDurationAtIndex(index).value() : 0;
849}
850
851void Internals::setImageFrameDecodingDuration(HTMLImageElement& element, float duration)
852{
853 if (auto* bitmapImage = bitmapImageFromImageElement(element))
854 bitmapImage->setFrameDecodingDurationForTesting(Seconds { duration });
855}
856
857void Internals::resetImageAnimation(HTMLImageElement& element)
858{
859 if (auto* image = imageFromImageElement(element))
860 image->resetAnimation();
861}
862
863bool Internals::isImageAnimating(HTMLImageElement& element)
864{
865 auto* image = imageFromImageElement(element);
866 return image && (image->isAnimating() || image->animationPending());
867}
868
869void Internals::setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement& element, bool enabled)
870{
871 if (auto* bitmapImage = bitmapImageFromImageElement(element))
872 bitmapImage->setClearDecoderAfterAsyncFrameRequestForTesting(enabled);
873}
874
875unsigned Internals::imageDecodeCount(HTMLImageElement& element)
876{
877 auto* bitmapImage = bitmapImageFromImageElement(element);
878 return bitmapImage ? bitmapImage->decodeCountForTesting() : 0;
879}
880
881unsigned Internals::pdfDocumentCachingCount(HTMLImageElement& element)
882{
883#if USE(CG)
884 auto* pdfDocumentImage = pdfDocumentImageFromImageElement(element);
885 return pdfDocumentImage ? pdfDocumentImage->cachingCountForTesting() : 0;
886#else
887 UNUSED_PARAM(element);
888 return 0;
889#endif
890}
891
892void Internals::setLargeImageAsyncDecodingEnabledForTesting(HTMLImageElement& element, bool enabled)
893{
894 if (auto* bitmapImage = bitmapImageFromImageElement(element))
895 bitmapImage->setLargeImageAsyncDecodingEnabledForTesting(enabled);
896}
897
898void Internals::setForceUpdateImageDataEnabledForTesting(HTMLImageElement& element, bool enabled)
899{
900 if (auto* cachedImage = element.cachedImage())
901 cachedImage->setForceUpdateImageDataEnabledForTesting(enabled);
902}
903
904void Internals::setGridMaxTracksLimit(unsigned maxTrackLimit)
905{
906 GridPosition::setMaxPositionForTesting(maxTrackLimit);
907}
908
909void Internals::clearPageCache()
910{
911 PageCache::singleton().pruneToSizeNow(0, PruningReason::None);
912}
913
914unsigned Internals::pageCacheSize() const
915{
916 return PageCache::singleton().pageCount();
917}
918
919void Internals::disableTileSizeUpdateDelay()
920{
921 Document* document = contextDocument();
922 if (!document || !document->frame())
923 return;
924
925 auto* view = document->frame()->view();
926 if (!view)
927 return;
928
929 if (auto* backing = view->tiledBacking())
930 backing->setTileSizeUpdateDelayDisabledForTesting(true);
931}
932
933void Internals::setSpeculativeTilingDelayDisabledForTesting(bool disabled)
934{
935 Document* document = contextDocument();
936 if (!document || !document->frame())
937 return;
938
939 if (auto* frameView = document->frame()->view())
940 frameView->setSpeculativeTilingDelayDisabledForTesting(disabled);
941}
942
943
944Node* Internals::treeScopeRootNode(Node& node)
945{
946 return &node.treeScope().rootNode();
947}
948
949Node* Internals::parentTreeScope(Node& node)
950{
951 const TreeScope* parentTreeScope = node.treeScope().parentTreeScope();
952 return parentTreeScope ? &parentTreeScope->rootNode() : nullptr;
953}
954
955ExceptionOr<unsigned> Internals::lastSpatialNavigationCandidateCount() const
956{
957 if (!contextDocument() || !contextDocument()->page())
958 return Exception { InvalidAccessError };
959
960 return contextDocument()->page()->lastSpatialNavigationCandidateCount();
961}
962
963unsigned Internals::numberOfActiveAnimations() const
964{
965 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled())
966 return frame()->document()->timeline().numberOfActiveAnimationsForTesting();
967 return frame()->animation().numberOfActiveAnimations(frame()->document());
968}
969
970ExceptionOr<bool> Internals::animationsAreSuspended() const
971{
972 Document* document = contextDocument();
973 if (!document || !document->frame())
974 return Exception { InvalidAccessError };
975
976 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled())
977 return document->timeline().animationsAreSuspended();
978 return document->frame()->animation().animationsAreSuspendedForDocument(document);
979}
980
981double Internals::animationsInterval() const
982{
983 Document* document = contextDocument();
984 if (!document)
985 return INFINITY;
986
987 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
988 if (auto timeline = document->existingTimeline())
989 return timeline->animationInterval().seconds();
990 return INFINITY;
991 }
992
993 if (!document->frame())
994 return INFINITY;
995 return document->frame()->animation().animationInterval().value();
996}
997
998ExceptionOr<void> Internals::suspendAnimations() const
999{
1000 Document* document = contextDocument();
1001 if (!document || !document->frame())
1002 return Exception { InvalidAccessError };
1003
1004 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
1005 document->timeline().suspendAnimations();
1006 for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
1007 if (Document* document = frame->document())
1008 document->timeline().suspendAnimations();
1009 }
1010 } else {
1011 document->frame()->animation().suspendAnimationsForDocument(document);
1012
1013 for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
1014 if (Document* document = frame->document())
1015 frame->animation().suspendAnimationsForDocument(document);
1016 }
1017 }
1018
1019 return { };
1020}
1021
1022ExceptionOr<void> Internals::resumeAnimations() const
1023{
1024 Document* document = contextDocument();
1025 if (!document || !document->frame())
1026 return Exception { InvalidAccessError };
1027
1028 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
1029 document->timeline().resumeAnimations();
1030 for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
1031 if (Document* document = frame->document())
1032 document->timeline().resumeAnimations();
1033 }
1034 } else {
1035 document->frame()->animation().resumeAnimationsForDocument(document);
1036
1037 for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) {
1038 if (Document* document = frame->document())
1039 frame->animation().resumeAnimationsForDocument(document);
1040 }
1041 }
1042
1043 return { };
1044}
1045
1046ExceptionOr<bool> Internals::pauseAnimationAtTimeOnElement(const String& animationName, double pauseTime, Element& element)
1047{
1048 if (pauseTime < 0)
1049 return Exception { InvalidAccessError };
1050 return frame()->animation().pauseAnimationAtTime(element, AtomicString(animationName), pauseTime);
1051}
1052
1053ExceptionOr<bool> Internals::pauseAnimationAtTimeOnPseudoElement(const String& animationName, double pauseTime, Element& element, const String& pseudoId)
1054{
1055 if (pauseTime < 0)
1056 return Exception { InvalidAccessError };
1057
1058 if (pseudoId != "before" && pseudoId != "after")
1059 return Exception { InvalidAccessError };
1060
1061 PseudoElement* pseudoElement = pseudoId == "before" ? element.beforePseudoElement() : element.afterPseudoElement();
1062 if (!pseudoElement)
1063 return Exception { InvalidAccessError };
1064
1065 return frame()->animation().pauseAnimationAtTime(*pseudoElement, AtomicString(animationName), pauseTime);
1066}
1067
1068ExceptionOr<bool> Internals::pauseTransitionAtTimeOnElement(const String& propertyName, double pauseTime, Element& element)
1069{
1070 if (pauseTime < 0)
1071 return Exception { InvalidAccessError };
1072 return frame()->animation().pauseTransitionAtTime(element, propertyName, pauseTime);
1073}
1074
1075ExceptionOr<bool> Internals::pauseTransitionAtTimeOnPseudoElement(const String& property, double pauseTime, Element& element, const String& pseudoId)
1076{
1077 if (pauseTime < 0)
1078 return Exception { InvalidAccessError };
1079
1080 if (pseudoId != "before" && pseudoId != "after")
1081 return Exception { InvalidAccessError };
1082
1083 PseudoElement* pseudoElement = pseudoId == "before" ? element.beforePseudoElement() : element.afterPseudoElement();
1084 if (!pseudoElement)
1085 return Exception { InvalidAccessError };
1086
1087 return frame()->animation().pauseTransitionAtTime(*pseudoElement, property, pauseTime);
1088}
1089
1090Vector<Internals::AcceleratedAnimation> Internals::acceleratedAnimationsForElement(Element& element)
1091{
1092 if (!RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled())
1093 return { };
1094
1095 Vector<Internals::AcceleratedAnimation> animations;
1096 for (const auto& animationAsPair : element.document().timeline().acceleratedAnimationsForElement(element))
1097 animations.append({ animationAsPair.first, animationAsPair.second });
1098 return animations;
1099}
1100
1101unsigned Internals::numberOfAnimationTimelineInvalidations() const
1102{
1103 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled())
1104 return frame()->document()->timeline().numberOfAnimationTimelineInvalidationsForTesting();
1105 return 0;
1106}
1107
1108ExceptionOr<RefPtr<Element>> Internals::pseudoElement(Element& element, const String& pseudoId)
1109{
1110 if (pseudoId != "before" && pseudoId != "after")
1111 return Exception { InvalidAccessError };
1112
1113 return pseudoId == "before" ? element.beforePseudoElement() : element.afterPseudoElement();
1114}
1115
1116ExceptionOr<String> Internals::elementRenderTreeAsText(Element& element)
1117{
1118 element.document().updateStyleIfNeeded();
1119
1120 String representation = externalRepresentation(&element);
1121 if (representation.isEmpty())
1122 return Exception { InvalidAccessError };
1123
1124 return representation;
1125}
1126
1127bool Internals::hasPausedImageAnimations(Element& element)
1128{
1129 return element.renderer() && element.renderer()->hasPausedImageAnimations();
1130}
1131
1132bool Internals::isPaintingFrequently(Element& element)
1133{
1134 return element.renderer() && element.renderer()->enclosingLayer() && element.renderer()->enclosingLayer()->paintingFrequently();
1135}
1136
1137void Internals::incrementFrequentPaintCounter(Element& element)
1138{
1139 if (element.renderer() && element.renderer()->enclosingLayer())
1140 element.renderer()->enclosingLayer()->simulateFrequentPaint();
1141}
1142
1143Ref<CSSComputedStyleDeclaration> Internals::computedStyleIncludingVisitedInfo(Element& element) const
1144{
1145 bool allowVisitedStyle = true;
1146 return CSSComputedStyleDeclaration::create(element, allowVisitedStyle);
1147}
1148
1149Node* Internals::ensureUserAgentShadowRoot(Element& host)
1150{
1151 return &host.ensureUserAgentShadowRoot();
1152}
1153
1154Node* Internals::shadowRoot(Element& host)
1155{
1156 return host.shadowRoot();
1157}
1158
1159ExceptionOr<String> Internals::shadowRootType(const Node& root) const
1160{
1161 if (!is<ShadowRoot>(root))
1162 return Exception { InvalidAccessError };
1163
1164 switch (downcast<ShadowRoot>(root).mode()) {
1165 case ShadowRootMode::UserAgent:
1166 return "UserAgentShadowRoot"_str;
1167 case ShadowRootMode::Closed:
1168 return "ClosedShadowRoot"_str;
1169 case ShadowRootMode::Open:
1170 return "OpenShadowRoot"_str;
1171 default:
1172 ASSERT_NOT_REACHED();
1173 return "Unknown"_str;
1174 }
1175}
1176
1177String Internals::shadowPseudoId(Element& element)
1178{
1179 return element.shadowPseudoId().string();
1180}
1181
1182void Internals::setShadowPseudoId(Element& element, const String& id)
1183{
1184 return element.setPseudo(id);
1185}
1186
1187static unsigned deferredStyleRulesCountForList(const Vector<RefPtr<StyleRuleBase>>& childRules)
1188{
1189 unsigned count = 0;
1190 for (auto rule : childRules) {
1191 if (is<StyleRule>(rule)) {
1192 auto* cssRule = downcast<StyleRule>(rule.get());
1193 if (!cssRule->propertiesWithoutDeferredParsing())
1194 count++;
1195 continue;
1196 }
1197
1198 StyleRuleGroup* groupRule = nullptr;
1199 if (is<StyleRuleMedia>(rule))
1200 groupRule = downcast<StyleRuleMedia>(rule.get());
1201 else if (is<StyleRuleSupports>(rule))
1202 groupRule = downcast<StyleRuleSupports>(rule.get());
1203 if (!groupRule)
1204 continue;
1205
1206 auto* groupChildRules = groupRule->childRulesWithoutDeferredParsing();
1207 if (!groupChildRules)
1208 continue;
1209
1210 count += deferredStyleRulesCountForList(*groupChildRules);
1211 }
1212
1213 return count;
1214}
1215
1216unsigned Internals::deferredStyleRulesCount(StyleSheet& styleSheet)
1217{
1218 return deferredStyleRulesCountForList(downcast<CSSStyleSheet>(styleSheet).contents().childRules());
1219}
1220
1221static unsigned deferredGroupRulesCountForList(const Vector<RefPtr<StyleRuleBase>>& childRules)
1222{
1223 unsigned count = 0;
1224 for (auto rule : childRules) {
1225 StyleRuleGroup* groupRule = nullptr;
1226 if (is<StyleRuleMedia>(rule))
1227 groupRule = downcast<StyleRuleMedia>(rule.get());
1228 else if (is<StyleRuleSupports>(rule))
1229 groupRule = downcast<StyleRuleSupports>(rule.get());
1230 if (!groupRule)
1231 continue;
1232
1233 auto* groupChildRules = groupRule->childRulesWithoutDeferredParsing();
1234 if (!groupChildRules)
1235 count++;
1236 else
1237 count += deferredGroupRulesCountForList(*groupChildRules);
1238 }
1239 return count;
1240}
1241
1242unsigned Internals::deferredGroupRulesCount(StyleSheet& styleSheet)
1243{
1244 return deferredGroupRulesCountForList(downcast<CSSStyleSheet>(styleSheet).contents().childRules());
1245}
1246
1247static unsigned deferredKeyframesRulesCountForList(const Vector<RefPtr<StyleRuleBase>>& childRules)
1248{
1249 unsigned count = 0;
1250 for (auto rule : childRules) {
1251 if (is<StyleRuleKeyframes>(rule)) {
1252 auto* cssRule = downcast<StyleRuleKeyframes>(rule.get());
1253 if (!cssRule->keyframesWithoutDeferredParsing())
1254 count++;
1255 continue;
1256 }
1257
1258 StyleRuleGroup* groupRule = nullptr;
1259 if (is<StyleRuleMedia>(rule))
1260 groupRule = downcast<StyleRuleMedia>(rule.get());
1261 else if (is<StyleRuleSupports>(rule))
1262 groupRule = downcast<StyleRuleSupports>(rule.get());
1263 if (!groupRule)
1264 continue;
1265
1266 auto* groupChildRules = groupRule->childRulesWithoutDeferredParsing();
1267 if (!groupChildRules)
1268 continue;
1269
1270 count += deferredKeyframesRulesCountForList(*groupChildRules);
1271 }
1272
1273 return count;
1274}
1275
1276unsigned Internals::deferredKeyframesRulesCount(StyleSheet& styleSheet)
1277{
1278 StyleSheetContents& contents = downcast<CSSStyleSheet>(styleSheet).contents();
1279 return deferredKeyframesRulesCountForList(contents.childRules());
1280}
1281
1282ExceptionOr<bool> Internals::isTimerThrottled(int timeoutId)
1283{
1284 auto* timer = scriptExecutionContext()->findTimeout(timeoutId);
1285 if (!timer)
1286 return Exception { NotFoundError };
1287
1288 if (timer->intervalClampedToMinimum() > timer->m_originalInterval)
1289 return true;
1290
1291 return !!timer->alignedFireTime(MonotonicTime { });
1292}
1293
1294bool Internals::isRequestAnimationFrameThrottled() const
1295{
1296 auto* scriptedAnimationController = contextDocument()->scriptedAnimationController();
1297 if (!scriptedAnimationController)
1298 return false;
1299 return scriptedAnimationController->isThrottled();
1300}
1301
1302double Internals::requestAnimationFrameInterval() const
1303{
1304 auto* scriptedAnimationController = contextDocument()->scriptedAnimationController();
1305 if (!scriptedAnimationController)
1306 return INFINITY;
1307 return scriptedAnimationController->interval().value();
1308}
1309
1310bool Internals::scriptedAnimationsAreSuspended() const
1311{
1312 Document* document = contextDocument();
1313 if (!document || !document->page())
1314 return true;
1315
1316 return document->page()->scriptedAnimationsSuspended();
1317}
1318
1319bool Internals::areTimersThrottled() const
1320{
1321 return contextDocument()->isTimerThrottlingEnabled();
1322}
1323
1324void Internals::setEventThrottlingBehaviorOverride(Optional<EventThrottlingBehavior> value)
1325{
1326 Document* document = contextDocument();
1327 if (!document || !document->page())
1328 return;
1329
1330 if (!value) {
1331 document->page()->setEventThrottlingBehaviorOverride(WTF::nullopt);
1332 return;
1333 }
1334
1335 switch (value.value()) {
1336 case Internals::EventThrottlingBehavior::Responsive:
1337 document->page()->setEventThrottlingBehaviorOverride(WebCore::EventThrottlingBehavior::Responsive);
1338 break;
1339 case Internals::EventThrottlingBehavior::Unresponsive:
1340 document->page()->setEventThrottlingBehaviorOverride(WebCore::EventThrottlingBehavior::Unresponsive);
1341 break;
1342 }
1343}
1344
1345Optional<Internals::EventThrottlingBehavior> Internals::eventThrottlingBehaviorOverride() const
1346{
1347 Document* document = contextDocument();
1348 if (!document || !document->page())
1349 return WTF::nullopt;
1350
1351 auto behavior = document->page()->eventThrottlingBehaviorOverride();
1352 if (!behavior)
1353 return WTF::nullopt;
1354
1355 switch (behavior.value()) {
1356 case WebCore::EventThrottlingBehavior::Responsive:
1357 return Internals::EventThrottlingBehavior::Responsive;
1358 case WebCore::EventThrottlingBehavior::Unresponsive:
1359 return Internals::EventThrottlingBehavior::Unresponsive;
1360 }
1361
1362 return WTF::nullopt;
1363}
1364
1365String Internals::visiblePlaceholder(Element& element)
1366{
1367 if (is<HTMLTextFormControlElement>(element)) {
1368 const HTMLTextFormControlElement& textFormControlElement = downcast<HTMLTextFormControlElement>(element);
1369 if (!textFormControlElement.isPlaceholderVisible())
1370 return String();
1371 if (HTMLElement* placeholderElement = textFormControlElement.placeholderElement())
1372 return placeholderElement->textContent();
1373 }
1374
1375 return String();
1376}
1377
1378void Internals::selectColorInColorChooser(HTMLInputElement& element, const String& colorValue)
1379{
1380 element.selectColor(colorValue);
1381}
1382
1383ExceptionOr<Vector<String>> Internals::formControlStateOfPreviousHistoryItem()
1384{
1385 HistoryItem* mainItem = frame()->loader().history().previousItem();
1386 if (!mainItem)
1387 return Exception { InvalidAccessError };
1388 String uniqueName = frame()->tree().uniqueName();
1389 if (mainItem->target() != uniqueName && !mainItem->childItemWithTarget(uniqueName))
1390 return Exception { InvalidAccessError };
1391 return Vector<String> { mainItem->target() == uniqueName ? mainItem->documentState() : mainItem->childItemWithTarget(uniqueName)->documentState() };
1392}
1393
1394ExceptionOr<void> Internals::setFormControlStateOfPreviousHistoryItem(const Vector<String>& state)
1395{
1396 HistoryItem* mainItem = frame()->loader().history().previousItem();
1397 if (!mainItem)
1398 return Exception { InvalidAccessError };
1399 String uniqueName = frame()->tree().uniqueName();
1400 if (mainItem->target() == uniqueName)
1401 mainItem->setDocumentState(state);
1402 else if (HistoryItem* subItem = mainItem->childItemWithTarget(uniqueName))
1403 subItem->setDocumentState(state);
1404 else
1405 return Exception { InvalidAccessError };
1406 return { };
1407}
1408
1409#if ENABLE(SPEECH_SYNTHESIS)
1410
1411void Internals::enableMockSpeechSynthesizer()
1412{
1413 Document* document = contextDocument();
1414 if (!document || !document->domWindow())
1415 return;
1416 SpeechSynthesis* synthesis = DOMWindowSpeechSynthesis::speechSynthesis(*document->domWindow());
1417 if (!synthesis)
1418 return;
1419
1420 synthesis->setPlatformSynthesizer(std::make_unique<PlatformSpeechSynthesizerMock>(synthesis));
1421}
1422
1423#endif
1424
1425#if ENABLE(WEB_RTC)
1426
1427void Internals::emulateRTCPeerConnectionPlatformEvent(RTCPeerConnection& connection, const String& action)
1428{
1429 if (!LibWebRTCProvider::webRTCAvailable())
1430 return;
1431
1432 connection.emulatePlatformEvent(action);
1433}
1434
1435void Internals::useMockRTCPeerConnectionFactory(const String& testCase)
1436{
1437 // FIXME: We should upgrade mocks to support unified plan APIs, until then use plan B in tests using mock.
1438
1439 ASSERT(!RuntimeEnabledFeatures::sharedFeatures().webRTCUnifiedPlanEnabled());
1440 if (!LibWebRTCProvider::webRTCAvailable())
1441 return;
1442
1443#if USE(LIBWEBRTC)
1444 Document* document = contextDocument();
1445 LibWebRTCProvider* provider = (document && document->page()) ? &document->page()->libWebRTCProvider() : nullptr;
1446 WebCore::useMockRTCPeerConnectionFactory(provider, testCase);
1447#else
1448 UNUSED_PARAM(testCase);
1449#endif
1450}
1451
1452void Internals::setICECandidateFiltering(bool enabled)
1453{
1454 auto* page = contextDocument()->page();
1455 if (!page)
1456 return;
1457
1458 auto& rtcController = page->rtcController();
1459 if (enabled)
1460 rtcController.enableICECandidateFiltering();
1461 else
1462 rtcController.disableICECandidateFilteringForAllOrigins();
1463}
1464
1465void Internals::setEnumeratingAllNetworkInterfacesEnabled(bool enabled)
1466{
1467#if USE(LIBWEBRTC)
1468 Document* document = contextDocument();
1469 auto* page = document->page();
1470 if (!page)
1471 return;
1472 auto& rtcProvider = page->libWebRTCProvider();
1473 if (enabled)
1474 rtcProvider.enableEnumeratingAllNetworkInterfaces();
1475 else
1476 rtcProvider.disableEnumeratingAllNetworkInterfaces();
1477#else
1478 UNUSED_PARAM(enabled);
1479#endif
1480}
1481
1482void Internals::stopPeerConnection(RTCPeerConnection& connection)
1483{
1484 ActiveDOMObject& object = connection;
1485 object.stop();
1486}
1487
1488void Internals::clearPeerConnectionFactory()
1489{
1490#if USE(LIBWEBRTC)
1491 if (auto* page = contextDocument()->page())
1492 page->libWebRTCProvider().clearFactory();
1493#endif
1494}
1495
1496void Internals::applyRotationForOutgoingVideoSources(RTCPeerConnection& connection)
1497{
1498 connection.applyRotationForOutgoingVideoSources();
1499}
1500#endif
1501
1502#if ENABLE(MEDIA_STREAM)
1503
1504void Internals::setMockMediaCaptureDevicesEnabled(bool enabled)
1505{
1506 Document* document = contextDocument();
1507 if (auto* page = document->page())
1508 page->settings().setMockCaptureDevicesEnabled(enabled);
1509}
1510
1511void Internals::setMediaCaptureRequiresSecureConnection(bool enabled)
1512{
1513 Document* document = contextDocument();
1514 if (auto* page = document->page())
1515 page->settings().setMediaCaptureRequiresSecureConnection(enabled);
1516}
1517
1518static std::unique_ptr<MediaRecorderPrivate> createRecorderMockSource()
1519{
1520 return std::unique_ptr<MediaRecorderPrivateMock>(new MediaRecorderPrivateMock);
1521}
1522
1523void Internals::setCustomPrivateRecorderCreator()
1524{
1525 WebCore::MediaRecorder::setCustomPrivateRecorderCreator(createRecorderMockSource);
1526}
1527
1528#endif
1529
1530ExceptionOr<Ref<DOMRect>> Internals::absoluteCaretBounds()
1531{
1532 Document* document = contextDocument();
1533 if (!document || !document->frame())
1534 return Exception { InvalidAccessError };
1535
1536 return DOMRect::create(document->frame()->selection().absoluteCaretBounds());
1537}
1538
1539ExceptionOr<bool> Internals::isCaretBlinkingSuspended()
1540{
1541 Document* document = contextDocument();
1542 if (!document || !document->frame())
1543 return Exception { InvalidAccessError };
1544
1545 return document->frame()->selection().isCaretBlinkingSuspended();
1546}
1547
1548Ref<DOMRect> Internals::boundingBox(Element& element)
1549{
1550 element.document().updateLayoutIgnorePendingStylesheets();
1551 auto renderer = element.renderer();
1552 if (!renderer)
1553 return DOMRect::create();
1554 return DOMRect::create(renderer->absoluteBoundingBoxRectIgnoringTransforms());
1555}
1556
1557ExceptionOr<Ref<DOMRectList>> Internals::inspectorHighlightRects()
1558{
1559 Document* document = contextDocument();
1560 if (!document || !document->page())
1561 return Exception { InvalidAccessError };
1562
1563 Highlight highlight;
1564 document->page()->inspectorController().getHighlight(highlight, InspectorOverlay::CoordinateSystem::View);
1565 return DOMRectList::create(highlight.quads);
1566}
1567
1568ExceptionOr<unsigned> Internals::markerCountForNode(Node& node, const String& markerType)
1569{
1570 OptionSet<DocumentMarker::MarkerType> markerTypes;
1571 if (!markerTypesFrom(markerType, markerTypes))
1572 return Exception { SyntaxError };
1573
1574 node.document().frame()->editor().updateEditorUINowIfScheduled();
1575 return node.document().markers().markersFor(node, markerTypes).size();
1576}
1577
1578ExceptionOr<RenderedDocumentMarker*> Internals::markerAt(Node& node, const String& markerType, unsigned index)
1579{
1580 node.document().updateLayoutIgnorePendingStylesheets();
1581
1582 OptionSet<DocumentMarker::MarkerType> markerTypes;
1583 if (!markerTypesFrom(markerType, markerTypes))
1584 return Exception { SyntaxError };
1585
1586 node.document().frame()->editor().updateEditorUINowIfScheduled();
1587
1588 Vector<RenderedDocumentMarker*> markers = node.document().markers().markersFor(node, markerTypes);
1589 if (markers.size() <= index)
1590 return nullptr;
1591 return markers[index];
1592}
1593
1594ExceptionOr<RefPtr<Range>> Internals::markerRangeForNode(Node& node, const String& markerType, unsigned index)
1595{
1596 auto result = markerAt(node, markerType, index);
1597 if (result.hasException())
1598 return result.releaseException();
1599 auto marker = result.releaseReturnValue();
1600 if (!marker)
1601 return nullptr;
1602 return RefPtr<Range> { Range::create(node.document(), &node, marker->startOffset(), &node, marker->endOffset()) };
1603}
1604
1605ExceptionOr<String> Internals::markerDescriptionForNode(Node& node, const String& markerType, unsigned index)
1606{
1607 auto result = markerAt(node, markerType, index);
1608 if (result.hasException())
1609 return result.releaseException();
1610 auto marker = result.releaseReturnValue();
1611 if (!marker)
1612 return String();
1613 return String { marker->description() };
1614}
1615
1616ExceptionOr<String> Internals::dumpMarkerRects(const String& markerTypeString)
1617{
1618 DocumentMarker::MarkerType markerType;
1619 if (!markerTypeFrom(markerTypeString, markerType))
1620 return Exception { SyntaxError };
1621
1622 contextDocument()->markers().updateRectsForInvalidatedMarkersOfType(markerType);
1623 auto rects = contextDocument()->markers().renderedRectsForMarkers(markerType);
1624
1625 StringBuilder rectString;
1626 rectString.appendLiteral("marker rects: ");
1627 for (const auto& rect : rects) {
1628 rectString.append('(');
1629 rectString.appendFixedPrecisionNumber(rect.x());
1630 rectString.appendLiteral(", ");
1631 rectString.appendFixedPrecisionNumber(rect.y());
1632 rectString.appendLiteral(", ");
1633 rectString.appendFixedPrecisionNumber(rect.width());
1634 rectString.appendLiteral(", ");
1635 rectString.appendFixedPrecisionNumber(rect.height());
1636 rectString.appendLiteral(") ");
1637 }
1638 return rectString.toString();
1639}
1640
1641void Internals::addTextMatchMarker(const Range& range, bool isActive)
1642{
1643 range.ownerDocument().updateLayoutIgnorePendingStylesheets();
1644 range.ownerDocument().markers().addTextMatchMarker(range, isActive);
1645}
1646
1647ExceptionOr<void> Internals::setMarkedTextMatchesAreHighlighted(bool flag)
1648{
1649 Document* document = contextDocument();
1650 if (!document || !document->frame())
1651 return Exception { InvalidAccessError };
1652 document->frame()->editor().setMarkedTextMatchesAreHighlighted(flag);
1653 return { };
1654}
1655
1656void Internals::invalidateFontCache()
1657{
1658 FontCache::singleton().invalidate();
1659}
1660
1661void Internals::setFontSmoothingEnabled(bool enabled)
1662{
1663 FontCascade::setShouldUseSmoothing(enabled);
1664}
1665
1666ExceptionOr<void> Internals::setLowPowerModeEnabled(bool isEnabled)
1667{
1668 auto* document = contextDocument();
1669 if (!document)
1670 return Exception { InvalidAccessError };
1671 auto* page = document->page();
1672 if (!page)
1673 return Exception { InvalidAccessError };
1674
1675 page->setLowPowerModeEnabledOverrideForTesting(isEnabled);
1676 return { };
1677}
1678
1679ExceptionOr<void> Internals::setScrollViewPosition(int x, int y)
1680{
1681 Document* document = contextDocument();
1682 if (!document || !document->view())
1683 return Exception { InvalidAccessError };
1684
1685 auto& frameView = *document->view();
1686 bool constrainsScrollingToContentEdgeOldValue = frameView.constrainsScrollingToContentEdge();
1687 bool scrollbarsSuppressedOldValue = frameView.scrollbarsSuppressed();
1688
1689 frameView.setConstrainsScrollingToContentEdge(false);
1690 frameView.setScrollbarsSuppressed(false);
1691 frameView.setScrollOffsetFromInternals({ x, y });
1692 frameView.setScrollbarsSuppressed(scrollbarsSuppressedOldValue);
1693 frameView.setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdgeOldValue);
1694
1695 return { };
1696}
1697
1698ExceptionOr<void> Internals::unconstrainedScrollTo(Element& element, double x, double y)
1699{
1700 Document* document = contextDocument();
1701 if (!document || !document->view())
1702 return Exception { InvalidAccessError };
1703
1704 element.scrollTo({ x, y }, ScrollClamping::Unclamped);
1705 return { };
1706}
1707
1708ExceptionOr<Ref<DOMRect>> Internals::layoutViewportRect()
1709{
1710 Document* document = contextDocument();
1711 if (!document || !document->frame())
1712 return Exception { InvalidAccessError };
1713
1714 document->updateLayoutIgnorePendingStylesheets();
1715
1716 auto& frameView = *document->view();
1717 return DOMRect::create(frameView.layoutViewportRect());
1718}
1719
1720ExceptionOr<Ref<DOMRect>> Internals::visualViewportRect()
1721{
1722 Document* document = contextDocument();
1723 if (!document || !document->frame())
1724 return Exception { InvalidAccessError };
1725
1726 document->updateLayoutIgnorePendingStylesheets();
1727
1728 auto& frameView = *document->view();
1729 return DOMRect::create(frameView.visualViewportRect());
1730}
1731
1732ExceptionOr<void> Internals::setViewIsTransparent(bool transparent)
1733{
1734 Document* document = contextDocument();
1735 if (!document || !document->view())
1736 return Exception { InvalidAccessError };
1737 Optional<Color> backgroundColor;
1738 if (transparent)
1739 backgroundColor = Color(Color::transparent);
1740 document->view()->updateBackgroundRecursively(backgroundColor);
1741 return { };
1742}
1743
1744ExceptionOr<String> Internals::viewBaseBackgroundColor()
1745{
1746 Document* document = contextDocument();
1747 if (!document || !document->view())
1748 return Exception { InvalidAccessError };
1749 return document->view()->baseBackgroundColor().cssText();
1750}
1751
1752ExceptionOr<void> Internals::setViewBaseBackgroundColor(const String& colorValue)
1753{
1754 Document* document = contextDocument();
1755 if (!document || !document->view())
1756 return Exception { InvalidAccessError };
1757
1758 if (colorValue == "transparent") {
1759 document->view()->setBaseBackgroundColor(Color::transparent);
1760 return { };
1761 }
1762 if (colorValue == "white") {
1763 document->view()->setBaseBackgroundColor(Color::white);
1764 return { };
1765 }
1766 return Exception { SyntaxError };
1767}
1768
1769ExceptionOr<void> Internals::setPagination(const String& mode, int gap, int pageLength)
1770{
1771 Document* document = contextDocument();
1772 if (!document || !document->page())
1773 return Exception { InvalidAccessError };
1774
1775 Pagination pagination;
1776 if (mode == "Unpaginated")
1777 pagination.mode = Pagination::Unpaginated;
1778 else if (mode == "LeftToRightPaginated")
1779 pagination.mode = Pagination::LeftToRightPaginated;
1780 else if (mode == "RightToLeftPaginated")
1781 pagination.mode = Pagination::RightToLeftPaginated;
1782 else if (mode == "TopToBottomPaginated")
1783 pagination.mode = Pagination::TopToBottomPaginated;
1784 else if (mode == "BottomToTopPaginated")
1785 pagination.mode = Pagination::BottomToTopPaginated;
1786 else
1787 return Exception { SyntaxError };
1788
1789 pagination.gap = gap;
1790 pagination.pageLength = pageLength;
1791 document->page()->setPagination(pagination);
1792
1793 return { };
1794}
1795
1796ExceptionOr<void> Internals::setPaginationLineGridEnabled(bool enabled)
1797{
1798 Document* document = contextDocument();
1799 if (!document || !document->page())
1800 return Exception { InvalidAccessError };
1801 document->page()->setPaginationLineGridEnabled(enabled);
1802 return { };
1803}
1804
1805ExceptionOr<String> Internals::configurationForViewport(float devicePixelRatio, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight)
1806{
1807 Document* document = contextDocument();
1808 if (!document || !document->page())
1809 return Exception { InvalidAccessError };
1810
1811 const int defaultLayoutWidthForNonMobilePages = 980;
1812
1813 ViewportArguments arguments = document->page()->viewportArguments();
1814 ViewportAttributes attributes = computeViewportAttributes(arguments, defaultLayoutWidthForNonMobilePages, deviceWidth, deviceHeight, devicePixelRatio, IntSize(availableWidth, availableHeight));
1815 restrictMinimumScaleFactorToViewportSize(attributes, IntSize(availableWidth, availableHeight), devicePixelRatio);
1816 restrictScaleFactorToInitialScaleIfNotUserScalable(attributes);
1817
1818 return makeString("viewport size ", FormattedNumber::fixedPrecision(attributes.layoutSize.width()), 'x', FormattedNumber::fixedPrecision(attributes.layoutSize.height()), " scale ", FormattedNumber::fixedPrecision(attributes.initialScale), " with limits [", FormattedNumber::fixedPrecision(attributes.minimumScale), ", ", FormattedNumber::fixedPrecision(attributes.maximumScale), "] and userScalable ", (attributes.userScalable ? "true" : "false"));
1819}
1820
1821ExceptionOr<bool> Internals::wasLastChangeUserEdit(Element& textField)
1822{
1823 if (is<HTMLInputElement>(textField))
1824 return downcast<HTMLInputElement>(textField).lastChangeWasUserEdit();
1825
1826 if (is<HTMLTextAreaElement>(textField))
1827 return downcast<HTMLTextAreaElement>(textField).lastChangeWasUserEdit();
1828
1829 return Exception { InvalidNodeTypeError };
1830}
1831
1832bool Internals::elementShouldAutoComplete(HTMLInputElement& element)
1833{
1834 return element.shouldAutocomplete();
1835}
1836
1837void Internals::setAutofilled(HTMLInputElement& element, bool enabled)
1838{
1839 element.setAutoFilled(enabled);
1840}
1841
1842static AutoFillButtonType toAutoFillButtonType(Internals::AutoFillButtonType type)
1843{
1844 switch (type) {
1845 case Internals::AutoFillButtonType::None:
1846 return AutoFillButtonType::None;
1847 case Internals::AutoFillButtonType::Credentials:
1848 return AutoFillButtonType::Credentials;
1849 case Internals::AutoFillButtonType::Contacts:
1850 return AutoFillButtonType::Contacts;
1851 case Internals::AutoFillButtonType::StrongPassword:
1852 return AutoFillButtonType::StrongPassword;
1853 case Internals::AutoFillButtonType::CreditCard:
1854 return AutoFillButtonType::CreditCard;
1855 }
1856 ASSERT_NOT_REACHED();
1857 return AutoFillButtonType::None;
1858}
1859
1860static Internals::AutoFillButtonType toInternalsAutoFillButtonType(AutoFillButtonType type)
1861{
1862 switch (type) {
1863 case AutoFillButtonType::None:
1864 return Internals::AutoFillButtonType::None;
1865 case AutoFillButtonType::Credentials:
1866 return Internals::AutoFillButtonType::Credentials;
1867 case AutoFillButtonType::Contacts:
1868 return Internals::AutoFillButtonType::Contacts;
1869 case AutoFillButtonType::StrongPassword:
1870 return Internals::AutoFillButtonType::StrongPassword;
1871 case AutoFillButtonType::CreditCard:
1872 return Internals::AutoFillButtonType::CreditCard;
1873 }
1874 ASSERT_NOT_REACHED();
1875 return Internals::AutoFillButtonType::None;
1876}
1877
1878void Internals::setShowAutoFillButton(HTMLInputElement& element, AutoFillButtonType type)
1879{
1880 element.setShowAutoFillButton(toAutoFillButtonType(type));
1881}
1882
1883auto Internals::autoFillButtonType(const HTMLInputElement& element) -> AutoFillButtonType
1884{
1885 return toInternalsAutoFillButtonType(element.autoFillButtonType());
1886}
1887
1888auto Internals::lastAutoFillButtonType(const HTMLInputElement& element) -> AutoFillButtonType
1889{
1890 return toInternalsAutoFillButtonType(element.lastAutoFillButtonType());
1891}
1892
1893ExceptionOr<void> Internals::scrollElementToRect(Element& element, int x, int y, int w, int h)
1894{
1895 FrameView* frameView = element.document().view();
1896 if (!frameView)
1897 return Exception { InvalidAccessError };
1898 frameView->scrollElementToRect(element, { x, y, w, h });
1899 return { };
1900}
1901
1902ExceptionOr<String> Internals::autofillFieldName(Element& element)
1903{
1904 if (!is<HTMLFormControlElement>(element))
1905 return Exception { InvalidNodeTypeError };
1906
1907 return String { downcast<HTMLFormControlElement>(element).autofillData().fieldName };
1908}
1909
1910ExceptionOr<void> Internals::invalidateControlTints()
1911{
1912 Document* document = contextDocument();
1913 if (!document || !document->view())
1914 return Exception { InvalidAccessError };
1915
1916 document->view()->invalidateControlTints();
1917 return { };
1918}
1919
1920RefPtr<Range> Internals::rangeFromLocationAndLength(Element& scope, int rangeLocation, int rangeLength)
1921{
1922 return TextIterator::rangeFromLocationAndLength(&scope, rangeLocation, rangeLength);
1923}
1924
1925unsigned Internals::locationFromRange(Element& scope, const Range& range)
1926{
1927 size_t location = 0;
1928 size_t unusedLength = 0;
1929 TextIterator::getLocationAndLengthFromRange(&scope, &range, location, unusedLength);
1930 return location;
1931}
1932
1933unsigned Internals::lengthFromRange(Element& scope, const Range& range)
1934{
1935 size_t unusedLocation = 0;
1936 size_t length = 0;
1937 TextIterator::getLocationAndLengthFromRange(&scope, &range, unusedLocation, length);
1938 return length;
1939}
1940
1941String Internals::rangeAsText(const Range& range)
1942{
1943 return range.text();
1944}
1945
1946String Internals::rangeAsTextUsingBackwardsTextIterator(const Range& range)
1947{
1948 return plainTextUsingBackwardsTextIteratorForTesting(range);
1949}
1950
1951Ref<Range> Internals::subrange(Range& range, int rangeLocation, int rangeLength)
1952{
1953 return TextIterator::subrange(range, rangeLocation, rangeLength);
1954}
1955
1956RefPtr<Range> Internals::rangeOfStringNearLocation(const Range& searchRange, const String& text, unsigned targetOffset)
1957{
1958 return findClosestPlainText(searchRange, text, { }, targetOffset);
1959}
1960
1961#if !PLATFORM(MAC)
1962ExceptionOr<RefPtr<Range>> Internals::rangeForDictionaryLookupAtLocation(int, int)
1963{
1964 return Exception { InvalidAccessError };
1965}
1966#endif
1967
1968ExceptionOr<void> Internals::setDelegatesScrolling(bool enabled)
1969{
1970 Document* document = contextDocument();
1971 // Delegate scrolling is valid only on mainframe's view.
1972 if (!document || !document->view() || !document->page() || &document->page()->mainFrame() != document->frame())
1973 return Exception { InvalidAccessError };
1974
1975 document->view()->setDelegatesScrolling(enabled);
1976 return { };
1977}
1978
1979ExceptionOr<int> Internals::lastSpellCheckRequestSequence()
1980{
1981 Document* document = contextDocument();
1982 if (!document || !document->frame())
1983 return Exception { InvalidAccessError };
1984
1985 return document->frame()->editor().spellChecker().lastRequestSequence();
1986}
1987
1988ExceptionOr<int> Internals::lastSpellCheckProcessedSequence()
1989{
1990 Document* document = contextDocument();
1991 if (!document || !document->frame())
1992 return Exception { InvalidAccessError };
1993
1994 return document->frame()->editor().spellChecker().lastProcessedSequence();
1995}
1996
1997Vector<String> Internals::userPreferredLanguages() const
1998{
1999 return WTF::userPreferredLanguages();
2000}
2001
2002void Internals::setUserPreferredLanguages(const Vector<String>& languages)
2003{
2004 overrideUserPreferredLanguages(languages);
2005}
2006
2007Vector<String> Internals::userPreferredAudioCharacteristics() const
2008{
2009 Document* document = contextDocument();
2010 if (!document || !document->page())
2011 return Vector<String>();
2012#if ENABLE(VIDEO_TRACK)
2013 return document->page()->group().captionPreferences().preferredAudioCharacteristics();
2014#else
2015 return Vector<String>();
2016#endif
2017}
2018
2019void Internals::setUserPreferredAudioCharacteristic(const String& characteristic)
2020{
2021 Document* document = contextDocument();
2022 if (!document || !document->page())
2023 return;
2024#if ENABLE(VIDEO_TRACK)
2025 document->page()->group().captionPreferences().setPreferredAudioCharacteristic(characteristic);
2026#else
2027 UNUSED_PARAM(characteristic);
2028#endif
2029}
2030
2031ExceptionOr<unsigned> Internals::wheelEventHandlerCount()
2032{
2033 Document* document = contextDocument();
2034 if (!document)
2035 return Exception { InvalidAccessError };
2036
2037 return document->wheelEventHandlerCount();
2038}
2039
2040ExceptionOr<unsigned> Internals::touchEventHandlerCount()
2041{
2042 Document* document = contextDocument();
2043 if (!document)
2044 return Exception { InvalidAccessError };
2045
2046 return document->touchEventHandlerCount();
2047}
2048
2049ExceptionOr<Ref<DOMRectList>> Internals::touchEventRectsForEvent(const String& eventName)
2050{
2051 Document* document = contextDocument();
2052 if (!document || !document->page())
2053 return Exception { InvalidAccessError };
2054
2055 return document->page()->touchEventRectsForEvent(eventName);
2056}
2057
2058ExceptionOr<Ref<DOMRectList>> Internals::passiveTouchEventListenerRects()
2059{
2060 Document* document = contextDocument();
2061 if (!document || !document->page())
2062 return Exception { InvalidAccessError };
2063
2064 return document->page()->passiveTouchEventListenerRects();
2065}
2066
2067// FIXME: Remove the document argument. It is almost always the same as
2068// contextDocument(), with the exception of a few tests that pass a
2069// different document, and could just make the call through another Internals
2070// instance instead.
2071ExceptionOr<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
2072{
2073 if (!document.frame() || !document.frame()->view())
2074 return Exception { InvalidAccessError };
2075
2076 Frame* frame = document.frame();
2077 FrameView* frameView = document.view();
2078 RenderView* renderView = document.renderView();
2079 if (!renderView)
2080 return nullptr;
2081
2082 document.updateLayoutIgnorePendingStylesheets();
2083
2084 float zoomFactor = frame->pageZoomFactor();
2085 LayoutPoint point(centerX * zoomFactor + frameView->scrollX(), centerY * zoomFactor + frameView->scrollY());
2086
2087 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::CollectMultipleElements;
2088 if (ignoreClipping)
2089 hitType |= HitTestRequest::IgnoreClipping;
2090 if (!allowUserAgentShadowContent)
2091 hitType |= HitTestRequest::DisallowUserAgentShadowContent;
2092 if (allowChildFrameContent)
2093 hitType |= HitTestRequest::AllowChildFrameContent;
2094
2095 HitTestRequest request(hitType);
2096
2097 // When ignoreClipping is false, this method returns null for coordinates outside of the viewport.
2098 if (!request.ignoreClipping() && !frameView->visibleContentRect().intersects(HitTestLocation::rectForPoint(point, topPadding, rightPadding, bottomPadding, leftPadding)))
2099 return nullptr;
2100
2101 HitTestResult result(point, topPadding, rightPadding, bottomPadding, leftPadding);
2102 renderView->hitTest(request, result);
2103 const HitTestResult::NodeSet& nodeSet = result.listBasedTestResult();
2104 Vector<Ref<Node>> matches;
2105 matches.reserveInitialCapacity(nodeSet.size());
2106 for (auto& node : nodeSet)
2107 matches.uncheckedAppend(*node);
2108
2109 return RefPtr<NodeList> { StaticNodeList::create(WTFMove(matches)) };
2110}
2111
2112class GetCallerCodeBlockFunctor {
2113public:
2114 GetCallerCodeBlockFunctor()
2115 : m_iterations(0)
2116 , m_codeBlock(0)
2117 {
2118 }
2119
2120 StackVisitor::Status operator()(StackVisitor& visitor) const
2121 {
2122 ++m_iterations;
2123 if (m_iterations < 2)
2124 return StackVisitor::Continue;
2125
2126 m_codeBlock = visitor->codeBlock();
2127 return StackVisitor::Done;
2128 }
2129
2130 CodeBlock* codeBlock() const { return m_codeBlock; }
2131
2132private:
2133 mutable int m_iterations;
2134 mutable CodeBlock* m_codeBlock;
2135};
2136
2137String Internals::parserMetaData(JSC::JSValue code)
2138{
2139 JSC::VM& vm = contextDocument()->vm();
2140 JSC::ExecState* exec = vm.topCallFrame;
2141 ScriptExecutable* executable;
2142
2143 if (!code || code.isNull() || code.isUndefined()) {
2144 GetCallerCodeBlockFunctor iter;
2145 exec->iterate(iter);
2146 CodeBlock* codeBlock = iter.codeBlock();
2147 executable = codeBlock->ownerExecutable();
2148 } else if (code.isFunction(vm)) {
2149 JSFunction* funcObj = JSC::jsCast<JSFunction*>(code.toObject(exec));
2150 executable = funcObj->jsExecutable();
2151 } else
2152 return String();
2153
2154 unsigned startLine = executable->firstLine();
2155 unsigned startColumn = executable->startColumn();
2156 unsigned endLine = executable->lastLine();
2157 unsigned endColumn = executable->endColumn();
2158
2159 StringBuilder result;
2160
2161 if (executable->isFunctionExecutable()) {
2162 FunctionExecutable* funcExecutable = reinterpret_cast<FunctionExecutable*>(executable);
2163 String inferredName = funcExecutable->ecmaName().string();
2164 result.appendLiteral("function \"");
2165 result.append(inferredName);
2166 result.append('"');
2167 } else if (executable->isEvalExecutable())
2168 result.appendLiteral("eval");
2169 else if (executable->isModuleProgramExecutable())
2170 result.appendLiteral("module");
2171 else if (executable->isProgramExecutable())
2172 result.appendLiteral("program");
2173 else
2174 ASSERT_NOT_REACHED();
2175
2176 result.appendLiteral(" { ");
2177 result.appendNumber(startLine);
2178 result.append(':');
2179 result.appendNumber(startColumn);
2180 result.appendLiteral(" - ");
2181 result.appendNumber(endLine);
2182 result.append(':');
2183 result.appendNumber(endColumn);
2184 result.appendLiteral(" }");
2185
2186 return result.toString();
2187}
2188
2189void Internals::updateEditorUINowIfScheduled()
2190{
2191 if (Document* document = contextDocument()) {
2192 if (Frame* frame = document->frame())
2193 frame->editor().updateEditorUINowIfScheduled();
2194 }
2195}
2196
2197bool Internals::hasSpellingMarker(int from, int length)
2198{
2199 Document* document = contextDocument();
2200 if (!document || !document->frame())
2201 return false;
2202
2203 updateEditorUINowIfScheduled();
2204
2205 return document->frame()->editor().selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length);
2206}
2207
2208bool Internals::hasAutocorrectedMarker(int from, int length)
2209{
2210 Document* document = contextDocument();
2211 if (!document || !document->frame())
2212 return false;
2213
2214 updateEditorUINowIfScheduled();
2215
2216 return document->frame()->editor().selectionStartHasMarkerFor(DocumentMarker::Autocorrected, from, length);
2217}
2218
2219void Internals::setContinuousSpellCheckingEnabled(bool enabled)
2220{
2221 if (!contextDocument() || !contextDocument()->frame())
2222 return;
2223
2224 if (enabled != contextDocument()->frame()->editor().isContinuousSpellCheckingEnabled())
2225 contextDocument()->frame()->editor().toggleContinuousSpellChecking();
2226}
2227
2228void Internals::setAutomaticQuoteSubstitutionEnabled(bool enabled)
2229{
2230 if (!contextDocument() || !contextDocument()->frame())
2231 return;
2232
2233#if USE(AUTOMATIC_TEXT_REPLACEMENT)
2234 if (enabled != contextDocument()->frame()->editor().isAutomaticQuoteSubstitutionEnabled())
2235 contextDocument()->frame()->editor().toggleAutomaticQuoteSubstitution();
2236#else
2237 UNUSED_PARAM(enabled);
2238#endif
2239}
2240
2241void Internals::setAutomaticLinkDetectionEnabled(bool enabled)
2242{
2243 if (!contextDocument() || !contextDocument()->frame())
2244 return;
2245
2246#if USE(AUTOMATIC_TEXT_REPLACEMENT)
2247 if (enabled != contextDocument()->frame()->editor().isAutomaticLinkDetectionEnabled())
2248 contextDocument()->frame()->editor().toggleAutomaticLinkDetection();
2249#else
2250 UNUSED_PARAM(enabled);
2251#endif
2252}
2253
2254void Internals::setAutomaticDashSubstitutionEnabled(bool enabled)
2255{
2256 if (!contextDocument() || !contextDocument()->frame())
2257 return;
2258
2259#if USE(AUTOMATIC_TEXT_REPLACEMENT)
2260 if (enabled != contextDocument()->frame()->editor().isAutomaticDashSubstitutionEnabled())
2261 contextDocument()->frame()->editor().toggleAutomaticDashSubstitution();
2262#else
2263 UNUSED_PARAM(enabled);
2264#endif
2265}
2266
2267void Internals::setAutomaticTextReplacementEnabled(bool enabled)
2268{
2269 if (!contextDocument() || !contextDocument()->frame())
2270 return;
2271
2272#if USE(AUTOMATIC_TEXT_REPLACEMENT)
2273 if (enabled != contextDocument()->frame()->editor().isAutomaticTextReplacementEnabled())
2274 contextDocument()->frame()->editor().toggleAutomaticTextReplacement();
2275#else
2276 UNUSED_PARAM(enabled);
2277#endif
2278}
2279
2280void Internals::setAutomaticSpellingCorrectionEnabled(bool enabled)
2281{
2282 if (!contextDocument() || !contextDocument()->frame())
2283 return;
2284
2285#if USE(AUTOMATIC_TEXT_REPLACEMENT)
2286 if (enabled != contextDocument()->frame()->editor().isAutomaticSpellingCorrectionEnabled())
2287 contextDocument()->frame()->editor().toggleAutomaticSpellingCorrection();
2288#else
2289 UNUSED_PARAM(enabled);
2290#endif
2291}
2292
2293void Internals::handleAcceptedCandidate(const String& candidate, unsigned location, unsigned length)
2294{
2295 if (!contextDocument() || !contextDocument()->frame())
2296 return;
2297
2298 TextCheckingResult result;
2299 result.type = TextCheckingType::None;
2300 result.location = location;
2301 result.length = length;
2302 result.replacement = candidate;
2303 contextDocument()->frame()->editor().handleAcceptedCandidate(result);
2304}
2305
2306void Internals::changeSelectionListType()
2307{
2308 if (auto frame = makeRefPtr(this->frame()))
2309 frame->editor().changeSelectionListType();
2310}
2311
2312bool Internals::isOverwriteModeEnabled()
2313{
2314 Document* document = contextDocument();
2315 if (!document || !document->frame())
2316 return false;
2317
2318 return document->frame()->editor().isOverwriteModeEnabled();
2319}
2320
2321void Internals::toggleOverwriteModeEnabled()
2322{
2323 Document* document = contextDocument();
2324 if (!document || !document->frame())
2325 return;
2326
2327 document->frame()->editor().toggleOverwriteModeEnabled();
2328}
2329
2330static ExceptionOr<FindOptions> parseFindOptions(const Vector<String>& optionList)
2331{
2332 const struct {
2333 const char* name;
2334 FindOptionFlag value;
2335 } flagList[] = {
2336 {"CaseInsensitive", CaseInsensitive},
2337 {"AtWordStarts", AtWordStarts},
2338 {"TreatMedialCapitalAsWordStart", TreatMedialCapitalAsWordStart},
2339 {"Backwards", Backwards},
2340 {"WrapAround", WrapAround},
2341 {"StartInSelection", StartInSelection},
2342 {"DoNotRevealSelection", DoNotRevealSelection},
2343 {"AtWordEnds", AtWordEnds},
2344 {"DoNotTraverseFlatTree", DoNotTraverseFlatTree},
2345 };
2346 FindOptions result;
2347 for (auto& option : optionList) {
2348 bool found = false;
2349 for (auto& flag : flagList) {
2350 if (flag.name == option) {
2351 result.add(flag.value);
2352 found = true;
2353 break;
2354 }
2355 }
2356 if (!found)
2357 return Exception { SyntaxError };
2358 }
2359 return result;
2360}
2361
2362ExceptionOr<RefPtr<Range>> Internals::rangeOfString(const String& text, RefPtr<Range>&& referenceRange, const Vector<String>& findOptions)
2363{
2364 Document* document = contextDocument();
2365 if (!document || !document->frame())
2366 return Exception { InvalidAccessError };
2367
2368 auto parsedOptions = parseFindOptions(findOptions);
2369 if (parsedOptions.hasException())
2370 return parsedOptions.releaseException();
2371
2372 return document->frame()->editor().rangeOfString(text, referenceRange.get(), parsedOptions.releaseReturnValue());
2373}
2374
2375ExceptionOr<unsigned> Internals::countMatchesForText(const String& text, const Vector<String>& findOptions, const String& markMatches)
2376{
2377 Document* document = contextDocument();
2378 if (!document || !document->frame())
2379 return Exception { InvalidAccessError };
2380
2381 auto parsedOptions = parseFindOptions(findOptions);
2382 if (parsedOptions.hasException())
2383 return parsedOptions.releaseException();
2384
2385 bool mark = markMatches == "mark";
2386 return document->frame()->editor().countMatchesForText(text, nullptr, parsedOptions.releaseReturnValue(), 1000, mark, nullptr);
2387}
2388
2389ExceptionOr<unsigned> Internals::countFindMatches(const String& text, const Vector<String>& findOptions)
2390{
2391 Document* document = contextDocument();
2392 if (!document || !document->page())
2393 return Exception { InvalidAccessError };
2394
2395 auto parsedOptions = parseFindOptions(findOptions);
2396 if (parsedOptions.hasException())
2397 return parsedOptions.releaseException();
2398
2399 return document->page()->countFindMatches(text, parsedOptions.releaseReturnValue(), 1000);
2400}
2401
2402unsigned Internals::numberOfIDBTransactions() const
2403{
2404 return IDBTransaction::numberOfIDBTransactions;
2405}
2406
2407unsigned Internals::numberOfLiveNodes() const
2408{
2409 unsigned nodeCount = 0;
2410 for (auto* document : Document::allDocuments())
2411 nodeCount += document->referencingNodeCount();
2412 return nodeCount;
2413}
2414
2415unsigned Internals::numberOfLiveDocuments() const
2416{
2417 return Document::allDocuments().size();
2418}
2419
2420unsigned Internals::referencingNodeCount(const Document& document) const
2421{
2422 return document.referencingNodeCount();
2423}
2424
2425#if ENABLE(INTERSECTION_OBSERVER)
2426unsigned Internals::numberOfIntersectionObservers(const Document& document) const
2427{
2428 return document.numberOfIntersectionObservers();
2429}
2430#endif
2431
2432uint64_t Internals::documentIdentifier(const Document& document) const
2433{
2434 return document.identifier().toUInt64();
2435}
2436
2437bool Internals::isDocumentAlive(uint64_t documentIdentifier) const
2438{
2439 return Document::allDocumentsMap().contains(makeObjectIdentifier<DocumentIdentifierType>(documentIdentifier));
2440}
2441
2442bool Internals::isAnyWorkletGlobalScopeAlive() const
2443{
2444#if ENABLE(CSS_PAINTING_API)
2445 return !WorkletGlobalScope::allWorkletGlobalScopesSet().isEmpty();
2446#else
2447 return false;
2448#endif
2449}
2450
2451String Internals::serviceWorkerClientIdentifier(const Document& document) const
2452{
2453#if ENABLE(SERVICE_WORKER)
2454 return ServiceWorkerClientIdentifier { ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(document.sessionID()).serverConnectionIdentifier(), document.identifier() }.toString();
2455#else
2456 UNUSED_PARAM(document);
2457 return String();
2458#endif
2459}
2460
2461RefPtr<WindowProxy> Internals::openDummyInspectorFrontend(const String& url)
2462{
2463 auto* inspectedPage = contextDocument()->frame()->page();
2464 auto* window = inspectedPage->mainFrame().document()->domWindow();
2465 auto frontendWindowProxy = window->open(*window, *window, url, "", "").releaseReturnValue();
2466 m_inspectorFrontend = std::make_unique<InspectorStubFrontend>(*inspectedPage, downcast<DOMWindow>(frontendWindowProxy->window()));
2467 return frontendWindowProxy;
2468}
2469
2470void Internals::closeDummyInspectorFrontend()
2471{
2472 m_inspectorFrontend = nullptr;
2473}
2474
2475ExceptionOr<void> Internals::setInspectorIsUnderTest(bool isUnderTest)
2476{
2477 Page* page = contextDocument()->frame()->page();
2478 if (!page)
2479 return Exception { InvalidAccessError };
2480
2481 page->inspectorController().setIsUnderTest(isUnderTest);
2482 return { };
2483}
2484
2485bool Internals::hasGrammarMarker(int from, int length)
2486{
2487 Document* document = contextDocument();
2488 if (!document || !document->frame())
2489 return false;
2490
2491 return document->frame()->editor().selectionStartHasMarkerFor(DocumentMarker::Grammar, from, length);
2492}
2493
2494unsigned Internals::numberOfScrollableAreas()
2495{
2496 Document* document = contextDocument();
2497 if (!document || !document->frame())
2498 return 0;
2499
2500 unsigned count = 0;
2501 Frame* frame = document->frame();
2502 if (frame->view()->scrollableAreas())
2503 count += frame->view()->scrollableAreas()->size();
2504
2505 for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2506 if (child->view() && child->view()->scrollableAreas())
2507 count += child->view()->scrollableAreas()->size();
2508 }
2509
2510 return count;
2511}
2512
2513ExceptionOr<bool> Internals::isPageBoxVisible(int pageNumber)
2514{
2515 Document* document = contextDocument();
2516 if (!document)
2517 return Exception { InvalidAccessError };
2518
2519 return document->isPageBoxVisible(pageNumber);
2520}
2521
2522static LayerTreeFlags toLayerTreeFlags(unsigned short flags)
2523{
2524 LayerTreeFlags layerTreeFlags = 0;
2525 if (flags & Internals::LAYER_TREE_INCLUDES_VISIBLE_RECTS)
2526 layerTreeFlags |= LayerTreeFlagsIncludeVisibleRects;
2527 if (flags & Internals::LAYER_TREE_INCLUDES_TILE_CACHES)
2528 layerTreeFlags |= LayerTreeFlagsIncludeTileCaches;
2529 if (flags & Internals::LAYER_TREE_INCLUDES_REPAINT_RECTS)
2530 layerTreeFlags |= LayerTreeFlagsIncludeRepaintRects;
2531 if (flags & Internals::LAYER_TREE_INCLUDES_PAINTING_PHASES)
2532 layerTreeFlags |= LayerTreeFlagsIncludePaintingPhases;
2533 if (flags & Internals::LAYER_TREE_INCLUDES_CONTENT_LAYERS)
2534 layerTreeFlags |= LayerTreeFlagsIncludeContentLayers;
2535 if (flags & Internals::LAYER_TREE_INCLUDES_ACCELERATES_DRAWING)
2536 layerTreeFlags |= LayerTreeFlagsIncludeAcceleratesDrawing;
2537 if (flags & Internals::LAYER_TREE_INCLUDES_BACKING_STORE_ATTACHED)
2538 layerTreeFlags |= LayerTreeFlagsIncludeBackingStoreAttached;
2539 if (flags & Internals::LAYER_TREE_INCLUDES_ROOT_LAYER_PROPERTIES)
2540 layerTreeFlags |= LayerTreeFlagsIncludeRootLayerProperties;
2541 if (flags & Internals::LAYER_TREE_INCLUDES_EVENT_REGION)
2542 layerTreeFlags |= LayerTreeFlagsIncludeEventRegion;
2543
2544 return layerTreeFlags;
2545}
2546
2547// FIXME: Remove the document argument. It is almost always the same as
2548// contextDocument(), with the exception of a few tests that pass a
2549// different document, and could just make the call through another Internals
2550// instance instead.
2551ExceptionOr<String> Internals::layerTreeAsText(Document& document, unsigned short flags) const
2552{
2553 if (!document.frame())
2554 return Exception { InvalidAccessError };
2555
2556 document.updateLayoutIgnorePendingStylesheets();
2557 return document.frame()->layerTreeAsText(toLayerTreeFlags(flags));
2558}
2559
2560ExceptionOr<uint64_t> Internals::layerIDForElement(Element& element)
2561{
2562 Document* document = contextDocument();
2563 if (!document || !document->frame())
2564 return Exception { InvalidAccessError };
2565
2566 element.document().updateLayoutIgnorePendingStylesheets();
2567
2568 if (!element.renderer() || !element.renderer()->hasLayer())
2569 return Exception { NotFoundError };
2570
2571 auto& layerModelObject = downcast<RenderLayerModelObject>(*element.renderer());
2572 if (!layerModelObject.layer()->isComposited())
2573 return Exception { NotFoundError };
2574
2575 auto* backing = layerModelObject.layer()->backing();
2576 return backing->graphicsLayer()->primaryLayerID();
2577}
2578
2579ExceptionOr<String> Internals::repaintRectsAsText() const
2580{
2581 Document* document = contextDocument();
2582 if (!document || !document->frame())
2583 return Exception { InvalidAccessError };
2584
2585 return document->frame()->trackedRepaintRectsAsText();
2586}
2587
2588ExceptionOr<String> Internals::scrollbarOverlayStyle(Node* node) const
2589{
2590 if (!node)
2591 node = contextDocument();
2592
2593 if (!node)
2594 return Exception { InvalidAccessError };
2595
2596 node->document().updateLayoutIgnorePendingStylesheets();
2597
2598 ScrollableArea* scrollableArea = nullptr;
2599 if (is<Document>(*node)) {
2600 auto* frameView = downcast<Document>(node)->view();
2601 if (!frameView)
2602 return Exception { InvalidAccessError };
2603
2604 scrollableArea = frameView;
2605 } else if (is<Element>(*node)) {
2606 auto& element = *downcast<Element>(node);
2607 if (!element.renderBox())
2608 return Exception { InvalidAccessError };
2609
2610 scrollableArea = element.renderBox()->layer();
2611 } else
2612 return Exception { InvalidNodeTypeError };
2613
2614 if (!scrollableArea)
2615 return Exception { InvalidNodeTypeError };
2616
2617 switch (scrollableArea->scrollbarOverlayStyle()) {
2618 case ScrollbarOverlayStyleDefault:
2619 return "default"_str;
2620 case ScrollbarOverlayStyleDark:
2621 return "dark"_str;
2622 case ScrollbarOverlayStyleLight:
2623 return "light"_str;
2624 }
2625
2626 ASSERT_NOT_REACHED();
2627 return "unknown"_str;
2628}
2629
2630ExceptionOr<bool> Internals::scrollbarUsingDarkAppearance(Node* node) const
2631{
2632 if (!node)
2633 node = contextDocument();
2634
2635 if (!node)
2636 return Exception { InvalidAccessError };
2637
2638 node->document().updateLayoutIgnorePendingStylesheets();
2639
2640 ScrollableArea* scrollableArea = nullptr;
2641 if (is<Document>(*node)) {
2642 auto* frameView = downcast<Document>(node)->view();
2643 if (!frameView)
2644 return Exception { InvalidAccessError };
2645
2646 scrollableArea = frameView;
2647 } else if (is<Element>(*node)) {
2648 auto& element = *downcast<Element>(node);
2649 if (!element.renderBox())
2650 return Exception { InvalidAccessError };
2651
2652 scrollableArea = element.renderBox()->layer();
2653 } else
2654 return Exception { InvalidNodeTypeError };
2655
2656 if (!scrollableArea)
2657 return Exception { InvalidNodeTypeError };
2658
2659 return scrollableArea->useDarkAppearance();
2660}
2661
2662ExceptionOr<String> Internals::scrollingStateTreeAsText() const
2663{
2664 Document* document = contextDocument();
2665 if (!document || !document->frame())
2666 return Exception { InvalidAccessError };
2667
2668 document->updateLayoutIgnorePendingStylesheets();
2669
2670 Page* page = document->page();
2671 if (!page)
2672 return String();
2673
2674 return page->scrollingStateTreeAsText();
2675}
2676
2677ExceptionOr<String> Internals::mainThreadScrollingReasons() const
2678{
2679 Document* document = contextDocument();
2680 if (!document || !document->frame())
2681 return Exception { InvalidAccessError };
2682
2683 Page* page = document->page();
2684 if (!page)
2685 return String();
2686
2687 return page->synchronousScrollingReasonsAsText();
2688}
2689
2690ExceptionOr<Ref<DOMRectList>> Internals::nonFastScrollableRects() const
2691{
2692 Document* document = contextDocument();
2693 if (!document || !document->frame())
2694 return Exception { InvalidAccessError };
2695
2696 Page* page = document->page();
2697 if (!page)
2698 return DOMRectList::create();
2699
2700 return page->nonFastScrollableRects();
2701}
2702
2703ExceptionOr<void> Internals::setElementUsesDisplayListDrawing(Element& element, bool usesDisplayListDrawing)
2704{
2705 Document* document = contextDocument();
2706 if (!document || !document->renderView())
2707 return Exception { InvalidAccessError };
2708
2709 element.document().updateLayoutIgnorePendingStylesheets();
2710
2711 if (!element.renderer())
2712 return Exception { InvalidAccessError };
2713
2714 if (is<HTMLCanvasElement>(element)) {
2715 downcast<HTMLCanvasElement>(element).setUsesDisplayListDrawing(usesDisplayListDrawing);
2716 return { };
2717 }
2718
2719 if (!element.renderer()->hasLayer())
2720 return Exception { InvalidAccessError };
2721
2722 RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
2723 if (!layer->isComposited())
2724 return Exception { InvalidAccessError };
2725
2726 layer->backing()->setUsesDisplayListDrawing(usesDisplayListDrawing);
2727 return { };
2728}
2729
2730ExceptionOr<void> Internals::setElementTracksDisplayListReplay(Element& element, bool isTrackingReplay)
2731{
2732 Document* document = contextDocument();
2733 if (!document || !document->renderView())
2734 return Exception { InvalidAccessError };
2735
2736 element.document().updateLayoutIgnorePendingStylesheets();
2737
2738 if (!element.renderer())
2739 return Exception { InvalidAccessError };
2740
2741 if (is<HTMLCanvasElement>(element)) {
2742 downcast<HTMLCanvasElement>(element).setTracksDisplayListReplay(isTrackingReplay);
2743 return { };
2744 }
2745
2746 if (!element.renderer()->hasLayer())
2747 return Exception { InvalidAccessError };
2748
2749 RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
2750 if (!layer->isComposited())
2751 return Exception { InvalidAccessError };
2752
2753 layer->backing()->setIsTrackingDisplayListReplay(isTrackingReplay);
2754 return { };
2755}
2756
2757ExceptionOr<String> Internals::displayListForElement(Element& element, unsigned short flags)
2758{
2759 Document* document = contextDocument();
2760 if (!document || !document->renderView())
2761 return Exception { InvalidAccessError };
2762
2763 element.document().updateLayoutIgnorePendingStylesheets();
2764
2765 if (!element.renderer())
2766 return Exception { InvalidAccessError };
2767
2768 DisplayList::AsTextFlags displayListFlags = 0;
2769 if (flags & DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS)
2770 displayListFlags |= DisplayList::AsTextFlag::IncludesPlatformOperations;
2771
2772 if (is<HTMLCanvasElement>(element))
2773 return downcast<HTMLCanvasElement>(element).displayListAsText(displayListFlags);
2774
2775 if (!element.renderer()->hasLayer())
2776 return Exception { InvalidAccessError };
2777
2778 RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
2779 if (!layer->isComposited())
2780 return Exception { InvalidAccessError };
2781
2782 return layer->backing()->displayListAsText(displayListFlags);
2783}
2784
2785ExceptionOr<String> Internals::replayDisplayListForElement(Element& element, unsigned short flags)
2786{
2787 Document* document = contextDocument();
2788 if (!document || !document->renderView())
2789 return Exception { InvalidAccessError };
2790
2791 element.document().updateLayoutIgnorePendingStylesheets();
2792
2793 if (!element.renderer())
2794 return Exception { InvalidAccessError };
2795
2796 DisplayList::AsTextFlags displayListFlags = 0;
2797 if (flags & DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS)
2798 displayListFlags |= DisplayList::AsTextFlag::IncludesPlatformOperations;
2799
2800 if (is<HTMLCanvasElement>(element))
2801 return downcast<HTMLCanvasElement>(element).replayDisplayListAsText(displayListFlags);
2802
2803 if (!element.renderer()->hasLayer())
2804 return Exception { InvalidAccessError };
2805
2806 RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
2807 if (!layer->isComposited())
2808 return Exception { InvalidAccessError };
2809
2810 return layer->backing()->replayDisplayListAsText(displayListFlags);
2811}
2812
2813ExceptionOr<void> Internals::garbageCollectDocumentResources() const
2814{
2815 Document* document = contextDocument();
2816 if (!document)
2817 return Exception { InvalidAccessError };
2818 document->cachedResourceLoader().garbageCollectDocumentResources();
2819 return { };
2820}
2821
2822bool Internals::isUnderMemoryPressure()
2823{
2824 return MemoryPressureHandler::singleton().isUnderMemoryPressure();
2825}
2826
2827void Internals::beginSimulatedMemoryPressure()
2828{
2829 MemoryPressureHandler::singleton().beginSimulatedMemoryPressure();
2830}
2831
2832void Internals::endSimulatedMemoryPressure()
2833{
2834 MemoryPressureHandler::singleton().endSimulatedMemoryPressure();
2835}
2836
2837ExceptionOr<void> Internals::insertAuthorCSS(const String& css) const
2838{
2839 Document* document = contextDocument();
2840 if (!document)
2841 return Exception { InvalidAccessError };
2842
2843 auto parsedSheet = StyleSheetContents::create(*document);
2844 parsedSheet.get().setIsUserStyleSheet(false);
2845 parsedSheet.get().parseString(css);
2846 document->extensionStyleSheets().addAuthorStyleSheetForTesting(WTFMove(parsedSheet));
2847 return { };
2848}
2849
2850ExceptionOr<void> Internals::insertUserCSS(const String& css) const
2851{
2852 Document* document = contextDocument();
2853 if (!document)
2854 return Exception { InvalidAccessError };
2855
2856 auto parsedSheet = StyleSheetContents::create(*document);
2857 parsedSheet.get().setIsUserStyleSheet(true);
2858 parsedSheet.get().parseString(css);
2859 document->extensionStyleSheets().addUserStyleSheet(WTFMove(parsedSheet));
2860 return { };
2861}
2862
2863String Internals::counterValue(Element& element)
2864{
2865 return counterValueForElement(&element);
2866}
2867
2868int Internals::pageNumber(Element& element, float pageWidth, float pageHeight)
2869{
2870 return PrintContext::pageNumberForElement(&element, { pageWidth, pageHeight });
2871}
2872
2873Vector<String> Internals::shortcutIconURLs() const
2874{
2875 if (!frame())
2876 return { };
2877
2878 auto* documentLoader = frame()->loader().documentLoader();
2879 if (!documentLoader)
2880 return { };
2881
2882 Vector<String> result;
2883 for (auto& linkIcon : documentLoader->linkIcons())
2884 result.append(linkIcon.url.string());
2885
2886 return result;
2887}
2888
2889int Internals::numberOfPages(float pageWidth, float pageHeight)
2890{
2891 if (!frame())
2892 return -1;
2893
2894 return PrintContext::numberOfPages(*frame(), FloatSize(pageWidth, pageHeight));
2895}
2896
2897ExceptionOr<String> Internals::pageProperty(const String& propertyName, int pageNumber) const
2898{
2899 if (!frame())
2900 return Exception { InvalidAccessError };
2901
2902 return PrintContext::pageProperty(frame(), propertyName.utf8().data(), pageNumber);
2903}
2904
2905ExceptionOr<String> Internals::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const
2906{
2907 if (!frame())
2908 return Exception { InvalidAccessError };
2909
2910 return PrintContext::pageSizeAndMarginsInPixels(frame(), pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft);
2911}
2912
2913ExceptionOr<float> Internals::pageScaleFactor() const
2914{
2915 Document* document = contextDocument();
2916 if (!document || !document->page())
2917 return Exception { InvalidAccessError };
2918
2919 return document->page()->pageScaleFactor();
2920}
2921
2922ExceptionOr<void> Internals::setPageScaleFactor(float scaleFactor, int x, int y)
2923{
2924 Document* document = contextDocument();
2925 if (!document || !document->page())
2926 return Exception { InvalidAccessError };
2927
2928 document->page()->setPageScaleFactor(scaleFactor, IntPoint(x, y));
2929 return { };
2930}
2931
2932ExceptionOr<void> Internals::setPageZoomFactor(float zoomFactor)
2933{
2934 Document* document = contextDocument();
2935 if (!document || !document->frame())
2936 return Exception { InvalidAccessError };
2937
2938 document->frame()->setPageZoomFactor(zoomFactor);
2939 return { };
2940}
2941
2942ExceptionOr<void> Internals::setTextZoomFactor(float zoomFactor)
2943{
2944 Document* document = contextDocument();
2945 if (!document || !document->frame())
2946 return Exception { InvalidAccessError };
2947
2948 document->frame()->setTextZoomFactor(zoomFactor);
2949 return { };
2950}
2951
2952ExceptionOr<void> Internals::setUseFixedLayout(bool useFixedLayout)
2953{
2954 Document* document = contextDocument();
2955 if (!document || !document->view())
2956 return Exception { InvalidAccessError };
2957
2958 document->view()->setUseFixedLayout(useFixedLayout);
2959 return { };
2960}
2961
2962ExceptionOr<void> Internals::setFixedLayoutSize(int width, int height)
2963{
2964 Document* document = contextDocument();
2965 if (!document || !document->view())
2966 return Exception { InvalidAccessError };
2967
2968 document->view()->setFixedLayoutSize(IntSize(width, height));
2969 return { };
2970}
2971
2972ExceptionOr<void> Internals::setViewExposedRect(float x, float y, float width, float height)
2973{
2974 Document* document = contextDocument();
2975 if (!document || !document->view())
2976 return Exception { InvalidAccessError };
2977
2978 document->view()->setViewExposedRect(FloatRect(x, y, width, height));
2979 return { };
2980}
2981
2982void Internals::setPrinting(int width, int height)
2983{
2984 printContextForTesting() = std::make_unique<PrintContext>(frame());
2985 printContextForTesting()->begin(width, height);
2986}
2987
2988void Internals::setHeaderHeight(float height)
2989{
2990 Document* document = contextDocument();
2991 if (!document || !document->view())
2992 return;
2993
2994 document->page()->setHeaderHeight(height);
2995}
2996
2997void Internals::setFooterHeight(float height)
2998{
2999 Document* document = contextDocument();
3000 if (!document || !document->view())
3001 return;
3002
3003 document->page()->setFooterHeight(height);
3004}
3005
3006void Internals::setTopContentInset(float contentInset)
3007{
3008 Document* document = contextDocument();
3009 if (!document || !document->page())
3010 return;
3011
3012 document->page()->setTopContentInset(contentInset);
3013}
3014
3015#if ENABLE(FULLSCREEN_API)
3016
3017void Internals::webkitWillEnterFullScreenForElement(Element& element)
3018{
3019 Document* document = contextDocument();
3020 if (!document)
3021 return;
3022 document->fullscreenManager().willEnterFullscreen(element);
3023}
3024
3025void Internals::webkitDidEnterFullScreenForElement(Element&)
3026{
3027 Document* document = contextDocument();
3028 if (!document)
3029 return;
3030 document->fullscreenManager().didEnterFullscreen();
3031}
3032
3033void Internals::webkitWillExitFullScreenForElement(Element&)
3034{
3035 Document* document = contextDocument();
3036 if (!document)
3037 return;
3038 document->fullscreenManager().willExitFullscreen();
3039}
3040
3041void Internals::webkitDidExitFullScreenForElement(Element&)
3042{
3043 Document* document = contextDocument();
3044 if (!document)
3045 return;
3046 document->fullscreenManager().didExitFullscreen();
3047}
3048
3049bool Internals::isAnimatingFullScreen() const
3050{
3051 Document* document = contextDocument();
3052 if (!document)
3053 return false;
3054 return document->fullscreenManager().isAnimatingFullscreen();
3055}
3056
3057#endif
3058
3059void Internals::setFullscreenInsets(FullscreenInsets insets)
3060{
3061 Page* page = contextDocument()->frame()->page();
3062 ASSERT(page);
3063
3064 page->setFullscreenInsets(FloatBoxExtent(insets.top, insets.right, insets.bottom, insets.left));
3065}
3066
3067void Internals::setFullscreenAutoHideDuration(double duration)
3068{
3069 Page* page = contextDocument()->frame()->page();
3070 ASSERT(page);
3071
3072 page->setFullscreenAutoHideDuration(Seconds(duration));
3073}
3074
3075void Internals::setFullscreenControlsHidden(bool hidden)
3076{
3077 Page* page = contextDocument()->frame()->page();
3078 ASSERT(page);
3079
3080 page->setFullscreenControlsHidden(hidden);
3081}
3082
3083void Internals::setApplicationCacheOriginQuota(unsigned long long quota)
3084{
3085 Document* document = contextDocument();
3086 if (!document || !document->page())
3087 return;
3088 document->page()->applicationCacheStorage().storeUpdatedQuotaForOrigin(&document->securityOrigin(), quota);
3089}
3090
3091void Internals::registerURLSchemeAsBypassingContentSecurityPolicy(const String& scheme)
3092{
3093 SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(scheme);
3094}
3095
3096void Internals::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(const String& scheme)
3097{
3098 SchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(scheme);
3099}
3100
3101void Internals::registerDefaultPortForProtocol(unsigned short port, const String& protocol)
3102{
3103 registerDefaultPortForProtocolForTesting(port, protocol);
3104}
3105
3106Ref<MallocStatistics> Internals::mallocStatistics() const
3107{
3108 return MallocStatistics::create();
3109}
3110
3111Ref<TypeConversions> Internals::typeConversions() const
3112{
3113 return TypeConversions::create();
3114}
3115
3116Ref<MemoryInfo> Internals::memoryInfo() const
3117{
3118 return MemoryInfo::create();
3119}
3120
3121Vector<String> Internals::getReferencedFilePaths() const
3122{
3123 frame()->loader().history().saveDocumentAndScrollState();
3124 return FormController::referencedFilePaths(frame()->loader().history().currentItem()->documentState());
3125}
3126
3127ExceptionOr<void> Internals::startTrackingRepaints()
3128{
3129 Document* document = contextDocument();
3130 if (!document || !document->view())
3131 return Exception { InvalidAccessError };
3132
3133 document->view()->setTracksRepaints(true);
3134 return { };
3135}
3136
3137ExceptionOr<void> Internals::stopTrackingRepaints()
3138{
3139 Document* document = contextDocument();
3140 if (!document || !document->view())
3141 return Exception { InvalidAccessError };
3142
3143 document->view()->setTracksRepaints(false);
3144 return { };
3145}
3146
3147ExceptionOr<void> Internals::startTrackingLayerFlushes()
3148{
3149 Document* document = contextDocument();
3150 if (!document || !document->renderView())
3151 return Exception { InvalidAccessError };
3152
3153 document->renderView()->compositor().startTrackingLayerFlushes();
3154 return { };
3155}
3156
3157ExceptionOr<unsigned> Internals::layerFlushCount()
3158{
3159 Document* document = contextDocument();
3160 if (!document || !document->renderView())
3161 return Exception { InvalidAccessError };
3162
3163 return document->renderView()->compositor().layerFlushCount();
3164}
3165
3166ExceptionOr<void> Internals::startTrackingStyleRecalcs()
3167{
3168 Document* document = contextDocument();
3169 if (!document)
3170 return Exception { InvalidAccessError };
3171
3172 document->startTrackingStyleRecalcs();
3173 return { };
3174}
3175
3176ExceptionOr<unsigned> Internals::styleRecalcCount()
3177{
3178 Document* document = contextDocument();
3179 if (!document)
3180 return Exception { InvalidAccessError };
3181
3182 return document->styleRecalcCount();
3183}
3184
3185unsigned Internals::lastStyleUpdateSize() const
3186{
3187 Document* document = contextDocument();
3188 if (!document)
3189 return 0;
3190 return document->lastStyleUpdateSizeForTesting();
3191}
3192
3193ExceptionOr<void> Internals::startTrackingCompositingUpdates()
3194{
3195 Document* document = contextDocument();
3196 if (!document || !document->renderView())
3197 return Exception { InvalidAccessError };
3198
3199 document->renderView()->compositor().startTrackingCompositingUpdates();
3200 return { };
3201}
3202
3203ExceptionOr<unsigned> Internals::compositingUpdateCount()
3204{
3205 Document* document = contextDocument();
3206 if (!document || !document->renderView())
3207 return Exception { InvalidAccessError };
3208
3209 return document->renderView()->compositor().compositingUpdateCount();
3210}
3211
3212ExceptionOr<void> Internals::setCompositingPolicyOverride(Optional<CompositingPolicy> policyOverride)
3213{
3214 Document* document = contextDocument();
3215 if (!document)
3216 return Exception { InvalidAccessError };
3217
3218 if (!policyOverride) {
3219 document->page()->setCompositingPolicyOverride(WTF::nullopt);
3220 return { };
3221 }
3222
3223 switch (policyOverride.value()) {
3224 case Internals::CompositingPolicy::Normal:
3225 document->page()->setCompositingPolicyOverride(WebCore::CompositingPolicy::Normal);
3226 break;
3227 case Internals::CompositingPolicy::Conservative:
3228 document->page()->setCompositingPolicyOverride(WebCore::CompositingPolicy::Conservative);
3229 break;
3230 }
3231
3232 return { };
3233}
3234
3235ExceptionOr<Optional<Internals::CompositingPolicy>> Internals::compositingPolicyOverride() const
3236{
3237 Document* document = contextDocument();
3238 if (!document)
3239 return Exception { InvalidAccessError };
3240
3241 auto policyOverride = document->page()->compositingPolicyOverride();
3242 if (!policyOverride)
3243 return { WTF::nullopt };
3244
3245 switch (policyOverride.value()) {
3246 case WebCore::CompositingPolicy::Normal:
3247 return { Internals::CompositingPolicy::Normal };
3248 case WebCore::CompositingPolicy::Conservative:
3249 return { Internals::CompositingPolicy::Conservative };
3250 }
3251
3252 return { Internals::CompositingPolicy::Normal };
3253}
3254
3255ExceptionOr<void> Internals::updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node* node)
3256{
3257 Document* document;
3258 if (!node)
3259 document = contextDocument();
3260 else if (is<Document>(*node))
3261 document = downcast<Document>(node);
3262 else if (is<HTMLIFrameElement>(*node))
3263 document = downcast<HTMLIFrameElement>(*node).contentDocument();
3264 else
3265 return Exception { TypeError };
3266
3267 document->updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks::Synchronously);
3268 return { };
3269}
3270
3271unsigned Internals::layoutCount() const
3272{
3273 Document* document = contextDocument();
3274 if (!document || !document->view())
3275 return 0;
3276 return document->view()->layoutContext().layoutCount();
3277}
3278
3279#if !PLATFORM(IOS_FAMILY)
3280static const char* cursorTypeToString(Cursor::Type cursorType)
3281{
3282 switch (cursorType) {
3283 case Cursor::Pointer: return "Pointer";
3284 case Cursor::Cross: return "Cross";
3285 case Cursor::Hand: return "Hand";
3286 case Cursor::IBeam: return "IBeam";
3287 case Cursor::Wait: return "Wait";
3288 case Cursor::Help: return "Help";
3289 case Cursor::EastResize: return "EastResize";
3290 case Cursor::NorthResize: return "NorthResize";
3291 case Cursor::NorthEastResize: return "NorthEastResize";
3292 case Cursor::NorthWestResize: return "NorthWestResize";
3293 case Cursor::SouthResize: return "SouthResize";
3294 case Cursor::SouthEastResize: return "SouthEastResize";
3295 case Cursor::SouthWestResize: return "SouthWestResize";
3296 case Cursor::WestResize: return "WestResize";
3297 case Cursor::NorthSouthResize: return "NorthSouthResize";
3298 case Cursor::EastWestResize: return "EastWestResize";
3299 case Cursor::NorthEastSouthWestResize: return "NorthEastSouthWestResize";
3300 case Cursor::NorthWestSouthEastResize: return "NorthWestSouthEastResize";
3301 case Cursor::ColumnResize: return "ColumnResize";
3302 case Cursor::RowResize: return "RowResize";
3303 case Cursor::MiddlePanning: return "MiddlePanning";
3304 case Cursor::EastPanning: return "EastPanning";
3305 case Cursor::NorthPanning: return "NorthPanning";
3306 case Cursor::NorthEastPanning: return "NorthEastPanning";
3307 case Cursor::NorthWestPanning: return "NorthWestPanning";
3308 case Cursor::SouthPanning: return "SouthPanning";
3309 case Cursor::SouthEastPanning: return "SouthEastPanning";
3310 case Cursor::SouthWestPanning: return "SouthWestPanning";
3311 case Cursor::WestPanning: return "WestPanning";
3312 case Cursor::Move: return "Move";
3313 case Cursor::VerticalText: return "VerticalText";
3314 case Cursor::Cell: return "Cell";
3315 case Cursor::ContextMenu: return "ContextMenu";
3316 case Cursor::Alias: return "Alias";
3317 case Cursor::Progress: return "Progress";
3318 case Cursor::NoDrop: return "NoDrop";
3319 case Cursor::Copy: return "Copy";
3320 case Cursor::None: return "None";
3321 case Cursor::NotAllowed: return "NotAllowed";
3322 case Cursor::ZoomIn: return "ZoomIn";
3323 case Cursor::ZoomOut: return "ZoomOut";
3324 case Cursor::Grab: return "Grab";
3325 case Cursor::Grabbing: return "Grabbing";
3326 case Cursor::Custom: return "Custom";
3327 }
3328
3329 ASSERT_NOT_REACHED();
3330 return "UNKNOWN";
3331}
3332#endif
3333
3334ExceptionOr<String> Internals::getCurrentCursorInfo()
3335{
3336 Document* document = contextDocument();
3337 if (!document || !document->frame())
3338 return Exception { InvalidAccessError };
3339
3340#if !PLATFORM(IOS_FAMILY)
3341 Cursor cursor = document->frame()->eventHandler().currentMouseCursor();
3342
3343 StringBuilder result;
3344 result.appendLiteral("type=");
3345 result.append(cursorTypeToString(cursor.type()));
3346 result.appendLiteral(" hotSpot=");
3347 result.appendNumber(cursor.hotSpot().x());
3348 result.append(',');
3349 result.appendNumber(cursor.hotSpot().y());
3350 if (cursor.image()) {
3351 FloatSize size = cursor.image()->size();
3352 result.appendLiteral(" image=");
3353 result.appendFixedPrecisionNumber(size.width());
3354 result.append('x');
3355 result.appendFixedPrecisionNumber(size.height());
3356 }
3357#if ENABLE(MOUSE_CURSOR_SCALE)
3358 if (cursor.imageScaleFactor() != 1) {
3359 result.appendLiteral(" scale=");
3360 result.appendFixedPrecisionNumber(cursor.imageScaleFactor(), 8);
3361 }
3362#endif
3363 return result.toString();
3364#else
3365 return "FAIL: Cursor details not available on this platform."_str;
3366#endif
3367}
3368
3369Ref<ArrayBuffer> Internals::serializeObject(const RefPtr<SerializedScriptValue>& value) const
3370{
3371 auto& bytes = value->data();
3372 return ArrayBuffer::create(bytes.data(), bytes.size());
3373}
3374
3375Ref<SerializedScriptValue> Internals::deserializeBuffer(ArrayBuffer& buffer) const
3376{
3377 Vector<uint8_t> bytes;
3378 bytes.append(static_cast<const uint8_t*>(buffer.data()), buffer.byteLength());
3379 return SerializedScriptValue::adopt(WTFMove(bytes));
3380}
3381
3382bool Internals::isFromCurrentWorld(JSC::JSValue value) const
3383{
3384 return isWorldCompatible(*contextDocument()->vm().topCallFrame, value);
3385}
3386
3387void Internals::setUsesOverlayScrollbars(bool enabled)
3388{
3389 WebCore::DeprecatedGlobalSettings::setUsesOverlayScrollbars(enabled);
3390}
3391
3392void Internals::setUsesMockScrollAnimator(bool enabled)
3393{
3394 WebCore::DeprecatedGlobalSettings::setUsesMockScrollAnimator(enabled);
3395}
3396
3397void Internals::forceReload(bool endToEnd)
3398{
3399 OptionSet<ReloadOption> reloadOptions;
3400 if (endToEnd)
3401 reloadOptions.add(ReloadOption::FromOrigin);
3402
3403 frame()->loader().reload(reloadOptions);
3404}
3405
3406void Internals::reloadExpiredOnly()
3407{
3408 frame()->loader().reload(ReloadOption::ExpiredOnly);
3409}
3410
3411void Internals::enableAutoSizeMode(bool enabled, int width, int height)
3412{
3413 auto* document = contextDocument();
3414 if (!document || !document->view())
3415 return;
3416 document->view()->enableAutoSizeMode(enabled, { width, height });
3417}
3418
3419#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
3420
3421void Internals::initializeMockCDM()
3422{
3423 LegacyCDM::registerCDMFactory([] (LegacyCDM* cdm) { return std::make_unique<LegacyMockCDM>(cdm); },
3424 LegacyMockCDM::supportsKeySystem, LegacyMockCDM::supportsKeySystemAndMimeType);
3425}
3426
3427#endif
3428
3429#if ENABLE(ENCRYPTED_MEDIA)
3430
3431Ref<MockCDMFactory> Internals::registerMockCDM()
3432{
3433 return MockCDMFactory::create();
3434}
3435
3436#endif
3437
3438String Internals::markerTextForListItem(Element& element)
3439{
3440 return WebCore::markerTextForListItem(&element);
3441}
3442
3443String Internals::toolTipFromElement(Element& element) const
3444{
3445 HitTestResult result;
3446 result.setInnerNode(&element);
3447 TextDirection direction;
3448 return result.title(direction);
3449}
3450
3451String Internals::getImageSourceURL(Element& element)
3452{
3453 return element.imageSourceURL();
3454}
3455
3456#if ENABLE(VIDEO)
3457
3458Vector<String> Internals::mediaResponseSources(HTMLMediaElement& media)
3459{
3460 auto* resourceLoader = media.lastMediaResourceLoaderForTesting();
3461 if (!resourceLoader)
3462 return { };
3463 Vector<String> result;
3464 auto responses = resourceLoader->responsesForTesting();
3465 for (auto& response : responses)
3466 result.append(responseSourceToString(response));
3467 return result;
3468}
3469
3470Vector<String> Internals::mediaResponseContentRanges(HTMLMediaElement& media)
3471{
3472 auto* resourceLoader = media.lastMediaResourceLoaderForTesting();
3473 if (!resourceLoader)
3474 return { };
3475 Vector<String> result;
3476 auto responses = resourceLoader->responsesForTesting();
3477 for (auto& response : responses)
3478 result.append(response.httpHeaderField(HTTPHeaderName::ContentRange));
3479 return result;
3480}
3481
3482void Internals::simulateAudioInterruption(HTMLMediaElement& element)
3483{
3484#if USE(GSTREAMER)
3485 element.player()->simulateAudioInterruption();
3486#else
3487 UNUSED_PARAM(element);
3488#endif
3489}
3490
3491ExceptionOr<bool> Internals::mediaElementHasCharacteristic(HTMLMediaElement& element, const String& characteristic)
3492{
3493 if (equalLettersIgnoringASCIICase(characteristic, "audible"))
3494 return element.hasAudio();
3495 if (equalLettersIgnoringASCIICase(characteristic, "visual"))
3496 return element.hasVideo();
3497 if (equalLettersIgnoringASCIICase(characteristic, "legible"))
3498 return element.hasClosedCaptions();
3499
3500 return Exception { SyntaxError };
3501}
3502
3503void Internals::beginSimulatedHDCPError(HTMLMediaElement& element)
3504{
3505 if (auto player = element.player())
3506 player->beginSimulatedHDCPError();
3507}
3508
3509void Internals::endSimulatedHDCPError(HTMLMediaElement& element)
3510{
3511 if (auto player = element.player())
3512 player->endSimulatedHDCPError();
3513}
3514
3515bool Internals::elementShouldBufferData(HTMLMediaElement& element)
3516{
3517 return element.bufferingPolicy() < MediaPlayer::BufferingPolicy::LimitReadAhead;
3518}
3519
3520String Internals::elementBufferingPolicy(HTMLMediaElement& element)
3521{
3522 switch (element.bufferingPolicy()) {
3523 case MediaPlayer::BufferingPolicy::Default:
3524 return "Default";
3525 case MediaPlayer::BufferingPolicy::LimitReadAhead:
3526 return "LimitReadAhead";
3527 case MediaPlayer::BufferingPolicy::MakeResourcesPurgeable:
3528 return "MakeResourcesPurgeable";
3529 case MediaPlayer::BufferingPolicy::PurgeResources:
3530 return "PurgeResources";
3531 }
3532
3533 ASSERT_NOT_REACHED();
3534 return "UNKNOWN";
3535}
3536#endif
3537
3538bool Internals::isSelectPopupVisible(HTMLSelectElement& element)
3539{
3540 element.document().updateLayoutIgnorePendingStylesheets();
3541
3542 auto* renderer = element.renderer();
3543 if (!is<RenderMenuList>(renderer))
3544 return false;
3545
3546#if !PLATFORM(IOS_FAMILY)
3547 return downcast<RenderMenuList>(*renderer).popupIsVisible();
3548#else
3549 return false;
3550#endif
3551}
3552
3553ExceptionOr<String> Internals::captionsStyleSheetOverride()
3554{
3555 Document* document = contextDocument();
3556 if (!document || !document->page())
3557 return Exception { InvalidAccessError };
3558
3559#if ENABLE(VIDEO_TRACK)
3560 return document->page()->group().captionPreferences().captionsStyleSheetOverride();
3561#else
3562 return String { emptyString() };
3563#endif
3564}
3565
3566ExceptionOr<void> Internals::setCaptionsStyleSheetOverride(const String& override)
3567{
3568 Document* document = contextDocument();
3569 if (!document || !document->page())
3570 return Exception { InvalidAccessError };
3571
3572#if ENABLE(VIDEO_TRACK)
3573 document->page()->group().captionPreferences().setCaptionsStyleSheetOverride(override);
3574#else
3575 UNUSED_PARAM(override);
3576#endif
3577 return { };
3578}
3579
3580ExceptionOr<void> Internals::setPrimaryAudioTrackLanguageOverride(const String& language)
3581{
3582 Document* document = contextDocument();
3583 if (!document || !document->page())
3584 return Exception { InvalidAccessError };
3585
3586#if ENABLE(VIDEO_TRACK)
3587 document->page()->group().captionPreferences().setPrimaryAudioTrackLanguageOverride(language);
3588#else
3589 UNUSED_PARAM(language);
3590#endif
3591 return { };
3592}
3593
3594ExceptionOr<void> Internals::setCaptionDisplayMode(const String& mode)
3595{
3596 Document* document = contextDocument();
3597 if (!document || !document->page())
3598 return Exception { InvalidAccessError };
3599
3600#if ENABLE(VIDEO_TRACK)
3601 auto& captionPreferences = document->page()->group().captionPreferences();
3602
3603 if (equalLettersIgnoringASCIICase(mode, "automatic"))
3604 captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::Automatic);
3605 else if (equalLettersIgnoringASCIICase(mode, "forcedonly"))
3606 captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::ForcedOnly);
3607 else if (equalLettersIgnoringASCIICase(mode, "alwayson"))
3608 captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::AlwaysOn);
3609 else if (equalLettersIgnoringASCIICase(mode, "manual"))
3610 captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::Manual);
3611 else
3612 return Exception { SyntaxError };
3613#else
3614 UNUSED_PARAM(mode);
3615#endif
3616 return { };
3617}
3618
3619#if ENABLE(VIDEO_TRACK)
3620RefPtr<TextTrackCueGeneric> Internals::createGenericCue(double startTime, double endTime, String text)
3621{
3622 Document* document = contextDocument();
3623 if (!document || !document->page())
3624 return nullptr;
3625 return TextTrackCueGeneric::create(*document, MediaTime::createWithDouble(startTime), MediaTime::createWithDouble(endTime), text);
3626}
3627#endif
3628
3629#if ENABLE(VIDEO)
3630
3631Ref<TimeRanges> Internals::createTimeRanges(Float32Array& startTimes, Float32Array& endTimes)
3632{
3633 ASSERT(startTimes.length() == endTimes.length());
3634 Ref<TimeRanges> ranges = TimeRanges::create();
3635
3636 unsigned count = std::min(startTimes.length(), endTimes.length());
3637 for (unsigned i = 0; i < count; ++i)
3638 ranges->add(startTimes.item(i), endTimes.item(i));
3639 return ranges;
3640}
3641
3642double Internals::closestTimeToTimeRanges(double time, TimeRanges& ranges)
3643{
3644 return ranges.nearest(time);
3645}
3646
3647#endif
3648
3649ExceptionOr<Ref<DOMRect>> Internals::selectionBounds()
3650{
3651 Document* document = contextDocument();
3652 if (!document || !document->frame())
3653 return Exception { InvalidAccessError };
3654
3655 return DOMRect::create(document->frame()->selection().selectionBounds());
3656}
3657
3658void Internals::setSelectionWithoutValidation(Ref<Node> baseNode, unsigned baseOffset, RefPtr<Node> extentNode, unsigned extentOffset)
3659{
3660 contextDocument()->frame()->selection().moveTo(
3661 VisiblePosition { createLegacyEditingPosition(baseNode.ptr(), baseOffset) },
3662 VisiblePosition { createLegacyEditingPosition(extentNode.get(), extentOffset) });
3663}
3664
3665ExceptionOr<bool> Internals::isPluginUnavailabilityIndicatorObscured(Element& element)
3666{
3667 if (!is<HTMLPlugInElement>(element))
3668 return Exception { InvalidAccessError };
3669
3670 return downcast<HTMLPlugInElement>(element).isReplacementObscured();
3671}
3672
3673ExceptionOr<String> Internals::unavailablePluginReplacementText(Element& element)
3674{
3675 if (!is<HTMLPlugInElement>(element))
3676 return Exception { InvalidAccessError };
3677
3678 auto* renderer = element.renderer();
3679 if (!is<RenderEmbeddedObject>(renderer))
3680 return String { };
3681
3682 return String { downcast<RenderEmbeddedObject>(*renderer).pluginReplacementTextIfUnavailable() };
3683}
3684
3685bool Internals::isPluginSnapshotted(Element& element)
3686{
3687 return is<HTMLPlugInElement>(element) && downcast<HTMLPlugInElement>(element).displayState() <= HTMLPlugInElement::DisplayingSnapshot;
3688}
3689
3690bool Internals::pluginIsBelowSizeThreshold(Element& element)
3691{
3692 return is<HTMLPlugInElement>(element) && downcast<HTMLPlugInElement>(element).isBelowSizeThreshold();
3693}
3694
3695#if ENABLE(MEDIA_SOURCE)
3696
3697void Internals::initializeMockMediaSource()
3698{
3699#if USE(AVFOUNDATION)
3700 WebCore::DeprecatedGlobalSettings::setAVFoundationEnabled(false);
3701#endif
3702#if USE(GSTREAMER)
3703 WebCore::DeprecatedGlobalSettings::setGStreamerEnabled(false);
3704#endif
3705 MediaPlayerFactorySupport::callRegisterMediaEngine(MockMediaPlayerMediaSource::registerMediaEngine);
3706}
3707
3708Vector<String> Internals::bufferedSamplesForTrackID(SourceBuffer& buffer, const AtomicString& trackID)
3709{
3710 return buffer.bufferedSamplesForTrackID(trackID);
3711}
3712
3713Vector<String> Internals::enqueuedSamplesForTrackID(SourceBuffer& buffer, const AtomicString& trackID)
3714{
3715 return buffer.enqueuedSamplesForTrackID(trackID);
3716}
3717
3718void Internals::setShouldGenerateTimestamps(SourceBuffer& buffer, bool flag)
3719{
3720 buffer.setShouldGenerateTimestamps(flag);
3721}
3722
3723#endif
3724
3725void Internals::enableMockMediaCapabilities()
3726{
3727 MediaEngineConfigurationFactory::enableMock();
3728}
3729
3730#if ENABLE(VIDEO)
3731
3732ExceptionOr<void> Internals::beginMediaSessionInterruption(const String& interruptionString)
3733{
3734 PlatformMediaSession::InterruptionType interruption = PlatformMediaSession::SystemInterruption;
3735
3736 if (equalLettersIgnoringASCIICase(interruptionString, "system"))
3737 interruption = PlatformMediaSession::SystemInterruption;
3738 else if (equalLettersIgnoringASCIICase(interruptionString, "systemsleep"))
3739 interruption = PlatformMediaSession::SystemSleep;
3740 else if (equalLettersIgnoringASCIICase(interruptionString, "enteringbackground"))
3741 interruption = PlatformMediaSession::EnteringBackground;
3742 else if (equalLettersIgnoringASCIICase(interruptionString, "suspendedunderlock"))
3743 interruption = PlatformMediaSession::SuspendedUnderLock;
3744 else
3745 return Exception { InvalidAccessError };
3746
3747 PlatformMediaSessionManager::sharedManager().beginInterruption(interruption);
3748 return { };
3749}
3750
3751void Internals::endMediaSessionInterruption(const String& flagsString)
3752{
3753 PlatformMediaSession::EndInterruptionFlags flags = PlatformMediaSession::NoFlags;
3754
3755 if (equalLettersIgnoringASCIICase(flagsString, "mayresumeplaying"))
3756 flags = PlatformMediaSession::MayResumePlaying;
3757
3758 PlatformMediaSessionManager::sharedManager().endInterruption(flags);
3759}
3760
3761void Internals::applicationWillBecomeInactive()
3762{
3763 PlatformMediaSessionManager::sharedManager().applicationWillBecomeInactive();
3764}
3765
3766void Internals::applicationDidBecomeActive()
3767{
3768 PlatformMediaSessionManager::sharedManager().applicationDidBecomeActive();
3769}
3770
3771void Internals::applicationWillEnterForeground(bool suspendedUnderLock) const
3772{
3773 PlatformMediaSessionManager::sharedManager().applicationWillEnterForeground(suspendedUnderLock);
3774}
3775
3776void Internals::applicationDidEnterBackground(bool suspendedUnderLock) const
3777{
3778 PlatformMediaSessionManager::sharedManager().applicationDidEnterBackground(suspendedUnderLock);
3779}
3780
3781static PlatformMediaSession::MediaType mediaTypeFromString(const String& mediaTypeString)
3782{
3783 if (equalLettersIgnoringASCIICase(mediaTypeString, "video"))
3784 return PlatformMediaSession::Video;
3785 if (equalLettersIgnoringASCIICase(mediaTypeString, "audio"))
3786 return PlatformMediaSession::Audio;
3787 if (equalLettersIgnoringASCIICase(mediaTypeString, "videoaudio"))
3788 return PlatformMediaSession::VideoAudio;
3789 if (equalLettersIgnoringASCIICase(mediaTypeString, "webaudio"))
3790 return PlatformMediaSession::WebAudio;
3791 if (equalLettersIgnoringASCIICase(mediaTypeString, "mediastreamcapturingaudio"))
3792 return PlatformMediaSession::MediaStreamCapturingAudio;
3793
3794 return PlatformMediaSession::None;
3795}
3796
3797ExceptionOr<void> Internals::setMediaSessionRestrictions(const String& mediaTypeString, StringView restrictionsString)
3798{
3799 PlatformMediaSession::MediaType mediaType = mediaTypeFromString(mediaTypeString);
3800 if (mediaType == PlatformMediaSession::None)
3801 return Exception { InvalidAccessError };
3802
3803 PlatformMediaSessionManager::SessionRestrictions restrictions = PlatformMediaSessionManager::sharedManager().restrictions(mediaType);
3804 PlatformMediaSessionManager::sharedManager().removeRestriction(mediaType, restrictions);
3805
3806 restrictions = PlatformMediaSessionManager::NoRestrictions;
3807
3808 for (StringView restrictionString : restrictionsString.split(',')) {
3809 if (equalLettersIgnoringASCIICase(restrictionString, "concurrentplaybacknotpermitted"))
3810 restrictions |= PlatformMediaSessionManager::ConcurrentPlaybackNotPermitted;
3811 if (equalLettersIgnoringASCIICase(restrictionString, "backgroundprocessplaybackrestricted"))
3812 restrictions |= PlatformMediaSessionManager::BackgroundProcessPlaybackRestricted;
3813 if (equalLettersIgnoringASCIICase(restrictionString, "backgroundtabplaybackrestricted"))
3814 restrictions |= PlatformMediaSessionManager::BackgroundTabPlaybackRestricted;
3815 if (equalLettersIgnoringASCIICase(restrictionString, "interruptedplaybacknotpermitted"))
3816 restrictions |= PlatformMediaSessionManager::InterruptedPlaybackNotPermitted;
3817 if (equalLettersIgnoringASCIICase(restrictionString, "inactiveprocessplaybackrestricted"))
3818 restrictions |= PlatformMediaSessionManager::InactiveProcessPlaybackRestricted;
3819 if (equalLettersIgnoringASCIICase(restrictionString, "suspendedunderlockplaybackrestricted"))
3820 restrictions |= PlatformMediaSessionManager::SuspendedUnderLockPlaybackRestricted;
3821 }
3822 PlatformMediaSessionManager::sharedManager().addRestriction(mediaType, restrictions);
3823 return { };
3824}
3825
3826ExceptionOr<String> Internals::mediaSessionRestrictions(const String& mediaTypeString) const
3827{
3828 PlatformMediaSession::MediaType mediaType = mediaTypeFromString(mediaTypeString);
3829 if (mediaType == PlatformMediaSession::None)
3830 return Exception { InvalidAccessError };
3831
3832 PlatformMediaSessionManager::SessionRestrictions restrictions = PlatformMediaSessionManager::sharedManager().restrictions(mediaType);
3833 if (restrictions == PlatformMediaSessionManager::NoRestrictions)
3834 return String();
3835
3836 StringBuilder builder;
3837 if (restrictions & PlatformMediaSessionManager::ConcurrentPlaybackNotPermitted)
3838 builder.append("concurrentplaybacknotpermitted");
3839 if (restrictions & PlatformMediaSessionManager::BackgroundProcessPlaybackRestricted) {
3840 if (!builder.isEmpty())
3841 builder.append(',');
3842 builder.append("backgroundprocessplaybackrestricted");
3843 }
3844 if (restrictions & PlatformMediaSessionManager::BackgroundTabPlaybackRestricted) {
3845 if (!builder.isEmpty())
3846 builder.append(',');
3847 builder.append("backgroundtabplaybackrestricted");
3848 }
3849 if (restrictions & PlatformMediaSessionManager::InterruptedPlaybackNotPermitted) {
3850 if (!builder.isEmpty())
3851 builder.append(',');
3852 builder.append("interruptedplaybacknotpermitted");
3853 }
3854 return builder.toString();
3855}
3856
3857void Internals::setMediaElementRestrictions(HTMLMediaElement& element, StringView restrictionsString)
3858{
3859 MediaElementSession::BehaviorRestrictions restrictions = element.mediaSession().behaviorRestrictions();
3860 element.mediaSession().removeBehaviorRestriction(restrictions);
3861
3862 restrictions = MediaElementSession::NoRestrictions;
3863
3864 for (StringView restrictionString : restrictionsString.split(',')) {
3865 if (equalLettersIgnoringASCIICase(restrictionString, "norestrictions"))
3866 restrictions |= MediaElementSession::NoRestrictions;
3867 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforload"))
3868 restrictions |= MediaElementSession::RequireUserGestureForLoad;
3869 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforvideoratechange"))
3870 restrictions |= MediaElementSession::RequireUserGestureForVideoRateChange;
3871 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforfullscreen"))
3872 restrictions |= MediaElementSession::RequireUserGestureForFullscreen;
3873 if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsenttoloadmedia"))
3874 restrictions |= MediaElementSession::RequirePageConsentToLoadMedia;
3875 if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsenttoresumemedia"))
3876 restrictions |= MediaElementSession::RequirePageConsentToResumeMedia;
3877#if ENABLE(WIRELESS_PLAYBACK_TARGET)
3878 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergesturetoshowplaybacktargetpicker"))
3879 restrictions |= MediaElementSession::RequireUserGestureToShowPlaybackTargetPicker;
3880 if (equalLettersIgnoringASCIICase(restrictionString, "wirelessvideoplaybackdisabled"))
3881 restrictions |= MediaElementSession::WirelessVideoPlaybackDisabled;
3882#endif
3883 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforaudioratechange"))
3884 restrictions |= MediaElementSession::RequireUserGestureForAudioRateChange;
3885 if (equalLettersIgnoringASCIICase(restrictionString, "autopreloadingnotpermitted"))
3886 restrictions |= MediaElementSession::AutoPreloadingNotPermitted;
3887 if (equalLettersIgnoringASCIICase(restrictionString, "invisibleautoplaynotpermitted"))
3888 restrictions |= MediaElementSession::InvisibleAutoplayNotPermitted;
3889 if (equalLettersIgnoringASCIICase(restrictionString, "overrideusergesturerequirementformaincontent"))
3890 restrictions |= MediaElementSession::OverrideUserGestureRequirementForMainContent;
3891 }
3892 element.mediaSession().addBehaviorRestriction(restrictions);
3893}
3894
3895ExceptionOr<void> Internals::postRemoteControlCommand(const String& commandString, float argument)
3896{
3897 PlatformMediaSession::RemoteControlCommandType command;
3898 PlatformMediaSession::RemoteCommandArgument parameter { argument };
3899
3900 if (equalLettersIgnoringASCIICase(commandString, "play"))
3901 command = PlatformMediaSession::PlayCommand;
3902 else if (equalLettersIgnoringASCIICase(commandString, "pause"))
3903 command = PlatformMediaSession::PauseCommand;
3904 else if (equalLettersIgnoringASCIICase(commandString, "stop"))
3905 command = PlatformMediaSession::StopCommand;
3906 else if (equalLettersIgnoringASCIICase(commandString, "toggleplaypause"))
3907 command = PlatformMediaSession::TogglePlayPauseCommand;
3908 else if (equalLettersIgnoringASCIICase(commandString, "beginseekingbackward"))
3909 command = PlatformMediaSession::BeginSeekingBackwardCommand;
3910 else if (equalLettersIgnoringASCIICase(commandString, "endseekingbackward"))
3911 command = PlatformMediaSession::EndSeekingBackwardCommand;
3912 else if (equalLettersIgnoringASCIICase(commandString, "beginseekingforward"))
3913 command = PlatformMediaSession::BeginSeekingForwardCommand;
3914 else if (equalLettersIgnoringASCIICase(commandString, "endseekingforward"))
3915 command = PlatformMediaSession::EndSeekingForwardCommand;
3916 else if (equalLettersIgnoringASCIICase(commandString, "seektoplaybackposition"))
3917 command = PlatformMediaSession::SeekToPlaybackPositionCommand;
3918 else
3919 return Exception { InvalidAccessError };
3920
3921 PlatformMediaSessionManager::sharedManager().didReceiveRemoteControlCommand(command, &parameter);
3922 return { };
3923}
3924
3925bool Internals::elementIsBlockingDisplaySleep(HTMLMediaElement& element) const
3926{
3927 return element.isDisablingSleep();
3928}
3929
3930#endif // ENABLE(VIDEO)
3931
3932#if ENABLE(MEDIA_SESSION)
3933
3934void Internals::sendMediaSessionStartOfInterruptionNotification(MediaSessionInterruptingCategory category)
3935{
3936 MediaSessionManager::singleton().didReceiveStartOfInterruptionNotification(category);
3937}
3938
3939void Internals::sendMediaSessionEndOfInterruptionNotification(MediaSessionInterruptingCategory category)
3940{
3941 MediaSessionManager::singleton().didReceiveEndOfInterruptionNotification(category);
3942}
3943
3944String Internals::mediaSessionCurrentState(MediaSession* session) const
3945{
3946 switch (session->currentState()) {
3947 case MediaSession::State::Active:
3948 return "active";
3949 case MediaSession::State::Interrupted:
3950 return "interrupted";
3951 case MediaSession::State::Idle:
3952 return "idle";
3953 }
3954}
3955
3956double Internals::mediaElementPlayerVolume(HTMLMediaElement* element) const
3957{
3958 ASSERT_ARG(element, element);
3959 return element->playerVolume();
3960}
3961
3962void Internals::sendMediaControlEvent(MediaControlEvent event)
3963{
3964 // FIXME: No good reason to use a single function with an argument instead of three functions.
3965 switch (event) {
3966 case MediControlEvent::PlayPause:
3967 MediaSessionManager::singleton().togglePlayback();
3968 break;
3969 case MediControlEvent::NextTrack:
3970 MediaSessionManager::singleton().skipToNextTrack();
3971 break;
3972 case MediControlEvent::PreviousTrack:
3973 MediaSessionManager::singleton().skipToPreviousTrack();
3974 break;
3975 }
3976}
3977
3978#endif // ENABLE(MEDIA_SESSION)
3979
3980#if ENABLE(WEB_AUDIO)
3981
3982void Internals::setAudioContextRestrictions(AudioContext& context, StringView restrictionsString)
3983{
3984 AudioContext::BehaviorRestrictions restrictions = context.behaviorRestrictions();
3985 context.removeBehaviorRestriction(restrictions);
3986
3987 restrictions = AudioContext::NoRestrictions;
3988
3989 for (StringView restrictionString : restrictionsString.split(',')) {
3990 if (equalLettersIgnoringASCIICase(restrictionString, "norestrictions"))
3991 restrictions |= AudioContext::NoRestrictions;
3992 if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforaudiostart"))
3993 restrictions |= AudioContext::RequireUserGestureForAudioStartRestriction;
3994 if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsentforaudiostart"))
3995 restrictions |= AudioContext::RequirePageConsentForAudioStartRestriction;
3996 }
3997 context.addBehaviorRestriction(restrictions);
3998}
3999
4000#endif
4001
4002void Internals::simulateSystemSleep() const
4003{
4004#if ENABLE(VIDEO)
4005 PlatformMediaSessionManager::sharedManager().systemWillSleep();
4006#endif
4007}
4008
4009void Internals::simulateSystemWake() const
4010{
4011#if ENABLE(VIDEO)
4012 PlatformMediaSessionManager::sharedManager().systemDidWake();
4013#endif
4014}
4015
4016ExceptionOr<Internals::NowPlayingState> Internals::nowPlayingState() const
4017{
4018#if ENABLE(VIDEO)
4019 return { { PlatformMediaSessionManager::sharedManager().lastUpdatedNowPlayingTitle(),
4020 PlatformMediaSessionManager::sharedManager().lastUpdatedNowPlayingDuration(),
4021 PlatformMediaSessionManager::sharedManager().lastUpdatedNowPlayingElapsedTime(),
4022 PlatformMediaSessionManager::sharedManager().lastUpdatedNowPlayingInfoUniqueIdentifier(),
4023 PlatformMediaSessionManager::sharedManager().hasActiveNowPlayingSession(),
4024 PlatformMediaSessionManager::sharedManager().registeredAsNowPlayingApplication()
4025 } };
4026#else
4027 return Exception { InvalidAccessError };
4028#endif
4029}
4030
4031#if ENABLE(VIDEO)
4032RefPtr<HTMLMediaElement> Internals::bestMediaElementForShowingPlaybackControlsManager(Internals::PlaybackControlsPurpose purpose)
4033{
4034 return HTMLMediaElement::bestMediaElementForShowingPlaybackControlsManager(purpose);
4035}
4036
4037Internals::MediaSessionState Internals::mediaSessionState(HTMLMediaElement& element)
4038{
4039 return element.mediaSession().state();
4040}
4041#endif
4042
4043#if ENABLE(WIRELESS_PLAYBACK_TARGET)
4044
4045void Internals::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
4046{
4047 Page* page = contextDocument()->frame()->page();
4048 ASSERT(page);
4049
4050 page->setMockMediaPlaybackTargetPickerEnabled(enabled);
4051}
4052
4053ExceptionOr<void> Internals::setMockMediaPlaybackTargetPickerState(const String& deviceName, const String& deviceState)
4054{
4055 Page* page = contextDocument()->frame()->page();
4056 ASSERT(page);
4057
4058 MediaPlaybackTargetContext::State state = MediaPlaybackTargetContext::Unknown;
4059
4060 if (equalLettersIgnoringASCIICase(deviceState, "deviceavailable"))
4061 state = MediaPlaybackTargetContext::OutputDeviceAvailable;
4062 else if (equalLettersIgnoringASCIICase(deviceState, "deviceunavailable"))
4063 state = MediaPlaybackTargetContext::OutputDeviceUnavailable;
4064 else if (equalLettersIgnoringASCIICase(deviceState, "unknown"))
4065 state = MediaPlaybackTargetContext::Unknown;
4066 else
4067 return Exception { InvalidAccessError };
4068
4069 page->setMockMediaPlaybackTargetPickerState(deviceName, state);
4070 return { };
4071}
4072
4073#endif
4074
4075ExceptionOr<Ref<MockPageOverlay>> Internals::installMockPageOverlay(PageOverlayType type)
4076{
4077 Document* document = contextDocument();
4078 if (!document || !document->page())
4079 return Exception { InvalidAccessError };
4080
4081 return MockPageOverlayClient::singleton().installOverlay(*document->page(), type == PageOverlayType::View ? PageOverlay::OverlayType::View : PageOverlay::OverlayType::Document);
4082}
4083
4084ExceptionOr<String> Internals::pageOverlayLayerTreeAsText(unsigned short flags) const
4085{
4086 Document* document = contextDocument();
4087 if (!document || !document->page())
4088 return Exception { InvalidAccessError };
4089
4090 document->updateLayoutIgnorePendingStylesheets();
4091
4092 return MockPageOverlayClient::singleton().layerTreeAsText(*document->page(), toLayerTreeFlags(flags));
4093}
4094
4095void Internals::setPageMuted(StringView statesString)
4096{
4097 Document* document = contextDocument();
4098 if (!document)
4099 return;
4100
4101 WebCore::MediaProducer::MutedStateFlags state = MediaProducer::NoneMuted;
4102 for (StringView stateString : statesString.split(',')) {
4103 if (equalLettersIgnoringASCIICase(stateString, "audio"))
4104 state |= MediaProducer::AudioIsMuted;
4105 if (equalLettersIgnoringASCIICase(stateString, "capturedevices"))
4106 state |= MediaProducer::AudioAndVideoCaptureIsMuted;
4107 if (equalLettersIgnoringASCIICase(stateString, "screencapture"))
4108 state |= MediaProducer::ScreenCaptureIsMuted;
4109 }
4110
4111 if (Page* page = document->page())
4112 page->setMuted(state);
4113}
4114
4115String Internals::pageMediaState()
4116{
4117 Document* document = contextDocument();
4118 if (!document || !document->page())
4119 return emptyString();
4120
4121 WebCore::MediaProducer::MediaStateFlags state = document->page()->mediaState();
4122 StringBuilder string;
4123 if (state & MediaProducer::IsPlayingAudio)
4124 string.append("IsPlayingAudio,");
4125 if (state & MediaProducer::IsPlayingVideo)
4126 string.append("IsPlayingVideo,");
4127 if (state & MediaProducer::IsPlayingToExternalDevice)
4128 string.append("IsPlayingToExternalDevice,");
4129 if (state & MediaProducer::RequiresPlaybackTargetMonitoring)
4130 string.append("RequiresPlaybackTargetMonitoring,");
4131 if (state & MediaProducer::ExternalDeviceAutoPlayCandidate)
4132 string.append("ExternalDeviceAutoPlayCandidate,");
4133 if (state & MediaProducer::DidPlayToEnd)
4134 string.append("DidPlayToEnd,");
4135 if (state & MediaProducer::IsSourceElementPlaying)
4136 string.append("IsSourceElementPlaying,");
4137
4138 if (state & MediaProducer::IsNextTrackControlEnabled)
4139 string.append("IsNextTrackControlEnabled,");
4140 if (state & MediaProducer::IsPreviousTrackControlEnabled)
4141 string.append("IsPreviousTrackControlEnabled,");
4142
4143 if (state & MediaProducer::HasPlaybackTargetAvailabilityListener)
4144 string.append("HasPlaybackTargetAvailabilityListener,");
4145 if (state & MediaProducer::HasAudioOrVideo)
4146 string.append("HasAudioOrVideo,");
4147 if (state & MediaProducer::HasActiveAudioCaptureDevice)
4148 string.append("HasActiveAudioCaptureDevice,");
4149 if (state & MediaProducer::HasActiveVideoCaptureDevice)
4150 string.append("HasActiveVideoCaptureDevice,");
4151 if (state & MediaProducer::HasMutedAudioCaptureDevice)
4152 string.append("HasMutedAudioCaptureDevice,");
4153 if (state & MediaProducer::HasMutedVideoCaptureDevice)
4154 string.append("HasMutedVideoCaptureDevice,");
4155 if (state & MediaProducer::HasUserInteractedWithMediaElement)
4156 string.append("HasUserInteractedWithMediaElement,");
4157 if (state & MediaProducer::HasActiveDisplayCaptureDevice)
4158 string.append("HasActiveDisplayCaptureDevice,");
4159 if (state & MediaProducer::HasMutedDisplayCaptureDevice)
4160 string.append("HasMutedDisplayCaptureDevice,");
4161
4162 if (string.isEmpty())
4163 string.append("IsNotPlaying");
4164 else
4165 string.resize(string.length() - 1);
4166
4167 return string.toString();
4168}
4169
4170void Internals::setPageDefersLoading(bool defersLoading)
4171{
4172 Document* document = contextDocument();
4173 if (!document)
4174 return;
4175 if (Page* page = document->page())
4176 page->setDefersLoading(defersLoading);
4177}
4178
4179ExceptionOr<bool> Internals::pageDefersLoading()
4180{
4181 Document* document = contextDocument();
4182 if (!document || !document->page())
4183 return Exception { InvalidAccessError };
4184 return document->page()->defersLoading();
4185}
4186
4187RefPtr<File> Internals::createFile(const String& path)
4188{
4189 Document* document = contextDocument();
4190 if (!document)
4191 return nullptr;
4192
4193 URL url = document->completeURL(path);
4194 if (!url.isLocalFile())
4195 return nullptr;
4196
4197 return File::create(url.fileSystemPath());
4198}
4199
4200void Internals::queueMicroTask(int testNumber)
4201{
4202 Document* document = contextDocument();
4203 if (!document)
4204 return;
4205
4206 auto microtask = std::make_unique<ActiveDOMCallbackMicrotask>(MicrotaskQueue::mainThreadQueue(), *document, [document, testNumber]() {
4207 document->addConsoleMessage(MessageSource::JS, MessageLevel::Debug, makeString("MicroTask #", testNumber, " has run."));
4208 });
4209
4210 MicrotaskQueue::mainThreadQueue().append(WTFMove(microtask));
4211}
4212
4213#if ENABLE(CONTENT_FILTERING)
4214
4215MockContentFilterSettings& Internals::mockContentFilterSettings()
4216{
4217 return MockContentFilterSettings::singleton();
4218}
4219
4220#endif
4221
4222#if ENABLE(CSS_SCROLL_SNAP)
4223
4224static void appendOffsets(StringBuilder& builder, const Vector<LayoutUnit>& snapOffsets)
4225{
4226 bool justStarting = true;
4227
4228 builder.appendLiteral("{ ");
4229 for (auto& coordinate : snapOffsets) {
4230 if (!justStarting)
4231 builder.appendLiteral(", ");
4232 else
4233 justStarting = false;
4234
4235 builder.appendNumber(coordinate.toUnsigned());
4236 }
4237 builder.appendLiteral(" }");
4238}
4239
4240void Internals::setPlatformMomentumScrollingPredictionEnabled(bool enabled)
4241{
4242 ScrollingMomentumCalculator::setPlatformMomentumScrollingPredictionEnabled(enabled);
4243}
4244
4245ExceptionOr<String> Internals::scrollSnapOffsets(Element& element)
4246{
4247 element.document().updateLayoutIgnorePendingStylesheets();
4248
4249 if (!element.renderBox())
4250 return String();
4251
4252 RenderBox& box = *element.renderBox();
4253 ScrollableArea* scrollableArea;
4254
4255 if (box.isBody()) {
4256 FrameView* frameView = box.frame().mainFrame().view();
4257 if (!frameView || !frameView->isScrollable())
4258 return Exception { InvalidAccessError };
4259 scrollableArea = frameView;
4260
4261 } else {
4262 if (!box.canBeScrolledAndHasScrollableArea())
4263 return Exception { InvalidAccessError };
4264 scrollableArea = box.layer();
4265 }
4266
4267 if (!scrollableArea)
4268 return String();
4269
4270 StringBuilder result;
4271
4272 if (auto* offsets = scrollableArea->horizontalSnapOffsets()) {
4273 if (offsets->size()) {
4274 result.appendLiteral("horizontal = ");
4275 appendOffsets(result, *offsets);
4276 }
4277 }
4278
4279 if (auto* offsets = scrollableArea->verticalSnapOffsets()) {
4280 if (offsets->size()) {
4281 if (result.length())
4282 result.appendLiteral(", ");
4283
4284 result.appendLiteral("vertical = ");
4285 appendOffsets(result, *offsets);
4286 }
4287 }
4288
4289 return result.toString();
4290}
4291
4292#endif
4293
4294bool Internals::testPreloaderSettingViewport()
4295{
4296 return testPreloadScannerViewportSupport(contextDocument());
4297}
4298
4299ExceptionOr<String> Internals::pathStringWithShrinkWrappedRects(const Vector<double>& rectComponents, double radius)
4300{
4301 if (rectComponents.size() % 4)
4302 return Exception { InvalidAccessError };
4303
4304 Vector<FloatRect> rects;
4305 for (unsigned i = 0; i < rectComponents.size(); i += 4)
4306 rects.append(FloatRect(rectComponents[i], rectComponents[i + 1], rectComponents[i + 2], rectComponents[i + 3]));
4307
4308 SVGPathStringBuilder builder;
4309 PathUtilities::pathWithShrinkWrappedRects(rects, radius).apply([&builder](const PathElement& element) {
4310 switch (element.type) {
4311 case PathElementMoveToPoint:
4312 builder.moveTo(element.points[0], false, AbsoluteCoordinates);
4313 return;
4314 case PathElementAddLineToPoint:
4315 builder.lineTo(element.points[0], AbsoluteCoordinates);
4316 return;
4317 case PathElementAddQuadCurveToPoint:
4318 builder.curveToQuadratic(element.points[0], element.points[1], AbsoluteCoordinates);
4319 return;
4320 case PathElementAddCurveToPoint:
4321 builder.curveToCubic(element.points[0], element.points[1], element.points[2], AbsoluteCoordinates);
4322 return;
4323 case PathElementCloseSubpath:
4324 builder.closePath();
4325 return;
4326 }
4327 ASSERT_NOT_REACHED();
4328 });
4329 return builder.result();
4330}
4331
4332
4333String Internals::getCurrentMediaControlsStatusForElement(HTMLMediaElement& mediaElement)
4334{
4335#if !ENABLE(MEDIA_CONTROLS_SCRIPT)
4336 UNUSED_PARAM(mediaElement);
4337 return String();
4338#else
4339 return mediaElement.getCurrentMediaControlsStatus();
4340#endif
4341}
4342
4343#if !PLATFORM(COCOA)
4344
4345String Internals::userVisibleString(const DOMURL& url)
4346{
4347 return WTF::URLHelpers::userVisibleURL(url.href().string().utf8());
4348}
4349
4350#endif
4351
4352void Internals::setShowAllPlugins(bool show)
4353{
4354 Document* document = contextDocument();
4355 if (!document)
4356 return;
4357
4358 Page* page = document->page();
4359 if (!page)
4360 return;
4361
4362 page->setShowAllPlugins(show);
4363}
4364
4365#if ENABLE(STREAMS_API)
4366
4367bool Internals::isReadableStreamDisturbed(JSC::ExecState& state, JSValue stream)
4368{
4369 return ReadableStream::isDisturbed(state, stream);
4370}
4371
4372JSValue Internals::cloneArrayBuffer(JSC::ExecState& state, JSValue buffer, JSValue srcByteOffset, JSValue srcLength)
4373{
4374 JSC::VM& vm = state.vm();
4375 JSGlobalObject* globalObject = vm.vmEntryGlobalObject(&state);
4376 JSVMClientData* clientData = static_cast<JSVMClientData*>(vm.clientData);
4377 const Identifier& privateName = clientData->builtinNames().cloneArrayBufferPrivateName();
4378 JSValue value;
4379 PropertySlot propertySlot(value, PropertySlot::InternalMethodType::Get);
4380 globalObject->methodTable(vm)->getOwnPropertySlot(globalObject, &state, privateName, propertySlot);
4381 value = propertySlot.getValue(&state, privateName);
4382 ASSERT(value.isFunction(vm));
4383
4384 JSObject* function = value.getObject();
4385 CallData callData;
4386 CallType callType = JSC::getCallData(vm, function, callData);
4387 ASSERT(callType != JSC::CallType::None);
4388 MarkedArgumentBuffer arguments;
4389 arguments.append(buffer);
4390 arguments.append(srcByteOffset);
4391 arguments.append(srcLength);
4392 ASSERT(!arguments.hasOverflowed());
4393
4394 return JSC::call(&state, function, callType, callData, JSC::jsUndefined(), arguments);
4395}
4396
4397#endif
4398
4399String Internals::resourceLoadStatisticsForURL(const DOMURL& url)
4400{
4401 return ResourceLoadObserver::shared().statisticsForURL(url.href());
4402}
4403
4404void Internals::setResourceLoadStatisticsEnabled(bool enable)
4405{
4406 DeprecatedGlobalSettings::setResourceLoadStatisticsEnabled(enable);
4407}
4408
4409String Internals::composedTreeAsText(Node& node)
4410{
4411 if (!is<ContainerNode>(node))
4412 return emptyString();
4413 return WebCore::composedTreeAsText(downcast<ContainerNode>(node));
4414}
4415
4416bool Internals::isProcessingUserGesture()
4417{
4418 return UserGestureIndicator::processingUserGesture();
4419}
4420
4421void Internals::withUserGesture(RefPtr<VoidCallback>&& callback)
4422{
4423 UserGestureIndicator gestureIndicator(ProcessingUserGesture, contextDocument());
4424 callback->handleEvent();
4425}
4426
4427bool Internals::userIsInteracting()
4428{
4429 if (auto* document = contextDocument()) {
4430 if (auto* page = document->page())
4431 return page->chrome().client().userIsInteracting();
4432 }
4433 return false;
4434}
4435
4436double Internals::lastHandledUserGestureTimestamp()
4437{
4438 Document* document = contextDocument();
4439 if (!document)
4440 return 0;
4441
4442 return document->lastHandledUserGestureTimestamp().secondsSinceEpoch().value();
4443}
4444
4445RefPtr<GCObservation> Internals::observeGC(JSC::JSValue value)
4446{
4447 if (!value.isObject())
4448 return nullptr;
4449 return GCObservation::create(asObject(value));
4450}
4451
4452void Internals::setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection)
4453{
4454 Document* document = contextDocument();
4455 if (!document)
4456 return;
4457
4458 Page* page = document->page();
4459 if (!page)
4460 return;
4461
4462 page->setUserInterfaceLayoutDirection(userInterfaceLayoutDirection == UserInterfaceLayoutDirection::LTR ? WebCore::UserInterfaceLayoutDirection::LTR : WebCore::UserInterfaceLayoutDirection::RTL);
4463}
4464
4465#if !PLATFORM(COCOA)
4466
4467bool Internals::userPrefersReducedMotion() const
4468{
4469 return false;
4470}
4471
4472#endif
4473
4474void Internals::reportBacktrace()
4475{
4476 WTFReportBacktrace();
4477}
4478
4479void Internals::setBaseWritingDirection(BaseWritingDirection direction)
4480{
4481 if (auto* document = contextDocument()) {
4482 if (auto* frame = document->frame()) {
4483 switch (direction) {
4484 case BaseWritingDirection::Ltr:
4485 frame->editor().setBaseWritingDirection(WritingDirection::LeftToRight);
4486 break;
4487 case BaseWritingDirection::Rtl:
4488 frame->editor().setBaseWritingDirection(WritingDirection::RightToLeft);
4489 break;
4490 case BaseWritingDirection::Natural:
4491 frame->editor().setBaseWritingDirection(WritingDirection::Natural);
4492 break;
4493 }
4494 }
4495 }
4496}
4497
4498#if ENABLE(POINTER_LOCK)
4499bool Internals::pageHasPendingPointerLock() const
4500{
4501 Document* document = contextDocument();
4502 if (!document)
4503 return false;
4504
4505 Page* page = document->page();
4506 if (!page)
4507 return false;
4508
4509 return page->pointerLockController().lockPending();
4510}
4511
4512bool Internals::pageHasPointerLock() const
4513{
4514 Document* document = contextDocument();
4515 if (!document)
4516 return false;
4517
4518 Page* page = document->page();
4519 if (!page)
4520 return false;
4521
4522 auto& controller = page->pointerLockController();
4523 return controller.element() && !controller.lockPending();
4524}
4525#endif
4526
4527void Internals::markContextAsInsecure()
4528{
4529 auto* document = contextDocument();
4530 if (!document)
4531 return;
4532
4533 document->securityOrigin().setIsPotentiallyTrustworthy(false);
4534}
4535
4536void Internals::postTask(RefPtr<VoidCallback>&& callback)
4537{
4538 auto* document = contextDocument();
4539 if (!document) {
4540 callback->handleEvent();
4541 return;
4542 }
4543
4544 document->postTask([callback = WTFMove(callback)](ScriptExecutionContext&) {
4545 callback->handleEvent();
4546 });
4547}
4548
4549Vector<String> Internals::accessKeyModifiers() const
4550{
4551 Vector<String> accessKeyModifierStrings;
4552
4553 for (auto modifier : EventHandler::accessKeyModifiers()) {
4554 switch (modifier) {
4555 case PlatformEvent::Modifier::AltKey:
4556 accessKeyModifierStrings.append("altKey"_s);
4557 break;
4558 case PlatformEvent::Modifier::ControlKey:
4559 accessKeyModifierStrings.append("ctrlKey"_s);
4560 break;
4561 case PlatformEvent::Modifier::MetaKey:
4562 accessKeyModifierStrings.append("metaKey"_s);
4563 break;
4564 case PlatformEvent::Modifier::ShiftKey:
4565 accessKeyModifierStrings.append("shiftKey"_s);
4566 break;
4567 case PlatformEvent::Modifier::CapsLockKey:
4568 accessKeyModifierStrings.append("capsLockKey"_s);
4569 break;
4570 case PlatformEvent::Modifier::AltGraphKey:
4571 ASSERT_NOT_REACHED(); // AltGraph is only for DOM API.
4572 break;
4573 }
4574 }
4575
4576 return accessKeyModifierStrings;
4577}
4578
4579void Internals::setQuickLookPassword(const String& password)
4580{
4581#if PLATFORM(IOS_FAMILY) && USE(QUICK_LOOK)
4582 auto& quickLookHandleClient = MockPreviewLoaderClient::singleton();
4583 PreviewLoader::setClientForTesting(&quickLookHandleClient);
4584 quickLookHandleClient.setPassword(password);
4585#else
4586 UNUSED_PARAM(password);
4587#endif
4588}
4589
4590void Internals::setAsRunningUserScripts(Document& document)
4591{
4592 document.setAsRunningUserScripts();
4593}
4594
4595#if ENABLE(APPLE_PAY)
4596void Internals::setHasStartedApplePaySession(Document& document)
4597{
4598 document.setHasStartedApplePaySession();
4599}
4600#endif
4601
4602#if ENABLE(WEBGL)
4603void Internals::simulateWebGLContextChanged(WebGLRenderingContext& context)
4604{
4605 context.simulateContextChanged();
4606}
4607
4608void Internals::failNextGPUStatusCheck(WebGLRenderingContext& context)
4609{
4610 context.setFailNextGPUStatusCheck();
4611}
4612
4613bool Internals::hasLowAndHighPowerGPUs()
4614{
4615#if PLATFORM(MAC)
4616 return WebCore::hasLowAndHighPowerGPUs();
4617#else
4618 return false;
4619#endif
4620}
4621#endif
4622
4623void Internals::setPageVisibility(bool isVisible)
4624{
4625 auto* document = contextDocument();
4626 if (!document || !document->page())
4627 return;
4628 auto& page = *document->page();
4629 auto state = page.activityState();
4630
4631 if (!isVisible)
4632 state.remove(ActivityState::IsVisible);
4633 else
4634 state.add(ActivityState::IsVisible);
4635
4636 page.setActivityState(state);
4637}
4638
4639void Internals::setPageIsFocusedAndActive(bool isFocusedAndActive)
4640{
4641 auto* document = contextDocument();
4642 if (!document || !document->page())
4643 return;
4644 auto& page = *document->page();
4645 auto state = page.activityState();
4646
4647 if (!isFocusedAndActive)
4648 state.remove({ ActivityState::IsFocused, ActivityState::WindowIsActive });
4649 else
4650 state.add({ ActivityState::IsFocused, ActivityState::WindowIsActive });
4651
4652 page.setActivityState(state);
4653}
4654
4655#if ENABLE(WEB_RTC)
4656void Internals::setH264HardwareEncoderAllowed(bool allowed)
4657{
4658 auto* document = contextDocument();
4659 if (!document || !document->page())
4660 return;
4661 document->page()->libWebRTCProvider().setH264HardwareEncoderAllowed(allowed);
4662}
4663#endif
4664
4665#if ENABLE(MEDIA_STREAM)
4666
4667void Internals::setCameraMediaStreamTrackOrientation(MediaStreamTrack& track, int orientation)
4668{
4669 auto& source = track.source();
4670 if (!source.isCaptureSource())
4671 return;
4672 m_orientationNotifier.orientationChanged(orientation);
4673 source.monitorOrientation(m_orientationNotifier);
4674}
4675
4676void Internals::observeMediaStreamTrack(MediaStreamTrack& track)
4677{
4678 m_track = &track;
4679 m_track->source().addObserver(*this);
4680}
4681
4682void Internals::grabNextMediaStreamTrackFrame(TrackFramePromise&& promise)
4683{
4684 m_nextTrackFramePromise = WTFMove(promise);
4685}
4686
4687void Internals::videoSampleAvailable(MediaSample& sample)
4688{
4689 m_trackVideoSampleCount++;
4690 if (!m_nextTrackFramePromise)
4691 return;
4692
4693 auto& videoSettings = m_track->source().settings();
4694 if (!videoSettings.width() || !videoSettings.height())
4695 return;
4696
4697 auto rgba = sample.getRGBAImageData();
4698 if (!rgba)
4699 return;
4700
4701 auto imageData = ImageData::create(rgba.releaseNonNull(), videoSettings.width(), videoSettings.height());
4702 if (!imageData.hasException())
4703 m_nextTrackFramePromise->resolve(imageData.releaseReturnValue().releaseNonNull());
4704 else
4705 m_nextTrackFramePromise->reject(imageData.exception().code());
4706 m_nextTrackFramePromise = WTF::nullopt;
4707}
4708
4709void Internals::delayMediaStreamTrackSamples(MediaStreamTrack& track, float delay)
4710{
4711 track.source().delaySamples(Seconds { delay });
4712}
4713
4714void Internals::setMediaStreamTrackMuted(MediaStreamTrack& track, bool muted)
4715{
4716 track.source().setMuted(muted);
4717}
4718
4719void Internals::removeMediaStreamTrack(MediaStream& stream, MediaStreamTrack& track)
4720{
4721 stream.internalRemoveTrack(track.id(), MediaStream::StreamModifier::Platform);
4722}
4723
4724void Internals::simulateMediaStreamTrackCaptureSourceFailure(MediaStreamTrack& track)
4725{
4726 track.source().captureFailed();
4727}
4728
4729void Internals::setMediaStreamTrackIdentifier(MediaStreamTrack& track, String&& id)
4730{
4731 track.setIdForTesting(WTFMove(id));
4732}
4733
4734void Internals::setMediaStreamSourceInterrupted(MediaStreamTrack& track, bool interrupted)
4735{
4736 track.source().setInterruptedForTesting(interrupted);
4737}
4738
4739void Internals::setDisableGetDisplayMediaUserGestureConstraint(bool value)
4740{
4741 Document* document = contextDocument();
4742 if (!document || !document->domWindow())
4743 return;
4744
4745 if (auto* mediaDevices = NavigatorMediaDevices::mediaDevices(document->domWindow()->navigator()))
4746 mediaDevices->setDisableGetDisplayMediaUserGestureConstraint(value);
4747}
4748#endif
4749
4750String Internals::audioSessionCategory() const
4751{
4752#if USE(AUDIO_SESSION)
4753 switch (AudioSession::sharedSession().category()) {
4754 case AudioSession::AmbientSound:
4755 return "AmbientSound"_s;
4756 case AudioSession::SoloAmbientSound:
4757 return "SoloAmbientSound"_s;
4758 case AudioSession::MediaPlayback:
4759 return "MediaPlayback"_s;
4760 case AudioSession::RecordAudio:
4761 return "RecordAudio"_s;
4762 case AudioSession::PlayAndRecord:
4763 return "PlayAndRecord"_s;
4764 case AudioSession::AudioProcessing:
4765 return "AudioProcessing"_s;
4766 case AudioSession::None:
4767 return "None"_s;
4768 }
4769#endif
4770 return emptyString();
4771}
4772
4773double Internals::preferredAudioBufferSize() const
4774{
4775#if USE(AUDIO_SESSION)
4776 return AudioSession::sharedSession().preferredBufferSize();
4777#endif
4778 return 0;
4779}
4780
4781bool Internals::audioSessionActive() const
4782{
4783#if USE(AUDIO_SESSION)
4784 return AudioSession::sharedSession().isActive();
4785#endif
4786 return false;
4787}
4788
4789void Internals::clearCacheStorageMemoryRepresentation(DOMPromiseDeferred<void>&& promise)
4790{
4791 auto* document = contextDocument();
4792 if (!document)
4793 return;
4794
4795 if (!m_cacheStorageConnection) {
4796 if (auto* page = contextDocument()->page())
4797 m_cacheStorageConnection = page->cacheStorageProvider().createCacheStorageConnection(page->sessionID());
4798 if (!m_cacheStorageConnection)
4799 return;
4800 }
4801 m_cacheStorageConnection->clearMemoryRepresentation(ClientOrigin { document->topOrigin().data(), document->securityOrigin().data() }, [promise = WTFMove(promise)] (auto && result) mutable {
4802 ASSERT_UNUSED(result, !result);
4803 promise.resolve();
4804 });
4805}
4806
4807void Internals::cacheStorageEngineRepresentation(DOMPromiseDeferred<IDLDOMString>&& promise)
4808{
4809 auto* document = contextDocument();
4810 if (!document)
4811 return;
4812
4813 if (!m_cacheStorageConnection) {
4814 if (auto* page = contextDocument()->page())
4815 m_cacheStorageConnection = page->cacheStorageProvider().createCacheStorageConnection(page->sessionID());
4816 if (!m_cacheStorageConnection)
4817 return;
4818 }
4819 m_cacheStorageConnection->engineRepresentation([promise = WTFMove(promise)](const String& result) mutable {
4820 promise.resolve(result);
4821 });
4822}
4823
4824void Internals::updateQuotaBasedOnSpaceUsage()
4825{
4826 auto* document = contextDocument();
4827 if (!document)
4828 return;
4829
4830 if (!m_cacheStorageConnection) {
4831 if (auto* page = contextDocument()->page())
4832 m_cacheStorageConnection = page->cacheStorageProvider().createCacheStorageConnection(page->sessionID());
4833 if (!m_cacheStorageConnection)
4834 return;
4835 }
4836
4837 m_cacheStorageConnection->updateQuotaBasedOnSpaceUsage(ClientOrigin { document->topOrigin().data(), document->securityOrigin().data() });
4838}
4839
4840void Internals::setConsoleMessageListener(RefPtr<StringCallback>&& listener)
4841{
4842 if (!contextDocument())
4843 return;
4844
4845 contextDocument()->setConsoleMessageListener(WTFMove(listener));
4846}
4847
4848void Internals::setResponseSizeWithPadding(FetchResponse& response, uint64_t size)
4849{
4850 response.setBodySizeWithPadding(size);
4851}
4852
4853uint64_t Internals::responseSizeWithPadding(FetchResponse& response) const
4854{
4855 return response.bodySizeWithPadding();
4856}
4857
4858#if ENABLE(SERVICE_WORKER)
4859void Internals::hasServiceWorkerRegistration(const String& clientURL, HasRegistrationPromise&& promise)
4860{
4861 if (!contextDocument())
4862 return;
4863
4864 URL parsedURL = contextDocument()->completeURL(clientURL);
4865
4866 return ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(contextDocument()->sessionID()).matchRegistration(SecurityOriginData { contextDocument()->topOrigin().data() }, parsedURL, [promise = WTFMove(promise)] (auto&& result) mutable {
4867 promise.resolve(!!result);
4868 });
4869}
4870
4871void Internals::terminateServiceWorker(ServiceWorker& worker)
4872{
4873 if (!contextDocument())
4874 return;
4875
4876 ServiceWorkerProvider::singleton().serviceWorkerConnectionForSession(contextDocument()->sessionID()).syncTerminateWorker(worker.identifier());
4877}
4878
4879bool Internals::hasServiceWorkerConnection()
4880{
4881 if (!contextDocument())
4882 return false;
4883
4884 return ServiceWorkerProvider::singleton().existingServiceWorkerConnectionForSession(contextDocument()->sessionID());
4885}
4886#endif
4887
4888#if ENABLE(APPLE_PAY)
4889MockPaymentCoordinator& Internals::mockPaymentCoordinator(Document& document)
4890{
4891 return downcast<MockPaymentCoordinator>(document.frame()->page()->paymentCoordinator().client());
4892}
4893#endif
4894
4895bool Internals::isSystemPreviewLink(Element& element) const
4896{
4897#if USE(SYSTEM_PREVIEW)
4898 return is<HTMLAnchorElement>(element) && downcast<HTMLAnchorElement>(element).isSystemPreviewLink();
4899#else
4900 UNUSED_PARAM(element);
4901 return false;
4902#endif
4903}
4904
4905bool Internals::isSystemPreviewImage(Element& element) const
4906{
4907#if USE(SYSTEM_PREVIEW)
4908 if (is<HTMLImageElement>(element))
4909 return downcast<HTMLImageElement>(element).isSystemPreviewImage();
4910 if (is<HTMLPictureElement>(element))
4911 return downcast<HTMLPictureElement>(element).isSystemPreviewImage();
4912 return false;
4913#else
4914 UNUSED_PARAM(element);
4915 return false;
4916#endif
4917}
4918
4919bool Internals::usingAppleInternalSDK() const
4920{
4921#if USE(APPLE_INTERNAL_SDK)
4922 return true;
4923#else
4924 return false;
4925#endif
4926}
4927
4928void Internals::setCaptureExtraNetworkLoadMetricsEnabled(bool value)
4929{
4930 platformStrategies()->loaderStrategy()->setCaptureExtraNetworkLoadMetricsEnabled(value);
4931}
4932
4933String Internals::ongoingLoadsDescriptions() const
4934{
4935 StringBuilder builder;
4936 builder.append('[');
4937 bool isStarting = true;
4938 for (auto& identifier : platformStrategies()->loaderStrategy()->ongoingLoads()) {
4939 if (isStarting)
4940 isStarting = false;
4941 else
4942 builder.append(',');
4943
4944 builder.append('[');
4945
4946 for (auto& info : platformStrategies()->loaderStrategy()->intermediateLoadInformationFromResourceLoadIdentifier(identifier))
4947 builder.append(makeString("[", (int)info.type, ",\"", info.request.url().string(), "\",\"", info.request.httpMethod(), "\",", info.response.httpStatusCode(), "]"));
4948
4949 builder.append(']');
4950 }
4951 builder.append(']');
4952 return builder.toString();
4953}
4954
4955void Internals::reloadWithoutContentExtensions()
4956{
4957 if (auto* frame = this->frame())
4958 frame->loader().reload(ReloadOption::DisableContentBlockers);
4959}
4960
4961void Internals::setUseSystemAppearance(bool value)
4962{
4963 if (!contextDocument() || !contextDocument()->page())
4964 return;
4965 contextDocument()->page()->setUseSystemAppearance(value);
4966}
4967
4968size_t Internals::pluginCount()
4969{
4970 if (!contextDocument() || !contextDocument()->page())
4971 return 0;
4972
4973 return contextDocument()->page()->pluginData().webVisiblePlugins().size();
4974}
4975
4976void Internals::notifyResourceLoadObserver()
4977{
4978 ResourceLoadObserver::shared().updateCentralStatisticsStore();
4979}
4980
4981unsigned Internals::primaryScreenDisplayID()
4982{
4983#if PLATFORM(MAC)
4984 return WebCore::primaryScreenDisplayID();
4985#else
4986 return 0;
4987#endif
4988}
4989
4990bool Internals::capsLockIsOn()
4991{
4992 return WebCore::PlatformKeyboardEvent::currentCapsLockState();
4993}
4994
4995bool Internals::supportsVCPEncoder()
4996{
4997#if defined(ENABLE_VCP_ENCODER)
4998 return ENABLE_VCP_ENCODER || ENABLE_VCP_VTB_ENCODER;
4999#else
5000 return false;
5001#endif
5002}
5003
5004Optional<HEVCParameterSet> Internals::parseHEVCCodecParameters(const String& codecString)
5005{
5006 return WebCore::parseHEVCCodecParameters(codecString);
5007}
5008
5009auto Internals::getCookies() const -> Vector<CookieData>
5010{
5011 auto* document = contextDocument();
5012 if (!document)
5013 return { };
5014
5015 auto* page = document->page();
5016 if (!page)
5017 return { };
5018
5019 Vector<Cookie> cookies;
5020 page->cookieJar().getRawCookies(*document, document->cookieURL(), cookies);
5021 return WTF::map(cookies, [](auto& cookie) {
5022 return CookieData { cookie };
5023 });
5024}
5025
5026void Internals::setAlwaysAllowLocalWebarchive(bool alwaysAllowLocalWebarchive)
5027{
5028 auto* localFrame = frame();
5029 if (!localFrame)
5030 return;
5031 localFrame->loader().setAlwaysAllowLocalWebarchive(alwaysAllowLocalWebarchive);
5032}
5033
5034void Internals::processWillSuspend()
5035{
5036 PlatformMediaSessionManager::sharedManager().processWillSuspend();
5037}
5038
5039void Internals::processDidResume()
5040{
5041 PlatformMediaSessionManager::sharedManager().processDidResume();
5042}
5043
5044void Internals::testDictionaryLogging()
5045{
5046 auto* document = contextDocument();
5047 if (!document)
5048 return;
5049
5050 auto* page = document->page();
5051 if (!page)
5052 return;
5053
5054 DiagnosticLoggingClient::ValueDictionary dictionary;
5055 dictionary.set("stringKey"_s, String("stringValue"));
5056 dictionary.set("uint64Key"_s, std::numeric_limits<uint64_t>::max());
5057 dictionary.set("int64Key"_s, std::numeric_limits<int64_t>::min());
5058 dictionary.set("boolKey"_s, true);
5059 dictionary.set("doubleKey"_s, 2.7182818284590452353602874);
5060
5061 page->diagnosticLoggingClient().logDiagnosticMessageWithValueDictionary("testMessage"_s, "testDescription"_s, dictionary, ShouldSample::No);
5062}
5063
5064void Internals::setXHRMaximumIntervalForUserGestureForwarding(XMLHttpRequest& request, double interval)
5065{
5066 request.setMaximumIntervalForUserGestureForwarding(interval);
5067}
5068
5069} // namespace WebCore
5070