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