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