Exit pointer lock when page goes into page cache.
[WebKit-https.git] / Source / WebCore / testing / Internals.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  * Copyright (C) 2013-2016 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 "AnimationController.h"
33 #include "ApplicationCacheStorage.h"
34 #include "Autofill.h"
35 #include "BackForwardController.h"
36 #include "BitmapImage.h"
37 #include "CachedImage.h"
38 #include "CachedResourceLoader.h"
39 #include "Chrome.h"
40 #include "ChromeClient.h"
41 #include "ClientRect.h"
42 #include "ClientRectList.h"
43 #include "ComposedTreeIterator.h"
44 #include "Cursor.h"
45 #include "DOMPath.h"
46 #include "DOMStringList.h"
47 #include "DOMWindow.h"
48 #include "DisplayList.h"
49 #include "Document.h"
50 #include "DocumentMarker.h"
51 #include "DocumentMarkerController.h"
52 #include "Editor.h"
53 #include "Element.h"
54 #include "EventHandler.h"
55 #include "ExceptionCode.h"
56 #include "ExtensionStyleSheets.h"
57 #include "File.h"
58 #include "FontCache.h"
59 #include "FormController.h"
60 #include "FrameLoader.h"
61 #include "FrameView.h"
62 #include "GCObservation.h"
63 #include "HTMLCanvasElement.h"
64 #include "HTMLIFrameElement.h"
65 #include "HTMLImageElement.h"
66 #include "HTMLInputElement.h"
67 #include "HTMLLinkElement.h"
68 #include "HTMLNames.h"
69 #include "HTMLPlugInElement.h"
70 #include "HTMLPreloadScanner.h"
71 #include "HTMLSelectElement.h"
72 #include "HTMLTextAreaElement.h"
73 #include "HTMLVideoElement.h"
74 #include "HistoryController.h"
75 #include "HistoryItem.h"
76 #include "HitTestResult.h"
77 #include "IconController.h"
78 #include "InspectorClient.h"
79 #include "InspectorController.h"
80 #include "InspectorFrontendClientLocal.h"
81 #include "InspectorOverlay.h"
82 #include "InstrumentingAgents.h"
83 #include "IntRect.h"
84 #include "InternalSettings.h"
85 #include "Language.h"
86 #include "MainFrame.h"
87 #include "MallocStatistics.h"
88 #include "MediaPlayer.h"
89 #include "MediaProducer.h"
90 #include "MemoryCache.h"
91 #include "MemoryInfo.h"
92 #include "MemoryPressureHandler.h"
93 #include "MockPageOverlay.h"
94 #include "MockPageOverlayClient.h"
95 #include "Page.h"
96 #include "PageCache.h"
97 #include "PageOverlay.h"
98 #include "PathUtilities.h"
99 #include "PlatformMediaSessionManager.h"
100 #include "PrintContext.h"
101 #include "PseudoElement.h"
102 #include "Range.h"
103 #include "RenderEmbeddedObject.h"
104 #include "RenderLayerBacking.h"
105 #include "RenderLayerCompositor.h"
106 #include "RenderMenuList.h"
107 #include "RenderTreeAsText.h"
108 #include "RenderView.h"
109 #include "RenderedDocumentMarker.h"
110 #include "ResourceLoadObserver.h"
111 #include "RuntimeEnabledFeatures.h"
112 #include "SVGPathStringBuilder.h"
113 #include "SchemeRegistry.h"
114 #include "ScriptedAnimationController.h"
115 #include "ScrollingCoordinator.h"
116 #include "SerializedScriptValue.h"
117 #include "Settings.h"
118 #include "ShadowRoot.h"
119 #include "SourceBuffer.h"
120 #include "SpellChecker.h"
121 #include "StaticNodeList.h"
122 #include "StyleScope.h"
123 #include "StyleSheetContents.h"
124 #include "TextIterator.h"
125 #include "TreeScope.h"
126 #include "TypeConversions.h"
127 #include "UserGestureIndicator.h"
128 #include "UserMediaController.h"
129 #include "ViewportArguments.h"
130 #include "WebCoreJSClientData.h"
131 #include "WorkerThread.h"
132 #include "XMLHttpRequest.h"
133 #include <bytecode/CodeBlock.h>
134 #include <inspector/InspectorAgentBase.h>
135 #include <inspector/InspectorFrontendChannel.h>
136 #include <inspector/InspectorValues.h>
137 #include <runtime/JSCInlines.h>
138 #include <runtime/JSCJSValue.h>
139 #include <wtf/text/CString.h>
140 #include <wtf/text/StringBuffer.h>
141 #include <wtf/text/StringBuilder.h>
142
143 #if ENABLE(INPUT_TYPE_COLOR)
144 #include "ColorChooser.h"
145 #endif
146
147 #if ENABLE(PROXIMITY_EVENTS)
148 #include "DeviceProximityController.h"
149 #endif
150
151 #if ENABLE(MOUSE_CURSOR_SCALE)
152 #include <wtf/dtoa.h>
153 #endif
154
155 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
156 #include "CDM.h"
157 #include "MockCDM.h"
158 #endif
159
160 #if ENABLE(VIDEO_TRACK)
161 #include "CaptionUserPreferences.h"
162 #include "PageGroup.h"
163 #endif
164
165 #if ENABLE(VIDEO)
166 #include "HTMLMediaElement.h"
167 #include "TimeRanges.h"
168 #endif
169
170 #if ENABLE(SPEECH_SYNTHESIS)
171 #include "DOMWindowSpeechSynthesis.h"
172 #include "PlatformSpeechSynthesizerMock.h"
173 #include "SpeechSynthesis.h"
174 #endif
175
176 #if ENABLE(VIBRATION)
177 #include "Vibration.h"
178 #endif
179
180 #if ENABLE(MEDIA_STREAM)
181 #include "MockRealtimeMediaSourceCenter.h"
182 #endif
183
184 #if ENABLE(WEB_RTC)
185 #include "MockMediaEndpoint.h"
186 #include "RTCPeerConnection.h"
187 #include "RTCPeerConnectionHandlerMock.h"
188 #endif
189
190 #if ENABLE(MEDIA_SOURCE)
191 #include "MockMediaPlayerMediaSource.h"
192 #endif
193
194 #if PLATFORM(MAC)
195 #include "DictionaryLookup.h"
196 #endif
197
198 #if ENABLE(CONTENT_FILTERING)
199 #include "MockContentFilterSettings.h"
200 #endif
201
202 #if ENABLE(WEB_AUDIO)
203 #include "AudioContext.h"
204 #endif
205
206 #if ENABLE(MEDIA_SESSION)
207 #include "MediaSession.h"
208 #include "MediaSessionManager.h"
209 #endif
210
211 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
212 #include "MediaPlaybackTargetContext.h"
213 #endif
214
215 #if ENABLE(POINTER_LOCK)
216 #include "PointerLockController.h"
217 #endif
218
219 using JSC::CallData;
220 using JSC::CallType;
221 using JSC::CodeBlock;
222 using JSC::FunctionExecutable;
223 using JSC::Identifier;
224 using JSC::JSFunction;
225 using JSC::JSGlobalObject;
226 using JSC::JSObject;
227 using JSC::JSValue;
228 using JSC::MarkedArgumentBuffer;
229 using JSC::PropertySlot;
230 using JSC::ScriptExecutable;
231 using JSC::StackVisitor;
232
233 using namespace Inspector;
234
235 namespace WebCore {
236
237 using namespace HTMLNames;
238
239 class InspectorStubFrontend final : public InspectorFrontendClientLocal, public FrontendChannel {
240 public:
241     InspectorStubFrontend(Page& inspectedPage, RefPtr<DOMWindow>&& frontendWindow);
242     virtual ~InspectorStubFrontend();
243
244 private:
245     void attachWindow(DockSide) final { }
246     void detachWindow() final { }
247     void closeWindow() final;
248     void bringToFront() final { }
249     String localizedStringsURL() final { return String(); }
250     void inspectedURLChanged(const String&) final { }
251     void setAttachedWindowHeight(unsigned) final { }
252     void setAttachedWindowWidth(unsigned) final { }
253
254     void sendMessageToFrontend(const String& message) final;
255     ConnectionType connectionType() const final { return ConnectionType::Local; }
256
257     Page* frontendPage() const
258     {
259         if (!m_frontendWindow || !m_frontendWindow->document())
260             return nullptr;
261
262         return m_frontendWindow->document()->page();
263     }
264
265     RefPtr<DOMWindow> m_frontendWindow;
266     InspectorController& m_frontendController;
267 };
268
269 InspectorStubFrontend::InspectorStubFrontend(Page& inspectedPage, RefPtr<DOMWindow>&& frontendWindow)
270     : InspectorFrontendClientLocal(&inspectedPage.inspectorController(), frontendWindow->document()->page(), std::make_unique<InspectorFrontendClientLocal::Settings>())
271     , m_frontendWindow(frontendWindow.copyRef())
272     , m_frontendController(frontendPage()->inspectorController())
273 {
274     ASSERT_ARG(frontendWindow, frontendWindow);
275
276     m_frontendController.setInspectorFrontendClient(this);
277     inspectedPage.inspectorController().connectFrontend(this);
278 }
279
280 InspectorStubFrontend::~InspectorStubFrontend()
281 {
282     closeWindow();
283 }
284
285 void InspectorStubFrontend::closeWindow()
286 {
287     if (!m_frontendWindow)
288         return;
289
290     m_frontendController.setInspectorFrontendClient(nullptr);
291     inspectedPage()->inspectorController().disconnectFrontend(this);
292
293     m_frontendWindow->close();
294     m_frontendWindow = nullptr;
295 }
296
297 void InspectorStubFrontend::sendMessageToFrontend(const String& message)
298 {
299     ASSERT_ARG(message, !message.isEmpty());
300
301     InspectorClient::doDispatchMessageOnFrontendPage(frontendPage(), message);
302 }
303
304 static bool markerTypeFrom(const String& markerType, DocumentMarker::MarkerType& result)
305 {
306     if (equalLettersIgnoringASCIICase(markerType, "spelling"))
307         result = DocumentMarker::Spelling;
308     else if (equalLettersIgnoringASCIICase(markerType, "grammar"))
309         result = DocumentMarker::Grammar;
310     else if (equalLettersIgnoringASCIICase(markerType, "textmatch"))
311         result = DocumentMarker::TextMatch;
312     else if (equalLettersIgnoringASCIICase(markerType, "replacement"))
313         result = DocumentMarker::Replacement;
314     else if (equalLettersIgnoringASCIICase(markerType, "correctionindicator"))
315         result = DocumentMarker::CorrectionIndicator;
316     else if (equalLettersIgnoringASCIICase(markerType, "rejectedcorrection"))
317         result = DocumentMarker::RejectedCorrection;
318     else if (equalLettersIgnoringASCIICase(markerType, "autocorrected"))
319         result = DocumentMarker::Autocorrected;
320     else if (equalLettersIgnoringASCIICase(markerType, "spellcheckingexemption"))
321         result = DocumentMarker::SpellCheckingExemption;
322     else if (equalLettersIgnoringASCIICase(markerType, "deletedautocorrection"))
323         result = DocumentMarker::DeletedAutocorrection;
324     else if (equalLettersIgnoringASCIICase(markerType, "dictationalternatives"))
325         result = DocumentMarker::DictationAlternatives;
326 #if ENABLE(TELEPHONE_NUMBER_DETECTION)
327     else if (equalLettersIgnoringASCIICase(markerType, "telephonenumber"))
328         result = DocumentMarker::TelephoneNumber;
329 #endif
330     else
331         return false;
332     
333     return true;
334 }
335
336 static bool markerTypesFrom(const String& markerType, DocumentMarker::MarkerTypes& result)
337 {
338     DocumentMarker::MarkerType singularResult;
339
340     if (markerType.isEmpty() || equalLettersIgnoringASCIICase(markerType, "all"))
341         result = DocumentMarker::AllMarkers();
342     else if (markerTypeFrom(markerType, singularResult))
343         result = singularResult;
344     else
345         return false;
346
347     return true;
348 }
349
350 const char* Internals::internalsId = "internals";
351
352 Ref<Internals> Internals::create(Document& document)
353 {
354     return adoptRef(*new Internals(document));
355 }
356
357 Internals::~Internals()
358 {
359 }
360
361 void Internals::resetToConsistentState(Page& page)
362 {
363     page.setPageScaleFactor(1, IntPoint(0, 0));
364     page.setPagination(Pagination());
365     page.setPaginationLineGridEnabled(false);
366
367     page.setDefersLoading(false);
368     
369     page.mainFrame().setTextZoomFactor(1.0f);
370     
371     FrameView* mainFrameView = page.mainFrame().view();
372     if (mainFrameView) {
373         mainFrameView->setHeaderHeight(0);
374         mainFrameView->setFooterHeight(0);
375         page.setTopContentInset(0);
376         mainFrameView->setUseFixedLayout(false);
377         mainFrameView->setFixedLayoutSize(IntSize());
378 #if USE(COORDINATED_GRAPHICS)
379         mainFrameView->setFixedVisibleContentRect(IntRect());
380 #endif
381     }
382
383     WebCore::clearDefaultPortForProtocolMapForTesting();
384     WebCore::overrideUserPreferredLanguages(Vector<String>());
385     WebCore::Settings::setUsesOverlayScrollbars(false);
386     WebCore::Settings::setUsesMockScrollAnimator(false);
387 #if ENABLE(VIDEO_TRACK)
388     page.group().captionPreferences().setTestingMode(true);
389     page.group().captionPreferences().setCaptionsStyleSheetOverride(emptyString());
390     page.group().captionPreferences().setTestingMode(false);
391 #endif
392     if (!page.mainFrame().editor().isContinuousSpellCheckingEnabled())
393         page.mainFrame().editor().toggleContinuousSpellChecking();
394     if (page.mainFrame().editor().isOverwriteModeEnabled())
395         page.mainFrame().editor().toggleOverwriteModeEnabled();
396     page.mainFrame().loader().clearTestingOverrides();
397     page.applicationCacheStorage().setDefaultOriginQuota(ApplicationCacheStorage::noQuota());
398 #if ENABLE(VIDEO)
399     PlatformMediaSessionManager::sharedManager().resetRestrictions();
400     PlatformMediaSessionManager::sharedManager().setWillIgnoreSystemInterruptions(true);
401 #endif
402 #if HAVE(ACCESSIBILITY)
403     AXObjectCache::setEnhancedUserInterfaceAccessibility(false);
404     AXObjectCache::disableAccessibility();
405 #endif
406
407     MockPageOverlayClient::singleton().uninstallAllOverlays();
408
409 #if ENABLE(CONTENT_FILTERING)
410     MockContentFilterSettings::reset();
411 #endif
412
413 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
414     page.setMockMediaPlaybackTargetPickerEnabled(true);
415     page.setMockMediaPlaybackTargetPickerState(emptyString(), MediaPlaybackTargetContext::Unknown);
416 #endif
417
418     page.setShowAllPlugins(false);
419 }
420
421 Internals::Internals(Document& document)
422     : ContextDestructionObserver(&document)
423 {
424 #if ENABLE(VIDEO_TRACK)
425     if (document.page())
426         document.page()->group().captionPreferences().setTestingMode(true);
427 #endif
428
429 #if ENABLE(MEDIA_STREAM)
430     setMockMediaCaptureDevicesEnabled(true);
431     WebCore::Settings::setMediaCaptureRequiresSecureConnection(false);
432 #endif
433
434 #if ENABLE(WEB_RTC)
435     enableMockMediaEndpoint();
436     enableMockRTCPeerConnectionHandler();
437 #endif
438
439 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
440     if (document.page())
441         document.page()->setMockMediaPlaybackTargetPickerEnabled(true);
442 #endif
443     RuntimeEnabledFeatures::sharedFeatures().reset();
444
445     if (contextDocument() && contextDocument()->frame()) {
446         setAutomaticSpellingCorrectionEnabled(true);
447         setAutomaticQuoteSubstitutionEnabled(false);
448         setAutomaticDashSubstitutionEnabled(false);
449         setAutomaticLinkDetectionEnabled(false);
450         setAutomaticTextReplacementEnabled(true);
451     }
452 }
453
454 Document* Internals::contextDocument() const
455 {
456     return downcast<Document>(scriptExecutionContext());
457 }
458
459 Frame* Internals::frame() const
460 {
461     if (!contextDocument())
462         return nullptr;
463     return contextDocument()->frame();
464 }
465
466 InternalSettings* Internals::settings() const
467 {
468     Document* document = contextDocument();
469     if (!document)
470         return nullptr;
471     Page* page = document->page();
472     if (!page)
473         return nullptr;
474     return InternalSettings::from(page);
475 }
476
477 unsigned Internals::workerThreadCount() const
478 {
479     return WorkerThread::workerThreadCount();
480 }
481
482 String Internals::address(Node& node)
483 {
484     return String::format("%p", &node);
485 }
486
487 bool Internals::nodeNeedsStyleRecalc(Node& node)
488 {
489     return node.needsStyleRecalc();
490 }
491
492 static String styleValidityToToString(Style::Validity validity)
493 {
494     switch (validity) {
495     case Style::Validity::Valid:
496         return "NoStyleChange";
497     case Style::Validity::ElementInvalid:
498         return "InlineStyleChange";
499     case Style::Validity::SubtreeInvalid:
500         return "FullStyleChange";
501     case Style::Validity::SubtreeAndRenderersInvalid:
502         return "ReconstructRenderTree";
503     }
504     ASSERT_NOT_REACHED();
505     return "";
506 }
507
508 String Internals::styleChangeType(Node& node)
509 {
510     node.document().styleScope().flushPendingUpdate();
511
512     return styleValidityToToString(node.styleValidity());
513 }
514
515 String Internals::description(JSC::JSValue value)
516 {
517     return toString(value);
518 }
519
520 bool Internals::isPreloaded(const String& url)
521 {
522     Document* document = contextDocument();
523     return document->cachedResourceLoader().isPreloaded(url);
524 }
525
526 bool Internals::isLoadingFromMemoryCache(const String& url)
527 {
528     if (!contextDocument() || !contextDocument()->page())
529         return false;
530
531     ResourceRequest request(contextDocument()->completeURL(url));
532 #if ENABLE(CACHE_PARTITIONING)
533     request.setDomainForCachePartition(contextDocument()->topOrigin()->domainForCachePartition());
534 #endif
535     CachedResource* resource = MemoryCache::singleton().resourceForRequest(request, contextDocument()->page()->sessionID());
536     return resource && resource->status() == CachedResource::Cached;
537 }
538
539 String Internals::xhrResponseSource(XMLHttpRequest& request)
540 {
541     if (request.resourceResponse().isNull())
542         return "Null response";
543     switch (request.resourceResponse().source()) {
544     case ResourceResponse::Source::Unknown:
545         return "Unknown";
546     case ResourceResponse::Source::Network:
547         return "Network";
548     case ResourceResponse::Source::DiskCache:
549         return "Disk cache";
550     case ResourceResponse::Source::DiskCacheAfterValidation:
551         return "Disk cache after validation";
552     case ResourceResponse::Source::MemoryCache:
553         return "Memory cache";
554     case ResourceResponse::Source::MemoryCacheAfterValidation:
555         return "Memory cache after validation";
556     }
557     ASSERT_NOT_REACHED();
558     return "Error";
559 }
560
561 bool Internals::isSharingStyleSheetContents(HTMLLinkElement& a, HTMLLinkElement& b)
562 {
563     if (!a.sheet() || !b.sheet())
564         return false;
565     return &a.sheet()->contents() == &b.sheet()->contents();
566 }
567
568 bool Internals::isStyleSheetLoadingSubresources(HTMLLinkElement& link)
569 {
570     return link.sheet() && link.sheet()->contents().isLoadingSubresources();
571 }
572
573 static ResourceRequestCachePolicy toResourceRequestCachePolicy(Internals::CachePolicy policy)
574 {
575     switch (policy) {
576     case Internals::CachePolicy::UseProtocolCachePolicy:
577         return UseProtocolCachePolicy;
578     case Internals::CachePolicy::ReloadIgnoringCacheData:
579         return ReloadIgnoringCacheData;
580     case Internals::CachePolicy::ReturnCacheDataElseLoad:
581         return ReturnCacheDataElseLoad;
582     case Internals::CachePolicy::ReturnCacheDataDontLoad:
583         return ReturnCacheDataDontLoad;
584     }
585     ASSERT_NOT_REACHED();
586     return UseProtocolCachePolicy;
587 }
588
589 void Internals::setOverrideCachePolicy(CachePolicy policy)
590 {
591     frame()->loader().setOverrideCachePolicyForTesting(toResourceRequestCachePolicy(policy));
592 }
593
594 ExceptionOr<void> Internals::setCanShowModalDialogOverride(bool allow)
595 {
596     if (!contextDocument() || !contextDocument()->domWindow())
597         return Exception { INVALID_ACCESS_ERR };
598
599     contextDocument()->domWindow()->setCanShowModalDialogOverride(allow);
600     return { };
601 }
602
603 static ResourceLoadPriority toResourceLoadPriority(Internals::ResourceLoadPriority priority)
604 {
605     switch (priority) {
606     case Internals::ResourceLoadPriority::ResourceLoadPriorityVeryLow:
607         return ResourceLoadPriority::VeryLow;
608     case Internals::ResourceLoadPriority::ResourceLoadPriorityLow:
609         return ResourceLoadPriority::Low;
610     case Internals::ResourceLoadPriority::ResourceLoadPriorityMedium:
611         return ResourceLoadPriority::Medium;
612     case Internals::ResourceLoadPriority::ResourceLoadPriorityHigh:
613         return ResourceLoadPriority::High;
614     case Internals::ResourceLoadPriority::ResourceLoadPriorityVeryHigh:
615         return ResourceLoadPriority::VeryHigh;
616     }
617     ASSERT_NOT_REACHED();
618     return ResourceLoadPriority::Low;
619 }
620
621 void Internals::setOverrideResourceLoadPriority(ResourceLoadPriority priority)
622 {
623     frame()->loader().setOverrideResourceLoadPriorityForTesting(toResourceLoadPriority(priority));
624 }
625
626 void Internals::setStrictRawResourceValidationPolicyDisabled(bool disabled)
627 {
628     frame()->loader().setStrictRawResourceValidationPolicyDisabledForTesting(disabled);
629 }
630
631 void Internals::clearMemoryCache()
632 {
633     MemoryCache::singleton().evictResources();
634 }
635
636 void Internals::pruneMemoryCacheToSize(unsigned size)
637 {
638     MemoryCache::singleton().pruneDeadResourcesToSize(size);
639     MemoryCache::singleton().pruneLiveResourcesToSize(size, true);
640 }
641
642 unsigned Internals::memoryCacheSize() const
643 {
644     return MemoryCache::singleton().size();
645 }
646
647 unsigned Internals::imageFrameIndex(HTMLImageElement& element)
648 {
649     auto* cachedImage = element.cachedImage();
650     if (!cachedImage)
651         return 0;
652
653     auto* image = cachedImage->image();
654     return is<BitmapImage>(image) ? downcast<BitmapImage>(*image).currentFrame() : 0;
655 }
656
657 void Internals::setImageFrameDecodingDuration(HTMLImageElement& element, float duration)
658 {
659     auto* cachedImage = element.cachedImage();
660     if (!cachedImage)
661         return;
662     
663     auto* image = cachedImage->image();
664     if (!is<BitmapImage>(image))
665         return;
666     
667     downcast<BitmapImage>(*image).setFrameDecodingDurationForTesting(duration);
668 }
669
670 void Internals::resetImageAnimation(HTMLImageElement& element)
671 {
672     auto* cachedImage = element.cachedImage();
673     if (!cachedImage)
674         return;
675
676     auto* image = cachedImage->image();
677     if (!is<BitmapImage>(image))
678         return;
679
680     image->resetAnimation();
681 }
682
683 void Internals::clearPageCache()
684 {
685     PageCache::singleton().pruneToSizeNow(0, PruningReason::None);
686 }
687
688 unsigned Internals::pageCacheSize() const
689 {
690     return PageCache::singleton().pageCount();
691 }
692
693 Node* Internals::treeScopeRootNode(Node& node)
694 {
695     return &node.treeScope().rootNode();
696 }
697
698 Node* Internals::parentTreeScope(Node& node)
699 {
700     const TreeScope* parentTreeScope = node.treeScope().parentTreeScope();
701     return parentTreeScope ? &parentTreeScope->rootNode() : nullptr;
702 }
703
704 ExceptionOr<unsigned> Internals::lastSpatialNavigationCandidateCount() const
705 {
706     if (!contextDocument() || !contextDocument()->page())
707         return Exception { INVALID_ACCESS_ERR };
708
709     return contextDocument()->page()->lastSpatialNavigationCandidateCount();
710 }
711
712 unsigned Internals::numberOfActiveAnimations() const
713 {
714     return frame()->animation().numberOfActiveAnimations(frame()->document());
715 }
716
717 ExceptionOr<bool> Internals::animationsAreSuspended() const
718 {
719     Document* document = contextDocument();
720     if (!document || !document->frame())
721         return Exception { INVALID_ACCESS_ERR };
722
723     return document->frame()->animation().isSuspended();
724 }
725
726 ExceptionOr<void> Internals::suspendAnimations() const
727 {
728     Document* document = contextDocument();
729     if (!document || !document->frame())
730         return Exception { INVALID_ACCESS_ERR };
731
732     document->frame()->animation().suspendAnimations();
733     return { };
734 }
735
736 ExceptionOr<void> Internals::resumeAnimations() const
737 {
738     Document* document = contextDocument();
739     if (!document || !document->frame())
740         return Exception { INVALID_ACCESS_ERR };
741
742     document->frame()->animation().resumeAnimations();
743     return { };
744 }
745
746 ExceptionOr<bool> Internals::pauseAnimationAtTimeOnElement(const String& animationName, double pauseTime, Element& element)
747 {
748     if (pauseTime < 0)
749         return Exception { INVALID_ACCESS_ERR };
750     return frame()->animation().pauseAnimationAtTime(element.renderer(), AtomicString(animationName), pauseTime);
751 }
752
753 ExceptionOr<bool> Internals::pauseAnimationAtTimeOnPseudoElement(const String& animationName, double pauseTime, Element& element, const String& pseudoId)
754 {
755     if (pauseTime < 0)
756         return Exception { INVALID_ACCESS_ERR };
757
758     if (pseudoId != "before" && pseudoId != "after")
759         return Exception { INVALID_ACCESS_ERR };
760
761     PseudoElement* pseudoElement = pseudoId == "before" ? element.beforePseudoElement() : element.afterPseudoElement();
762     if (!pseudoElement)
763         return Exception { INVALID_ACCESS_ERR };
764
765     return frame()->animation().pauseAnimationAtTime(pseudoElement->renderer(), AtomicString(animationName), pauseTime);
766 }
767
768 ExceptionOr<bool> Internals::pauseTransitionAtTimeOnElement(const String& propertyName, double pauseTime, Element& element)
769 {
770     if (pauseTime < 0)
771         return Exception { INVALID_ACCESS_ERR };
772     return frame()->animation().pauseTransitionAtTime(element.renderer(), propertyName, pauseTime);
773 }
774
775 ExceptionOr<bool> Internals::pauseTransitionAtTimeOnPseudoElement(const String& property, double pauseTime, Element& element, const String& pseudoId)
776 {
777     if (pauseTime < 0)
778         return Exception { INVALID_ACCESS_ERR };
779
780     if (pseudoId != "before" && pseudoId != "after")
781         return Exception { INVALID_ACCESS_ERR };
782
783     PseudoElement* pseudoElement = pseudoId == "before" ? element.beforePseudoElement() : element.afterPseudoElement();
784     if (!pseudoElement)
785         return Exception { INVALID_ACCESS_ERR };
786
787     return frame()->animation().pauseTransitionAtTime(pseudoElement->renderer(), property, pauseTime);
788 }
789
790 ExceptionOr<String> Internals::elementRenderTreeAsText(Element& element)
791 {
792     element.document().updateStyleIfNeeded();
793
794     String representation = externalRepresentation(&element);
795     if (representation.isEmpty())
796         return Exception { INVALID_ACCESS_ERR };
797
798     return WTFMove(representation);
799 }
800
801 bool Internals::hasPausedImageAnimations(Element& element)
802 {
803     return element.renderer() && element.renderer()->hasPausedImageAnimations();
804 }
805
806 RefPtr<CSSComputedStyleDeclaration> Internals::computedStyleIncludingVisitedInfo(Element& element) const
807 {
808     bool allowVisitedStyle = true;
809     return CSSComputedStyleDeclaration::create(element, allowVisitedStyle);
810 }
811
812 Node* Internals::ensureUserAgentShadowRoot(Element& host)
813 {
814     return &host.ensureUserAgentShadowRoot();
815 }
816
817 Node* Internals::shadowRoot(Element& host)
818 {
819     return host.shadowRoot();
820 }
821
822 ExceptionOr<String> Internals::shadowRootType(const Node& root) const
823 {
824     if (!is<ShadowRoot>(root))
825         return Exception { INVALID_ACCESS_ERR };
826
827     switch (downcast<ShadowRoot>(root).mode()) {
828     case ShadowRootMode::UserAgent:
829         return String("UserAgentShadowRoot");
830     case ShadowRootMode::Closed:
831         return String("ClosedShadowRoot");
832     case ShadowRootMode::Open:
833         return String("OpenShadowRoot");
834     default:
835         ASSERT_NOT_REACHED();
836         return String("Unknown");
837     }
838 }
839
840 String Internals::shadowPseudoId(Element& element)
841 {
842     return element.shadowPseudoId().string();
843 }
844
845 void Internals::setShadowPseudoId(Element& element, const String& id)
846 {
847     return element.setPseudo(id);
848 }
849
850 ExceptionOr<bool> Internals::isTimerThrottled(int timeoutId)
851 {
852     DOMTimer* timer = scriptExecutionContext()->findTimeout(timeoutId);
853     if (!timer)
854         return Exception { NOT_FOUND_ERR };
855     return timer->m_throttleState == DOMTimer::ShouldThrottle;
856 }
857
858 bool Internals::isRequestAnimationFrameThrottled() const
859 {
860 #if ENABLE(REQUEST_ANIMATION_FRAME)
861     auto* scriptedAnimationController = contextDocument()->scriptedAnimationController();
862     if (!scriptedAnimationController)
863         return false;
864     return scriptedAnimationController->isThrottled();
865 #else
866     return false;
867 #endif
868 }
869
870 bool Internals::areTimersThrottled() const
871 {
872     return contextDocument()->isTimerThrottlingEnabled();
873 }
874
875 void Internals::setEventThrottlingBehaviorOverride(std::optional<EventThrottlingBehavior> value)
876 {
877     Document* document = contextDocument();
878     if (!document || !document->page())
879         return;
880
881     if (!value) {
882         document->page()->setEventThrottlingBehaviorOverride(std::nullopt);
883         return;
884     }
885
886     switch (value.value()) {
887     case Internals::EventThrottlingBehavior::Responsive:
888         document->page()->setEventThrottlingBehaviorOverride(WebCore::EventThrottlingBehavior::Responsive);
889         break;
890     case Internals::EventThrottlingBehavior::Unresponsive:
891         document->page()->setEventThrottlingBehaviorOverride(WebCore::EventThrottlingBehavior::Unresponsive);
892         break;
893     }
894 }
895
896 std::optional<Internals::EventThrottlingBehavior> Internals::eventThrottlingBehaviorOverride() const
897 {
898     Document* document = contextDocument();
899     if (!document || !document->page())
900         return std::nullopt;
901
902     auto behavior = document->page()->eventThrottlingBehaviorOverride();
903     if (!behavior)
904         return std::nullopt;
905     
906     switch (behavior.value()) {
907     case WebCore::EventThrottlingBehavior::Responsive:
908         return Internals::EventThrottlingBehavior::Responsive;
909     case WebCore::EventThrottlingBehavior::Unresponsive:
910         return Internals::EventThrottlingBehavior::Unresponsive;
911     }
912
913     return std::nullopt;
914 }
915
916 String Internals::visiblePlaceholder(Element& element)
917 {
918     if (is<HTMLTextFormControlElement>(element)) {
919         const HTMLTextFormControlElement& textFormControlElement = downcast<HTMLTextFormControlElement>(element);
920         if (!textFormControlElement.isPlaceholderVisible())
921             return String();
922         if (HTMLElement* placeholderElement = textFormControlElement.placeholderElement())
923             return placeholderElement->textContent();
924     }
925
926     return String();
927 }
928
929 void Internals::selectColorInColorChooser(HTMLInputElement& element, const String& colorValue)
930 {
931     element.selectColor(Color(colorValue));
932 }
933
934 ExceptionOr<Vector<String>> Internals::formControlStateOfPreviousHistoryItem()
935 {
936     HistoryItem* mainItem = frame()->loader().history().previousItem();
937     if (!mainItem)
938         return Exception { INVALID_ACCESS_ERR };
939     String uniqueName = frame()->tree().uniqueName();
940     if (mainItem->target() != uniqueName && !mainItem->childItemWithTarget(uniqueName))
941         return Exception { INVALID_ACCESS_ERR };
942     return Vector<String> { mainItem->target() == uniqueName ? mainItem->documentState() : mainItem->childItemWithTarget(uniqueName)->documentState() };
943 }
944
945 ExceptionOr<void> Internals::setFormControlStateOfPreviousHistoryItem(const Vector<String>& state)
946 {
947     HistoryItem* mainItem = frame()->loader().history().previousItem();
948     if (!mainItem)
949         return Exception { INVALID_ACCESS_ERR };
950     String uniqueName = frame()->tree().uniqueName();
951     if (mainItem->target() == uniqueName)
952         mainItem->setDocumentState(state);
953     else if (HistoryItem* subItem = mainItem->childItemWithTarget(uniqueName))
954         subItem->setDocumentState(state);
955     else
956         return Exception { INVALID_ACCESS_ERR };
957     return { };
958 }
959
960 #if ENABLE(SPEECH_SYNTHESIS)
961
962 void Internals::enableMockSpeechSynthesizer()
963 {
964     Document* document = contextDocument();
965     if (!document || !document->domWindow())
966         return;
967     SpeechSynthesis* synthesis = DOMWindowSpeechSynthesis::speechSynthesis(*document->domWindow());
968     if (!synthesis)
969         return;
970     
971     synthesis->setPlatformSynthesizer(std::make_unique<PlatformSpeechSynthesizerMock>(synthesis));
972 }
973
974 #endif
975
976 #if ENABLE(WEB_RTC)
977
978 void Internals::enableMockMediaEndpoint()
979 {
980     MediaEndpoint::create = MockMediaEndpoint::create;
981 }
982
983 void Internals::enableMockRTCPeerConnectionHandler()
984 {
985     RTCPeerConnectionHandler::create = RTCPeerConnectionHandlerMock::create;
986 }
987
988 void Internals::emulateRTCPeerConnectionPlatformEvent(RTCPeerConnection& connection, const String& action)
989 {
990     connection.emulatePlatformEvent(action);
991 }
992
993 #endif
994
995 #if ENABLE(MEDIA_STREAM)
996
997 void Internals::setMockMediaCaptureDevicesEnabled(bool enabled)
998 {
999     WebCore::Settings::setMockCaptureDevicesEnabled(enabled);
1000 }
1001
1002 #endif
1003
1004 ExceptionOr<Ref<ClientRect>> Internals::absoluteCaretBounds()
1005 {
1006     Document* document = contextDocument();
1007     if (!document || !document->frame())
1008         return Exception { INVALID_ACCESS_ERR };
1009
1010     return ClientRect::create(document->frame()->selection().absoluteCaretBounds());
1011 }
1012
1013 Ref<ClientRect> Internals::boundingBox(Element& element)
1014 {
1015     element.document().updateLayoutIgnorePendingStylesheets();
1016     auto renderer = element.renderer();
1017     if (!renderer)
1018         return ClientRect::create();
1019     return ClientRect::create(renderer->absoluteBoundingBoxRectIgnoringTransforms());
1020 }
1021
1022 ExceptionOr<Ref<ClientRectList>> Internals::inspectorHighlightRects()
1023 {
1024     Document* document = contextDocument();
1025     if (!document || !document->page())
1026         return Exception { INVALID_ACCESS_ERR };
1027
1028     Highlight highlight;
1029     document->page()->inspectorController().getHighlight(highlight, InspectorOverlay::CoordinateSystem::View);
1030     return ClientRectList::create(highlight.quads);
1031 }
1032
1033 ExceptionOr<String> Internals::inspectorHighlightObject()
1034 {
1035     Document* document = contextDocument();
1036     if (!document || !document->page())
1037         return Exception { INVALID_ACCESS_ERR };
1038
1039     return document->page()->inspectorController().buildObjectForHighlightedNodes()->toJSONString();
1040 }
1041
1042 ExceptionOr<unsigned> Internals::markerCountForNode(Node& node, const String& markerType)
1043 {
1044     DocumentMarker::MarkerTypes markerTypes = 0;
1045     if (!markerTypesFrom(markerType, markerTypes))
1046         return Exception { SYNTAX_ERR };
1047
1048     node.document().frame()->editor().updateEditorUINowIfScheduled();
1049     return node.document().markers().markersFor(&node, markerTypes).size();
1050 }
1051
1052 ExceptionOr<RenderedDocumentMarker*> Internals::markerAt(Node& node, const String& markerType, unsigned index)
1053 {
1054     node.document().updateLayoutIgnorePendingStylesheets();
1055
1056     DocumentMarker::MarkerTypes markerTypes = 0;
1057     if (!markerTypesFrom(markerType, markerTypes))
1058         return Exception { SYNTAX_ERR };
1059
1060     node.document().frame()->editor().updateEditorUINowIfScheduled();
1061
1062     Vector<RenderedDocumentMarker*> markers = node.document().markers().markersFor(&node, markerTypes);
1063     if (markers.size() <= index)
1064         return nullptr;
1065     return markers[index];
1066 }
1067
1068 ExceptionOr<RefPtr<Range>> Internals::markerRangeForNode(Node& node, const String& markerType, unsigned index)
1069 {
1070     auto result = markerAt(node, markerType, index);
1071     if (result.hasException())
1072         return result.releaseException();
1073     auto marker = result.releaseReturnValue();
1074     if (!marker)
1075         return nullptr;
1076     return RefPtr<Range> { Range::create(node.document(), &node, marker->startOffset(), &node, marker->endOffset()) };
1077 }
1078
1079 ExceptionOr<String> Internals::markerDescriptionForNode(Node& node, const String& markerType, unsigned index)
1080 {
1081     auto result = markerAt(node, markerType, index);
1082     if (result.hasException())
1083         return result.releaseException();
1084     auto marker = result.releaseReturnValue();
1085     if (!marker)
1086         return String();
1087     return String { marker->description() };
1088 }
1089
1090 ExceptionOr<String> Internals::dumpMarkerRects(const String& markerTypeString)
1091 {
1092     DocumentMarker::MarkerType markerType;
1093     if (!markerTypeFrom(markerTypeString, markerType))
1094         return Exception { SYNTAX_ERR };
1095
1096     contextDocument()->markers().updateRectsForInvalidatedMarkersOfType(markerType);
1097     auto rects = contextDocument()->markers().renderedRectsForMarkers(markerType);
1098
1099     StringBuilder rectString;
1100     rectString.appendLiteral("marker rects: ");
1101     for (const auto& rect : rects) {
1102         rectString.append('(');
1103         rectString.appendNumber(rect.x());
1104         rectString.appendLiteral(", ");
1105         rectString.appendNumber(rect.y());
1106         rectString.appendLiteral(", ");
1107         rectString.appendNumber(rect.width());
1108         rectString.appendLiteral(", ");
1109         rectString.appendNumber(rect.height());
1110         rectString.appendLiteral(") ");
1111     }
1112     return rectString.toString();
1113 }
1114
1115 void Internals::addTextMatchMarker(const Range& range, bool isActive)
1116 {
1117     range.ownerDocument().updateLayoutIgnorePendingStylesheets();
1118     range.ownerDocument().markers().addTextMatchMarker(&range, isActive);
1119 }
1120
1121 ExceptionOr<void> Internals::setMarkedTextMatchesAreHighlighted(bool flag)
1122 {
1123     Document* document = contextDocument();
1124     if (!document || !document->frame())
1125         return Exception { INVALID_ACCESS_ERR };
1126     document->frame()->editor().setMarkedTextMatchesAreHighlighted(flag);
1127     return { };
1128 }
1129
1130 void Internals::invalidateFontCache()
1131 {
1132     FontCache::singleton().invalidate();
1133 }
1134
1135 ExceptionOr<void> Internals::setScrollViewPosition(int x, int y)
1136 {
1137     Document* document = contextDocument();
1138     if (!document || !document->view())
1139         return Exception { INVALID_ACCESS_ERR };
1140
1141     auto& frameView = *document->view();
1142     bool constrainsScrollingToContentEdgeOldValue = frameView.constrainsScrollingToContentEdge();
1143     bool scrollbarsSuppressedOldValue = frameView.scrollbarsSuppressed();
1144
1145     frameView.setConstrainsScrollingToContentEdge(false);
1146     frameView.setScrollbarsSuppressed(false);
1147     frameView.setScrollOffsetFromInternals({ x, y });
1148     frameView.setScrollbarsSuppressed(scrollbarsSuppressedOldValue);
1149     frameView.setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdgeOldValue);
1150
1151     return { };
1152 }
1153
1154 ExceptionOr<Ref<ClientRect>> Internals::layoutViewportRect()
1155 {
1156     Document* document = contextDocument();
1157     if (!document || !document->frame())
1158         return Exception { INVALID_ACCESS_ERR };
1159
1160     document->updateLayoutIgnorePendingStylesheets();
1161
1162     auto& frameView = *document->view();
1163     return ClientRect::create(frameView.layoutViewportRect());
1164 }
1165
1166 ExceptionOr<Ref<ClientRect>> Internals::visualViewportRect()
1167 {
1168     Document* document = contextDocument();
1169     if (!document || !document->frame())
1170         return Exception { INVALID_ACCESS_ERR };
1171
1172     document->updateLayoutIgnorePendingStylesheets();
1173
1174     auto& frameView = *document->view();
1175     return ClientRect::create(frameView.visualViewportRect());
1176 }
1177
1178 ExceptionOr<void> Internals::setViewBaseBackgroundColor(const String& colorValue)
1179 {
1180     Document* document = contextDocument();
1181     if (!document || !document->view())
1182         return Exception { INVALID_ACCESS_ERR };
1183
1184     document->view()->setBaseBackgroundColor(Color(colorValue));
1185     return { };
1186 }
1187
1188 ExceptionOr<void> Internals::setPagination(const String& mode, int gap, int pageLength)
1189 {
1190     Document* document = contextDocument();
1191     if (!document || !document->page())
1192         return Exception { INVALID_ACCESS_ERR };
1193
1194     Pagination pagination;
1195     if (mode == "Unpaginated")
1196         pagination.mode = Pagination::Unpaginated;
1197     else if (mode == "LeftToRightPaginated")
1198         pagination.mode = Pagination::LeftToRightPaginated;
1199     else if (mode == "RightToLeftPaginated")
1200         pagination.mode = Pagination::RightToLeftPaginated;
1201     else if (mode == "TopToBottomPaginated")
1202         pagination.mode = Pagination::TopToBottomPaginated;
1203     else if (mode == "BottomToTopPaginated")
1204         pagination.mode = Pagination::BottomToTopPaginated;
1205     else
1206         return Exception { SYNTAX_ERR };
1207
1208     pagination.gap = gap;
1209     pagination.pageLength = pageLength;
1210     document->page()->setPagination(pagination);
1211
1212     return { };
1213 }
1214
1215 ExceptionOr<void> Internals::setPaginationLineGridEnabled(bool enabled)
1216 {
1217     Document* document = contextDocument();
1218     if (!document || !document->page())
1219         return Exception { INVALID_ACCESS_ERR };
1220     document->page()->setPaginationLineGridEnabled(enabled);
1221     return { };
1222 }
1223
1224 ExceptionOr<String> Internals::configurationForViewport(float devicePixelRatio, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight)
1225 {
1226     Document* document = contextDocument();
1227     if (!document || !document->page())
1228         return Exception { INVALID_ACCESS_ERR };
1229
1230     const int defaultLayoutWidthForNonMobilePages = 980;
1231
1232     ViewportArguments arguments = document->page()->viewportArguments();
1233     ViewportAttributes attributes = computeViewportAttributes(arguments, defaultLayoutWidthForNonMobilePages, deviceWidth, deviceHeight, devicePixelRatio, IntSize(availableWidth, availableHeight));
1234     restrictMinimumScaleFactorToViewportSize(attributes, IntSize(availableWidth, availableHeight), devicePixelRatio);
1235     restrictScaleFactorToInitialScaleIfNotUserScalable(attributes);
1236
1237     return String { "viewport size " + String::number(attributes.layoutSize.width()) + "x" + String::number(attributes.layoutSize.height()) + " scale " + String::number(attributes.initialScale) + " with limits [" + String::number(attributes.minimumScale) + ", " + String::number(attributes.maximumScale) + "] and userScalable " + (attributes.userScalable ? "true" : "false") };
1238 }
1239
1240 ExceptionOr<bool> Internals::wasLastChangeUserEdit(Element& textField)
1241 {
1242     if (is<HTMLInputElement>(textField))
1243         return downcast<HTMLInputElement>(textField).lastChangeWasUserEdit();
1244
1245     if (is<HTMLTextAreaElement>(textField))
1246         return downcast<HTMLTextAreaElement>(textField).lastChangeWasUserEdit();
1247
1248     return Exception { INVALID_NODE_TYPE_ERR };
1249 }
1250
1251 bool Internals::elementShouldAutoComplete(HTMLInputElement& element)
1252 {
1253     return element.shouldAutocomplete();
1254 }
1255
1256 void Internals::setEditingValue(HTMLInputElement& element, const String& value)
1257 {
1258     element.setEditingValue(value);
1259 }
1260
1261 void Internals::setAutofilled(HTMLInputElement& element, bool enabled)
1262 {
1263     element.setAutoFilled(enabled);
1264 }
1265
1266 static AutoFillButtonType toAutoFillButtonType(Internals::AutoFillButtonType type)
1267 {
1268     switch (type) {
1269     case Internals::AutoFillButtonType::AutoFillButtonTypeNone:
1270         return AutoFillButtonType::None;
1271     case Internals::AutoFillButtonType::AutoFillButtonTypeCredentials:
1272         return AutoFillButtonType::Credentials;
1273     case Internals::AutoFillButtonType::AutoFillButtonTypeContacts:
1274         return AutoFillButtonType::Contacts;
1275     }
1276     ASSERT_NOT_REACHED();
1277     return AutoFillButtonType::None;
1278 }
1279
1280 void Internals::setShowAutoFillButton(HTMLInputElement& element, AutoFillButtonType type)
1281 {
1282     element.setShowAutoFillButton(toAutoFillButtonType(type));
1283 }
1284
1285 ExceptionOr<void> Internals::scrollElementToRect(Element& element, int x, int y, int w, int h)
1286 {
1287     FrameView* frameView = element.document().view();
1288     if (!frameView)
1289         return Exception { INVALID_ACCESS_ERR };
1290     frameView->scrollElementToRect(element, { x, y, w, h });
1291     return { };
1292 }
1293
1294 ExceptionOr<String> Internals::autofillFieldName(Element& element)
1295 {
1296     if (!is<HTMLFormControlElement>(element))
1297         return Exception { INVALID_NODE_TYPE_ERR };
1298
1299     return String { downcast<HTMLFormControlElement>(element).autofillData().fieldName };
1300 }
1301
1302 ExceptionOr<void> Internals::paintControlTints()
1303 {
1304     Document* document = contextDocument();
1305     if (!document || !document->view())
1306         return Exception { INVALID_ACCESS_ERR };
1307
1308     document->view()->paintControlTints();
1309     return { };
1310 }
1311
1312 RefPtr<Range> Internals::rangeFromLocationAndLength(Element& scope, int rangeLocation, int rangeLength)
1313 {
1314     return TextIterator::rangeFromLocationAndLength(&scope, rangeLocation, rangeLength);
1315 }
1316
1317 unsigned Internals::locationFromRange(Element& scope, const Range& range)
1318 {
1319     size_t location = 0;
1320     size_t unusedLength = 0;
1321     TextIterator::getLocationAndLengthFromRange(&scope, &range, location, unusedLength);
1322     return location;
1323 }
1324
1325 unsigned Internals::lengthFromRange(Element& scope, const Range& range)
1326 {
1327     size_t unusedLocation = 0;
1328     size_t length = 0;
1329     TextIterator::getLocationAndLengthFromRange(&scope, &range, unusedLocation, length);
1330     return length;
1331 }
1332
1333 String Internals::rangeAsText(const Range& range)
1334 {
1335     return range.text();
1336 }
1337
1338 RefPtr<Range> Internals::subrange(Range& range, int rangeLocation, int rangeLength)
1339 {
1340     return TextIterator::subrange(&range, rangeLocation, rangeLength);
1341 }
1342
1343 ExceptionOr<RefPtr<Range>> Internals::rangeForDictionaryLookupAtLocation(int x, int y)
1344 {
1345 #if PLATFORM(MAC)
1346     Document* document = contextDocument();
1347     if (!document || !document->frame())
1348         return Exception { INVALID_ACCESS_ERR };
1349
1350     document->updateLayoutIgnorePendingStylesheets();
1351     
1352     HitTestResult result = document->frame()->mainFrame().eventHandler().hitTestResultAtPoint(IntPoint(x, y));
1353     NSDictionary *options = nullptr;
1354     return DictionaryLookup::rangeAtHitTestResult(result, &options);
1355 #else
1356     UNUSED_PARAM(x);
1357     UNUSED_PARAM(y);
1358     return Exception { INVALID_ACCESS_ERR };
1359 #endif
1360 }
1361
1362 ExceptionOr<void> Internals::setDelegatesScrolling(bool enabled)
1363 {
1364     Document* document = contextDocument();
1365     // Delegate scrolling is valid only on mainframe's view.
1366     if (!document || !document->view() || !document->page() || &document->page()->mainFrame() != document->frame())
1367         return Exception { INVALID_ACCESS_ERR };
1368
1369     document->view()->setDelegatesScrolling(enabled);
1370     return { };
1371 }
1372
1373 ExceptionOr<int> Internals::lastSpellCheckRequestSequence()
1374 {
1375     Document* document = contextDocument();
1376     if (!document || !document->frame())
1377         return Exception { INVALID_ACCESS_ERR };
1378
1379     return document->frame()->editor().spellChecker().lastRequestSequence();
1380 }
1381
1382 ExceptionOr<int> Internals::lastSpellCheckProcessedSequence()
1383 {
1384     Document* document = contextDocument();
1385     if (!document || !document->frame())
1386         return Exception { INVALID_ACCESS_ERR };
1387
1388     return document->frame()->editor().spellChecker().lastProcessedSequence();
1389 }
1390
1391 Vector<String> Internals::userPreferredLanguages() const
1392 {
1393     return WebCore::userPreferredLanguages();
1394 }
1395
1396 void Internals::setUserPreferredLanguages(const Vector<String>& languages)
1397 {
1398     WebCore::overrideUserPreferredLanguages(languages);
1399 }
1400
1401 Vector<String> Internals::userPreferredAudioCharacteristics() const
1402 {
1403     Document* document = contextDocument();
1404     if (!document || !document->page())
1405         return Vector<String>();
1406 #if ENABLE(VIDEO_TRACK)
1407     return document->page()->group().captionPreferences().preferredAudioCharacteristics();
1408 #else
1409     return Vector<String>();
1410 #endif
1411 }
1412
1413 void Internals::setUserPreferredAudioCharacteristic(const String& characteristic)
1414 {
1415     Document* document = contextDocument();
1416     if (!document || !document->page())
1417         return;
1418 #if ENABLE(VIDEO_TRACK)
1419     document->page()->group().captionPreferences().setPreferredAudioCharacteristic(characteristic);
1420 #else
1421     UNUSED_PARAM(characteristic);
1422 #endif
1423 }
1424
1425 ExceptionOr<unsigned> Internals::wheelEventHandlerCount()
1426 {
1427     Document* document = contextDocument();
1428     if (!document)
1429         return Exception { INVALID_ACCESS_ERR };
1430
1431     return document->wheelEventHandlerCount();
1432 }
1433
1434 ExceptionOr<unsigned> Internals::touchEventHandlerCount()
1435 {
1436     Document* document = contextDocument();
1437     if (!document)
1438         return Exception { INVALID_ACCESS_ERR };
1439
1440     return document->touchEventHandlerCount();
1441 }
1442
1443 // FIXME: Remove the document argument. It is almost always the same as
1444 // contextDocument(), with the exception of a few tests that pass a
1445 // different document, and could just make the call through another Internals
1446 // instance instead.
1447 ExceptionOr<RefPtr<NodeList>> Internals::nodesFromRect(Document& document, int centerX, int centerY, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent, bool allowChildFrameContent) const
1448 {
1449     if (!document.frame() || !document.frame()->view())
1450         return Exception { INVALID_ACCESS_ERR };
1451
1452     Frame* frame = document.frame();
1453     FrameView* frameView = document.view();
1454     RenderView* renderView = document.renderView();
1455     if (!renderView)
1456         return nullptr;
1457
1458     document.updateLayoutIgnorePendingStylesheets();
1459
1460     float zoomFactor = frame->pageZoomFactor();
1461     LayoutPoint point(centerX * zoomFactor + frameView->scrollX(), centerY * zoomFactor + frameView->scrollY());
1462
1463     HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
1464     if (ignoreClipping)
1465         hitType |= HitTestRequest::IgnoreClipping;
1466     if (!allowShadowContent)
1467         hitType |= HitTestRequest::DisallowUserAgentShadowContent;
1468     if (allowChildFrameContent)
1469         hitType |= HitTestRequest::AllowChildFrameContent;
1470
1471     HitTestRequest request(hitType);
1472
1473     // When ignoreClipping is false, this method returns null for coordinates outside of the viewport.
1474     if (!request.ignoreClipping() && !frameView->visibleContentRect().intersects(HitTestLocation::rectForPoint(point, topPadding, rightPadding, bottomPadding, leftPadding)))
1475         return nullptr;
1476
1477     Vector<Ref<Node>> matches;
1478
1479     // Need padding to trigger a rect based hit test, but we want to return a NodeList
1480     // so we special case this.
1481     if (!topPadding && !rightPadding && !bottomPadding && !leftPadding) {
1482         HitTestResult result(point);
1483         renderView->hitTest(request, result);
1484         if (result.innerNode())
1485             matches.append(*result.innerNode()->deprecatedShadowAncestorNode());
1486     } else {
1487         HitTestResult result(point, topPadding, rightPadding, bottomPadding, leftPadding);
1488         renderView->hitTest(request, result);
1489         
1490         const HitTestResult::NodeSet& nodeSet = result.rectBasedTestResult();
1491         matches.reserveInitialCapacity(nodeSet.size());
1492         for (auto& node : nodeSet)
1493             matches.uncheckedAppend(*node);
1494     }
1495
1496     return RefPtr<NodeList> { StaticNodeList::create(WTFMove(matches)) };
1497 }
1498
1499 class GetCallerCodeBlockFunctor {
1500 public:
1501     GetCallerCodeBlockFunctor()
1502         : m_iterations(0)
1503         , m_codeBlock(0)
1504     {
1505     }
1506
1507     StackVisitor::Status operator()(StackVisitor& visitor) const
1508     {
1509         ++m_iterations;
1510         if (m_iterations < 2)
1511             return StackVisitor::Continue;
1512
1513         m_codeBlock = visitor->codeBlock();
1514         return StackVisitor::Done;
1515     }
1516
1517     CodeBlock* codeBlock() const { return m_codeBlock; }
1518
1519 private:
1520     mutable int m_iterations;
1521     mutable CodeBlock* m_codeBlock;
1522 };
1523
1524 String Internals::parserMetaData(JSC::JSValue code)
1525 {
1526     JSC::VM& vm = contextDocument()->vm();
1527     JSC::ExecState* exec = vm.topCallFrame;
1528     ScriptExecutable* executable;
1529
1530     if (!code || code.isNull() || code.isUndefined()) {
1531         GetCallerCodeBlockFunctor iter;
1532         exec->iterate(iter);
1533         CodeBlock* codeBlock = iter.codeBlock();
1534         executable = codeBlock->ownerScriptExecutable();
1535     } else if (code.isFunction()) {
1536         JSFunction* funcObj = JSC::jsCast<JSFunction*>(code.toObject(exec));
1537         executable = funcObj->jsExecutable();
1538     } else
1539         return String();
1540
1541     unsigned startLine = executable->firstLine();
1542     unsigned startColumn = executable->startColumn();
1543     unsigned endLine = executable->lastLine();
1544     unsigned endColumn = executable->endColumn();
1545
1546     StringBuilder result;
1547
1548     if (executable->isFunctionExecutable()) {
1549         FunctionExecutable* funcExecutable = reinterpret_cast<FunctionExecutable*>(executable);
1550         String inferredName = funcExecutable->inferredName().string();
1551         result.appendLiteral("function \"");
1552         result.append(inferredName);
1553         result.append('"');
1554     } else if (executable->isEvalExecutable())
1555         result.appendLiteral("eval");
1556     else if (executable->isModuleProgramExecutable())
1557         result.appendLiteral("module");
1558     else if (executable->isProgramExecutable())
1559         result.appendLiteral("program");
1560     else
1561         ASSERT_NOT_REACHED();
1562
1563     result.appendLiteral(" { ");
1564     result.appendNumber(startLine);
1565     result.append(':');
1566     result.appendNumber(startColumn);
1567     result.appendLiteral(" - ");
1568     result.appendNumber(endLine);
1569     result.append(':');
1570     result.appendNumber(endColumn);
1571     result.appendLiteral(" }");
1572
1573     return result.toString();
1574 }
1575
1576 ExceptionOr<void> Internals::setDeviceProximity(const String&, double value, double min, double max)
1577 {
1578     Document* document = contextDocument();
1579     if (!document || !document->page())
1580         return Exception { INVALID_ACCESS_ERR };
1581
1582 #if ENABLE(PROXIMITY_EVENTS)
1583     DeviceProximityController::from(document->page())->didChangeDeviceProximity(value, min, max);
1584 #else
1585     UNUSED_PARAM(value);
1586     UNUSED_PARAM(min);
1587     UNUSED_PARAM(max);
1588 #endif
1589     return { };
1590 }
1591
1592 void Internals::updateEditorUINowIfScheduled()
1593 {
1594     if (Document* document = contextDocument()) {
1595         if (Frame* frame = document->frame())
1596             frame->editor().updateEditorUINowIfScheduled();
1597     }
1598 }
1599
1600 bool Internals::hasSpellingMarker(int from, int length)
1601 {
1602     Document* document = contextDocument();
1603     if (!document || !document->frame())
1604         return false;
1605
1606     updateEditorUINowIfScheduled();
1607
1608     return document->frame()->editor().selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length);
1609 }
1610     
1611 bool Internals::hasAutocorrectedMarker(int from, int length)
1612 {
1613     Document* document = contextDocument();
1614     if (!document || !document->frame())
1615         return false;
1616
1617     updateEditorUINowIfScheduled();
1618
1619     return document->frame()->editor().selectionStartHasMarkerFor(DocumentMarker::Autocorrected, from, length);
1620 }
1621
1622 void Internals::setContinuousSpellCheckingEnabled(bool enabled)
1623 {
1624     if (!contextDocument() || !contextDocument()->frame())
1625         return;
1626
1627     if (enabled != contextDocument()->frame()->editor().isContinuousSpellCheckingEnabled())
1628         contextDocument()->frame()->editor().toggleContinuousSpellChecking();
1629 }
1630
1631 void Internals::setAutomaticQuoteSubstitutionEnabled(bool enabled)
1632 {
1633     if (!contextDocument() || !contextDocument()->frame())
1634         return;
1635
1636 #if USE(AUTOMATIC_TEXT_REPLACEMENT)
1637     if (enabled != contextDocument()->frame()->editor().isAutomaticQuoteSubstitutionEnabled())
1638         contextDocument()->frame()->editor().toggleAutomaticQuoteSubstitution();
1639 #else
1640     UNUSED_PARAM(enabled);
1641 #endif
1642 }
1643
1644 void Internals::setAutomaticLinkDetectionEnabled(bool enabled)
1645 {
1646     if (!contextDocument() || !contextDocument()->frame())
1647         return;
1648
1649 #if USE(AUTOMATIC_TEXT_REPLACEMENT)
1650     if (enabled != contextDocument()->frame()->editor().isAutomaticLinkDetectionEnabled())
1651         contextDocument()->frame()->editor().toggleAutomaticLinkDetection();
1652 #else
1653     UNUSED_PARAM(enabled);
1654 #endif
1655 }
1656
1657 void Internals::setAutomaticDashSubstitutionEnabled(bool enabled)
1658 {
1659     if (!contextDocument() || !contextDocument()->frame())
1660         return;
1661
1662 #if USE(AUTOMATIC_TEXT_REPLACEMENT)
1663     if (enabled != contextDocument()->frame()->editor().isAutomaticDashSubstitutionEnabled())
1664         contextDocument()->frame()->editor().toggleAutomaticDashSubstitution();
1665 #else
1666     UNUSED_PARAM(enabled);
1667 #endif
1668 }
1669
1670 void Internals::setAutomaticTextReplacementEnabled(bool enabled)
1671 {
1672     if (!contextDocument() || !contextDocument()->frame())
1673         return;
1674
1675 #if USE(AUTOMATIC_TEXT_REPLACEMENT)
1676     if (enabled != contextDocument()->frame()->editor().isAutomaticTextReplacementEnabled())
1677         contextDocument()->frame()->editor().toggleAutomaticTextReplacement();
1678 #else
1679     UNUSED_PARAM(enabled);
1680 #endif
1681 }
1682
1683 void Internals::setAutomaticSpellingCorrectionEnabled(bool enabled)
1684 {
1685     if (!contextDocument() || !contextDocument()->frame())
1686         return;
1687
1688 #if USE(AUTOMATIC_TEXT_REPLACEMENT)
1689     if (enabled != contextDocument()->frame()->editor().isAutomaticSpellingCorrectionEnabled())
1690         contextDocument()->frame()->editor().toggleAutomaticSpellingCorrection();
1691 #else
1692     UNUSED_PARAM(enabled);
1693 #endif
1694 }
1695
1696 void Internals::handleAcceptedCandidate(const String& candidate, unsigned location, unsigned length)
1697 {
1698     if (!contextDocument() || !contextDocument()->frame())
1699         return;
1700
1701     TextCheckingResult result;
1702     result.type = TextCheckingTypeNone;
1703     result.location = location;
1704     result.length = length;
1705     result.replacement = candidate;
1706     contextDocument()->frame()->editor().handleAcceptedCandidate(result);
1707 }
1708
1709 bool Internals::isOverwriteModeEnabled()
1710 {
1711     Document* document = contextDocument();
1712     if (!document || !document->frame())
1713         return false;
1714
1715     return document->frame()->editor().isOverwriteModeEnabled();
1716 }
1717
1718 void Internals::toggleOverwriteModeEnabled()
1719 {
1720     Document* document = contextDocument();
1721     if (!document || !document->frame())
1722         return;
1723
1724     document->frame()->editor().toggleOverwriteModeEnabled();
1725 }
1726
1727 unsigned Internals::countMatchesForText(const String& text, unsigned findOptions, const String& markMatches)
1728 {
1729     Document* document = contextDocument();
1730     if (!document || !document->frame())
1731         return 0;
1732
1733     bool mark = markMatches == "mark";
1734     return document->frame()->editor().countMatchesForText(text, nullptr, findOptions, 1000, mark, nullptr);
1735 }
1736
1737 unsigned Internals::countFindMatches(const String& text, unsigned findOptions)
1738 {
1739     Document* document = contextDocument();
1740     if (!document || !document->page())
1741         return 0;
1742
1743     return document->page()->countFindMatches(text, findOptions, 1000);
1744 }
1745
1746 unsigned Internals::numberOfLiveNodes() const
1747 {
1748     unsigned nodeCount = 0;
1749     for (auto* document : Document::allDocuments())
1750         nodeCount += document->referencingNodeCount();
1751     return nodeCount;
1752 }
1753
1754 unsigned Internals::numberOfLiveDocuments() const
1755 {
1756     return Document::allDocuments().size();
1757 }
1758
1759 RefPtr<DOMWindow> Internals::openDummyInspectorFrontend(const String& url)
1760 {
1761     Page* inspectedPage = contextDocument()->frame()->page();
1762     RefPtr<DOMWindow> window = inspectedPage->mainFrame().document()->domWindow();
1763     RefPtr<DOMWindow> frontendWindow = window->open(url, "", "", *window, *window);
1764     m_inspectorFrontend = std::make_unique<InspectorStubFrontend>(*inspectedPage, frontendWindow.copyRef());
1765
1766     return frontendWindow;
1767 }
1768
1769 void Internals::closeDummyInspectorFrontend()
1770 {
1771     m_inspectorFrontend = nullptr;
1772 }
1773
1774 ExceptionOr<void> Internals::setInspectorIsUnderTest(bool isUnderTest)
1775 {
1776     Page* page = contextDocument()->frame()->page();
1777     if (!page)
1778         return Exception { INVALID_ACCESS_ERR };
1779
1780     page->inspectorController().setIsUnderTest(isUnderTest);
1781     return { };
1782 }
1783
1784 bool Internals::hasGrammarMarker(int from, int length)
1785 {
1786     Document* document = contextDocument();
1787     if (!document || !document->frame())
1788         return false;
1789
1790     return document->frame()->editor().selectionStartHasMarkerFor(DocumentMarker::Grammar, from, length);
1791 }
1792
1793 unsigned Internals::numberOfScrollableAreas()
1794 {
1795     Document* document = contextDocument();
1796     if (!document || !document->frame())
1797         return 0;
1798
1799     unsigned count = 0;
1800     Frame* frame = document->frame();
1801     if (frame->view()->scrollableAreas())
1802         count += frame->view()->scrollableAreas()->size();
1803
1804     for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
1805         if (child->view() && child->view()->scrollableAreas())
1806             count += child->view()->scrollableAreas()->size();
1807     }
1808
1809     return count;
1810 }
1811     
1812 ExceptionOr<bool> Internals::isPageBoxVisible(int pageNumber)
1813 {
1814     Document* document = contextDocument();
1815     if (!document)
1816         return Exception { INVALID_ACCESS_ERR };
1817
1818     return document->isPageBoxVisible(pageNumber);
1819 }
1820
1821 // FIXME: Remove the document argument. It is almost always the same as
1822 // contextDocument(), with the exception of a few tests that pass a
1823 // different document, and could just make the call through another Internals
1824 // instance instead.
1825 ExceptionOr<String> Internals::layerTreeAsText(Document& document, unsigned short flags) const
1826 {
1827     if (!document.frame())
1828         return Exception { INVALID_ACCESS_ERR };
1829
1830     LayerTreeFlags layerTreeFlags = 0;
1831     if (flags & LAYER_TREE_INCLUDES_VISIBLE_RECTS)
1832         layerTreeFlags |= LayerTreeFlagsIncludeVisibleRects;
1833     if (flags & LAYER_TREE_INCLUDES_TILE_CACHES)
1834         layerTreeFlags |= LayerTreeFlagsIncludeTileCaches;
1835     if (flags & LAYER_TREE_INCLUDES_REPAINT_RECTS)
1836         layerTreeFlags |= LayerTreeFlagsIncludeRepaintRects;
1837     if (flags & LAYER_TREE_INCLUDES_PAINTING_PHASES)
1838         layerTreeFlags |= LayerTreeFlagsIncludePaintingPhases;
1839     if (flags & LAYER_TREE_INCLUDES_CONTENT_LAYERS)
1840         layerTreeFlags |= LayerTreeFlagsIncludeContentLayers;
1841
1842     return document.frame()->layerTreeAsText(layerTreeFlags);
1843 }
1844
1845 ExceptionOr<String> Internals::repaintRectsAsText() const
1846 {
1847     Document* document = contextDocument();
1848     if (!document || !document->frame())
1849         return Exception { INVALID_ACCESS_ERR };
1850
1851     return document->frame()->trackedRepaintRectsAsText();
1852 }
1853
1854 ExceptionOr<String> Internals::scrollingStateTreeAsText() const
1855 {
1856     Document* document = contextDocument();
1857     if (!document || !document->frame())
1858         return Exception { INVALID_ACCESS_ERR };
1859
1860     Page* page = document->page();
1861     if (!page)
1862         return String();
1863
1864     return page->scrollingStateTreeAsText();
1865 }
1866
1867 ExceptionOr<String> Internals::mainThreadScrollingReasons() const
1868 {
1869     Document* document = contextDocument();
1870     if (!document || !document->frame())
1871         return Exception { INVALID_ACCESS_ERR };
1872
1873     Page* page = document->page();
1874     if (!page)
1875         return String();
1876
1877     return page->synchronousScrollingReasonsAsText();
1878 }
1879
1880 ExceptionOr<RefPtr<ClientRectList>> Internals::nonFastScrollableRects() const
1881 {
1882     Document* document = contextDocument();
1883     if (!document || !document->frame())
1884         return Exception { INVALID_ACCESS_ERR };
1885
1886     Page* page = document->page();
1887     if (!page)
1888         return nullptr;
1889
1890     return RefPtr<ClientRectList> { page->nonFastScrollableRects() };
1891 }
1892
1893 ExceptionOr<void> Internals::setElementUsesDisplayListDrawing(Element& element, bool usesDisplayListDrawing)
1894 {
1895     Document* document = contextDocument();
1896     if (!document || !document->renderView())
1897         return Exception { INVALID_ACCESS_ERR };
1898
1899     if (!element.renderer())
1900         return Exception { INVALID_ACCESS_ERR };
1901
1902     if (is<HTMLCanvasElement>(element)) {
1903         downcast<HTMLCanvasElement>(element).setUsesDisplayListDrawing(usesDisplayListDrawing);
1904         return { };
1905     }
1906
1907     if (!element.renderer()->hasLayer())
1908         return Exception { INVALID_ACCESS_ERR };
1909     
1910     RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
1911     if (!layer->isComposited())
1912         return Exception { INVALID_ACCESS_ERR };
1913     
1914     layer->backing()->setUsesDisplayListDrawing(usesDisplayListDrawing);
1915     return { };
1916 }
1917
1918 ExceptionOr<void> Internals::setElementTracksDisplayListReplay(Element& element, bool isTrackingReplay)
1919 {
1920     Document* document = contextDocument();
1921     if (!document || !document->renderView())
1922         return Exception { INVALID_ACCESS_ERR };
1923
1924     if (!element.renderer())
1925         return Exception { INVALID_ACCESS_ERR };
1926
1927     if (is<HTMLCanvasElement>(element)) {
1928         downcast<HTMLCanvasElement>(element).setTracksDisplayListReplay(isTrackingReplay);
1929         return { };
1930     }
1931
1932     if (!element.renderer()->hasLayer())
1933         return Exception { INVALID_ACCESS_ERR };
1934
1935     RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
1936     if (!layer->isComposited())
1937         return Exception { INVALID_ACCESS_ERR };
1938     
1939     layer->backing()->setIsTrackingDisplayListReplay(isTrackingReplay);
1940     return { };
1941 }
1942
1943 ExceptionOr<String> Internals::displayListForElement(Element& element, unsigned short flags)
1944 {
1945     Document* document = contextDocument();
1946     if (!document || !document->renderView())
1947         return Exception { INVALID_ACCESS_ERR };
1948
1949     if (!element.renderer())
1950         return Exception { INVALID_ACCESS_ERR };
1951
1952     DisplayList::AsTextFlags displayListFlags = 0;
1953     if (flags & DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS)
1954         displayListFlags |= DisplayList::AsTextFlag::IncludesPlatformOperations;
1955
1956     if (is<HTMLCanvasElement>(element))
1957         return downcast<HTMLCanvasElement>(element).displayListAsText(displayListFlags);
1958
1959     if (!element.renderer()->hasLayer())
1960         return Exception { INVALID_ACCESS_ERR };
1961
1962     RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
1963     if (!layer->isComposited())
1964         return Exception { INVALID_ACCESS_ERR };
1965
1966     return layer->backing()->displayListAsText(displayListFlags);
1967 }
1968
1969 ExceptionOr<String> Internals::replayDisplayListForElement(Element& element, unsigned short flags)
1970 {
1971     Document* document = contextDocument();
1972     if (!document || !document->renderView())
1973         return Exception { INVALID_ACCESS_ERR };
1974
1975     if (!element.renderer())
1976         return Exception { INVALID_ACCESS_ERR };
1977
1978     DisplayList::AsTextFlags displayListFlags = 0;
1979     if (flags & DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS)
1980         displayListFlags |= DisplayList::AsTextFlag::IncludesPlatformOperations;
1981
1982     if (is<HTMLCanvasElement>(element))
1983         return downcast<HTMLCanvasElement>(element).replayDisplayListAsText(displayListFlags);
1984
1985     if (!element.renderer()->hasLayer())
1986         return Exception { INVALID_ACCESS_ERR };
1987
1988     RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer();
1989     if (!layer->isComposited())
1990         return Exception { INVALID_ACCESS_ERR };
1991
1992     return layer->backing()->replayDisplayListAsText(displayListFlags);
1993 }
1994
1995 ExceptionOr<void> Internals::garbageCollectDocumentResources() const
1996 {
1997     Document* document = contextDocument();
1998     if (!document)
1999         return Exception { INVALID_ACCESS_ERR };
2000     document->cachedResourceLoader().garbageCollectDocumentResources();
2001     return { };
2002 }
2003
2004 bool Internals::isUnderMemoryPressure()
2005 {
2006     return MemoryPressureHandler::singleton().isUnderMemoryPressure();
2007 }
2008
2009 void Internals::beginSimulatedMemoryPressure()
2010 {
2011     MemoryPressureHandler::singleton().beginSimulatedMemoryPressure();
2012 }
2013
2014 void Internals::endSimulatedMemoryPressure()
2015 {
2016     MemoryPressureHandler::singleton().endSimulatedMemoryPressure();
2017 }
2018
2019 ExceptionOr<void> Internals::insertAuthorCSS(const String& css) const
2020 {
2021     Document* document = contextDocument();
2022     if (!document)
2023         return Exception { INVALID_ACCESS_ERR };
2024
2025     auto parsedSheet = StyleSheetContents::create(*document);
2026     parsedSheet.get().setIsUserStyleSheet(false);
2027     parsedSheet.get().parseString(css);
2028     document->extensionStyleSheets().addAuthorStyleSheetForTesting(WTFMove(parsedSheet));
2029     return { };
2030 }
2031
2032 ExceptionOr<void> Internals::insertUserCSS(const String& css) const
2033 {
2034     Document* document = contextDocument();
2035     if (!document)
2036         return Exception { INVALID_ACCESS_ERR };
2037
2038     auto parsedSheet = StyleSheetContents::create(*document);
2039     parsedSheet.get().setIsUserStyleSheet(true);
2040     parsedSheet.get().parseString(css);
2041     document->extensionStyleSheets().addUserStyleSheet(WTFMove(parsedSheet));
2042     return { };
2043 }
2044
2045 String Internals::counterValue(Element& element)
2046 {
2047     return counterValueForElement(&element);
2048 }
2049
2050 int Internals::pageNumber(Element& element, float pageWidth, float pageHeight)
2051 {
2052     return PrintContext::pageNumberForElement(&element, { pageWidth, pageHeight });
2053 }
2054
2055 Vector<String> Internals::shortcutIconURLs() const
2056 {
2057     Vector<String> vector;
2058
2059     if (!frame())
2060         return vector;
2061
2062     auto string = frame()->loader().icon().url().string();
2063     if (!string.isNull())
2064         vector.append(string);
2065     return vector;
2066 }
2067
2068 int Internals::numberOfPages(float pageWidth, float pageHeight)
2069 {
2070     if (!frame())
2071         return -1;
2072
2073     return PrintContext::numberOfPages(*frame(), FloatSize(pageWidth, pageHeight));
2074 }
2075
2076 ExceptionOr<String> Internals::pageProperty(const String& propertyName, int pageNumber) const
2077 {
2078     if (!frame())
2079         return Exception { INVALID_ACCESS_ERR };
2080
2081     return PrintContext::pageProperty(frame(), propertyName.utf8().data(), pageNumber);
2082 }
2083
2084 ExceptionOr<String> Internals::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const
2085 {
2086     if (!frame())
2087         return Exception { INVALID_ACCESS_ERR };
2088
2089     return PrintContext::pageSizeAndMarginsInPixels(frame(), pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft);
2090 }
2091
2092 ExceptionOr<float> Internals::pageScaleFactor() const
2093 {
2094     Document* document = contextDocument();
2095     if (!document || !document->page())
2096         return Exception { INVALID_ACCESS_ERR };
2097
2098     return document->page()->pageScaleFactor();
2099 }
2100
2101 ExceptionOr<void> Internals::setPageScaleFactor(float scaleFactor, int x, int y)
2102 {
2103     Document* document = contextDocument();
2104     if (!document || !document->page())
2105         return Exception { INVALID_ACCESS_ERR };
2106
2107     document->page()->setPageScaleFactor(scaleFactor, IntPoint(x, y));
2108     return { };
2109 }
2110
2111 ExceptionOr<void> Internals::setPageZoomFactor(float zoomFactor)
2112 {
2113     Document* document = contextDocument();
2114     if (!document || !document->frame())
2115         return Exception { INVALID_ACCESS_ERR };
2116
2117     document->frame()->setPageZoomFactor(zoomFactor);
2118     return { };
2119 }
2120
2121 ExceptionOr<void> Internals::setTextZoomFactor(float zoomFactor)
2122 {
2123     Document* document = contextDocument();
2124     if (!document || !document->frame())
2125         return Exception { INVALID_ACCESS_ERR };
2126
2127     document->frame()->setTextZoomFactor(zoomFactor);
2128     return { };
2129 }
2130
2131 ExceptionOr<void> Internals::setUseFixedLayout(bool useFixedLayout)
2132 {
2133     Document* document = contextDocument();
2134     if (!document || !document->view())
2135         return Exception { INVALID_ACCESS_ERR };
2136
2137     document->view()->setUseFixedLayout(useFixedLayout);
2138     return { };
2139 }
2140
2141 ExceptionOr<void> Internals::setFixedLayoutSize(int width, int height)
2142 {
2143     Document* document = contextDocument();
2144     if (!document || !document->view())
2145         return Exception { INVALID_ACCESS_ERR };
2146
2147     document->view()->setFixedLayoutSize(IntSize(width, height));
2148     return { };
2149 }
2150
2151 ExceptionOr<void> Internals::setViewExposedRect(float x, float y, float width, float height)
2152 {
2153     Document* document = contextDocument();
2154     if (!document || !document->view())
2155         return Exception { INVALID_ACCESS_ERR };
2156
2157     document->view()->setViewExposedRect(FloatRect(x, y, width, height));
2158     return { };
2159 }
2160
2161 void Internals::setHeaderHeight(float height)
2162 {
2163     Document* document = contextDocument();
2164     if (!document || !document->view())
2165         return;
2166
2167     document->view()->setHeaderHeight(height);
2168 }
2169
2170 void Internals::setFooterHeight(float height)
2171 {
2172     Document* document = contextDocument();
2173     if (!document || !document->view())
2174         return;
2175
2176     document->view()->setFooterHeight(height);
2177 }
2178     
2179 void Internals::setTopContentInset(float contentInset)
2180 {
2181     Document* document = contextDocument();
2182     if (!document || !document->page())
2183         return;
2184
2185     document->page()->setTopContentInset(contentInset);
2186 }
2187
2188 #if ENABLE(FULLSCREEN_API)
2189
2190 void Internals::webkitWillEnterFullScreenForElement(Element& element)
2191 {
2192     Document* document = contextDocument();
2193     if (!document)
2194         return;
2195     document->webkitWillEnterFullScreenForElement(&element);
2196 }
2197
2198 void Internals::webkitDidEnterFullScreenForElement(Element& element)
2199 {
2200     Document* document = contextDocument();
2201     if (!document)
2202         return;
2203     document->webkitDidEnterFullScreenForElement(&element);
2204 }
2205
2206 void Internals::webkitWillExitFullScreenForElement(Element& element)
2207 {
2208     Document* document = contextDocument();
2209     if (!document)
2210         return;
2211     document->webkitWillExitFullScreenForElement(&element);
2212 }
2213
2214 void Internals::webkitDidExitFullScreenForElement(Element& element)
2215 {
2216     Document* document = contextDocument();
2217     if (!document)
2218         return;
2219     document->webkitDidExitFullScreenForElement(&element);
2220 }
2221
2222 #endif
2223
2224 void Internals::setApplicationCacheOriginQuota(unsigned long long quota)
2225 {
2226     Document* document = contextDocument();
2227     if (!document || !document->page())
2228         return;
2229     document->page()->applicationCacheStorage().storeUpdatedQuotaForOrigin(document->securityOrigin(), quota);
2230 }
2231
2232 void Internals::registerURLSchemeAsBypassingContentSecurityPolicy(const String& scheme)
2233 {
2234     SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(scheme);
2235 }
2236
2237 void Internals::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(const String& scheme)
2238 {
2239     SchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(scheme);
2240 }
2241
2242 void Internals::registerDefaultPortForProtocol(unsigned short port, const String& protocol)
2243 {
2244     registerDefaultPortForProtocolForTesting(port, protocol);
2245 }
2246
2247 Ref<MallocStatistics> Internals::mallocStatistics() const
2248 {
2249     return MallocStatistics::create();
2250 }
2251
2252 Ref<TypeConversions> Internals::typeConversions() const
2253 {
2254     return TypeConversions::create();
2255 }
2256
2257 Ref<MemoryInfo> Internals::memoryInfo() const
2258 {
2259     return MemoryInfo::create();
2260 }
2261
2262 Vector<String> Internals::getReferencedFilePaths() const
2263 {
2264     frame()->loader().history().saveDocumentAndScrollState();
2265     return FormController::getReferencedFilePaths(frame()->loader().history().currentItem()->documentState());
2266 }
2267
2268 ExceptionOr<void> Internals::startTrackingRepaints()
2269 {
2270     Document* document = contextDocument();
2271     if (!document || !document->view())
2272         return Exception { INVALID_ACCESS_ERR };
2273
2274     document->view()->setTracksRepaints(true);
2275     return { };
2276 }
2277
2278 ExceptionOr<void> Internals::stopTrackingRepaints()
2279 {
2280     Document* document = contextDocument();
2281     if (!document || !document->view())
2282         return Exception { INVALID_ACCESS_ERR };
2283
2284     document->view()->setTracksRepaints(false);
2285     return { };
2286 }
2287
2288 ExceptionOr<void> Internals::startTrackingLayerFlushes()
2289 {
2290     Document* document = contextDocument();
2291     if (!document || !document->renderView())
2292         return Exception { INVALID_ACCESS_ERR };
2293
2294     document->renderView()->compositor().startTrackingLayerFlushes();
2295     return { };
2296 }
2297
2298 ExceptionOr<unsigned> Internals::layerFlushCount()
2299 {
2300     Document* document = contextDocument();
2301     if (!document || !document->renderView())
2302         return Exception { INVALID_ACCESS_ERR };
2303
2304     return document->renderView()->compositor().layerFlushCount();
2305 }
2306
2307 ExceptionOr<void> Internals::startTrackingStyleRecalcs()
2308 {
2309     Document* document = contextDocument();
2310     if (!document)
2311         return Exception { INVALID_ACCESS_ERR };
2312
2313     document->startTrackingStyleRecalcs();
2314     return { };
2315 }
2316
2317 ExceptionOr<unsigned> Internals::styleRecalcCount()
2318 {
2319     Document* document = contextDocument();
2320     if (!document)
2321         return Exception { INVALID_ACCESS_ERR };
2322     
2323     return document->styleRecalcCount();
2324 }
2325
2326 unsigned Internals::lastStyleUpdateSize() const
2327 {
2328     Document* document = contextDocument();
2329     if (!document)
2330         return 0;
2331     return document->lastStyleUpdateSizeForTesting();
2332 }
2333
2334 ExceptionOr<void> Internals::startTrackingCompositingUpdates()
2335 {
2336     Document* document = contextDocument();
2337     if (!document || !document->renderView())
2338         return Exception { INVALID_ACCESS_ERR };
2339
2340     document->renderView()->compositor().startTrackingCompositingUpdates();
2341     return { };
2342 }
2343
2344 ExceptionOr<unsigned> Internals::compositingUpdateCount()
2345 {
2346     Document* document = contextDocument();
2347     if (!document || !document->renderView())
2348         return Exception { INVALID_ACCESS_ERR };
2349     
2350     return document->renderView()->compositor().compositingUpdateCount();
2351 }
2352
2353 ExceptionOr<void> Internals::updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node* node)
2354 {
2355     Document* document;
2356     if (!node)
2357         document = contextDocument();
2358     else if (is<Document>(*node))
2359         document = downcast<Document>(node);
2360     else if (is<HTMLIFrameElement>(*node))
2361         document = downcast<HTMLIFrameElement>(*node).contentDocument();
2362     else
2363         return Exception { TypeError };
2364
2365     document->updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks::Synchronously);
2366     return { };
2367 }
2368
2369 unsigned Internals::layoutCount() const
2370 {
2371     Document* document = contextDocument();
2372     if (!document || !document->view())
2373         return 0;
2374     return document->view()->layoutCount();
2375 }
2376
2377 #if !PLATFORM(IOS)
2378 static const char* cursorTypeToString(Cursor::Type cursorType)
2379 {
2380     switch (cursorType) {
2381     case Cursor::Pointer: return "Pointer";
2382     case Cursor::Cross: return "Cross";
2383     case Cursor::Hand: return "Hand";
2384     case Cursor::IBeam: return "IBeam";
2385     case Cursor::Wait: return "Wait";
2386     case Cursor::Help: return "Help";
2387     case Cursor::EastResize: return "EastResize";
2388     case Cursor::NorthResize: return "NorthResize";
2389     case Cursor::NorthEastResize: return "NorthEastResize";
2390     case Cursor::NorthWestResize: return "NorthWestResize";
2391     case Cursor::SouthResize: return "SouthResize";
2392     case Cursor::SouthEastResize: return "SouthEastResize";
2393     case Cursor::SouthWestResize: return "SouthWestResize";
2394     case Cursor::WestResize: return "WestResize";
2395     case Cursor::NorthSouthResize: return "NorthSouthResize";
2396     case Cursor::EastWestResize: return "EastWestResize";
2397     case Cursor::NorthEastSouthWestResize: return "NorthEastSouthWestResize";
2398     case Cursor::NorthWestSouthEastResize: return "NorthWestSouthEastResize";
2399     case Cursor::ColumnResize: return "ColumnResize";
2400     case Cursor::RowResize: return "RowResize";
2401     case Cursor::MiddlePanning: return "MiddlePanning";
2402     case Cursor::EastPanning: return "EastPanning";
2403     case Cursor::NorthPanning: return "NorthPanning";
2404     case Cursor::NorthEastPanning: return "NorthEastPanning";
2405     case Cursor::NorthWestPanning: return "NorthWestPanning";
2406     case Cursor::SouthPanning: return "SouthPanning";
2407     case Cursor::SouthEastPanning: return "SouthEastPanning";
2408     case Cursor::SouthWestPanning: return "SouthWestPanning";
2409     case Cursor::WestPanning: return "WestPanning";
2410     case Cursor::Move: return "Move";
2411     case Cursor::VerticalText: return "VerticalText";
2412     case Cursor::Cell: return "Cell";
2413     case Cursor::ContextMenu: return "ContextMenu";
2414     case Cursor::Alias: return "Alias";
2415     case Cursor::Progress: return "Progress";
2416     case Cursor::NoDrop: return "NoDrop";
2417     case Cursor::Copy: return "Copy";
2418     case Cursor::None: return "None";
2419     case Cursor::NotAllowed: return "NotAllowed";
2420     case Cursor::ZoomIn: return "ZoomIn";
2421     case Cursor::ZoomOut: return "ZoomOut";
2422     case Cursor::Grab: return "Grab";
2423     case Cursor::Grabbing: return "Grabbing";
2424     case Cursor::Custom: return "Custom";
2425     }
2426
2427     ASSERT_NOT_REACHED();
2428     return "UNKNOWN";
2429 }
2430 #endif
2431
2432 ExceptionOr<String> Internals::getCurrentCursorInfo()
2433 {
2434     Document* document = contextDocument();
2435     if (!document || !document->frame())
2436         return Exception { INVALID_ACCESS_ERR };
2437
2438 #if !PLATFORM(IOS)
2439     Cursor cursor = document->frame()->eventHandler().currentMouseCursor();
2440
2441     StringBuilder result;
2442     result.appendLiteral("type=");
2443     result.append(cursorTypeToString(cursor.type()));
2444     result.appendLiteral(" hotSpot=");
2445     result.appendNumber(cursor.hotSpot().x());
2446     result.append(',');
2447     result.appendNumber(cursor.hotSpot().y());
2448     if (cursor.image()) {
2449         FloatSize size = cursor.image()->size();
2450         result.appendLiteral(" image=");
2451         result.appendNumber(size.width());
2452         result.append('x');
2453         result.appendNumber(size.height());
2454     }
2455 #if ENABLE(MOUSE_CURSOR_SCALE)
2456     if (cursor.imageScaleFactor() != 1) {
2457         result.appendLiteral(" scale=");
2458         NumberToStringBuffer buffer;
2459         result.append(numberToFixedPrecisionString(cursor.imageScaleFactor(), 8, buffer, true));
2460     }
2461 #endif
2462     return result.toString();
2463 #else
2464     return String { "FAIL: Cursor details not available on this platform." };
2465 #endif
2466 }
2467
2468 RefPtr<ArrayBuffer> Internals::serializeObject(PassRefPtr<SerializedScriptValue> value) const
2469 {
2470     auto& bytes = value->data();
2471     return ArrayBuffer::create(bytes.data(), bytes.size());
2472 }
2473
2474 RefPtr<SerializedScriptValue> Internals::deserializeBuffer(ArrayBuffer& buffer) const
2475 {
2476     Vector<uint8_t> bytes;
2477     bytes.append(static_cast<const uint8_t*>(buffer.data()), buffer.byteLength());
2478     return SerializedScriptValue::adopt(WTFMove(bytes));
2479 }
2480
2481 bool Internals::isFromCurrentWorld(JSC::JSValue value) const
2482 {
2483     ASSERT(value);
2484     JSC::ExecState& state = *contextDocument()->vm().topCallFrame;
2485     return !value.isObject() || &worldForDOMObject(asObject(value)) == &currentWorld(&state);
2486 }
2487
2488 void Internals::setUsesOverlayScrollbars(bool enabled)
2489 {
2490     WebCore::Settings::setUsesOverlayScrollbars(enabled);
2491 }
2492
2493 void Internals::setUsesMockScrollAnimator(bool enabled)
2494 {
2495     WebCore::Settings::setUsesMockScrollAnimator(enabled);
2496 }
2497
2498 void Internals::forceReload(bool endToEnd)
2499 {
2500     frame()->loader().reload(endToEnd);
2501 }
2502
2503 void Internals::enableAutoSizeMode(bool enabled, int minimumWidth, int minimumHeight, int maximumWidth, int maximumHeight)
2504 {
2505     Document* document = contextDocument();
2506     if (!document || !document->view())
2507         return;
2508     document->view()->enableAutoSizeMode(enabled, IntSize(minimumWidth, minimumHeight), IntSize(maximumWidth, maximumHeight));
2509 }
2510
2511 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
2512 void Internals::initializeMockCDM()
2513 {
2514     CDM::registerCDMFactory([](CDM* cdm) { return std::make_unique<MockCDM>(cdm); },
2515         MockCDM::supportsKeySystem, MockCDM::supportsKeySystemAndMimeType);
2516 }
2517 #endif
2518
2519 String Internals::markerTextForListItem(Element& element)
2520 {
2521     return WebCore::markerTextForListItem(&element);
2522 }
2523
2524 String Internals::toolTipFromElement(Element& element) const
2525 {
2526     HitTestResult result;
2527     result.setInnerNode(&element);
2528     TextDirection direction;
2529     return result.title(direction);
2530 }
2531
2532 String Internals::getImageSourceURL(Element& element)
2533 {
2534     return element.imageSourceURL();
2535 }
2536
2537 #if ENABLE(VIDEO)
2538
2539 void Internals::simulateAudioInterruption(HTMLMediaElement& element)
2540 {
2541 #if USE(GSTREAMER)
2542     element.player()->simulateAudioInterruption();
2543 #else
2544     UNUSED_PARAM(element);
2545 #endif
2546 }
2547
2548 ExceptionOr<bool> Internals::mediaElementHasCharacteristic(HTMLMediaElement& element, const String& characteristic)
2549 {
2550     if (equalLettersIgnoringASCIICase(characteristic, "audible"))
2551         return element.hasAudio();
2552     if (equalLettersIgnoringASCIICase(characteristic, "visual"))
2553         return element.hasVideo();
2554     if (equalLettersIgnoringASCIICase(characteristic, "legible"))
2555         return element.hasClosedCaptions();
2556
2557     return Exception { SYNTAX_ERR };
2558 }
2559
2560 #endif
2561
2562 bool Internals::isSelectPopupVisible(HTMLSelectElement& element)
2563 {
2564     auto* renderer = element.renderer();
2565     ASSERT(renderer);
2566     if (!is<RenderMenuList>(*renderer))
2567         return false;
2568
2569 #if !PLATFORM(IOS)
2570     return downcast<RenderMenuList>(*renderer).popupIsVisible();
2571 #else
2572     return false;
2573 #endif
2574 }
2575
2576 ExceptionOr<String> Internals::captionsStyleSheetOverride()
2577 {
2578     Document* document = contextDocument();
2579     if (!document || !document->page())
2580         return Exception { INVALID_ACCESS_ERR };
2581
2582 #if ENABLE(VIDEO_TRACK)
2583     return document->page()->group().captionPreferences().captionsStyleSheetOverride();
2584 #else
2585     return String { emptyString() };
2586 #endif
2587 }
2588
2589 ExceptionOr<void> Internals::setCaptionsStyleSheetOverride(const String& override)
2590 {
2591     Document* document = contextDocument();
2592     if (!document || !document->page())
2593         return Exception { INVALID_ACCESS_ERR };
2594
2595 #if ENABLE(VIDEO_TRACK)
2596     document->page()->group().captionPreferences().setCaptionsStyleSheetOverride(override);
2597 #else
2598     UNUSED_PARAM(override);
2599 #endif
2600     return { };
2601 }
2602
2603 ExceptionOr<void> Internals::setPrimaryAudioTrackLanguageOverride(const String& language)
2604 {
2605     Document* document = contextDocument();
2606     if (!document || !document->page())
2607         return Exception { INVALID_ACCESS_ERR };
2608
2609 #if ENABLE(VIDEO_TRACK)
2610     document->page()->group().captionPreferences().setPrimaryAudioTrackLanguageOverride(language);
2611 #else
2612     UNUSED_PARAM(language);
2613 #endif
2614     return { };
2615 }
2616
2617 ExceptionOr<void> Internals::setCaptionDisplayMode(const String& mode)
2618 {
2619     Document* document = contextDocument();
2620     if (!document || !document->page())
2621         return Exception { INVALID_ACCESS_ERR };
2622     
2623 #if ENABLE(VIDEO_TRACK)
2624     auto& captionPreferences = document->page()->group().captionPreferences();
2625     
2626     if (equalLettersIgnoringASCIICase(mode, "automatic"))
2627         captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::Automatic);
2628     else if (equalLettersIgnoringASCIICase(mode, "forcedonly"))
2629         captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::ForcedOnly);
2630     else if (equalLettersIgnoringASCIICase(mode, "alwayson"))
2631         captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::AlwaysOn);
2632     else if (equalLettersIgnoringASCIICase(mode, "manual"))
2633         captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::Manual);
2634     else
2635         return Exception { SYNTAX_ERR };
2636 #else
2637     UNUSED_PARAM(mode);
2638 #endif
2639     return { };
2640 }
2641
2642 #if ENABLE(VIDEO)
2643
2644 Ref<TimeRanges> Internals::createTimeRanges(Float32Array& startTimes, Float32Array& endTimes)
2645 {
2646     ASSERT(startTimes.length() == endTimes.length());
2647     Ref<TimeRanges> ranges = TimeRanges::create();
2648
2649     unsigned count = std::min(startTimes.length(), endTimes.length());
2650     for (unsigned i = 0; i < count; ++i)
2651         ranges->add(startTimes.item(i), endTimes.item(i));
2652     return ranges;
2653 }
2654
2655 double Internals::closestTimeToTimeRanges(double time, TimeRanges& ranges)
2656 {
2657     return ranges.nearest(time);
2658 }
2659
2660 #endif
2661
2662 ExceptionOr<Ref<ClientRect>> Internals::selectionBounds()
2663 {
2664     Document* document = contextDocument();
2665     if (!document || !document->frame())
2666         return Exception { INVALID_ACCESS_ERR };
2667
2668     return ClientRect::create(document->frame()->selection().selectionBounds());
2669 }
2670
2671 #if ENABLE(VIBRATION)
2672
2673 bool Internals::isVibrating()
2674 {
2675     auto* document = contextDocument();
2676     auto* page = document ? document->page() : nullptr;
2677     return page && Vibration::from(page)->isVibrating();
2678 }
2679
2680 #endif
2681
2682 ExceptionOr<bool> Internals::isPluginUnavailabilityIndicatorObscured(Element& element)
2683 {
2684     auto* renderer = element.renderer();
2685     if (!is<RenderEmbeddedObject>(renderer))
2686         return Exception { INVALID_ACCESS_ERR };
2687
2688     return downcast<RenderEmbeddedObject>(*renderer).isReplacementObscured();
2689 }
2690     
2691 bool Internals::isPluginSnapshotted(Element& element)
2692 {
2693     return is<HTMLPlugInElement>(element) && downcast<HTMLPlugInElement>(element).displayState() <= HTMLPlugInElement::DisplayingSnapshot;
2694 }
2695     
2696 #if ENABLE(MEDIA_SOURCE)
2697
2698 void Internals::initializeMockMediaSource()
2699 {
2700 #if USE(AVFOUNDATION)
2701     WebCore::Settings::setAVFoundationEnabled(false);
2702 #endif
2703     MediaPlayerFactorySupport::callRegisterMediaEngine(MockMediaPlayerMediaSource::registerMediaEngine);
2704 }
2705
2706 Vector<String> Internals::bufferedSamplesForTrackID(SourceBuffer& buffer, const AtomicString& trackID)
2707 {
2708     return buffer.bufferedSamplesForTrackID(trackID);
2709 }
2710     
2711 Vector<String> Internals::enqueuedSamplesForTrackID(SourceBuffer& buffer, const AtomicString& trackID)
2712 {
2713     return buffer.enqueuedSamplesForTrackID(trackID);
2714 }
2715
2716 void Internals::setShouldGenerateTimestamps(SourceBuffer& buffer, bool flag)
2717 {
2718     buffer.setShouldGenerateTimestamps(flag);
2719 }
2720
2721 #endif
2722
2723 #if ENABLE(VIDEO)
2724
2725 ExceptionOr<void> Internals::beginMediaSessionInterruption(const String& interruptionString)
2726 {
2727     PlatformMediaSession::InterruptionType interruption = PlatformMediaSession::SystemInterruption;
2728
2729     if (equalLettersIgnoringASCIICase(interruptionString, "system"))
2730         interruption = PlatformMediaSession::SystemInterruption;
2731     else if (equalLettersIgnoringASCIICase(interruptionString, "systemsleep"))
2732         interruption = PlatformMediaSession::SystemSleep;
2733     else if (equalLettersIgnoringASCIICase(interruptionString, "enteringbackground"))
2734         interruption = PlatformMediaSession::EnteringBackground;
2735     else if (equalLettersIgnoringASCIICase(interruptionString, "suspendedunderlock"))
2736         interruption = PlatformMediaSession::SuspendedUnderLock;
2737     else
2738         return Exception { INVALID_ACCESS_ERR };
2739
2740     PlatformMediaSessionManager::sharedManager().beginInterruption(interruption);
2741     return { };
2742 }
2743
2744 void Internals::endMediaSessionInterruption(const String& flagsString)
2745 {
2746     PlatformMediaSession::EndInterruptionFlags flags = PlatformMediaSession::NoFlags;
2747
2748     if (equalLettersIgnoringASCIICase(flagsString, "mayresumeplaying"))
2749         flags = PlatformMediaSession::MayResumePlaying;
2750     
2751     PlatformMediaSessionManager::sharedManager().endInterruption(flags);
2752 }
2753
2754 void Internals::applicationDidEnterForeground() const
2755 {
2756     PlatformMediaSessionManager::sharedManager().applicationDidEnterForeground();
2757 }
2758
2759 void Internals::applicationWillEnterBackground() const
2760 {
2761     PlatformMediaSessionManager::sharedManager().applicationWillEnterBackground();
2762 }
2763
2764 static PlatformMediaSession::MediaType mediaTypeFromString(const String& mediaTypeString)
2765 {
2766     if (equalLettersIgnoringASCIICase(mediaTypeString, "video"))
2767         return PlatformMediaSession::Video;
2768     if (equalLettersIgnoringASCIICase(mediaTypeString, "audio"))
2769         return PlatformMediaSession::Audio;
2770     if (equalLettersIgnoringASCIICase(mediaTypeString, "videoaudio"))
2771         return PlatformMediaSession::VideoAudio;
2772     if (equalLettersIgnoringASCIICase(mediaTypeString, "webaudio"))
2773         return PlatformMediaSession::WebAudio;
2774
2775     return PlatformMediaSession::None;
2776 }
2777
2778 ExceptionOr<void> Internals::setMediaSessionRestrictions(const String& mediaTypeString, const String& restrictionsString)
2779 {
2780     PlatformMediaSession::MediaType mediaType = mediaTypeFromString(mediaTypeString);
2781     if (mediaType == PlatformMediaSession::None)
2782         return Exception { INVALID_ACCESS_ERR };
2783
2784     PlatformMediaSessionManager::SessionRestrictions restrictions = PlatformMediaSessionManager::sharedManager().restrictions(mediaType);
2785     PlatformMediaSessionManager::sharedManager().removeRestriction(mediaType, restrictions);
2786
2787     restrictions = PlatformMediaSessionManager::NoRestrictions;
2788
2789     Vector<String> restrictionsArray;
2790     restrictionsString.split(',', false, restrictionsArray);
2791     for (auto& restrictionString : restrictionsArray) {
2792         if (equalLettersIgnoringASCIICase(restrictionString, "concurrentplaybacknotpermitted"))
2793             restrictions |= PlatformMediaSessionManager::ConcurrentPlaybackNotPermitted;
2794         if (equalLettersIgnoringASCIICase(restrictionString, "backgroundprocessplaybackrestricted"))
2795             restrictions |= PlatformMediaSessionManager::BackgroundProcessPlaybackRestricted;
2796         if (equalLettersIgnoringASCIICase(restrictionString, "backgroundtabplaybackrestricted"))
2797             restrictions |= PlatformMediaSessionManager::BackgroundTabPlaybackRestricted;
2798         if (equalLettersIgnoringASCIICase(restrictionString, "interruptedplaybacknotpermitted"))
2799             restrictions |= PlatformMediaSessionManager::InterruptedPlaybackNotPermitted;
2800     }
2801     PlatformMediaSessionManager::sharedManager().addRestriction(mediaType, restrictions);
2802     return { };
2803 }
2804
2805 ExceptionOr<String> Internals::mediaSessionRestrictions(const String& mediaTypeString) const
2806 {
2807     PlatformMediaSession::MediaType mediaType = mediaTypeFromString(mediaTypeString);
2808     if (mediaType == PlatformMediaSession::None)
2809         return Exception { INVALID_ACCESS_ERR };
2810
2811     PlatformMediaSessionManager::SessionRestrictions restrictions = PlatformMediaSessionManager::sharedManager().restrictions(mediaType);
2812     if (restrictions == PlatformMediaSessionManager::NoRestrictions)
2813         return String();
2814
2815     StringBuilder builder;
2816     if (restrictions & PlatformMediaSessionManager::ConcurrentPlaybackNotPermitted)
2817         builder.append("concurrentplaybacknotpermitted");
2818     if (restrictions & PlatformMediaSessionManager::BackgroundProcessPlaybackRestricted) {
2819         if (!builder.isEmpty())
2820             builder.append(',');
2821         builder.append("backgroundprocessplaybackrestricted");
2822     }
2823     if (restrictions & PlatformMediaSessionManager::BackgroundTabPlaybackRestricted) {
2824         if (!builder.isEmpty())
2825             builder.append(',');
2826         builder.append("backgroundtabplaybackrestricted");
2827     }
2828     if (restrictions & PlatformMediaSessionManager::InterruptedPlaybackNotPermitted) {
2829         if (!builder.isEmpty())
2830             builder.append(',');
2831         builder.append("interruptedplaybacknotpermitted");
2832     }
2833     return builder.toString();
2834 }
2835
2836 void Internals::setMediaElementRestrictions(HTMLMediaElement& element, const String& restrictionsString)
2837 {
2838     MediaElementSession::BehaviorRestrictions restrictions = element.mediaSession().behaviorRestrictions();
2839     element.mediaSession().removeBehaviorRestriction(restrictions);
2840
2841     restrictions = MediaElementSession::NoRestrictions;
2842
2843     Vector<String> restrictionsArray;
2844     restrictionsString.split(',', false, restrictionsArray);
2845     for (auto& restrictionString : restrictionsArray) {
2846         if (equalLettersIgnoringASCIICase(restrictionString, "norestrictions"))
2847             restrictions |= MediaElementSession::NoRestrictions;
2848         if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforload"))
2849             restrictions |= MediaElementSession::RequireUserGestureForLoad;
2850         if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforvideoratechange"))
2851             restrictions |= MediaElementSession::RequireUserGestureForVideoRateChange;
2852         if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforfullscreen"))
2853             restrictions |= MediaElementSession::RequireUserGestureForFullscreen;
2854         if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsenttoloadmedia"))
2855             restrictions |= MediaElementSession::RequirePageConsentToLoadMedia;
2856         if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsenttoresumemedia"))
2857             restrictions |= MediaElementSession::RequirePageConsentToResumeMedia;
2858 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
2859         if (equalLettersIgnoringASCIICase(restrictionString, "requireusergesturetoshowplaybacktargetpicker"))
2860             restrictions |= MediaElementSession::RequireUserGestureToShowPlaybackTargetPicker;
2861         if (equalLettersIgnoringASCIICase(restrictionString, "wirelessvideoplaybackdisabled"))
2862             restrictions |= MediaElementSession::WirelessVideoPlaybackDisabled;
2863 #endif
2864         if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforaudioratechange"))
2865             restrictions |= MediaElementSession::RequireUserGestureForAudioRateChange;
2866         if (equalLettersIgnoringASCIICase(restrictionString, "metadatapreloadingnotpermitted"))
2867             restrictions |= MediaElementSession::MetadataPreloadingNotPermitted;
2868         if (equalLettersIgnoringASCIICase(restrictionString, "autopreloadingnotpermitted"))
2869             restrictions |= MediaElementSession::AutoPreloadingNotPermitted;
2870         if (equalLettersIgnoringASCIICase(restrictionString, "invisibleautoplaynotpermitted"))
2871             restrictions |= MediaElementSession::InvisibleAutoplayNotPermitted;
2872         if (equalLettersIgnoringASCIICase(restrictionString, "overrideusergesturerequirementformaincontent"))
2873             restrictions |= MediaElementSession::OverrideUserGestureRequirementForMainContent;
2874     }
2875     element.mediaSession().addBehaviorRestriction(restrictions);
2876 }
2877
2878 ExceptionOr<void> Internals::postRemoteControlCommand(const String& commandString, float argument)
2879 {
2880     PlatformMediaSession::RemoteControlCommandType command;
2881     PlatformMediaSession::RemoteCommandArgument parameter { argument };
2882
2883     if (equalLettersIgnoringASCIICase(commandString, "play"))
2884         command = PlatformMediaSession::PlayCommand;
2885     else if (equalLettersIgnoringASCIICase(commandString, "pause"))
2886         command = PlatformMediaSession::PauseCommand;
2887     else if (equalLettersIgnoringASCIICase(commandString, "stop"))
2888         command = PlatformMediaSession::StopCommand;
2889     else if (equalLettersIgnoringASCIICase(commandString, "toggleplaypause"))
2890         command = PlatformMediaSession::TogglePlayPauseCommand;
2891     else if (equalLettersIgnoringASCIICase(commandString, "beginseekingbackward"))
2892         command = PlatformMediaSession::BeginSeekingBackwardCommand;
2893     else if (equalLettersIgnoringASCIICase(commandString, "endseekingbackward"))
2894         command = PlatformMediaSession::EndSeekingBackwardCommand;
2895     else if (equalLettersIgnoringASCIICase(commandString, "beginseekingforward"))
2896         command = PlatformMediaSession::BeginSeekingForwardCommand;
2897     else if (equalLettersIgnoringASCIICase(commandString, "endseekingforward"))
2898         command = PlatformMediaSession::EndSeekingForwardCommand;
2899     else if (equalLettersIgnoringASCIICase(commandString, "seektoplaybackposition"))
2900         command = PlatformMediaSession::SeekToPlaybackPositionCommand;
2901     else
2902         return Exception { INVALID_ACCESS_ERR };
2903     
2904     PlatformMediaSessionManager::sharedManager().didReceiveRemoteControlCommand(command, &parameter);
2905     return { };
2906 }
2907
2908 bool Internals::elementIsBlockingDisplaySleep(HTMLMediaElement& element) const
2909 {
2910     return element.isDisablingSleep();
2911 }
2912
2913 #endif // ENABLE(VIDEO)
2914
2915 #if ENABLE(MEDIA_SESSION)
2916
2917 void Internals::sendMediaSessionStartOfInterruptionNotification(MediaSessionInterruptingCategory category)
2918 {
2919     MediaSessionManager::singleton().didReceiveStartOfInterruptionNotification(category);
2920 }
2921
2922 void Internals::sendMediaSessionEndOfInterruptionNotification(MediaSessionInterruptingCategory category)
2923 {
2924     MediaSessionManager::singleton().didReceiveEndOfInterruptionNotification(category);
2925 }
2926
2927 String Internals::mediaSessionCurrentState(MediaSession* session) const
2928 {
2929     switch (session->currentState()) {
2930     case MediaSession::State::Active:
2931         return "active";
2932     case MediaSession::State::Interrupted:
2933         return "interrupted";
2934     case MediaSession::State::Idle:
2935         return "idle";
2936     }
2937 }
2938
2939 double Internals::mediaElementPlayerVolume(HTMLMediaElement* element) const
2940 {
2941     ASSERT_ARG(element, element);
2942     return element->playerVolume();
2943 }
2944
2945 void Internals::sendMediaControlEvent(MediaControlEvent event)
2946 {
2947     // FIXME: No good reason to use a single function with an argument instead of three functions.
2948     switch (event) {
2949     case MediControlEvent::PlayPause:
2950         MediaSessionManager::singleton().togglePlayback();
2951         break;
2952     case MediControlEvent::NextTrack:
2953         MediaSessionManager::singleton().skipToNextTrack();
2954         break;
2955     case MediControlEvent::PreviousTrack:
2956         MediaSessionManager::singleton().skipToPreviousTrack();
2957         break;
2958     }
2959 }
2960
2961 #endif // ENABLE(MEDIA_SESSION)
2962
2963 #if ENABLE(WEB_AUDIO)
2964
2965 void Internals::setAudioContextRestrictions(AudioContext& context, const String& restrictionsString)
2966 {
2967     AudioContext::BehaviorRestrictions restrictions = context.behaviorRestrictions();
2968     context.removeBehaviorRestriction(restrictions);
2969
2970     restrictions = AudioContext::NoRestrictions;
2971
2972     Vector<String> restrictionsArray;
2973     restrictionsString.split(',', false, restrictionsArray);
2974     for (auto& restrictionString : restrictionsArray) {
2975         if (equalLettersIgnoringASCIICase(restrictionString, "norestrictions"))
2976             restrictions |= AudioContext::NoRestrictions;
2977         if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforaudiostart"))
2978             restrictions |= AudioContext::RequireUserGestureForAudioStartRestriction;
2979         if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsentforaudiostart"))
2980             restrictions |= AudioContext::RequirePageConsentForAudioStartRestriction;
2981     }
2982     context.addBehaviorRestriction(restrictions);
2983 }
2984
2985 #endif
2986
2987 void Internals::simulateSystemSleep() const
2988 {
2989 #if ENABLE(VIDEO)
2990     PlatformMediaSessionManager::sharedManager().systemWillSleep();
2991 #endif
2992 }
2993
2994 void Internals::simulateSystemWake() const
2995 {
2996 #if ENABLE(VIDEO)
2997     PlatformMediaSessionManager::sharedManager().systemDidWake();
2998 #endif
2999 }
3000
3001 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
3002
3003 void Internals::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
3004 {
3005     Page* page = contextDocument()->frame()->page();
3006     ASSERT(page);
3007
3008     page->setMockMediaPlaybackTargetPickerEnabled(enabled);
3009 }
3010
3011 ExceptionOr<void> Internals::setMockMediaPlaybackTargetPickerState(const String& deviceName, const String& deviceState)
3012 {
3013     Page* page = contextDocument()->frame()->page();
3014     ASSERT(page);
3015
3016     MediaPlaybackTargetContext::State state = MediaPlaybackTargetContext::Unknown;
3017
3018     if (equalLettersIgnoringASCIICase(deviceState, "deviceavailable"))
3019         state = MediaPlaybackTargetContext::OutputDeviceAvailable;
3020     else if (equalLettersIgnoringASCIICase(deviceState, "deviceunavailable"))
3021         state = MediaPlaybackTargetContext::OutputDeviceUnavailable;
3022     else if (equalLettersIgnoringASCIICase(deviceState, "unknown"))
3023         state = MediaPlaybackTargetContext::Unknown;
3024     else
3025         return Exception { INVALID_ACCESS_ERR };
3026
3027     page->setMockMediaPlaybackTargetPickerState(deviceName, state);
3028     return { };
3029 }
3030
3031 #endif
3032
3033 ExceptionOr<Ref<MockPageOverlay>> Internals::installMockPageOverlay(PageOverlayType type)
3034 {
3035     Document* document = contextDocument();
3036     if (!document || !document->frame())
3037         return Exception { INVALID_ACCESS_ERR };
3038
3039     return MockPageOverlayClient::singleton().installOverlay(document->frame()->mainFrame(), type == PageOverlayType::View ? PageOverlay::OverlayType::View : PageOverlay::OverlayType::Document);
3040 }
3041
3042 ExceptionOr<String> Internals::pageOverlayLayerTreeAsText() const
3043 {
3044     Document* document = contextDocument();
3045     if (!document || !document->frame())
3046         return Exception { INVALID_ACCESS_ERR };
3047
3048     document->updateLayout();
3049
3050     return MockPageOverlayClient::singleton().layerTreeAsText(document->frame()->mainFrame());
3051 }
3052
3053 void Internals::setPageMuted(const String& states)
3054 {
3055     Document* document = contextDocument();
3056     if (!document)
3057         return;
3058
3059     WebCore::MediaProducer::MutedStateFlags state = MediaProducer::NoneMuted;
3060     Vector<String> stateString;
3061     states.split(',', false, stateString);
3062     for (auto& muteString : stateString) {
3063         if (equalLettersIgnoringASCIICase(muteString, "audio"))
3064             state |= MediaProducer::AudioIsMuted;
3065         if (equalLettersIgnoringASCIICase(muteString, "capturedevices"))
3066             state |= MediaProducer::CaptureDevicesAreMuted;
3067     }
3068
3069     if (Page* page = document->page())
3070         page->setMuted(state);
3071 }
3072
3073 String Internals::pageMediaState()
3074 {
3075     Document* document = contextDocument();
3076     if (!document || !document->page())
3077         return emptyString();
3078
3079     WebCore::MediaProducer::MediaStateFlags state = document->page()->mediaState();
3080     StringBuilder string;
3081     if (state & MediaProducer::IsPlayingAudio)
3082         string.append("IsPlayingAudio,");
3083     if (state & MediaProducer::IsPlayingVideo)
3084         string.append("IsPlayingVideo,");
3085     if (state & MediaProducer::IsPlayingToExternalDevice)
3086         string.append("IsPlayingToExternalDevice,");
3087     if (state & MediaProducer::RequiresPlaybackTargetMonitoring)
3088         string.append("RequiresPlaybackTargetMonitoring,");
3089     if (state & MediaProducer::ExternalDeviceAutoPlayCandidate)
3090         string.append("ExternalDeviceAutoPlayCandidate,");
3091     if (state & MediaProducer::DidPlayToEnd)
3092         string.append("DidPlayToEnd,");
3093     if (state & MediaProducer::IsSourceElementPlaying)
3094         string.append("IsSourceElementPlaying,");
3095
3096     if (state & MediaProducer::IsNextTrackControlEnabled)
3097         string.append("IsNextTrackControlEnabled,");
3098     if (state & MediaProducer::IsPreviousTrackControlEnabled)
3099         string.append("IsPreviousTrackControlEnabled,");
3100
3101     if (state & MediaProducer::HasPlaybackTargetAvailabilityListener)
3102         string.append("HasPlaybackTargetAvailabilityListener,");
3103     if (state & MediaProducer::HasAudioOrVideo)
3104         string.append("HasAudioOrVideo,");
3105     if (state & MediaProducer::HasActiveAudioCaptureDevice)
3106         string.append("HasActiveAudioCaptureDevice,");
3107     if (state & MediaProducer::HasActiveVideoCaptureDevice)
3108         string.append("HasActiveVideoCaptureDevice,");
3109
3110     if (string.isEmpty())
3111         string.append("IsNotPlaying");
3112     else
3113         string.resize(string.length() - 1);
3114
3115     return string.toString();
3116 }
3117
3118 void Internals::setPageDefersLoading(bool defersLoading)
3119 {
3120     Document* document = contextDocument();
3121     if (!document)
3122         return;
3123     if (Page* page = document->page())
3124         page->setDefersLoading(defersLoading);
3125 }
3126
3127 RefPtr<File> Internals::createFile(const String& path)
3128 {
3129     Document* document = contextDocument();
3130     if (!document)
3131         return nullptr;
3132
3133     URL url = document->completeURL(path);
3134     if (!url.isLocalFile())
3135         return nullptr;
3136
3137     return File::create(url.fileSystemPath());
3138 }
3139
3140 void Internals::queueMicroTask(int testNumber)
3141 {
3142     Document* document = contextDocument();
3143     if (!document)
3144         return;
3145
3146     auto microtask = std::make_unique<ActiveDOMCallbackMicrotask>(MicrotaskQueue::mainThreadQueue(), *document, [document, testNumber]() {
3147         document->addConsoleMessage(MessageSource::JS, MessageLevel::Debug, makeString("MicroTask #", String::number(testNumber), " has run."));
3148     });
3149
3150     MicrotaskQueue::mainThreadQueue().append(WTFMove(microtask));
3151 }
3152
3153 #if ENABLE(CONTENT_FILTERING)
3154
3155 MockContentFilterSettings& Internals::mockContentFilterSettings()
3156 {
3157     return MockContentFilterSettings::singleton();
3158 }
3159
3160 #endif
3161
3162 #if ENABLE(CSS_SCROLL_SNAP)
3163
3164 static void appendOffsets(StringBuilder& builder, const Vector<LayoutUnit>& snapOffsets)
3165 {
3166     bool justStarting = true;
3167
3168     builder.appendLiteral("{ ");
3169     for (auto& coordinate : snapOffsets) {
3170         if (!justStarting)
3171             builder.appendLiteral(", ");
3172         else
3173             justStarting = false;
3174         
3175         builder.append(String::number(coordinate.toUnsigned()));
3176     }
3177     builder.appendLiteral(" }");
3178 }
3179     
3180 ExceptionOr<String> Internals::scrollSnapOffsets(Element& element)
3181 {
3182     if (!element.renderBox())
3183         return String();
3184
3185     RenderBox& box = *element.renderBox();
3186     ScrollableArea* scrollableArea;
3187     
3188     if (box.isBody()) {
3189         FrameView* frameView = box.frame().mainFrame().view();
3190         if (!frameView || !frameView->isScrollable())
3191             return Exception { INVALID_ACCESS_ERR };
3192         scrollableArea = frameView;
3193         
3194     } else {
3195         if (!box.canBeScrolledAndHasScrollableArea())
3196             return Exception { INVALID_ACCESS_ERR };
3197         scrollableArea = box.layer();
3198     }
3199
3200     if (!scrollableArea)
3201         return String();
3202     
3203     StringBuilder result;
3204
3205     if (scrollableArea->horizontalSnapOffsets()) {
3206         result.appendLiteral("horizontal = ");
3207         appendOffsets(result, *scrollableArea->horizontalSnapOffsets());
3208     }
3209
3210     if (scrollableArea->verticalSnapOffsets()) {
3211         if (result.length())
3212             result.appendLiteral(", ");
3213
3214         result.appendLiteral("vertical = ");
3215         appendOffsets(result, *scrollableArea->verticalSnapOffsets());
3216     }
3217
3218     return result.toString();
3219 }
3220
3221 #endif
3222
3223 bool Internals::testPreloaderSettingViewport()
3224 {
3225     return testPreloadScannerViewportSupport(contextDocument());
3226 }
3227
3228 ExceptionOr<String> Internals::pathStringWithShrinkWrappedRects(const Vector<double>& rectComponents, double radius)
3229 {
3230     if (rectComponents.size() % 4)
3231         return Exception { INVALID_ACCESS_ERR };
3232
3233     Vector<FloatRect> rects;
3234     for (unsigned i = 0; i < rectComponents.size(); i += 4)
3235         rects.append(FloatRect(rectComponents[i], rectComponents[i + 1], rectComponents[i + 2], rectComponents[i + 3]));
3236
3237     SVGPathStringBuilder builder;
3238     PathUtilities::pathWithShrinkWrappedRects(rects, radius).apply([&builder](const PathElement& element) {
3239         switch (element.type) {
3240         case PathElementMoveToPoint:
3241             builder.moveTo(element.points[0], false, AbsoluteCoordinates);
3242             return;
3243         case PathElementAddLineToPoint:
3244             builder.lineTo(element.points[0], AbsoluteCoordinates);
3245             return;
3246         case PathElementAddQuadCurveToPoint:
3247             builder.curveToQuadratic(element.points[0], element.points[1], AbsoluteCoordinates);
3248             return;
3249         case PathElementAddCurveToPoint:
3250             builder.curveToCubic(element.points[0], element.points[1], element.points[2], AbsoluteCoordinates);
3251             return;
3252         case PathElementCloseSubpath:
3253             builder.closePath();
3254             return;
3255         }
3256         ASSERT_NOT_REACHED();
3257     });
3258     return builder.result();
3259 }
3260
3261
3262 String Internals::getCurrentMediaControlsStatusForElement(HTMLMediaElement& mediaElement)
3263 {
3264 #if !ENABLE(MEDIA_CONTROLS_SCRIPT)
3265     UNUSED_PARAM(mediaElement);
3266     return String();
3267 #else
3268     return mediaElement.getCurrentMediaControlsStatus();
3269 #endif
3270 }
3271
3272 #if !PLATFORM(COCOA)
3273
3274 String Internals::userVisibleString(const DOMURL&)
3275 {
3276     // Cocoa-specific function. Could ASSERT_NOT_REACHED, but that's probably overkill.
3277     return String();
3278 }
3279
3280 #endif
3281
3282 void Internals::setShowAllPlugins(bool show)
3283 {
3284     Document* document = contextDocument();
3285     if (!document)
3286         return;
3287     
3288     Page* page = document->page();
3289     if (!page)
3290         return;
3291
3292     page->setShowAllPlugins(show);
3293 }
3294
3295 #if ENABLE(READABLE_STREAM_API)
3296
3297 bool Internals::isReadableStreamDisturbed(JSC::ExecState& state, JSValue stream)
3298 {
3299     JSGlobalObject* globalObject = state.vmEntryGlobalObject();
3300     JSVMClientData* clientData = static_cast<JSVMClientData*>(state.vm().clientData);
3301     const Identifier& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().isReadableStreamDisturbedPrivateName();
3302     JSValue value;
3303     PropertySlot propertySlot(value, PropertySlot::InternalMethodType::Get);
3304     globalObject->methodTable()->getOwnPropertySlot(globalObject, &state, privateName, propertySlot);
3305     value = propertySlot.getValue(&state, privateName);
3306     ASSERT(value.isFunction());
3307
3308     JSObject* function = value.getObject();
3309     CallData callData;
3310     CallType callType = JSC::getCallData(function, callData);
3311     ASSERT(callType != JSC::CallType::None);
3312     MarkedArgumentBuffer arguments;
3313     arguments.append(stream);
3314     JSValue returnedValue = JSC::call(&state, function, callType, callData, JSC::jsUndefined(), arguments);
3315     ASSERT(returnedValue.isBoolean());
3316
3317     return returnedValue.asBoolean();
3318 }
3319
3320 #endif
3321
3322 String Internals::resourceLoadStatisticsForOrigin(const String& origin)
3323 {
3324     return ResourceLoadObserver::sharedObserver().statisticsForOrigin(origin);
3325 }
3326
3327 void Internals::setResourceLoadStatisticsEnabled(bool enable)
3328 {
3329     Settings::setResourceLoadStatisticsEnabled(enable);
3330 }
3331
3332 String Internals::composedTreeAsText(Node& node)
3333 {
3334     if (!is<ContainerNode>(node))
3335         return emptyString();
3336     return WebCore::composedTreeAsText(downcast<ContainerNode>(node));
3337 }
3338
3339 void Internals::setLinkPreloadSupport(bool enable)
3340 {
3341     RuntimeEnabledFeatures::sharedFeatures().setLinkPreloadEnabled(enable);
3342 }
3343
3344 #if ENABLE(CSS_GRID_LAYOUT)
3345
3346 void Internals::setCSSGridLayoutEnabled(bool enable)
3347 {
3348     RuntimeEnabledFeatures::sharedFeatures().setCSSGridLayoutEnabled(enable);
3349 }
3350
3351 #endif
3352
3353 #if ENABLE(WEBGL2)
3354
3355 bool Internals::webGL2Enabled() const
3356 {
3357     return RuntimeEnabledFeatures::sharedFeatures().webGL2Enabled();
3358 }
3359
3360 void Internals::setWebGL2Enabled(bool enable)
3361 {
3362     RuntimeEnabledFeatures::sharedFeatures().setWebGL2Enabled(enable);
3363 }
3364
3365 #endif
3366
3367 void Internals::setResourceTimingSupport(bool enable)
3368 {
3369     RuntimeEnabledFeatures::sharedFeatures().setResourceTimingEnabled(enable);
3370 }
3371
3372 bool Internals::isProcessingUserGesture()
3373 {
3374     return UserGestureIndicator::processingUserGesture();
3375 }
3376
3377 RefPtr<GCObservation> Internals::observeGC(JSC::JSValue value)
3378 {
3379     if (!value || value.isNull() || value.isUndefined() || !value.getObject())
3380         return nullptr;
3381
3382     return GCObservation::create(value.getObject());
3383 }
3384
3385 void Internals::setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection)
3386 {
3387     Document* document = contextDocument();
3388     if (!document)
3389         return;
3390
3391     Page* page = document->page();
3392     if (!page)
3393         return;
3394
3395     page->setUserInterfaceLayoutDirection(userInterfaceLayoutDirection == UserInterfaceLayoutDirection::LTR ? WebCore::UserInterfaceLayoutDirection::LTR : WebCore::UserInterfaceLayoutDirection::RTL);
3396 }
3397
3398 #if !PLATFORM(COCOA)
3399
3400 bool Internals::userPrefersReducedMotion() const
3401 {
3402     return false;
3403 }
3404
3405 #endif
3406
3407 void Internals::reportBacktrace()
3408 {
3409     WTFReportBacktrace();
3410 }
3411
3412 #if ENABLE(POINTER_LOCK)
3413 bool Internals::pageHasPendingPointerLock() const
3414 {
3415     Document* document = contextDocument();
3416     if (!document)
3417         return false;
3418
3419     Page* page = document->page();
3420     if (!page)
3421         return false;
3422
3423     return page->pointerLockController().lockPending();
3424 }
3425
3426 bool Internals::pageHasPointerLock() const
3427 {
3428     Document* document = contextDocument();
3429     if (!document)
3430         return false;
3431
3432     Page* page = document->page();
3433     if (!page)
3434         return false;
3435
3436     auto& controller = page->pointerLockController();
3437     return controller.element() && !controller.lockPending();
3438 }
3439 #endif
3440
3441
3442 } // namespace WebCore