[WebAuthn] Move the mock testing entrance to Internals
[WebKit-https.git] / Source / WebKit / UIProcess / WebPageProxy.cpp
1 /*
2  * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
3  * Copyright (C) 2012 Intel Corporation. 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  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "WebPageProxy.h"
29
30 #include "APIArray.h"
31 #include "APIAttachment.h"
32 #include "APIContextMenuClient.h"
33 #include "APIFindClient.h"
34 #include "APIFindMatchesClient.h"
35 #include "APIFormClient.h"
36 #include "APIFrameInfo.h"
37 #include "APIFullscreenClient.h"
38 #include "APIGeometry.h"
39 #include "APIHistoryClient.h"
40 #include "APIHitTestResult.h"
41 #include "APIIconLoadingClient.h"
42 #include "APILegacyContextHistoryClient.h"
43 #include "APILoaderClient.h"
44 #include "APINavigation.h"
45 #include "APINavigationAction.h"
46 #include "APINavigationClient.h"
47 #include "APINavigationResponse.h"
48 #include "APIOpenPanelParameters.h"
49 #include "APIPageConfiguration.h"
50 #include "APIPolicyClient.h"
51 #include "APISecurityOrigin.h"
52 #include "APIUIClient.h"
53 #include "APIURLRequest.h"
54 #include "APIWebsitePolicies.h"
55 #include "AuthenticationChallengeProxy.h"
56 #include "AuthenticationDecisionListener.h"
57 #include "DataReference.h"
58 #include "DownloadProxy.h"
59 #include "DrawingAreaMessages.h"
60 #include "DrawingAreaProxy.h"
61 #include "ElementContext.h"
62 #include "EventDispatcherMessages.h"
63 #include "FormDataReference.h"
64 #include "FrameInfoData.h"
65 #include "LegacyGlobalSettings.h"
66 #include "LoadParameters.h"
67 #include "Logging.h"
68 #include "NativeWebGestureEvent.h"
69 #include "NativeWebKeyboardEvent.h"
70 #include "NativeWebMouseEvent.h"
71 #include "NativeWebWheelEvent.h"
72 #include "NavigationActionData.h"
73 #include "NetworkProcessMessages.h"
74 #include "NetworkProcessProxy.h"
75 #include "NotificationPermissionRequest.h"
76 #include "NotificationPermissionRequestManager.h"
77 #include "OptionalCallbackID.h"
78 #include "PageClient.h"
79 #include "PluginInformation.h"
80 #include "PluginProcessManager.h"
81 #include "PrintInfo.h"
82 #include "ProvisionalPageProxy.h"
83 #include "SafeBrowsingWarning.h"
84 #include "ShareSheetCallbackID.h"
85 #include "SharedBufferDataReference.h"
86 #include "SyntheticEditingCommandType.h"
87 #include "TextChecker.h"
88 #include "TextCheckerState.h"
89 #include "URLSchemeTaskParameters.h"
90 #include "UndoOrRedo.h"
91 #include "UserMediaPermissionRequestProxy.h"
92 #include "UserMediaProcessManager.h"
93 #include "WKContextPrivate.h"
94 #include "WebAutomationSession.h"
95 #include "WebBackForwardList.h"
96 #include "WebBackForwardListItem.h"
97 #include "WebCertificateInfo.h"
98 #include "WebContextMenuItem.h"
99 #include "WebContextMenuProxy.h"
100 #include "WebCoreArgumentCoders.h"
101 #include "WebEditCommandProxy.h"
102 #include "WebEvent.h"
103 #include "WebEventConversion.h"
104 #include "WebFramePolicyListenerProxy.h"
105 #include "WebFullScreenManagerProxy.h"
106 #include "WebFullScreenManagerProxyMessages.h"
107 #include "WebImage.h"
108 #include "WebInspectorProxy.h"
109 #include "WebInspectorUtilities.h"
110 #include "WebNavigationDataStore.h"
111 #include "WebNavigationState.h"
112 #include "WebNotificationManagerProxy.h"
113 #include "WebOpenPanelResultListenerProxy.h"
114 #include "WebPageCreationParameters.h"
115 #include "WebPageDebuggable.h"
116 #include "WebPageGroup.h"
117 #include "WebPageGroupData.h"
118 #include "WebPageInspectorController.h"
119 #include "WebPageMessages.h"
120 #include "WebPageProxyMessages.h"
121 #include "WebPaymentCoordinatorProxy.h"
122 #include "WebPopupItem.h"
123 #include "WebPopupMenuProxy.h"
124 #include "WebPreferences.h"
125 #include "WebPreferencesKeys.h"
126 #include "WebProcessMessages.h"
127 #include "WebProcessPool.h"
128 #include "WebProcessProxy.h"
129 #include "WebProtectionSpace.h"
130 #include "WebResourceLoadStatisticsStore.h"
131 #include "WebURLSchemeHandler.h"
132 #include "WebUserContentControllerProxy.h"
133 #include "WebViewDidMoveToWindowObserver.h"
134 #include "WebsiteDataStore.h"
135 #include <WebCore/AdClickAttribution.h>
136 #include <WebCore/BitmapImage.h>
137 #include <WebCore/CrossSiteNavigationDataTransfer.h>
138 #include <WebCore/DOMPasteAccess.h>
139 #include <WebCore/DeprecatedGlobalSettings.h>
140 #include <WebCore/DiagnosticLoggingClient.h>
141 #include <WebCore/DiagnosticLoggingKeys.h>
142 #include <WebCore/DragController.h>
143 #include <WebCore/DragData.h>
144 #include <WebCore/EventNames.h>
145 #include <WebCore/FloatRect.h>
146 #include <WebCore/FocusDirection.h>
147 #include <WebCore/FontAttributeChanges.h>
148 #include <WebCore/FrameLoader.h>
149 #include <WebCore/GlobalFrameIdentifier.h>
150 #include <WebCore/GlobalWindowIdentifier.h>
151 #include <WebCore/JSDOMBinding.h>
152 #include <WebCore/JSDOMExceptionHandling.h>
153 #include <WebCore/LengthBox.h>
154 #include <WebCore/MIMETypeRegistry.h>
155 #include <WebCore/MediaStreamRequest.h>
156 #include <WebCore/PerformanceLoggingClient.h>
157 #include <WebCore/PlatformEvent.h>
158 #include <WebCore/PublicSuffix.h>
159 #include <WebCore/RenderEmbeddedObject.h>
160 #include <WebCore/ResourceLoadStatistics.h>
161 #include <WebCore/SSLKeyGenerator.h>
162 #include <WebCore/SerializedCryptoKeyWrap.h>
163 #include <WebCore/ShareData.h>
164 #include <WebCore/SharedBuffer.h>
165 #include <WebCore/ShouldTreatAsContinuingLoad.h>
166 #include <WebCore/TextCheckerClient.h>
167 #include <WebCore/TextIndicator.h>
168 #include <WebCore/ValidationBubble.h>
169 #include <WebCore/WindowFeatures.h>
170 #include <WebCore/WritingDirection.h>
171 #include <stdio.h>
172 #include <wtf/NeverDestroyed.h>
173 #include <wtf/SystemTracing.h>
174 #include <wtf/URL.h>
175 #include <wtf/URLParser.h>
176 #include <wtf/text/StringView.h>
177 #include <wtf/text/TextStream.h>
178
179 #if ENABLE(APPLICATION_MANIFEST)
180 #include "APIApplicationManifest.h"
181 #endif
182
183 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
184 #include "RemoteScrollingCoordinatorProxy.h"
185 #endif
186
187 #ifndef NDEBUG
188 #include <wtf/RefCountedLeakCounter.h>
189 #endif
190
191 #if PLATFORM(COCOA)
192 #include "AttributedString.h"
193 #include "InsertTextOptions.h"
194 #include "RemoteLayerTreeDrawingAreaProxy.h"
195 #include "RemoteLayerTreeScrollingPerformanceData.h"
196 #include "TouchBarMenuData.h"
197 #include "TouchBarMenuItemData.h"
198 #include "VersionChecks.h"
199 #include "VideoFullscreenManagerProxy.h"
200 #include "VideoFullscreenManagerProxyMessages.h"
201 #include <WebCore/RunLoopObserver.h>
202 #include <WebCore/TextIndicatorWindow.h>
203 #include <wtf/MachSendRight.h>
204 #endif
205
206 #if PLATFORM(COCOA) || PLATFORM(GTK)
207 #include "ViewSnapshotStore.h"
208 #endif
209
210 #if PLATFORM(GTK)
211 #include "WebSelectionData.h"
212 #endif
213
214 #if USE(CAIRO)
215 #include <WebCore/CairoUtilities.h>
216 #endif
217
218 #if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
219 #include <WebCore/MediaPlaybackTarget.h>
220 #include <WebCore/WebMediaSessionManager.h>
221 #endif
222
223 #if ENABLE(MEDIA_SESSION)
224 #include "WebMediaSessionFocusManager.h"
225 #include "WebMediaSessionMetadata.h"
226 #include <WebCore/MediaSessionMetadata.h>
227 #endif
228
229 #if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
230 #include "PlaybackSessionManagerProxy.h"
231 #endif
232
233 #if ENABLE(WEB_AUTHN)
234 #include "WebAuthenticatorCoordinatorProxy.h"
235 #endif
236
237 #if ENABLE(REMOTE_INSPECTOR)
238 #include <JavaScriptCore/RemoteInspector.h>
239 #endif
240
241 #if HAVE(SEC_KEY_PROXY)
242 #include "SecKeyProxyStore.h"
243 #endif
244
245 #if HAVE(PENCILKIT)
246 #include "EditableImageController.h"
247 #endif
248
249 #if HAVE(APP_SSO)
250 #include "SOAuthorizationCoordinator.h"
251 #endif
252
253 #if USE(DIRECT2D)
254 #include <d3d11_1.h>
255 #endif
256
257 // This controls what strategy we use for mouse wheel coalescing.
258 #define MERGE_WHEEL_EVENTS 1
259
260 #define MESSAGE_CHECK(process, assertion) MESSAGE_CHECK_BASE(assertion, process->connection())
261 #define MESSAGE_CHECK_URL(process, url) MESSAGE_CHECK_BASE(checkURLReceivedFromCurrentOrPreviousWebProcess(process, url), process->connection())
262
263 #define RELEASE_LOG_IF_ALLOWED(channel, fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), channel, "%p - [pageProxyID=%llu, webPageID=%llu, PID=%i] WebPageProxy::" fmt, this, m_identifier.toUInt64(), m_webPageID.toUInt64(), m_process->processIdentifier(), ##__VA_ARGS__)
264 #define RELEASE_LOG_ERROR_IF_ALLOWED(channel, fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), channel, "%p - [pageProxyID=%llu, webPageID=%llu, PID=%i] WebPageProxy::" fmt, this, m_identifier.toUInt64(), m_webPageID.toUInt64(), m_process->processIdentifier(), ##__VA_ARGS__)
265
266 // Represents the number of wheel events we can hold in the queue before we start pushing them preemptively.
267 static const unsigned wheelEventQueueSizeThreshold = 10;
268
269 static const Seconds resetRecentCrashCountDelay = 30_s;
270 static unsigned maximumWebProcessRelaunchAttempts = 1;
271
272 namespace WebKit {
273 using namespace WebCore;
274
275 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageProxyCounter, ("WebPageProxy"));
276
277 class StorageRequests {
278     WTF_MAKE_NONCOPYABLE(StorageRequests); WTF_MAKE_FAST_ALLOCATED;
279     friend NeverDestroyed<StorageRequests>;
280 public:
281     static StorageRequests& singleton();
282
283     void processOrAppend(CompletionHandler<void()>&& completionHandler)
284     {
285         if (m_requestsAreBeingProcessed) {
286             m_requests.append(WTFMove(completionHandler));
287             return;
288         }
289         m_requestsAreBeingProcessed = true;
290         completionHandler();
291     }
292
293     void processNextIfAny()
294     {
295         if (m_requests.isEmpty()) {
296             m_requestsAreBeingProcessed = false;
297             return;
298         }
299         m_requests.takeFirst()();
300     }
301
302 private:
303     StorageRequests() { }
304     ~StorageRequests() { }
305
306     Deque<CompletionHandler<void()>> m_requests;
307     bool m_requestsAreBeingProcessed { false };
308 };
309
310 StorageRequests& StorageRequests::singleton()
311 {
312     static NeverDestroyed<StorageRequests> requests;
313     return requests;
314 }
315
316 #if !LOG_DISABLED
317 static const char* webMouseEventTypeString(WebEvent::Type type)
318 {
319     switch (type) {
320     case WebEvent::MouseDown:
321         return "MouseDown";
322     case WebEvent::MouseUp:
323         return "MouseUp";
324     case WebEvent::MouseMove:
325         return "MouseMove";
326     case WebEvent::MouseForceChanged:
327         return "MouseForceChanged";
328     case WebEvent::MouseForceDown:
329         return "MouseForceDown";
330     case WebEvent::MouseForceUp:
331         return "MouseForceUp";
332     default:
333         ASSERT_NOT_REACHED();
334         return "<unknown>";
335     }
336 }
337
338 static const char* webKeyboardEventTypeString(WebEvent::Type type)
339 {
340     switch (type) {
341     case WebEvent::KeyDown:
342         return "KeyDown";
343     case WebEvent::KeyUp:
344         return "KeyUp";
345     case WebEvent::RawKeyDown:
346         return "RawKeyDown";
347     case WebEvent::Char:
348         return "Char";
349     default:
350         ASSERT_NOT_REACHED();
351         return "<unknown>";
352     }
353 }
354 #endif // !LOG_DISABLED
355
356 class PageClientProtector {
357     WTF_MAKE_NONCOPYABLE(PageClientProtector);
358 public:
359     PageClientProtector(PageClient& pageClient)
360         : m_pageClient(makeWeakPtr(pageClient))
361     {
362         m_pageClient->refView();
363     }
364
365     ~PageClientProtector()
366     {
367         ASSERT(m_pageClient);
368         m_pageClient->derefView();
369     }
370
371 private:
372     WeakPtr<PageClient> m_pageClient;
373 };
374
375 void WebPageProxy::forMostVisibleWebPageIfAny(PAL::SessionID sessionID, const SecurityOriginData& origin, CompletionHandler<void(WebPageProxy*)>&& completionHandler)
376 {
377     // FIXME: If not finding right away a visible page, we might want to try again for a given period of time when there is a change of visibility.
378     WebPageProxy* selectedPage = nullptr;
379     WebProcessProxy::forWebPagesWithOrigin(sessionID, origin, [&](auto& page) {
380         if (!page.mainFrame())
381             return;
382         if (page.isViewVisible() && (!selectedPage || !selectedPage->isViewVisible())) {
383             selectedPage = &page;
384             return;
385         }
386         if (page.isViewFocused() && (!selectedPage || !selectedPage->isViewFocused())) {
387             selectedPage = &page;
388             return;
389         }
390     });
391     completionHandler(selectedPage);
392 }
393
394 Ref<WebPageProxy> WebPageProxy::create(PageClient& pageClient, WebProcessProxy& process, Ref<API::PageConfiguration>&& configuration)
395 {
396     return adoptRef(*new WebPageProxy(pageClient, process, WTFMove(configuration)));
397 }
398
399 WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, Ref<API::PageConfiguration>&& configuration)
400     : m_identifier(Identifier::generate())
401     , m_webPageID(PageIdentifier::generate())
402     , m_pageClient(makeWeakPtr(pageClient))
403     , m_configuration(WTFMove(configuration))
404     , m_navigationClient(makeUniqueRef<API::NavigationClient>())
405     , m_historyClient(makeUniqueRef<API::HistoryClient>())
406     , m_iconLoadingClient(makeUnique<API::IconLoadingClient>())
407     , m_formClient(makeUnique<API::FormClient>())
408     , m_uiClient(makeUnique<API::UIClient>())
409     , m_findClient(makeUnique<API::FindClient>())
410     , m_findMatchesClient(makeUnique<API::FindMatchesClient>())
411 #if ENABLE(CONTEXT_MENUS)
412     , m_contextMenuClient(makeUnique<API::ContextMenuClient>())
413 #endif
414     , m_navigationState(makeUnique<WebNavigationState>())
415     , m_process(process)
416     , m_pageGroup(*m_configuration->pageGroup())
417     , m_preferences(*m_configuration->preferences())
418     , m_userContentController(*m_configuration->userContentController())
419     , m_visitedLinkStore(*m_configuration->visitedLinkStore())
420     , m_websiteDataStore(*m_configuration->websiteDataStore())
421     , m_userAgent(standardUserAgent())
422     , m_overrideContentSecurityPolicy { m_configuration->overrideContentSecurityPolicy() }
423     , m_treatsSHA1CertificatesAsInsecure(m_configuration->treatsSHA1SignedCertificatesAsInsecure())
424 #if ENABLE(FULLSCREEN_API)
425     , m_fullscreenClient(makeUnique<API::FullscreenClient>())
426 #endif
427     , m_geolocationPermissionRequestManager(*this)
428     , m_notificationPermissionRequestManager(*this)
429 #if PLATFORM(IOS_FAMILY)
430     , m_alwaysRunsAtForegroundPriority(m_configuration->alwaysRunsAtForegroundPriority())
431 #endif
432     , m_initialCapitalizationEnabled(m_configuration->initialCapitalizationEnabled())
433     , m_cpuLimit(m_configuration->cpuLimit())
434     , m_backForwardList(WebBackForwardList::create(*this))
435     , m_waitsForPaintAfterViewDidMoveToWindow(m_configuration->waitsForPaintAfterViewDidMoveToWindow())
436     , m_hasRunningProcess(process.state() != WebProcessProxy::State::Terminated)
437     , m_controlledByAutomation(m_configuration->isControlledByAutomation())
438 #if PLATFORM(COCOA)
439     , m_isSmartInsertDeleteEnabled(TextChecker::isSmartInsertDeleteEnabled())
440 #endif
441     , m_pageLoadState(*this)
442     , m_configurationPreferenceValues(m_configuration->preferenceValues())
443     , m_inspectorController(makeUnique<WebPageInspectorController>(*this))
444 #if ENABLE(REMOTE_INSPECTOR)
445     , m_inspectorDebuggable(makeUnique<WebPageDebuggable>(*this))
446 #endif
447     , m_resetRecentCrashCountTimer(RunLoop::main(), this, &WebPageProxy::resetRecentCrashCount)
448 {
449     RELEASE_LOG_IF_ALLOWED(Loading, "constructor:");
450
451     if (!m_configuration->drawsBackground())
452         m_backgroundColor = Color(Color::transparent);
453
454     updateActivityState();
455     updateThrottleState();
456     updateHiddenPageThrottlingAutoIncreases();
457     
458 #if HAVE(OUT_OF_PROCESS_LAYER_HOSTING)
459     m_layerHostingMode = m_activityState & ActivityState::IsInWindow ? WebPageProxy::pageClient().viewLayerHostingMode() : LayerHostingMode::OutOfProcess;
460 #endif
461
462     platformInitialize();
463
464 #ifndef NDEBUG
465     webPageProxyCounter.increment();
466 #endif
467
468     WebProcessPool::statistics().wkPageCount++;
469
470     m_preferences->addPage(*this);
471     m_pageGroup->addPage(this);
472
473     m_inspector = WebInspectorProxy::create(this);
474
475     if (hasRunningProcess())
476         didAttachToRunningProcess();
477
478     m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID, *this);
479
480 #if PLATFORM(IOS_FAMILY)
481     DeprecatedGlobalSettings::setDisableScreenSizeOverride(preferencesStore().getBoolValueForKey(WebPreferencesKey::disableScreenSizeOverrideKey()));
482 #endif
483
484 #if PLATFORM(COCOA)
485     m_activityStateChangeDispatcher = makeUnique<RunLoopObserver>(static_cast<CFIndex>(RunLoopObserver::WellKnownRunLoopOrders::ActivityStateChange), [this] {
486         this->dispatchActivityStateChange();
487     });
488 #endif
489
490 #if ENABLE(REMOTE_INSPECTOR)
491     m_inspectorDebuggable->setRemoteDebuggingAllowed(true);
492     m_inspectorDebuggable->init();
493 #endif
494
495     createInspectorTargets();
496 }
497
498 WebPageProxy::~WebPageProxy()
499 {
500     RELEASE_LOG_IF_ALLOWED(Loading, "destructor:");
501
502     ASSERT(m_process->webPage(m_identifier) != this);
503 #if !ASSERT_DISABLED
504     for (WebPageProxy* page : m_process->pages())
505         ASSERT(page != this);
506 #endif
507
508     setPageLoadStateObserver(nullptr);
509
510     if (!m_isClosed)
511         close();
512
513     WebProcessPool::statistics().wkPageCount--;
514
515     if (m_spellDocumentTag)
516         TextChecker::closeSpellDocumentWithTag(m_spellDocumentTag.value());
517
518     m_preferences->removePage(*this);
519     m_pageGroup->removePage(this);
520
521 #ifndef NDEBUG
522     webPageProxyCounter.decrement();
523 #endif
524 }
525
526 // FIXME: Should return a const PageClient& and add a separate non-const
527 // version of this function, but several PageClient methods will need to become
528 // const for this to be possible.
529 PageClient& WebPageProxy::pageClient() const
530 {
531     ASSERT(m_pageClient);
532     return *m_pageClient;
533 }
534
535 PAL::SessionID WebPageProxy::sessionID() const
536 {
537     return m_websiteDataStore->sessionID();
538 }
539
540 DrawingAreaProxy* WebPageProxy::provisionalDrawingArea() const
541 {
542     if (m_provisionalPage && m_provisionalPage->drawingArea())
543         return m_provisionalPage->drawingArea();
544     return drawingArea();
545 }
546
547 const API::PageConfiguration& WebPageProxy::configuration() const
548 {
549     return m_configuration.get();
550 }
551
552 ProcessID WebPageProxy::processIdentifier() const
553 {
554     if (m_isClosed)
555         return 0;
556
557     return m_process->processIdentifier();
558 }
559
560 bool WebPageProxy::hasRunningProcess() const
561 {
562     // A page that has been explicitly closed is never valid.
563     if (m_isClosed)
564         return false;
565
566     return m_hasRunningProcess;
567 }
568
569 void WebPageProxy::notifyProcessPoolToPrewarm()
570 {
571     m_process->processPool().didReachGoodTimeToPrewarm();
572 }
573
574 void WebPageProxy::setPreferences(WebPreferences& preferences)
575 {
576     if (&preferences == m_preferences.ptr())
577         return;
578
579     m_preferences->removePage(*this);
580     m_preferences = preferences;
581     m_preferences->addPage(*this);
582
583     preferencesDidChange();
584 }
585     
586 void WebPageProxy::setHistoryClient(UniqueRef<API::HistoryClient>&& historyClient)
587 {
588     m_historyClient = WTFMove(historyClient);
589 }
590
591 void WebPageProxy::setNavigationClient(UniqueRef<API::NavigationClient>&& navigationClient)
592 {
593     m_navigationClient = WTFMove(navigationClient);
594 }
595
596 void WebPageProxy::setLoaderClient(std::unique_ptr<API::LoaderClient>&& loaderClient)
597 {
598     m_loaderClient = WTFMove(loaderClient);
599 }
600
601 void WebPageProxy::setPolicyClient(std::unique_ptr<API::PolicyClient>&& policyClient)
602 {
603     m_policyClient = WTFMove(policyClient);
604 }
605
606 void WebPageProxy::setFormClient(std::unique_ptr<API::FormClient>&& formClient)
607 {
608     if (!formClient) {
609         m_formClient = makeUnique<API::FormClient>();
610         return;
611     }
612
613     m_formClient = WTFMove(formClient);
614 }
615
616 void WebPageProxy::setUIClient(std::unique_ptr<API::UIClient>&& uiClient)
617 {
618     if (!uiClient) {
619         m_uiClient = makeUnique<API::UIClient>();
620         return;
621     }
622
623     m_uiClient = WTFMove(uiClient);
624
625     if (hasRunningProcess())
626         m_process->send(Messages::WebPage::SetCanRunBeforeUnloadConfirmPanel(m_uiClient->canRunBeforeUnloadConfirmPanel()), m_webPageID);
627
628     setCanRunModal(m_uiClient->canRunModal());
629     setNeedsFontAttributes(m_uiClient->needsFontAttributes());
630 }
631
632 void WebPageProxy::setIconLoadingClient(std::unique_ptr<API::IconLoadingClient>&& iconLoadingClient)
633 {
634     bool hasClient = iconLoadingClient.get();
635     if (!iconLoadingClient)
636         m_iconLoadingClient = makeUnique<API::IconLoadingClient>();
637     else
638         m_iconLoadingClient = WTFMove(iconLoadingClient);
639
640     if (!hasRunningProcess())
641         return;
642
643     m_process->send(Messages::WebPage::SetUseIconLoadingClient(hasClient), m_webPageID);
644 }
645
646 void WebPageProxy::setPageLoadStateObserver(std::unique_ptr<PageLoadState::Observer>&& observer)
647 {
648     if (m_pageLoadStateObserver)
649         pageLoadState().removeObserver(*m_pageLoadStateObserver);
650     m_pageLoadStateObserver = WTFMove(observer);
651     if (m_pageLoadStateObserver)
652         pageLoadState().addObserver(*m_pageLoadStateObserver);
653 }
654
655 void WebPageProxy::setFindClient(std::unique_ptr<API::FindClient>&& findClient)
656 {
657     if (!findClient) {
658         m_findClient = makeUnique<API::FindClient>();
659         return;
660     }
661     
662     m_findClient = WTFMove(findClient);
663 }
664
665 void WebPageProxy::setFindMatchesClient(std::unique_ptr<API::FindMatchesClient>&& findMatchesClient)
666 {
667     if (!findMatchesClient) {
668         m_findMatchesClient = makeUnique<API::FindMatchesClient>();
669         return;
670     }
671
672     m_findMatchesClient = WTFMove(findMatchesClient);
673 }
674
675 void WebPageProxy::setDiagnosticLoggingClient(std::unique_ptr<API::DiagnosticLoggingClient>&& diagnosticLoggingClient)
676 {
677     m_diagnosticLoggingClient = WTFMove(diagnosticLoggingClient);
678 }
679
680 #if ENABLE(CONTEXT_MENUS)
681 void WebPageProxy::setContextMenuClient(std::unique_ptr<API::ContextMenuClient>&& contextMenuClient)
682 {
683     if (!contextMenuClient) {
684         m_contextMenuClient = makeUnique<API::ContextMenuClient>();
685         return;
686     }
687
688     m_contextMenuClient = WTFMove(contextMenuClient);
689 }
690 #endif
691
692 void WebPageProxy::setInjectedBundleClient(const WKPageInjectedBundleClientBase* client)
693 {
694     if (!client) {
695         m_injectedBundleClient = nullptr;
696         return;
697     }
698
699     m_injectedBundleClient = makeUnique<WebPageInjectedBundleClient>();
700     m_injectedBundleClient->initialize(client);
701 }
702
703 void WebPageProxy::handleMessage(IPC::Connection& connection, const String& messageName, const WebKit::UserData& messageBody)
704 {
705     ASSERT(m_process->connection() == &connection);
706
707     if (!m_injectedBundleClient)
708         return;
709
710     m_injectedBundleClient->didReceiveMessageFromInjectedBundle(this, messageName, m_process->transformHandlesToObjects(messageBody.object()).get());
711 }
712
713 void WebPageProxy::handleSynchronousMessage(IPC::Connection& connection, const String& messageName, const UserData& messageBody, CompletionHandler<void(UserData&&)>&& completionHandler)
714 {
715     ASSERT(m_process->connection() == &connection);
716
717     if (!m_injectedBundleClient)
718         return completionHandler({ });
719
720     RefPtr<API::Object> returnData;
721     m_injectedBundleClient->didReceiveSynchronousMessageFromInjectedBundle(this, messageName, m_process->transformHandlesToObjects(messageBody.object()).get(), [completionHandler = WTFMove(completionHandler), process = m_process.copyRef()] (RefPtr<API::Object>&& returnData) mutable {
722         completionHandler(UserData(process->transformObjectsToHandles(returnData.get())));
723     });
724 }
725
726 void WebPageProxy::launchProcess(const RegistrableDomain& registrableDomain, ProcessLaunchReason reason)
727 {
728     ASSERT(!m_isClosed);
729     ASSERT(!hasRunningProcess());
730
731     RELEASE_LOG_IF_ALLOWED(Loading, "launchProcess:" PRIu64);
732
733     m_process->removeWebPage(*this, WebProcessProxy::EndsUsingDataStore::Yes);
734     m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID);
735
736     auto& processPool = m_process->processPool();
737
738     auto* relatedPage = m_configuration->relatedPage();
739     if (relatedPage && !relatedPage->isClosed())
740         m_process = relatedPage->ensureRunningProcess();
741     else
742         m_process = processPool.processForRegistrableDomain(m_websiteDataStore.get(), this, registrableDomain);
743     m_hasRunningProcess = true;
744
745     m_process->addExistingWebPage(*this, WebProcessProxy::BeginsUsingDataStore::Yes);
746     m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID, *this);
747
748     finishAttachingToWebProcess(reason);
749 }
750
751 bool WebPageProxy::suspendCurrentPageIfPossible(API::Navigation& navigation, Optional<FrameIdentifier> mainFrameID, ProcessSwapRequestedByClient processSwapRequestedByClient, ShouldDelayClosingUntilEnteringAcceleratedCompositingMode shouldDelayClosingUntilEnteringAcceleratedCompositingMode)
752 {
753     m_lastSuspendedPage = nullptr;
754
755     if (!mainFrameID)
756         return false;
757
758     if (!hasCommittedAnyProvisionalLoads()) {
759         RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because has not committed any load yet", m_process->processIdentifier());
760         return false;
761     }
762
763     if (isPageOpenedByDOMShowingInitialEmptyDocument()) {
764         RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because it is showing the initial empty document", m_process->processIdentifier());
765         return false;
766     }
767
768     auto* fromItem = navigation.fromItem();
769
770     // If the source and the destination back / forward list items are the same, then this is a client-side redirect. In this case,
771     // there is no need to suspend the previous page as there will be no way to get back to it.
772     if (fromItem && fromItem == m_backForwardList->currentItem()) {
773         RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because this is a client-side redirect", m_process->processIdentifier());
774         return false;
775     }
776
777     if (fromItem && fromItem->url() != pageLoadState().url()) {
778         RELEASE_LOG_ERROR_IF_ALLOWED(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because fromItem's URL does not match the page URL.", m_process->processIdentifier());
779         ASSERT_NOT_REACHED();
780         return false;
781     }
782
783     RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "suspendCurrentPageIfPossible: Suspending current page for process pid %i", m_process->processIdentifier());
784     auto suspendedPage = makeUnique<SuspendedPageProxy>(*this, m_process.copyRef(), *mainFrameID, shouldDelayClosingUntilEnteringAcceleratedCompositingMode);
785
786     LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " created suspended page %s for process pid %i, back/forward item %s" PRIu64, identifier().toUInt64(), suspendedPage->loggingString(), m_process->processIdentifier(), fromItem ? fromItem->itemID().logString() : 0);
787
788     // If the client forced a swap then it may not be web-compatible to keep the previous page because other windows may have an opener link to it. We thus close it as soon as we
789     // can do so without flashing.
790     if (processSwapRequestedByClient == ProcessSwapRequestedByClient::Yes)
791         suspendedPage->closeWithoutFlashing();
792
793     if (fromItem && m_preferences->usesPageCache())
794         fromItem->setSuspendedPage(suspendedPage.get());
795
796     m_lastSuspendedPage = makeWeakPtr(*suspendedPage);
797     m_process->processPool().addSuspendedPage(WTFMove(suspendedPage));
798     return true;
799 }
800
801 void WebPageProxy::swapToWebProcess(Ref<WebProcessProxy>&& process, PageIdentifier webPageID, std::unique_ptr<DrawingAreaProxy>&& drawingArea, RefPtr<WebFrameProxy>&& mainFrame)
802 {
803     ASSERT(!m_isClosed);
804     RELEASE_LOG_IF_ALLOWED(Loading, "swapToWebProcess: newWebPageID=%" PRIu64, webPageID.toUInt64());
805
806     m_process = WTFMove(process);
807     m_webPageID = webPageID;
808     pageClient().didChangeWebPageID();
809     m_websiteDataStore = m_process->websiteDataStore();
810
811     if (m_logger)
812         m_logger->setEnabled(this, isAlwaysOnLoggingAllowed());
813
814     ASSERT(!m_drawingArea);
815     setDrawingArea(WTFMove(drawingArea));
816     ASSERT(!m_mainFrame);
817     m_mainFrame = WTFMove(mainFrame);
818     m_hasRunningProcess = true;
819
820     m_process->addExistingWebPage(*this, WebProcessProxy::BeginsUsingDataStore::No);
821     m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID, *this);
822
823     finishAttachingToWebProcess(ProcessLaunchReason::ProcessSwap);
824 }
825
826 void WebPageProxy::finishAttachingToWebProcess(ProcessLaunchReason reason)
827 {
828     ASSERT(m_process->state() != AuxiliaryProcessProxy::State::Terminated);
829
830     updateActivityState();
831     updateThrottleState();
832
833     didAttachToRunningProcess();
834
835     // In the process-swap case, the ProvisionalPageProxy already took care of initializing the WebPage in the WebProcess.
836     if (reason != ProcessLaunchReason::ProcessSwap)
837         initializeWebPage();
838
839     m_inspector->updateForNewPageProcess(this);
840
841 #if ENABLE(REMOTE_INSPECTOR)
842     remoteInspectorInformationDidChange();
843 #endif
844
845     clearInspectorTargets();
846     createInspectorTargets();
847
848     pageClient().didRelaunchProcess();
849     m_pageLoadState.didSwapWebProcesses();
850     if (reason != ProcessLaunchReason::InitialProcess)
851         m_drawingArea->waitForBackingStoreUpdateOnNextPaint();
852 }
853
854 void WebPageProxy::didAttachToRunningProcess()
855 {
856     ASSERT(hasRunningProcess());
857
858 #if ENABLE(FULLSCREEN_API)
859     ASSERT(!m_fullScreenManager);
860     m_fullScreenManager = makeUnique<WebFullScreenManagerProxy>(*this, pageClient().fullScreenManagerProxyClient());
861 #endif
862 #if PLATFORM(IOS_FAMILY) && HAVE(AVKIT) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
863     ASSERT(!m_playbackSessionManager);
864     m_playbackSessionManager = PlaybackSessionManagerProxy::create(*this);
865     ASSERT(!m_videoFullscreenManager);
866     m_videoFullscreenManager = VideoFullscreenManagerProxy::create(*this, *m_playbackSessionManager);
867 #endif
868
869 #if ENABLE(APPLE_PAY)
870     ASSERT(!m_paymentCoordinator);
871     m_paymentCoordinator = makeUnique<WebPaymentCoordinatorProxy>(*this);
872 #endif
873
874 #if USE(SYSTEM_PREVIEW)
875     ASSERT(!m_systemPreviewController);
876     m_systemPreviewController = makeUnique<SystemPreviewController>(*this);
877 #endif
878
879 #if ENABLE(WEB_AUTHN)
880     ASSERT(!m_credentialsMessenger);
881     m_credentialsMessenger = makeUnique<WebAuthenticatorCoordinatorProxy>(*this);
882 #endif
883
884 #if HAVE(PENCILKIT)
885     ASSERT(!m_editableImageController);
886     m_editableImageController = makeUnique<EditableImageController>(*this);
887 #endif
888 }
889
890 RefPtr<API::Navigation> WebPageProxy::launchProcessForReload()
891 {
892     RELEASE_LOG_IF_ALLOWED(Loading, "launchProcessForReload:");
893
894     if (m_isClosed) {
895         RELEASE_LOG_IF_ALLOWED(Loading, "launchProcessForReload: page is closed");
896         return nullptr;
897     }
898     
899     ASSERT(!hasRunningProcess());
900     auto registrableDomain = m_backForwardList->currentItem() ? RegistrableDomain { URL(URL(), m_backForwardList->currentItem()->url()) } : RegistrableDomain { };
901     launchProcess(registrableDomain, ProcessLaunchReason::Crash);
902
903     if (!m_backForwardList->currentItem()) {
904         RELEASE_LOG_IF_ALLOWED(Loading, "launchProcessForReload: no current item to reload");
905         return nullptr;
906     }
907
908     auto navigation = m_navigationState->createReloadNavigation();
909
910     String url = currentURL();
911     if (!url.isEmpty()) {
912         auto transaction = m_pageLoadState.transaction();
913         m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), url });
914     }
915
916     // We allow stale content when reloading a WebProcess that's been killed or crashed.
917     m_process->send(Messages::WebPage::GoToBackForwardItem(navigation->navigationID(), m_backForwardList->currentItem()->itemID(), FrameLoadType::IndexedBackForward, ShouldTreatAsContinuingLoad::No, WTF::nullopt), m_webPageID);
918     m_process->responsivenessTimer().start();
919
920     return navigation;
921 }
922
923 RefPtr<API::Navigation> WebPageProxy::launchProcessWithItem(WebBackForwardListItem& item)
924 {
925     RELEASE_LOG_IF_ALLOWED(Loading, "launchProcessWithItem:");
926
927     if (m_isClosed) {
928         RELEASE_LOG_IF_ALLOWED(Loading, "launchProcessWithItem: page is closed");
929         return nullptr;
930     }
931
932     ASSERT(!hasRunningProcess());
933     launchProcess(RegistrableDomain { URL(URL(), item.url()) }, ProcessLaunchReason::InitialProcess);
934
935     if (&item != m_backForwardList->currentItem())
936         m_backForwardList->goToItem(item);
937
938     auto navigation = m_navigationState->createBackForwardNavigation(item, m_backForwardList->currentItem(), FrameLoadType::IndexedBackForward);
939
940     m_process->send(Messages::WebPage::GoToBackForwardItem(navigation->navigationID(), item.itemID(), FrameLoadType::IndexedBackForward, ShouldTreatAsContinuingLoad::No, WTF::nullopt), m_webPageID);
941     m_process->responsivenessTimer().start();
942
943     return navigation;
944 }
945
946 void WebPageProxy::setDrawingArea(std::unique_ptr<DrawingAreaProxy>&& drawingArea)
947 {
948     m_drawingArea = WTFMove(drawingArea);
949     if (!m_drawingArea)
950         return;
951
952 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
953     if (m_drawingArea->type() == DrawingAreaTypeRemoteLayerTree) {
954         m_scrollingCoordinatorProxy = makeUnique<RemoteScrollingCoordinatorProxy>(*this);
955 #if PLATFORM(IOS_FAMILY)
956         // On iOS, main frame scrolls are sent in terms of visible rect updates.
957         m_scrollingCoordinatorProxy->setPropagatesMainFrameScrolls(false);
958 #endif
959     }
960 #endif
961 }
962
963 void WebPageProxy::initializeWebPage()
964 {
965     if (!hasRunningProcess())
966         return;
967
968     setDrawingArea(pageClient().createDrawingAreaProxy(m_process));
969     ASSERT(m_drawingArea);
970
971     process().send(Messages::WebProcess::CreateWebPage(m_webPageID, creationParameters(m_process, *m_drawingArea)), 0);
972
973     m_process->addVisitedLinkStoreUser(visitedLinkStore(), m_identifier);
974 }
975
976 void WebPageProxy::close()
977 {
978     if (m_isClosed)
979         return;
980
981     RELEASE_LOG_IF_ALLOWED(Loading, "close:");
982
983     m_isClosed = true;
984
985     reportPageLoadResult(ResourceError { ResourceError::Type::Cancellation });
986
987     if (m_activePopupMenu)
988         m_activePopupMenu->cancelTracking();
989
990     if (m_controlledByAutomation) {
991         if (auto* automationSession = process().processPool().automationSession())
992             automationSession->willClosePage(*this);
993     }
994
995 #if ENABLE(CONTEXT_MENUS)
996     m_activeContextMenu = nullptr;
997 #endif
998
999     m_provisionalPage = nullptr;
1000
1001     m_inspector->invalidate();
1002
1003     m_backForwardList->pageClosed();
1004     m_inspectorController->pageClosed();
1005 #if ENABLE(REMOTE_INSPECTOR)
1006     m_inspectorDebuggable = nullptr;
1007 #endif
1008     pageClient().pageClosed();
1009
1010     m_process->disconnectFramesFromPage(this);
1011
1012     resetState(ResetStateReason::PageInvalidated);
1013
1014     m_loaderClient = nullptr;
1015     m_navigationClient = makeUniqueRef<API::NavigationClient>();
1016     m_policyClient = nullptr;
1017     m_iconLoadingClient = makeUnique<API::IconLoadingClient>();
1018     m_formClient = makeUnique<API::FormClient>();
1019     m_uiClient = makeUnique<API::UIClient>();
1020     m_findClient = makeUnique<API::FindClient>();
1021     m_findMatchesClient = makeUnique<API::FindMatchesClient>();
1022     m_diagnosticLoggingClient = nullptr;
1023 #if ENABLE(CONTEXT_MENUS)
1024     m_contextMenuClient = makeUnique<API::ContextMenuClient>();
1025 #endif
1026 #if ENABLE(FULLSCREEN_API)
1027     m_fullscreenClient = makeUnique<API::FullscreenClient>();
1028 #endif
1029
1030     m_process->processPool().removeAllSuspendedPagesForPage(*this);
1031
1032     m_process->send(Messages::WebPage::Close(), m_webPageID);
1033     m_process->removeWebPage(*this, WebProcessProxy::EndsUsingDataStore::Yes);
1034     m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID);
1035     m_process->processPool().supplement<WebNotificationManagerProxy>()->clearNotifications(this);
1036
1037     // Null out related WebPageProxy to avoid leaks.
1038     m_configuration->setRelatedPage(nullptr);
1039
1040 #if PLATFORM(IOS_FAMILY)
1041     // Make sure we don't hold a process assertion after getting closed.
1042     m_activityToken = nullptr;
1043 #endif
1044
1045     stopAllURLSchemeTasks();
1046     updatePlayingMediaDidChange(MediaProducer::IsNotPlaying);
1047 }
1048
1049 bool WebPageProxy::tryClose()
1050 {
1051     if (!hasRunningProcess())
1052         return true;
1053
1054     RELEASE_LOG_IF_ALLOWED(Loading, "tryClose:");
1055
1056     // Close without delay if the process allows it. Our goal is to terminate
1057     // the process, so we check a per-process status bit.
1058     if (m_process->isSuddenTerminationEnabled())
1059         return true;
1060
1061     m_process->send(Messages::WebPage::TryClose(), m_webPageID);
1062     m_process->responsivenessTimer().start();
1063     return false;
1064 }
1065
1066 void WebPageProxy::maybeInitializeSandboxExtensionHandle(WebProcessProxy& process, const URL& url, const URL& resourceDirectoryURL, SandboxExtension::Handle& sandboxExtensionHandle)
1067 {
1068     if (!url.isLocalFile())
1069         return;
1070
1071 #if HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_PID)
1072     // If the process is still launching then it does not have a PID yet. We will take care of creating the sandbox extension
1073     // once the process has finished launching.
1074     if (process.isLaunching())
1075         return;
1076 #endif
1077
1078     if (!resourceDirectoryURL.isEmpty()) {
1079         if (process.hasAssumedReadAccessToURL(resourceDirectoryURL))
1080             return;
1081
1082 #if HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_PID)
1083         if (SandboxExtension::createHandleForReadByPid(resourceDirectoryURL.fileSystemPath(), process.processIdentifier(), sandboxExtensionHandle)) {
1084             process.assumeReadAccessToBaseURL(*this, resourceDirectoryURL);
1085             return;
1086         }
1087 #else
1088         if (SandboxExtension::createHandle(resourceDirectoryURL.fileSystemPath(), SandboxExtension::Type::ReadOnly, sandboxExtensionHandle)) {
1089             process.assumeReadAccessToBaseURL(*this, resourceDirectoryURL);
1090             return;
1091         }
1092 #endif
1093     }
1094
1095     if (process.hasAssumedReadAccessToURL(url))
1096         return;
1097
1098     // Inspector resources are in a directory with assumed access.
1099     ASSERT_WITH_SECURITY_IMPLICATION(!WebKit::isInspectorPage(*this));
1100
1101 #if HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_PID)
1102     if (SandboxExtension::createHandleForReadByPid("/", process.processIdentifier(), sandboxExtensionHandle)) {
1103         willAcquireUniversalFileReadSandboxExtension(process);
1104         return;
1105     }
1106 #else
1107     if (SandboxExtension::createHandle("/", SandboxExtension::Type::ReadOnly, sandboxExtensionHandle)) {
1108         willAcquireUniversalFileReadSandboxExtension(process);
1109         return;
1110     }
1111 #endif
1112
1113 #if PLATFORM(COCOA)
1114     if (!linkedOnOrAfter(SDKVersion::FirstWithoutUnconditionalUniversalSandboxExtension))
1115         willAcquireUniversalFileReadSandboxExtension(process);
1116 #endif
1117
1118     // We failed to issue an universal file read access sandbox, fall back to issuing one for the base URL instead.
1119     auto baseURL = URL(URL(), url.baseAsString());
1120     auto basePath = baseURL.fileSystemPath();
1121     if (basePath.isNull())
1122         return;
1123 #if HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_PID)
1124     if (SandboxExtension::createHandleForReadByPid(basePath, process.processIdentifier(), sandboxExtensionHandle))
1125         process.assumeReadAccessToBaseURL(*this, baseURL);
1126 #else
1127     if (SandboxExtension::createHandle(basePath, SandboxExtension::Type::ReadOnly, sandboxExtensionHandle))
1128         process.assumeReadAccessToBaseURL(*this, baseURL);
1129 #endif
1130 }
1131
1132 #if !PLATFORM(COCOA)
1133 void WebPageProxy::addPlatformLoadParameters(LoadParameters&)
1134 {
1135 }
1136 #endif
1137
1138 WebProcessProxy& WebPageProxy::ensureRunningProcess()
1139 {
1140     if (!hasRunningProcess())
1141         launchProcess({ }, ProcessLaunchReason::InitialProcess);
1142
1143     return m_process;
1144 }
1145
1146 RefPtr<API::Navigation> WebPageProxy::loadRequest(ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData)
1147 {
1148     if (m_isClosed)
1149         return nullptr;
1150
1151     RELEASE_LOG_IF_ALLOWED(Loading, "loadRequest:");
1152
1153     if (!hasRunningProcess())
1154         launchProcess(RegistrableDomain { request.url() }, ProcessLaunchReason::InitialProcess);
1155
1156     auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem());
1157     loadRequestWithNavigationShared(m_process.copyRef(), m_webPageID, navigation.get(), WTFMove(request), shouldOpenExternalURLsPolicy, userData, ShouldTreatAsContinuingLoad::No);
1158     return navigation;
1159 }
1160
1161 void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& process, WebCore::PageIdentifier webPageID, API::Navigation& navigation, ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& websitePolicies)
1162 {
1163     ASSERT(!m_isClosed);
1164
1165     RELEASE_LOG_IF_ALLOWED(Loading, "loadRequestWithNavigationShared:");
1166
1167     auto transaction = m_pageLoadState.transaction();
1168
1169     auto url = request.url();
1170     if (shouldTreatAsContinuingLoad != ShouldTreatAsContinuingLoad::Yes)
1171         m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), url });
1172
1173     LoadParameters loadParameters;
1174     loadParameters.navigationID = navigation.navigationID();
1175     loadParameters.request = WTFMove(request);
1176     loadParameters.shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
1177     loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1178     loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::Yes;
1179     loadParameters.websitePolicies = WTFMove(websitePolicies);
1180     loadParameters.lockHistory = navigation.lockHistory();
1181     loadParameters.lockBackForwardList = navigation.lockBackForwardList();
1182     loadParameters.clientRedirectSourceForHistory = navigation.clientRedirectSourceForHistory();
1183     maybeInitializeSandboxExtensionHandle(process, url, m_pageLoadState.resourceDirectoryURL(), loadParameters.sandboxExtensionHandle);
1184
1185     addPlatformLoadParameters(loadParameters);
1186
1187 #if HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_PID)
1188     if (!process->isLaunching() || !url.isLocalFile())
1189         process->send(Messages::WebPage::LoadRequest(loadParameters), webPageID);
1190     else
1191         process->send(Messages::WebPage::LoadRequestWaitingForPID(loadParameters, m_pageLoadState.resourceDirectoryURL(), m_identifier), webPageID);
1192 #else
1193     process->send(Messages::WebPage::LoadRequest(loadParameters), webPageID);
1194 #endif
1195     process->responsivenessTimer().start();
1196 }
1197
1198 RefPtr<API::Navigation> WebPageProxy::loadFile(const String& fileURLString, const String& resourceDirectoryURLString, API::Object* userData)
1199 {
1200     RELEASE_LOG_IF_ALLOWED(Loading, "loadFile:");
1201
1202     if (m_isClosed) {
1203         RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: page is closed");
1204         return nullptr;
1205     }
1206
1207     if (!hasRunningProcess())
1208         launchProcess({ }, ProcessLaunchReason::InitialProcess);
1209
1210     URL fileURL = URL(URL(), fileURLString);
1211     if (!fileURL.isLocalFile()) {
1212         RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: file is not local");
1213         return nullptr;
1214     }
1215
1216     URL resourceDirectoryURL;
1217     if (resourceDirectoryURLString.isNull())
1218         resourceDirectoryURL = URL({ }, "file:///"_s);
1219     else {
1220         resourceDirectoryURL = URL(URL(), resourceDirectoryURLString);
1221         if (!resourceDirectoryURL.isLocalFile()) {
1222             RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: resource URL is not local");
1223             return nullptr;
1224         }
1225     }
1226
1227     auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(fileURL), m_backForwardList->currentItem());
1228
1229     auto transaction = m_pageLoadState.transaction();
1230
1231     m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), fileURLString }, resourceDirectoryURL);
1232
1233     LoadParameters loadParameters;
1234     loadParameters.navigationID = navigation->navigationID();
1235     loadParameters.request = fileURL;
1236     loadParameters.shouldOpenExternalURLsPolicy = ShouldOpenExternalURLsPolicy::ShouldNotAllow;
1237     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1238     maybeInitializeSandboxExtensionHandle(m_process, fileURL, resourceDirectoryURL, loadParameters.sandboxExtensionHandle);
1239     addPlatformLoadParameters(loadParameters);
1240
1241 #if HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_PID)
1242     if (m_process->isLaunching())
1243         m_process->send(Messages::WebPage::LoadRequestWaitingForPID(loadParameters, resourceDirectoryURL, m_identifier), m_webPageID);
1244     else
1245         m_process->send(Messages::WebPage::LoadRequest(loadParameters), m_webPageID);
1246 #else
1247     m_process->send(Messages::WebPage::LoadRequest(loadParameters), m_webPageID);
1248 #endif
1249     m_process->responsivenessTimer().start();
1250
1251     return navigation;
1252 }
1253
1254 RefPtr<API::Navigation> WebPageProxy::loadData(const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
1255 {
1256     RELEASE_LOG_IF_ALLOWED(Loading, "loadData:");
1257
1258     if (m_isClosed) {
1259         RELEASE_LOG_IF_ALLOWED(Loading, "loadData: page is closed");
1260         return nullptr;
1261     }
1262
1263     if (!hasRunningProcess())
1264         launchProcess({ }, ProcessLaunchReason::InitialProcess);
1265
1266     auto navigation = m_navigationState->createLoadDataNavigation(makeUnique<API::SubstituteData>(data.vector(), MIMEType, encoding, baseURL, userData));
1267     loadDataWithNavigationShared(m_process.copyRef(), m_webPageID, navigation, data, MIMEType, encoding, baseURL, userData, ShouldTreatAsContinuingLoad::No, WTF::nullopt, shouldOpenExternalURLsPolicy);
1268     return navigation;
1269 }
1270
1271 void WebPageProxy::loadDataWithNavigationShared(Ref<WebProcessProxy>&& process, WebCore::PageIdentifier webPageID, API::Navigation& navigation, const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& websitePolicies, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
1272 {
1273     RELEASE_LOG_IF_ALLOWED(Loading, "loadDataWithNavigation");
1274
1275     ASSERT(!m_isClosed);
1276
1277     auto transaction = m_pageLoadState.transaction();
1278
1279     m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), !baseURL.isEmpty() ? baseURL : WTF::blankURL().string() });
1280
1281     LoadParameters loadParameters;
1282     loadParameters.navigationID = navigation.navigationID();
1283     loadParameters.data = data;
1284     loadParameters.MIMEType = MIMEType;
1285     loadParameters.encodingName = encoding;
1286     loadParameters.baseURLString = baseURL;
1287     loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::Yes;
1288     loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1289     loadParameters.websitePolicies = WTFMove(websitePolicies);
1290     loadParameters.shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
1291     addPlatformLoadParameters(loadParameters);
1292
1293     process->assumeReadAccessToBaseURL(*this, baseURL);
1294     process->send(Messages::WebPage::LoadData(loadParameters), webPageID);
1295     process->responsivenessTimer().start();
1296 }
1297
1298 void WebPageProxy::loadAlternateHTML(const IPC::DataReference& htmlData, const String& encoding, const URL& baseURL, const URL& unreachableURL, API::Object* userData)
1299 {
1300     RELEASE_LOG_IF_ALLOWED(Loading, "loadAlternateHTML");
1301
1302     // When the UIProcess is in the process of handling a failing provisional load, do not attempt to
1303     // start a second alternative HTML load as this will prevent the page load state from being
1304     // handled properly.
1305     if (m_isClosed || m_isLoadingAlternateHTMLStringForFailingProvisionalLoad) {
1306         RELEASE_LOG_IF_ALLOWED(Loading, "loadAlternateHTML: page is closed (or other)");
1307         return;
1308     }
1309
1310     if (!m_failingProvisionalLoadURL.isEmpty())
1311         m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = true;
1312
1313     if (!hasRunningProcess())
1314         launchProcess(RegistrableDomain { baseURL }, ProcessLaunchReason::InitialProcess);
1315
1316     auto transaction = m_pageLoadState.transaction();
1317
1318     m_pageLoadState.setPendingAPIRequest(transaction, { 0, unreachableURL });
1319     m_pageLoadState.setUnreachableURL(transaction, unreachableURL);
1320
1321     if (m_mainFrame)
1322         m_mainFrame->setUnreachableURL(unreachableURL);
1323
1324     LoadParameters loadParameters;
1325     loadParameters.navigationID = 0;
1326     loadParameters.data = htmlData;
1327     loadParameters.MIMEType = "text/html"_s;
1328     loadParameters.encodingName = encoding;
1329     loadParameters.baseURLString = baseURL;
1330     loadParameters.unreachableURLString = unreachableURL;
1331     loadParameters.provisionalLoadErrorURLString = m_failingProvisionalLoadURL;
1332     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1333     addPlatformLoadParameters(loadParameters);
1334
1335     m_process->assumeReadAccessToBaseURL(*this, baseURL);
1336     m_process->assumeReadAccessToBaseURL(*this, unreachableURL);
1337     m_process->send(Messages::WebPage::LoadAlternateHTML(loadParameters), m_webPageID);
1338     m_process->responsivenessTimer().start();
1339 }
1340
1341 void WebPageProxy::loadWebArchiveData(API::Data* webArchiveData, API::Object* userData)
1342 {
1343     RELEASE_LOG_IF_ALLOWED(Loading, "loadWebArchiveData:");
1344
1345     if (m_isClosed) {
1346         RELEASE_LOG_IF_ALLOWED(Loading, "loadWebArchiveData: page is closed");
1347         return;
1348     }
1349
1350     if (!hasRunningProcess())
1351         launchProcess({ }, ProcessLaunchReason::InitialProcess);
1352
1353     auto transaction = m_pageLoadState.transaction();
1354     m_pageLoadState.setPendingAPIRequest(transaction, { 0, WTF::blankURL().string() });
1355
1356     LoadParameters loadParameters;
1357     loadParameters.navigationID = 0;
1358     loadParameters.data = webArchiveData->dataReference();
1359     loadParameters.MIMEType = "application/x-webarchive"_s;
1360     loadParameters.encodingName = "utf-16"_s;
1361     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1362     addPlatformLoadParameters(loadParameters);
1363
1364     m_process->send(Messages::WebPage::LoadData(loadParameters), m_webPageID);
1365     m_process->responsivenessTimer().start();
1366 }
1367
1368 void WebPageProxy::navigateToPDFLinkWithSimulatedClick(const String& urlString, IntPoint documentPoint, IntPoint screenPoint)
1369 {
1370     RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick:");
1371
1372     if (m_isClosed) {
1373         RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick: page is closed:");
1374         return;
1375     }
1376
1377     if (WTF::protocolIsJavaScript(urlString))
1378         return;
1379
1380     if (!hasRunningProcess())
1381         launchProcess(RegistrableDomain { URL(URL(), urlString) }, ProcessLaunchReason::InitialProcess);
1382
1383     m_process->send(Messages::WebPage::NavigateToPDFLinkWithSimulatedClick(urlString, documentPoint, screenPoint), m_webPageID);
1384     m_process->responsivenessTimer().start();
1385 }
1386
1387 void WebPageProxy::stopLoading()
1388 {
1389     RELEASE_LOG_IF_ALLOWED(Loading, "stopLoading:");
1390
1391     if (!hasRunningProcess()) {
1392         RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick: page is not valid");
1393         return;
1394     }
1395
1396     m_process->send(Messages::WebPage::StopLoading(), m_webPageID);
1397     if (m_provisionalPage) {
1398         m_provisionalPage->cancel();
1399         m_provisionalPage = nullptr;
1400     }
1401     m_process->responsivenessTimer().start();
1402 }
1403
1404 RefPtr<API::Navigation> WebPageProxy::reload(OptionSet<WebCore::ReloadOption> options)
1405 {
1406     RELEASE_LOG_IF_ALLOWED(Loading, "reload:");
1407
1408     SandboxExtension::Handle sandboxExtensionHandle;
1409
1410     String url = currentURL();
1411     if (!url.isEmpty()) {
1412         // We may not have an extension yet if back/forward list was reinstated after a WebProcess crash or a browser relaunch
1413         maybeInitializeSandboxExtensionHandle(m_process, URL(URL(), url), currentResourceDirectoryURL(), sandboxExtensionHandle);
1414     }
1415
1416     if (!hasRunningProcess())
1417         return launchProcessForReload();
1418     
1419     auto navigation = m_navigationState->createReloadNavigation();
1420
1421     if (!url.isEmpty()) {
1422         auto transaction = m_pageLoadState.transaction();
1423         m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), url });
1424     }
1425
1426     // Store decision to reload without content blockers on the navigation so that we can later set the corresponding
1427     // WebsitePolicies flag in WebPageProxy::receivedNavigationPolicyDecision().
1428     if (options.contains(WebCore::ReloadOption::DisableContentBlockers))
1429         navigation->setUserContentExtensionsEnabled(false);
1430
1431     m_process->send(Messages::WebPage::Reload(navigation->navigationID(), options.toRaw(), sandboxExtensionHandle), m_webPageID);
1432     m_process->responsivenessTimer().start();
1433
1434 #if ENABLE(SPEECH_SYNTHESIS)
1435     resetSpeechSynthesizer();
1436 #endif
1437
1438     return navigation;
1439 }
1440
1441 void WebPageProxy::recordAutomaticNavigationSnapshot()
1442 {
1443     if (m_shouldSuppressNextAutomaticNavigationSnapshot)
1444         return;
1445
1446     if (WebBackForwardListItem* item = m_backForwardList->currentItem())
1447         recordNavigationSnapshot(*item);
1448 }
1449
1450 void WebPageProxy::recordNavigationSnapshot(WebBackForwardListItem& item)
1451 {
1452     if (!m_shouldRecordNavigationSnapshots)
1453         return;
1454
1455 #if PLATFORM(COCOA) || PLATFORM(GTK)
1456     ViewSnapshotStore::singleton().recordSnapshot(*this, item);
1457 #else
1458     UNUSED_PARAM(item);
1459 #endif
1460 }
1461
1462 RefPtr<API::Navigation> WebPageProxy::goForward()
1463 {
1464     WebBackForwardListItem* forwardItem = m_backForwardList->forwardItem();
1465     if (!forwardItem)
1466         return nullptr;
1467
1468     return goToBackForwardItem(*forwardItem, FrameLoadType::Forward);
1469 }
1470
1471 RefPtr<API::Navigation> WebPageProxy::goBack()
1472 {
1473     WebBackForwardListItem* backItem = m_backForwardList->backItem();
1474     if (!backItem)
1475         return nullptr;
1476
1477     return goToBackForwardItem(*backItem, FrameLoadType::Back);
1478 }
1479
1480 RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item)
1481 {
1482     return goToBackForwardItem(item, FrameLoadType::IndexedBackForward);
1483 }
1484
1485 RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item, FrameLoadType frameLoadType)
1486 {
1487     RELEASE_LOG_IF_ALLOWED(Loading, "goToBackForwardItem:");
1488     LOG(Loading, "WebPageProxy %p goToBackForwardItem to item URL %s", this, item.url().utf8().data());
1489
1490     if (!hasRunningProcess())
1491         return launchProcessWithItem(item);
1492
1493     RefPtr<API::Navigation> navigation;
1494     if (!m_backForwardList->currentItem()->itemIsInSameDocument(item))
1495         navigation = m_navigationState->createBackForwardNavigation(item, m_backForwardList->currentItem(), frameLoadType);
1496
1497     auto transaction = m_pageLoadState.transaction();
1498     m_pageLoadState.setPendingAPIRequest(transaction, { navigation ? navigation->navigationID() : 0, item.url() });
1499
1500     m_process->send(Messages::WebPage::GoToBackForwardItem(navigation ? navigation->navigationID() : 0, item.itemID(), frameLoadType, ShouldTreatAsContinuingLoad::No, WTF::nullopt), m_webPageID);
1501     m_process->responsivenessTimer().start();
1502
1503     return navigation;
1504 }
1505
1506 void WebPageProxy::tryRestoreScrollPosition()
1507 {
1508     RELEASE_LOG_IF_ALLOWED(Loading, "tryRestoreScrollPosition:");
1509
1510     if (!hasRunningProcess()) {
1511         RELEASE_LOG_IF_ALLOWED(Loading, "tryRestoreScrollPosition: page is not valid");
1512         return;
1513     }
1514
1515     m_process->send(Messages::WebPage::TryRestoreScrollPosition(), m_webPageID);
1516 }
1517
1518 void WebPageProxy::didChangeBackForwardList(WebBackForwardListItem* added, Vector<Ref<WebBackForwardListItem>>&& removed)
1519 {
1520     PageClientProtector protector(pageClient());
1521
1522     if (!m_navigationClient->didChangeBackForwardList(*this, added, removed) && m_loaderClient)
1523         m_loaderClient->didChangeBackForwardList(*this, added, WTFMove(removed));
1524
1525     auto transaction = m_pageLoadState.transaction();
1526
1527     m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
1528     m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
1529 }
1530
1531 void WebPageProxy::willGoToBackForwardListItem(const BackForwardItemIdentifier& itemID, bool inPageCache)
1532 {
1533     PageClientProtector protector(pageClient());
1534
1535     if (auto* item = m_backForwardList->itemForID(itemID))
1536         m_navigationClient->willGoToBackForwardListItem(*this, *item, inPageCache);
1537 }
1538
1539 bool WebPageProxy::shouldKeepCurrentBackForwardListItemInList(WebBackForwardListItem& item)
1540 {
1541     PageClientProtector protector(pageClient());
1542
1543     return !m_loaderClient || m_loaderClient->shouldKeepCurrentBackForwardListItemInList(*this, item);
1544 }
1545
1546 bool WebPageProxy::canShowMIMEType(const String& mimeType)
1547 {
1548     if (MIMETypeRegistry::canShowMIMEType(mimeType))
1549         return true;
1550
1551 #if ENABLE(NETSCAPE_PLUGIN_API)
1552     String newMimeType = mimeType;
1553     PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL());
1554     if (!plugin.path.isNull() && m_preferences->pluginsEnabled())
1555         return true;
1556 #endif // ENABLE(NETSCAPE_PLUGIN_API)
1557
1558 #if PLATFORM(COCOA)
1559     // On Mac, we can show PDFs.
1560     if (MIMETypeRegistry::isPDFOrPostScriptMIMEType(mimeType) && !WebProcessPool::omitPDFSupport())
1561         return true;
1562 #endif // PLATFORM(COCOA)
1563
1564     return false;
1565 }
1566
1567 void WebPageProxy::setControlledByAutomation(bool controlled)
1568 {
1569     if (m_controlledByAutomation == controlled)
1570         return;
1571
1572     m_controlledByAutomation = controlled;
1573
1574     if (!hasRunningProcess())
1575         return;
1576
1577     m_process->send(Messages::WebPage::SetControlledByAutomation(controlled), m_webPageID);
1578     m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation));
1579 }
1580
1581 void WebPageProxy::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type)
1582 {
1583     m_inspectorController->createInspectorTarget(targetId, type);
1584 }
1585
1586 void WebPageProxy::destroyInspectorTarget(const String& targetId)
1587 {
1588     m_inspectorController->destroyInspectorTarget(targetId);
1589 }
1590
1591 void WebPageProxy::sendMessageToInspectorFrontend(const String& targetId, const String& message)
1592 {
1593     m_inspectorController->sendMessageToInspectorFrontend(targetId, message);
1594 }
1595
1596 #if ENABLE(REMOTE_INSPECTOR)
1597 void WebPageProxy::setIndicating(bool indicating)
1598 {
1599     if (!hasRunningProcess())
1600         return;
1601
1602     m_process->send(Messages::WebPage::SetIndicating(indicating), m_webPageID);
1603 }
1604
1605 bool WebPageProxy::allowsRemoteInspection() const
1606 {
1607     return m_inspectorDebuggable->remoteDebuggingAllowed();
1608 }
1609
1610 void WebPageProxy::setAllowsRemoteInspection(bool allow)
1611 {
1612     m_inspectorDebuggable->setRemoteDebuggingAllowed(allow);
1613 }
1614
1615 String WebPageProxy::remoteInspectionNameOverride() const
1616 {
1617     return m_inspectorDebuggable->nameOverride();
1618 }
1619
1620 void WebPageProxy::setRemoteInspectionNameOverride(const String& name)
1621 {
1622     m_inspectorDebuggable->setNameOverride(name);
1623 }
1624
1625 void WebPageProxy::remoteInspectorInformationDidChange()
1626 {
1627     m_inspectorDebuggable->update();
1628 }
1629 #endif
1630
1631 void WebPageProxy::clearInspectorTargets()
1632 {
1633     m_inspectorController->clearTargets();
1634 }
1635
1636 void WebPageProxy::createInspectorTargets()
1637 {
1638     String pageTargetId = makeString("page-", m_webPageID.toUInt64());
1639     m_inspectorController->createInspectorTarget(pageTargetId, Inspector::InspectorTargetType::Page);
1640 }
1641
1642 void WebPageProxy::setBackgroundColor(const Optional<Color>& color)
1643 {
1644     if (m_backgroundColor == color)
1645         return;
1646
1647     m_backgroundColor = color;
1648     if (hasRunningProcess())
1649         m_process->send(Messages::WebPage::SetBackgroundColor(color), m_webPageID);
1650 }
1651
1652 void WebPageProxy::setTopContentInset(float contentInset)
1653 {
1654     if (m_topContentInset == contentInset)
1655         return;
1656
1657     m_topContentInset = contentInset;
1658
1659     if (!hasRunningProcess())
1660         return;
1661 #if PLATFORM(COCOA)
1662     MachSendRight fence = m_drawingArea->createFence();
1663
1664     auto fenceAttachment = IPC::Attachment(fence.leakSendRight(), MACH_MSG_TYPE_MOVE_SEND);
1665     m_process->send(Messages::WebPage::SetTopContentInsetFenced(contentInset, fenceAttachment), m_webPageID);
1666 #else
1667     m_process->send(Messages::WebPage::SetTopContentInset(contentInset), m_webPageID);
1668 #endif
1669 }
1670
1671 void WebPageProxy::setUnderlayColor(const Color& color)
1672 {
1673     if (m_underlayColor == color)
1674         return;
1675
1676     m_underlayColor = color;
1677
1678     if (hasRunningProcess())
1679         m_process->send(Messages::WebPage::SetUnderlayColor(color), m_webPageID);
1680 }
1681
1682 void WebPageProxy::viewWillStartLiveResize()
1683 {
1684     if (!hasRunningProcess())
1685         return;
1686
1687     closeOverlayedViews();
1688     m_process->send(Messages::WebPage::ViewWillStartLiveResize(), m_webPageID);
1689 }
1690
1691 void WebPageProxy::viewWillEndLiveResize()
1692 {
1693     if (!hasRunningProcess())
1694         return;
1695     m_process->send(Messages::WebPage::ViewWillEndLiveResize(), m_webPageID);
1696 }
1697
1698 void WebPageProxy::setViewNeedsDisplay(const Region& region)
1699 {
1700     pageClient().setViewNeedsDisplay(region);
1701 }
1702
1703 void WebPageProxy::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin)
1704 {
1705     pageClient().requestScroll(scrollPosition, scrollOrigin);
1706 }
1707
1708 WebCore::FloatPoint WebPageProxy::viewScrollPosition() const
1709 {
1710     return pageClient().viewScrollPosition();
1711 }
1712
1713 void WebPageProxy::setSuppressVisibilityUpdates(bool flag)
1714 {
1715     if (m_suppressVisibilityUpdates == flag)
1716         return;
1717     m_suppressVisibilityUpdates = flag;
1718
1719     if (!m_suppressVisibilityUpdates) {
1720 #if PLATFORM(COCOA)
1721         m_activityStateChangeDispatcher->schedule();
1722 #else
1723         dispatchActivityStateChange();
1724 #endif
1725     }
1726 }
1727
1728 void WebPageProxy::updateActivityState(OptionSet<ActivityState::Flag> flagsToUpdate)
1729 {
1730     bool wasVisible = isViewVisible();
1731     m_activityState.remove(flagsToUpdate);
1732     if (flagsToUpdate & ActivityState::IsFocused && pageClient().isViewFocused())
1733         m_activityState.add(ActivityState::IsFocused);
1734     if (flagsToUpdate & ActivityState::WindowIsActive && pageClient().isViewWindowActive())
1735         m_activityState.add(ActivityState::WindowIsActive);
1736     if (flagsToUpdate & ActivityState::IsVisible) {
1737         bool isNowVisible = pageClient().isViewVisible();
1738         if (isNowVisible)
1739             m_activityState.add(ActivityState::IsVisible);
1740         if (wasVisible != isNowVisible)
1741             RELEASE_LOG_IF_ALLOWED(ViewState, "updateActivityState: view visibility state changed %d -> %d", wasVisible, isNowVisible);
1742     }
1743     if (flagsToUpdate & ActivityState::IsVisibleOrOccluded && pageClient().isViewVisibleOrOccluded())
1744         m_activityState.add(ActivityState::IsVisibleOrOccluded);
1745     if (flagsToUpdate & ActivityState::IsInWindow && pageClient().isViewInWindow())
1746         m_activityState.add(ActivityState::IsInWindow);
1747     if (flagsToUpdate & ActivityState::IsVisuallyIdle && pageClient().isVisuallyIdle())
1748         m_activityState.add(ActivityState::IsVisuallyIdle);
1749     if (flagsToUpdate & ActivityState::IsAudible && m_mediaState & MediaProducer::IsPlayingAudio && !(m_mutedState & MediaProducer::AudioIsMuted))
1750         m_activityState.add(ActivityState::IsAudible);
1751     if (flagsToUpdate & ActivityState::IsLoading && m_pageLoadState.isLoading())
1752         m_activityState.add(ActivityState::IsLoading);
1753     if (flagsToUpdate & ActivityState::IsCapturingMedia && m_mediaState & (MediaProducer::HasActiveAudioCaptureDevice | MediaProducer::HasActiveVideoCaptureDevice))
1754         m_activityState.add(ActivityState::IsCapturingMedia);
1755 }
1756
1757 void WebPageProxy::activityStateDidChange(OptionSet<ActivityState::Flag> mayHaveChanged, bool wantsSynchronousReply, ActivityStateChangeDispatchMode dispatchMode)
1758 {
1759     LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " activityStateDidChange - mayHaveChanged " << mayHaveChanged);
1760
1761     m_potentiallyChangedActivityStateFlags.add(mayHaveChanged);
1762     m_activityStateChangeWantsSynchronousReply = m_activityStateChangeWantsSynchronousReply || wantsSynchronousReply;
1763
1764     if (m_suppressVisibilityUpdates && dispatchMode != ActivityStateChangeDispatchMode::Immediate)
1765         return;
1766
1767 #if PLATFORM(COCOA)
1768     bool isNewlyInWindow = !isInWindow() && (mayHaveChanged & ActivityState::IsInWindow) && pageClient().isViewInWindow();
1769     if (dispatchMode == ActivityStateChangeDispatchMode::Immediate || isNewlyInWindow) {
1770         dispatchActivityStateChange();
1771         return;
1772     }
1773     m_activityStateChangeDispatcher->schedule();
1774 #else
1775     UNUSED_PARAM(dispatchMode);
1776     dispatchActivityStateChange();
1777 #endif
1778 }
1779
1780 void WebPageProxy::viewDidLeaveWindow()
1781 {
1782     closeOverlayedViews();
1783 #if PLATFORM(IOS_FAMILY) && HAVE(AVKIT) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
1784     // When leaving the current page, close the video fullscreen.
1785     if (m_videoFullscreenManager && m_videoFullscreenManager->hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModeStandard))
1786         m_videoFullscreenManager->requestHideAndExitFullscreen();
1787 #endif
1788 }
1789
1790 void WebPageProxy::viewDidEnterWindow()
1791 {
1792     LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
1793     if (m_layerHostingMode != layerHostingMode) {
1794         m_layerHostingMode = layerHostingMode;
1795         m_process->send(Messages::WebPage::SetLayerHostingMode(layerHostingMode), m_webPageID);
1796     }
1797 }
1798
1799 void WebPageProxy::dispatchActivityStateChange()
1800 {
1801 #if PLATFORM(COCOA)
1802     m_activityStateChangeDispatcher->invalidate();
1803 #endif
1804
1805     if (!hasRunningProcess())
1806         return;
1807
1808     LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " dispatchActivityStateChange - potentiallyChangedActivityStateFlags " << m_potentiallyChangedActivityStateFlags);
1809
1810     // If the visibility state may have changed, then so may the visually idle & occluded agnostic state.
1811     if (m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible)
1812         m_potentiallyChangedActivityStateFlags.add({ ActivityState::IsVisibleOrOccluded, ActivityState::IsVisuallyIdle });
1813
1814     // Record the prior view state, update the flags that may have changed,
1815     // and check which flags have actually changed.
1816     auto previousActivityState = m_activityState;
1817     updateActivityState(m_potentiallyChangedActivityStateFlags);
1818     auto changed = m_activityState ^ previousActivityState;
1819
1820     if (changed)
1821         LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " dispatchActivityStateChange: state changed from " << previousActivityState << " to " << m_activityState);
1822
1823     if ((changed & ActivityState::WindowIsActive) && isViewWindowActive())
1824         updateCurrentModifierState();
1825
1826     if ((m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible) && isViewVisible())
1827         viewIsBecomingVisible();
1828
1829     bool isNowInWindow = (changed & ActivityState::IsInWindow) && isInWindow();
1830     // We always want to wait for the Web process to reply if we've been in-window before and are coming back in-window.
1831     if (m_viewWasEverInWindow && isNowInWindow) {
1832         if (m_drawingArea->hasVisibleContent() && m_waitsForPaintAfterViewDidMoveToWindow && !m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow)
1833             m_activityStateChangeWantsSynchronousReply = true;
1834         m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow = false;
1835     }
1836
1837     // Don't wait synchronously if the view state is not visible. (This matters in particular on iOS, where a hidden page may be suspended.)
1838     if (!(m_activityState & ActivityState::IsVisible))
1839         m_activityStateChangeWantsSynchronousReply = false;
1840
1841     auto activityStateChangeID = m_activityStateChangeWantsSynchronousReply ? takeNextActivityStateChangeID() : static_cast<ActivityStateChangeID>(ActivityStateChangeAsynchronous);
1842
1843     if (changed || activityStateChangeID != ActivityStateChangeAsynchronous || !m_nextActivityStateChangeCallbacks.isEmpty())
1844         m_process->send(Messages::WebPage::SetActivityState(m_activityState, activityStateChangeID, m_nextActivityStateChangeCallbacks), m_webPageID);
1845
1846     m_nextActivityStateChangeCallbacks.clear();
1847
1848     // This must happen after the SetActivityState message is sent, to ensure the page visibility event can fire.
1849     updateThrottleState();
1850
1851 #if ENABLE(POINTER_LOCK)
1852     if (((changed & ActivityState::IsVisible) && !isViewVisible()) || ((changed & ActivityState::WindowIsActive) && !pageClient().isViewWindowActive())
1853         || ((changed & ActivityState::IsFocused) && !(m_activityState & ActivityState::IsFocused)))
1854         requestPointerUnlock();
1855 #endif
1856
1857     if (changed & ActivityState::IsVisible) {
1858         if (isViewVisible())
1859             m_visiblePageToken = m_process->visiblePageToken();
1860         else {
1861             m_visiblePageToken = nullptr;
1862
1863             // If we've started the responsiveness timer as part of telling the web process to update the backing store
1864             // state, it might not send back a reply (since it won't paint anything if the web page is hidden) so we
1865             // stop the unresponsiveness timer here.
1866             m_process->responsivenessTimer().stop();
1867         }
1868     }
1869
1870     if (changed & ActivityState::IsInWindow) {
1871         if (isInWindow())
1872             viewDidEnterWindow();
1873         else
1874             viewDidLeaveWindow();
1875     }
1876
1877     updateBackingStoreDiscardableState();
1878
1879     if (activityStateChangeID != ActivityStateChangeAsynchronous)
1880         waitForDidUpdateActivityState(activityStateChangeID);
1881
1882     m_potentiallyChangedActivityStateFlags = { };
1883     m_activityStateChangeWantsSynchronousReply = false;
1884     m_viewWasEverInWindow |= isNowInWindow;
1885 }
1886
1887 bool WebPageProxy::isAlwaysOnLoggingAllowed() const
1888 {
1889     return sessionID().isAlwaysOnLoggingAllowed();
1890 }
1891
1892 void WebPageProxy::updateThrottleState()
1893 {
1894     bool processSuppressionEnabled = m_preferences->pageVisibilityBasedProcessSuppressionEnabled();
1895
1896     // If process suppression is not enabled take a token on the process pool to disable suppression of support processes.
1897     if (!processSuppressionEnabled)
1898         m_preventProcessSuppressionCount = m_process->processPool().processSuppressionDisabledForPageCount();
1899     else if (!m_preventProcessSuppressionCount)
1900         m_preventProcessSuppressionCount = nullptr;
1901
1902     if (m_activityState & ActivityState::IsVisuallyIdle)
1903         m_pageIsUserObservableCount = nullptr;
1904     else if (!m_pageIsUserObservableCount)
1905         m_pageIsUserObservableCount = m_process->processPool().userObservablePageCount();
1906
1907 #if PLATFORM(IOS_FAMILY)
1908     bool isCapturingMedia = m_activityState.contains(ActivityState::IsCapturingMedia);
1909     bool isAudible = m_activityState.contains(ActivityState::IsAudible);
1910     if (!isViewVisible() && !m_alwaysRunsAtForegroundPriority && !isCapturingMedia && !isAudible) {
1911         if (m_activityToken) {
1912             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because the view is no longer visible");
1913             m_activityToken = nullptr;
1914         }
1915     } else if (!m_activityToken) {
1916         if (isViewVisible())
1917             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because the view is visible");
1918         else if (isAudible)
1919             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because we are playing audio");
1920         else if (isCapturingMedia)
1921             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because media capture is active");
1922         else
1923             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion even though the view is not visible because m_alwaysRunsAtForegroundPriority is true");
1924         m_activityToken = m_process->throttler().foregroundActivityToken();
1925     }
1926 #endif
1927 }
1928
1929 void WebPageProxy::updateHiddenPageThrottlingAutoIncreases()
1930 {
1931     if (!m_preferences->hiddenPageDOMTimerThrottlingAutoIncreases())
1932         m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = nullptr;
1933     else if (!m_hiddenPageDOMTimerThrottlingAutoIncreasesCount)
1934         m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = m_process->processPool().hiddenPageThrottlingAutoIncreasesCount();
1935 }
1936
1937 void WebPageProxy::layerHostingModeDidChange()
1938 {
1939     LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
1940     if (m_layerHostingMode == layerHostingMode)
1941         return;
1942
1943     m_layerHostingMode = layerHostingMode;
1944
1945     if (hasRunningProcess())
1946         m_process->send(Messages::WebPage::SetLayerHostingMode(layerHostingMode), m_webPageID);
1947 }
1948
1949 void WebPageProxy::waitForDidUpdateActivityState(ActivityStateChangeID activityStateChangeID)
1950 {
1951     if (!hasRunningProcess())
1952         return;
1953
1954     if (m_process->state() != WebProcessProxy::State::Running)
1955         return;
1956
1957     // If we have previously timed out with no response from the WebProcess, don't block the UIProcess again until it starts responding.
1958     if (m_waitingForDidUpdateActivityState)
1959         return;
1960
1961 #if PLATFORM(IOS_FAMILY)
1962     // Hail Mary check. Should not be possible (dispatchActivityStateChange should force async if not visible,
1963     // and if visible we should be holding an assertion) - but we should never block on a suspended process.
1964     if (!m_activityToken) {
1965         ASSERT_NOT_REACHED();
1966         return;
1967     }
1968 #endif
1969
1970     m_waitingForDidUpdateActivityState = true;
1971
1972     m_drawingArea->waitForDidUpdateActivityState(activityStateChangeID);
1973 }
1974
1975 IntSize WebPageProxy::viewSize() const
1976 {
1977     return pageClient().viewSize();
1978 }
1979
1980 void WebPageProxy::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& keyboardEvent, WTF::Function<void (CallbackBase::Error)>&& callbackFunction)
1981 {
1982     if (!hasRunningProcess()) {
1983         callbackFunction(CallbackBase::Error::OwnerWasInvalidated);
1984         return;
1985     }
1986
1987     auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
1988     m_process->send(Messages::WebPage::SetInitialFocus(forward, isKeyboardEventValid, keyboardEvent, callbackID), m_webPageID);
1989 }
1990
1991 void WebPageProxy::clearSelection()
1992 {
1993     if (!hasRunningProcess())
1994         return;
1995     m_process->send(Messages::WebPage::ClearSelection(), m_webPageID);
1996 }
1997
1998 void WebPageProxy::restoreSelectionInFocusedEditableElement()
1999 {
2000     if (!hasRunningProcess())
2001         return;
2002     m_process->send(Messages::WebPage::RestoreSelectionInFocusedEditableElement(), m_webPageID);
2003 }
2004
2005 void WebPageProxy::validateCommand(const String& commandName, WTF::Function<void (const String&, bool, int32_t, CallbackBase::Error)>&& callbackFunction)
2006 {
2007     if (!hasRunningProcess()) {
2008         callbackFunction(String(), false, 0, CallbackBase::Error::Unknown);
2009         return;
2010     }
2011
2012     auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
2013     m_process->send(Messages::WebPage::ValidateCommand(commandName, callbackID), m_webPageID);
2014 }
2015
2016 void WebPageProxy::increaseListLevel()
2017 {
2018     if (!hasRunningProcess())
2019         return;
2020
2021     m_process->send(Messages::WebPage::IncreaseListLevel(), m_webPageID);
2022 }
2023
2024 void WebPageProxy::decreaseListLevel()
2025 {
2026     if (!hasRunningProcess())
2027         return;
2028
2029     m_process->send(Messages::WebPage::DecreaseListLevel(), m_webPageID);
2030 }
2031
2032 void WebPageProxy::changeListType()
2033 {
2034     if (!hasRunningProcess())
2035         return;
2036
2037     m_process->send(Messages::WebPage::ChangeListType(), m_webPageID);
2038 }
2039
2040 void WebPageProxy::setBaseWritingDirection(WritingDirection direction)
2041 {
2042     if (!hasRunningProcess())
2043         return;
2044
2045     m_process->send(Messages::WebPage::SetBaseWritingDirection(direction), m_webPageID);
2046 }
2047
2048 void WebPageProxy::updateFontAttributesAfterEditorStateChange()
2049 {
2050     m_cachedFontAttributesAtSelectionStart.reset();
2051
2052     if (m_editorState.isMissingPostLayoutData)
2053         return;
2054
2055     if (auto fontAttributes = m_editorState.postLayoutData().fontAttributes) {
2056         m_uiClient->didChangeFontAttributes(*fontAttributes);
2057         m_cachedFontAttributesAtSelectionStart = WTFMove(fontAttributes);
2058     }
2059 }
2060
2061 void WebPageProxy::setNeedsFontAttributes(bool needsFontAttributes)
2062 {
2063     if (m_needsFontAttributes == needsFontAttributes)
2064         return;
2065
2066     m_needsFontAttributes = needsFontAttributes;
2067
2068     if (hasRunningProcess())
2069         m_process->send(Messages::WebPage::SetNeedsFontAttributes(needsFontAttributes), m_webPageID);
2070 }
2071
2072 bool WebPageProxy::maintainsInactiveSelection() const
2073 {
2074     // Regardless of what the client wants to do, keep selections if a local Inspector is open.
2075     // Otherwise, there is no way to use the console to inspect the state of a selection.
2076     if (inspector() && inspector()->isVisible())
2077         return true;
2078
2079     return m_maintainsInactiveSelection;
2080 }
2081
2082 void WebPageProxy::setMaintainsInactiveSelection(bool newValue)
2083 {
2084     m_maintainsInactiveSelection = newValue;
2085 }
2086
2087 void WebPageProxy::scheduleFullEditorStateUpdate()
2088 {
2089     if (!hasRunningProcess())
2090         return;
2091
2092     m_process->send(Messages::WebPage::ScheduleFullEditorStateUpdate(), m_webPageID);
2093 }
2094
2095 void WebPageProxy::selectAll()
2096 {
2097     if (!hasRunningProcess())
2098         return;
2099
2100     m_process->send(Messages::WebPage::SelectAll(), m_webPageID);
2101 }
2102
2103 void WebPageProxy::executeEditCommand(const String& commandName, const String& argument, WTF::Function<void(CallbackBase::Error)>&& callbackFunction)
2104 {
2105     if (!hasRunningProcess()) {
2106         callbackFunction(CallbackBase::Error::Unknown);
2107         return;
2108     }
2109
2110     auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
2111     m_process->send(Messages::WebPage::ExecuteEditCommandWithCallback(commandName, argument, callbackID), m_webPageID);
2112 }
2113     
2114 void WebPageProxy::executeEditCommand(const String& commandName, const String& argument)
2115 {
2116     static NeverDestroyed<String> ignoreSpellingCommandName(MAKE_STATIC_STRING_IMPL("ignoreSpelling"));
2117
2118     if (!hasRunningProcess())
2119         return;
2120
2121     if (commandName == ignoreSpellingCommandName)
2122         ++m_pendingLearnOrIgnoreWordMessageCount;
2123
2124     m_process->send(Messages::WebPage::ExecuteEditCommand(commandName, argument), m_webPageID);
2125 }
2126
2127 void WebPageProxy::requestFontAttributesAtSelectionStart(Function<void(const WebCore::FontAttributes&, CallbackBase::Error)>&& callback)
2128 {
2129     if (!hasRunningProcess()) {
2130         callback({ }, CallbackBase::Error::Unknown);
2131         return;
2132     }
2133
2134     auto callbackID = m_callbacks.put(WTFMove(callback), m_process->throttler().backgroundActivityToken());
2135     m_process->send(Messages::WebPage::RequestFontAttributesAtSelectionStart(callbackID), m_webPageID);
2136 }
2137
2138 void WebPageProxy::fontAttributesCallback(const WebCore::FontAttributes& attributes, CallbackID callbackID)
2139 {
2140     m_cachedFontAttributesAtSelectionStart = attributes;
2141
2142     if (auto callback = m_callbacks.take<FontAttributesCallback>(callbackID))
2143         callback->performCallbackWithReturnValue(attributes);
2144 }
2145
2146 void WebPageProxy::setEditable(bool editable)
2147 {
2148     if (editable == m_isEditable)
2149         return;
2150
2151     m_isEditable = editable;
2152
2153     if (!hasRunningProcess())
2154         return;
2155
2156     m_process->send(Messages::WebPage::SetEditable(editable), m_webPageID);
2157 }
2158     
2159 void WebPageProxy::setMediaStreamCaptureMuted(bool muted)
2160 {
2161     if (muted)
2162         setMuted(m_mutedState | WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2163     else
2164         setMuted(m_mutedState & ~WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2165 }
2166
2167 void WebPageProxy::activateMediaStreamCaptureInPage()
2168 {
2169 #if ENABLE(MEDIA_STREAM)
2170     UserMediaProcessManager::singleton().muteCaptureMediaStreamsExceptIn(*this);
2171 #endif
2172     setMuted(m_mutedState & ~WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2173 }
2174
2175 #if !PLATFORM(IOS_FAMILY)
2176 void WebPageProxy::didCommitLayerTree(const RemoteLayerTreeTransaction&)
2177 {
2178 }
2179
2180 void WebPageProxy::layerTreeCommitComplete()
2181 {
2182 }
2183 #endif
2184
2185 #if ENABLE(DRAG_SUPPORT)
2186 void WebPageProxy::dragEntered(DragData& dragData, const String& dragStorageName)
2187 {
2188     performDragControllerAction(DragControllerAction::Entered, dragData, dragStorageName, { }, { });
2189 }
2190
2191 void WebPageProxy::dragUpdated(DragData& dragData, const String& dragStorageName)
2192 {
2193     performDragControllerAction(DragControllerAction::Updated, dragData, dragStorageName, { }, { });
2194 }
2195
2196 void WebPageProxy::dragExited(DragData& dragData, const String& dragStorageName)
2197 {
2198     performDragControllerAction(DragControllerAction::Exited, dragData, dragStorageName, { }, { });
2199 }
2200
2201 void WebPageProxy::performDragOperation(DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsForUpload)
2202 {
2203     performDragControllerAction(DragControllerAction::PerformDragOperation, dragData, dragStorageName, WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionsForUpload));
2204 }
2205
2206 void WebPageProxy::performDragControllerAction(DragControllerAction action, DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsForUpload)
2207 {
2208     if (!hasRunningProcess())
2209         return;
2210 #if PLATFORM(GTK)
2211     UNUSED_PARAM(dragStorageName);
2212     UNUSED_PARAM(sandboxExtensionHandle);
2213     UNUSED_PARAM(sandboxExtensionsForUpload);
2214
2215     String url = dragData.asURL();
2216     if (!url.isEmpty())
2217         m_process->assumeReadAccessToBaseURL(*this, url);
2218
2219     ASSERT(dragData.platformData());
2220     WebSelectionData selection(*dragData.platformData());
2221     m_process->send(Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), selection, dragData.flags()), m_webPageID);
2222 #else
2223     m_process->send(Messages::WebPage::PerformDragControllerAction(action, dragData, sandboxExtensionHandle, sandboxExtensionsForUpload), m_webPageID);
2224 #endif
2225 }
2226
2227 void WebPageProxy::didPerformDragControllerAction(uint64_t dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect, const IntRect& editableElementRect)
2228 {
2229     MESSAGE_CHECK(m_process, dragOperation <= DragOperationDelete);
2230
2231     m_currentDragOperation = static_cast<DragOperation>(dragOperation);
2232     m_currentDragHandlingMethod = dragHandlingMethod;
2233     m_currentDragIsOverFileInput = mouseIsOverFileInput;
2234     m_currentDragNumberOfFilesToBeAccepted = numberOfItemsToBeAccepted;
2235     m_currentDragCaretEditableElementRect = editableElementRect;
2236     setDragCaretRect(insertionRect);
2237 }
2238
2239 #if PLATFORM(GTK)
2240 void WebPageProxy::startDrag(WebSelectionData&& selection, uint64_t dragOperation, const ShareableBitmap::Handle& dragImageHandle)
2241 {
2242     RefPtr<ShareableBitmap> dragImage = !dragImageHandle.isNull() ? ShareableBitmap::create(dragImageHandle) : nullptr;
2243     pageClient().startDrag(WTFMove(selection.selectionData), static_cast<WebCore::DragOperation>(dragOperation), WTFMove(dragImage));
2244
2245     didStartDrag();
2246 }
2247 #endif
2248
2249 void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t operation)
2250 {
2251     if (!hasRunningProcess())
2252         return;
2253     m_process->send(Messages::WebPage::DragEnded(clientPosition, globalPosition, operation), m_webPageID);
2254     setDragCaretRect({ });
2255 }
2256
2257 void WebPageProxy::didPerformDragOperation(bool handled)
2258 {
2259     pageClient().didPerformDragOperation(handled);
2260 }
2261
2262 void WebPageProxy::didStartDrag()
2263 {
2264     if (hasRunningProcess())
2265         m_process->send(Messages::WebPage::DidStartDrag(), m_webPageID);
2266 }
2267     
2268 void WebPageProxy::dragCancelled()
2269 {
2270     if (hasRunningProcess())
2271         m_process->send(Messages::WebPage::DragCancelled(), m_webPageID);
2272 }
2273
2274 void WebPageProxy::didEndDragging()
2275 {
2276     resetCurrentDragInformation();
2277 }
2278
2279 void WebPageProxy::resetCurrentDragInformation()
2280 {
2281     m_currentDragOperation = WebCore::DragOperationNone;
2282     m_currentDragHandlingMethod = DragHandlingMethod::None;
2283     m_currentDragIsOverFileInput = false;
2284     m_currentDragNumberOfFilesToBeAccepted = 0;
2285     setDragCaretRect({ });
2286 }
2287
2288 #if !ENABLE(DATA_INTERACTION)
2289
2290 void WebPageProxy::setDragCaretRect(const IntRect& dragCaretRect)
2291 {
2292     m_currentDragCaretRect = dragCaretRect;
2293 }
2294
2295 #endif
2296
2297 #endif // ENABLE(DRAG_SUPPORT)
2298
2299 static bool removeOldRedundantEvent(Deque<NativeWebMouseEvent>& queue, WebEvent::Type incomingEventType)
2300 {
2301     if (incomingEventType != WebEvent::MouseMove && incomingEventType != WebEvent::MouseForceChanged)
2302         return false;
2303
2304     auto it = queue.rbegin();
2305     auto end = queue.rend();
2306
2307     // Must not remove the first event in the deque, since it is already being dispatched.
2308     if (it != end)
2309         --end;
2310
2311     for (; it != end; ++it) {
2312         auto type = it->type();
2313         if (type == incomingEventType) {
2314             queue.remove(--it.base());
2315             return true;
2316         }
2317         if (type != WebEvent::MouseMove && type != WebEvent::MouseForceChanged)
2318             break;
2319     }
2320     return false;
2321 }
2322
2323 void WebPageProxy::handleMouseEvent(const NativeWebMouseEvent& event)
2324 {
2325     if (!hasRunningProcess())
2326         return;
2327
2328 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2329     if (m_scrollingCoordinatorProxy)
2330         m_scrollingCoordinatorProxy->handleMouseEvent(platform(event));
2331 #endif
2332
2333     // If we receive multiple mousemove or mouseforcechanged events and the most recent mousemove or mouseforcechanged event
2334     // (respectively) has not yet been sent to WebProcess for processing, remove the pending mouse event and insert the new
2335     // event in the queue.
2336     bool didRemoveEvent = removeOldRedundantEvent(m_mouseEventQueue, event.type());
2337     m_mouseEventQueue.append(event);
2338
2339 #if LOG_DISABLED
2340     UNUSED_PARAM(didRemoveEvent);
2341 #else
2342     LOG(MouseHandling, "UIProcess: %s mouse event %s (queue size %zu)", didRemoveEvent ? "replaced" : "enqueued", webMouseEventTypeString(event.type()), m_mouseEventQueue.size());
2343 #endif
2344
2345     if (m_mouseEventQueue.size() == 1) // Otherwise, called from DidReceiveEvent message handler.
2346         processNextQueuedMouseEvent();
2347 }
2348     
2349 void WebPageProxy::processNextQueuedMouseEvent()
2350 {
2351     if (!hasRunningProcess())
2352         return;
2353
2354     ASSERT(!m_mouseEventQueue.isEmpty());
2355
2356     const NativeWebMouseEvent& event = m_mouseEventQueue.first();
2357
2358     if (pageClient().windowIsFrontWindowUnderMouse(event))
2359         setToolTip(String());
2360
2361     WebEvent::Type eventType = event.type();
2362     if (eventType == WebEvent::MouseDown || eventType == WebEvent::MouseForceChanged || eventType == WebEvent::MouseForceDown)
2363         m_process->responsivenessTimer().startWithLazyStop();
2364     else if (eventType != WebEvent::MouseMove) {
2365         // NOTE: This does not start the responsiveness timer because mouse move should not indicate interaction.
2366         m_process->responsivenessTimer().start();
2367     }
2368
2369     LOG(MouseHandling, "UIProcess: sent mouse event %s (queue size %zu)", webMouseEventTypeString(eventType), m_mouseEventQueue.size());
2370     m_process->send(Messages::WebPage::MouseEvent(event), m_webPageID);
2371 }
2372
2373 #if MERGE_WHEEL_EVENTS
2374 static bool canCoalesce(const WebWheelEvent& a, const WebWheelEvent& b)
2375 {
2376     if (a.position() != b.position())
2377         return false;
2378     if (a.globalPosition() != b.globalPosition())
2379         return false;
2380     if (a.modifiers() != b.modifiers())
2381         return false;
2382     if (a.granularity() != b.granularity())
2383         return false;
2384 #if PLATFORM(COCOA)
2385     if (a.phase() != b.phase())
2386         return false;
2387     if (a.momentumPhase() != b.momentumPhase())
2388         return false;
2389     if (a.hasPreciseScrollingDeltas() != b.hasPreciseScrollingDeltas())
2390         return false;
2391 #endif
2392
2393     return true;
2394 }
2395
2396 static WebWheelEvent coalesce(const WebWheelEvent& a, const WebWheelEvent& b)
2397 {
2398     ASSERT(canCoalesce(a, b));
2399
2400     FloatSize mergedDelta = a.delta() + b.delta();
2401     FloatSize mergedWheelTicks = a.wheelTicks() + b.wheelTicks();
2402
2403 #if PLATFORM(COCOA)
2404     FloatSize mergedUnacceleratedScrollingDelta = a.unacceleratedScrollingDelta() + b.unacceleratedScrollingDelta();
2405
2406     return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.directionInvertedFromDevice(), b.phase(), b.momentumPhase(), b.hasPreciseScrollingDeltas(), b.scrollCount(), mergedUnacceleratedScrollingDelta, b.modifiers(), b.timestamp());
2407 #else
2408     return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.modifiers(), b.timestamp());
2409 #endif
2410 }
2411 #endif // MERGE_WHEEL_EVENTS
2412
2413 static WebWheelEvent coalescedWheelEvent(Deque<NativeWebWheelEvent>& queue, Vector<NativeWebWheelEvent>& coalescedEvents)
2414 {
2415     ASSERT(!queue.isEmpty());
2416     ASSERT(coalescedEvents.isEmpty());
2417
2418 #if MERGE_WHEEL_EVENTS
2419     NativeWebWheelEvent firstEvent = queue.takeFirst();
2420     coalescedEvents.append(firstEvent);
2421
2422     WebWheelEvent event = firstEvent;
2423     while (!queue.isEmpty() && canCoalesce(event, queue.first())) {
2424         NativeWebWheelEvent firstEvent = queue.takeFirst();
2425         coalescedEvents.append(firstEvent);
2426         event = coalesce(event, firstEvent);
2427     }
2428
2429     return event;
2430 #else
2431     while (!queue.isEmpty())
2432         coalescedEvents.append(queue.takeFirst());
2433     return coalescedEvents.last();
2434 #endif
2435 }
2436
2437 void WebPageProxy::handleWheelEvent(const NativeWebWheelEvent& event)
2438 {
2439 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2440     if (m_scrollingCoordinatorProxy && m_scrollingCoordinatorProxy->handleWheelEvent(platform(event)))
2441         return;
2442 #endif
2443
2444     if (!hasRunningProcess())
2445         return;
2446
2447     closeOverlayedViews();
2448
2449     if (!m_currentlyProcessedWheelEvents.isEmpty()) {
2450         m_wheelEventQueue.append(event);
2451         if (!shouldProcessWheelEventNow(event))
2452             return;
2453         // The queue has too many wheel events, so push a new event.
2454     }
2455
2456     if (!m_wheelEventQueue.isEmpty()) {
2457         processNextQueuedWheelEvent();
2458         return;
2459     }
2460
2461     auto coalescedWheelEvent = makeUnique<Vector<NativeWebWheelEvent>>();
2462     coalescedWheelEvent->append(event);
2463     m_currentlyProcessedWheelEvents.append(WTFMove(coalescedWheelEvent));
2464     sendWheelEvent(event);
2465 }
2466
2467 void WebPageProxy::processNextQueuedWheelEvent()
2468 {
2469     auto nextCoalescedEvent = makeUnique<Vector<NativeWebWheelEvent>>();
2470     WebWheelEvent nextWheelEvent = coalescedWheelEvent(m_wheelEventQueue, *nextCoalescedEvent.get());
2471     m_currentlyProcessedWheelEvents.append(WTFMove(nextCoalescedEvent));
2472     sendWheelEvent(nextWheelEvent);
2473 }
2474
2475 void WebPageProxy::sendWheelEvent(const WebWheelEvent& event)
2476 {
2477     m_process->send(
2478         Messages::EventDispatcher::WheelEvent(
2479             m_webPageID,
2480             event,
2481             shouldUseImplicitRubberBandControl() ? !m_backForwardList->backItem() : rubberBandsAtLeft(),
2482             shouldUseImplicitRubberBandControl() ? !m_backForwardList->forwardItem() : rubberBandsAtRight(),
2483             rubberBandsAtTop(),
2484             rubberBandsAtBottom()
2485         ), 0);
2486
2487     // Manually ping the web process to check for responsiveness since our wheel
2488     // event will dispatch to a non-main thread, which always responds.
2489     m_process->isResponsiveWithLazyStop();
2490 }
2491
2492 bool WebPageProxy::shouldProcessWheelEventNow(const WebWheelEvent& event) const
2493 {
2494 #if PLATFORM(GTK)
2495     // Don't queue events representing a non-trivial scrolling phase to
2496     // avoid having them trapped in the queue, potentially preventing a
2497     // scrolling session to beginning or end correctly.
2498     // This is only needed by platforms whose WebWheelEvent has this phase
2499     // information (Cocoa and GTK+) but Cocoa was fine without it.
2500     if (event.phase() == WebWheelEvent::Phase::PhaseNone
2501         || event.phase() == WebWheelEvent::Phase::PhaseChanged
2502         || event.momentumPhase() == WebWheelEvent::Phase::PhaseNone
2503         || event.momentumPhase() == WebWheelEvent::Phase::PhaseChanged)
2504         return true;
2505 #else
2506     UNUSED_PARAM(event);
2507 #endif
2508     if (m_wheelEventQueue.size() >= wheelEventQueueSizeThreshold)
2509         return true;
2510     return false;
2511 }
2512
2513 void WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event)
2514 {
2515     if (!hasRunningProcess())
2516         return;
2517     
2518     LOG(KeyHandling, "WebPageProxy::handleKeyboardEvent: %s", webKeyboardEventTypeString(event.type()));
2519
2520     m_keyEventQueue.append(event);
2521
2522     ResponsivenessTimer& responsivenessTimer = m_process->responsivenessTimer();
2523     if (event.type() == WebEvent::KeyDown)
2524         responsivenessTimer.startWithLazyStop();
2525     else
2526         responsivenessTimer.start();
2527
2528     if (m_keyEventQueue.size() == 1) { // Otherwise, sent from DidReceiveEvent message handler.
2529         LOG(KeyHandling, " UI process: sent keyEvent from handleKeyboardEvent");
2530         m_process->send(Messages::WebPage::KeyEvent(event), m_webPageID);
2531     }
2532 }
2533
2534 WebPreferencesStore WebPageProxy::preferencesStore() const
2535 {
2536     if (m_configurationPreferenceValues.isEmpty())
2537         return m_preferences->store();
2538
2539     WebPreferencesStore store = m_preferences->store();
2540     for (const auto& preference : m_configurationPreferenceValues)
2541         store.m_values.set(preference.key, preference.value);
2542
2543     return store;
2544 }
2545
2546 #if ENABLE(NETSCAPE_PLUGIN_API)
2547 void WebPageProxy::findPlugin(const String& mimeType, uint32_t processType, const String& urlString, const String& frameURLString, const String& pageURLString, bool allowOnlyApplicationPlugins, Messages::WebPageProxy::FindPlugin::DelayedReply&& reply)
2548 {
2549     PageClientProtector protector(pageClient());
2550
2551     MESSAGE_CHECK_URL(m_process, urlString);
2552
2553     URL pluginURL = URL { URL(), urlString };
2554     String newMimeType = mimeType.convertToASCIILowercase();
2555
2556     PluginData::AllowedPluginTypes allowedPluginTypes = allowOnlyApplicationPlugins ? PluginData::OnlyApplicationPlugins : PluginData::AllPlugins;
2557
2558     URL pageURL = URL { URL(), pageURLString };
2559     if (!m_process->processPool().pluginInfoStore().isSupportedPlugin(mimeType, pluginURL, frameURLString, pageURL)) {
2560         reply(0, newMimeType, PluginModuleLoadNormally, { }, true);
2561         return;
2562     }
2563
2564     PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, pluginURL, allowedPluginTypes);
2565     if (!plugin.path) {
2566         reply(0, newMimeType, PluginModuleLoadNormally, { }, false);
2567         return;
2568     }
2569
2570     uint32_t pluginLoadPolicy = PluginInfoStore::defaultLoadPolicyForPlugin(plugin);
2571
2572 #if PLATFORM(COCOA)
2573     auto pluginInformation = createPluginInformationDictionary(plugin, frameURLString, String(), pageURLString, String(), String());
2574 #endif
2575
2576     auto findPluginCompletion = [processType, reply = WTFMove(reply), newMimeType = WTFMove(newMimeType), plugin = WTFMove(plugin)] (uint32_t pluginLoadPolicy, const String& unavailabilityDescription) mutable {
2577         PluginProcessSandboxPolicy pluginProcessSandboxPolicy = PluginProcessSandboxPolicyNormal;
2578         switch (pluginLoadPolicy) {
2579         case PluginModuleLoadNormally:
2580             pluginProcessSandboxPolicy = PluginProcessSandboxPolicyNormal;
2581             break;
2582         case PluginModuleLoadUnsandboxed:
2583             pluginProcessSandboxPolicy = PluginProcessSandboxPolicyUnsandboxed;
2584             break;
2585
2586         case PluginModuleBlockedForSecurity:
2587         case PluginModuleBlockedForCompatibility:
2588             reply(0, newMimeType, pluginLoadPolicy, unavailabilityDescription, false);
2589             return;
2590         }
2591
2592         reply(PluginProcessManager::singleton().pluginProcessToken(plugin, static_cast<PluginProcessType>(processType), pluginProcessSandboxPolicy), newMimeType, pluginLoadPolicy, unavailabilityDescription, false);
2593     };
2594
2595 #if PLATFORM(COCOA)
2596     m_navigationClient->decidePolicyForPluginLoad(*this, static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy), pluginInformation.get(), WTFMove(findPluginCompletion));
2597 #else
2598     findPluginCompletion(pluginLoadPolicy, { });
2599 #endif
2600 }
2601
2602 #endif // ENABLE(NETSCAPE_PLUGIN_API)
2603
2604 #if ENABLE(TOUCH_EVENTS)
2605
2606 static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b)
2607 {
2608     if (static_cast<uintptr_t>(b) > static_cast<uintptr_t>(a))
2609         return b;
2610     return a;
2611 }
2612
2613 void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent)
2614 {
2615 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2616     const EventNames& names = eventNames();
2617     for (auto& touchPoint : touchStartEvent.touchPoints()) {
2618         IntPoint location = touchPoint.location();
2619         auto updateTrackingType = [this, location](TrackingType& trackingType, const AtomString& eventName) {
2620             if (trackingType == TrackingType::Synchronous)
2621                 return;
2622
2623             TrackingType trackingTypeForLocation = m_scrollingCoordinatorProxy->eventTrackingTypeForPoint(eventName, location);
2624
2625             trackingType = mergeTrackingTypes(trackingType, trackingTypeForLocation);
2626         };
2627         updateTrackingType(m_touchAndPointerEventTracking.touchForceChangedTracking, names.touchforcechangeEvent);
2628         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.touchstartEvent);
2629         updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.touchmoveEvent);
2630         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.touchendEvent);
2631         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointeroverEvent);
2632         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointerenterEvent);
2633         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointerdownEvent);
2634         updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.pointermoveEvent);
2635         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointerupEvent);
2636         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointeroutEvent);
2637         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointerleaveEvent);
2638         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.mousedownEvent);
2639         updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.mousemoveEvent);
2640         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.mouseupEvent);
2641     }
2642 #else
2643     UNUSED_PARAM(touchStartEvent);
2644     m_touchAndPointerEventTracking.touchForceChangedTracking = TrackingType::Synchronous;
2645     m_touchAndPointerEventTracking.touchStartTracking = TrackingType::Synchronous;
2646     m_touchAndPointerEventTracking.touchMoveTracking = TrackingType::Synchronous;
2647     m_touchAndPointerEventTracking.touchEndTracking = TrackingType::Synchronous;
2648 #endif // ENABLE(ASYNC_SCROLLING)
2649 }
2650
2651 TrackingType WebPageProxy::touchEventTrackingType(const WebTouchEvent& touchStartEvent) const
2652 {
2653     // We send all events if any type is needed, we just do it asynchronously for the types that are not tracked.
2654     //
2655     // Touch events define a sequence with strong dependencies. For example, we can expect
2656     // a TouchMove to only appear after a TouchStart, and the ids of the touch points is consistent between
2657     // the two.
2658     //
2659     // WebCore should not have to set up its state correctly after some events were dismissed.
2660     // For example, we don't want to send a TouchMoved without a TouchPressed.
2661     // We send everything, WebCore updates its internal state and dispatch what is needed to the page.
2662     TrackingType globalTrackingType = m_touchAndPointerEventTracking.isTrackingAnything() ? TrackingType::Asynchronous : TrackingType::NotTracking;
2663
2664     globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchForceChangedTracking);
2665     for (auto& touchPoint : touchStartEvent.touchPoints()) {
2666         switch (touchPoint.state()) {
2667         case WebPlatformTouchPoint::TouchReleased:
2668             globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchEndTracking);
2669             break;
2670         case WebPlatformTouchPoint::TouchPressed:
2671             globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchStartTracking);
2672             break;
2673         case WebPlatformTouchPoint::TouchMoved:
2674         case WebPlatformTouchPoint::TouchStationary:
2675             globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchMoveTracking);
2676             break;
2677         case WebPlatformTouchPoint::TouchCancelled:
2678             globalTrackingType = mergeTrackingTypes(globalTrackingType, TrackingType::Asynchronous);
2679             break;
2680         }
2681     }
2682
2683     return globalTrackingType;
2684 }
2685
2686 #endif
2687
2688 #if ENABLE(MAC_GESTURE_EVENTS)
2689 void WebPageProxy::handleGestureEvent(const NativeWebGestureEvent& event)
2690 {
2691     if (!hasRunningProcess())
2692         return;
2693
2694     m_gestureEventQueue.append(event);
2695     // FIXME: Consider doing some coalescing here.
2696
2697     ResponsivenessTimer& responsivenessTimer = m_process->responsivenessTimer();
2698     if (event.type() == WebEvent::GestureStart || event.type() == WebEvent::GestureChange)
2699         responsivenessTimer.startWithLazyStop();
2700     else
2701         responsivenessTimer.start();
2702
2703     m_process->send(Messages::EventDispatcher::GestureEvent(m_webPageID, event), 0);
2704 }
2705 #endif
2706
2707 #if ENABLE(IOS_TOUCH_EVENTS)
2708 void WebPageProxy::handleTouchEventSynchronously(NativeWebTouchEvent& event)
2709 {
2710     if (!hasRunningProcess())
2711         return;
2712
2713     TraceScope scope(SyncTouchEventStart, SyncTouchEventEnd);
2714
2715     updateTouchEventTracking(event);
2716
2717     TrackingType touchEventsTrackingType = touchEventTrackingType(event);
2718     if (touchEventsTrackingType == TrackingType::NotTracking)
2719         return;
2720
2721     if (touchEventsTrackingType == TrackingType::Asynchronous) {
2722         // We can end up here if a native gesture has not started but the event handlers are passive.
2723         //
2724         // The client of WebPageProxy asks the event to be sent synchronously since the touch event
2725         // can prevent a native gesture.
2726         // But, here we know that all events handlers that can handle this events are passive.
2727         // We can use asynchronous dispatch and pretend to the client that the page does nothing with the events.
2728         event.setCanPreventNativeGestures(false);
2729         handleTouchEventAsynchronously(event);
2730         didReceiveEvent(event.type(), false);
2731         return;
2732     }
2733
2734     m_process->responsivenessTimer().start();
2735     bool handled = false;
2736     bool replyReceived = m_process->sendSync(Messages::WebPage::TouchEventSync(event), Messages::WebPage::TouchEventSync::Reply(handled), m_webPageID, 1_s, IPC::SendSyncOption::ForceDispatchWhenDestinationIsWaitingForUnboundedSyncReply);
2737     // If the sync request has timed out, we should consider the event handled. The Web Process is too busy to answer any questions, so the default action is also likely to have issues.
2738     if (!replyReceived)
2739         handled = true;
2740     didReceiveEvent(event.type(), handled);
2741     pageClient().doneWithTouchEvent(event, handled);
2742     m_process->responsivenessTimer().stop();
2743
2744     if (event.allTouchPointsAreReleased()) {
2745         m_touchAndPointerEventTracking.reset();
2746         didReleaseAllTouchPoints();
2747     }
2748 }
2749
2750 void WebPageProxy::resetPotentialTapSecurityOrigin()
2751 {
2752     if (!hasRunningProcess())
2753         return;
2754
2755     m_process->send(Messages::WebPage::ResetPotentialTapSecurityOrigin(), m_webPageID);
2756 }
2757
2758 void WebPageProxy::handleTouchEventAsynchronously(const NativeWebTouchEvent& event)
2759 {
2760     if (!hasRunningProcess())
2761         return;
2762
2763     TrackingType touchEventsTrackingType = touchEventTrackingType(event);
2764     if (touchEventsTrackingType == TrackingType::NotTracking)
2765         return;
2766
2767     m_process->send(Messages::EventDispatcher::TouchEvent(m_webPageID, event), 0);
2768
2769     if (event.allTouchPointsAreReleased()) {
2770         m_touchAndPointerEventTracking.reset();
2771         didReleaseAllTouchPoints();
2772     }
2773 }
2774
2775 #elif ENABLE(TOUCH_EVENTS)
2776 void WebPageProxy::handleTouchEvent(const NativeWebTouchEvent& event)
2777 {
2778     if (!hasRunningProcess())
2779         return;
2780
2781     updateTouchEventTracking(event);
2782
2783     if (touchEventTrackingType(event) == TrackingType::NotTracking)
2784         return;
2785
2786     // If the page is suspended, which should be the case during panning, pinching
2787     // and animation on the page itself (kinetic scrolling, tap to zoom) etc, then
2788     // we do not send any of the events to the page even if is has listeners.
2789     if (!m_isPageSuspended) {
2790         m_touchEventQueue.append(event);
2791         m_process->responsivenessTimer().start();
2792         m_process->send(Messages::WebPage::TouchEvent(event), m_webPageID);
2793     } else {
2794         if (m_touchEventQueue.isEmpty()) {
2795             bool isEventHandled = false;
2796             pageClient().doneWithTouchEvent(event, isEventHandled);
2797         } else {
2798             // We attach the incoming events to the newest queued event so that all
2799             // the events are delivered in the correct order when the event is dequed.
2800             QueuedTouchEvents& lastEvent = m_touchEventQueue.last();
2801             lastEvent.deferredTouchEvents.append(event);
2802         }
2803     }
2804
2805     if (event.allTouchPointsAreReleased()) {
2806         m_touchAndPointerEventTracking.reset();
2807         didReleaseAllTouchPoints();
2808     }
2809 }
2810 #endif // ENABLE(TOUCH_EVENTS)
2811
2812 #if ENABLE(POINTER_EVENTS)
2813 void WebPageProxy::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint)
2814 {
2815     m_process->send(Messages::WebPage::CancelPointer(pointerId, documentPoint), m_webPageID);
2816 }
2817
2818 void WebPageProxy::touchWithIdentifierWasRemoved(WebCore::PointerID pointerId)
2819 {
2820     m_process->send(Messages::WebPage::TouchWithIdentifierWasRemoved(pointerId), m_webPageID);
2821 }
2822 #endif
2823
2824 void WebPageProxy::scrollBy(ScrollDirection direction, ScrollGranularity granularity)
2825 {
2826     if (!hasRunningProcess())
2827         return;
2828
2829     m_process->send(Messages::WebPage::ScrollBy(direction, granularity), m_webPageID);
2830 }
2831
2832 void WebPageProxy::centerSelectionInVisibleArea()
2833 {
2834     if (!hasRunningProcess())
2835         return;
2836
2837     m_process->send(Messages::WebPage::CenterSelectionInVisibleArea(), m_webPageID);
2838 }
2839
2840 class WebPageProxy::PolicyDecisionSender : public RefCounted<PolicyDecisionSender> {
2841 public:
2842     using SendFunction = CompletionHandler<void(PolicyCheckIdentifier, PolicyAction, uint64_t newNavigationID, DownloadID, Optional<WebsitePoliciesData>)>;
2843
2844     static Ref<PolicyDecisionSender> create(PolicyCheckIdentifier identifier, SendFunction&& sendFunction)
2845     {
2846         return adoptRef(*new PolicyDecisionSender(identifier, WTFMove(sendFunction)));
2847     }
2848
2849     template<typename... Args> void send(Args... args)
2850     {
2851         if (m_sendFunction)
2852             m_sendFunction(m_identifier, std::forward<Args>(args)...);
2853     }
2854 private:
2855     PolicyDecisionSender(PolicyCheckIdentifier identifier, SendFunction sendFunction)
2856         : m_sendFunction(WTFMove(sendFunction))
2857         , m_identifier(identifier)
2858         { }
2859
2860     SendFunction m_sendFunction;
2861     PolicyCheckIdentifier m_identifier;
2862 };
2863
2864 void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, API::Navigation* navigation, ProcessSwapRequestedByClient processSwapRequestedByClient, WebFrameProxy& frame, API::WebsitePolicies* policies, Ref<PolicyDecisionSender>&& sender)
2865 {
2866     Ref<WebsiteDataStore> websiteDataStore = m_websiteDataStore.copyRef();
2867     Optional<WebsitePoliciesData> data;
2868     if (policies) {
2869         data = policies->data();
2870         if (policies->websiteDataStore() && policies->websiteDataStore() != websiteDataStore.ptr()) {
2871             websiteDataStore = *policies->websiteDataStore();
2872             processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
2873         }
2874     }
2875
2876     if (navigation && !navigation->userContentExtensionsEnabled()) {
2877         if (!data)
2878             data = WebsitePoliciesData { };
2879         data->contentBlockersEnabled = false;
2880     }
2881
2882 #if ENABLE(DEVICE_ORIENTATION)
2883     if (navigation && (!data || data->deviceOrientationAndMotionAccessState == WebCore::DeviceOrientationOrMotionPermissionState::Prompt)) {
2884         auto deviceOrientationPermission = websiteDataStore->deviceOrientationAndMotionAccessController().cachedDeviceOrientationPermission(SecurityOriginData::fromURL(navigation->currentRequest().url()));
2885         if (deviceOrientationPermission != WebCore::DeviceOrientationOrMotionPermissionState::Prompt) {
2886             if (!data)
2887                 data = WebsitePoliciesData { };
2888             data->deviceOrientationAndMotionAccessState = deviceOrientationPermission;
2889         }
2890     }
2891 #endif
2892
2893 #if PLATFORM(COCOA)
2894     static const bool forceDownloadFromDownloadAttribute = false;
2895 #else
2896     static const bool forceDownloadFromDownloadAttribute = true;
2897 #endif
2898     if (policyAction == PolicyAction::Use && navigation && (navigation->isSystemPreview() || (forceDownloadFromDownloadAttribute && navigation->shouldPerformDownload())))
2899         policyAction = PolicyAction::Download;
2900
2901     if (policyAction != PolicyAction::Use || !frame.isMainFrame() || !navigation) {
2902         receivedPolicyDecision(policyAction, navigation, WTFMove(data), WTFMove(sender));
2903         return;
2904     }
2905
2906     Ref<WebProcessProxy> sourceProcess = process();
2907     URL sourceURL = URL { URL(), pageLoadState().url() };
2908     if (auto* provisionalPage = provisionalPageProxy()) {
2909         if (provisionalPage->navigationID() == navigation->navigationID()) {
2910             sourceProcess = provisionalPage->process();
2911             sourceURL = provisionalPage->provisionalURL();
2912         }
2913     }
2914
2915     process().processPool().processForNavigation(*this, *navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, WTFMove(websiteDataStore), [this, protectedThis = makeRef(*this), policyAction, navigation = makeRef(*navigation), sourceProcess = sourceProcess.copyRef(),
2916         data = WTFMove(data), sender = WTFMove(sender), processSwapRequestedByClient] (Ref<WebProcessProxy>&& processForNavigation, SuspendedPageProxy* destinationSuspendedPage, const String& reason) mutable {
2917         // If the navigation has been destroyed, then no need to proceed.
2918         if (isClosed() || !navigationState().hasNavigation(navigation->navigationID())) {
2919             receivedPolicyDecision(policyAction, navigation.ptr(), WTFMove(data), WTFMove(sender));
2920             return;
2921         }
2922
2923         bool shouldProcessSwap = processForNavigation.ptr() != sourceProcess.ptr();
2924         if (shouldProcessSwap) {
2925             policyAction = PolicyAction::StopAllLoads;
2926             RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "decidePolicyForNavigationAction, swapping process %i with process %i for navigation, reason: %{public}s", processIdentifier(), processForNavigation->processIdentifier(), reason.utf8().data());
2927             LOG(ProcessSwapping, "(ProcessSwapping) Switching from process %i to new process (%i) for navigation %" PRIu64 " '%s'", processIdentifier(), processForNavigation->processIdentifier(), navigation->navigationID(), navigation->loggingString());
2928         } else
2929             RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "decidePolicyForNavigationAction: keep using process %i for navigation, reason: %{public}s", processIdentifier(), reason.utf8().data());
2930
2931         if (shouldProcessSwap) {
2932             auto suspendedPage = destinationSuspendedPage ? process().processPool().takeSuspendedPage(*destinationSuspendedPage) : nullptr;
2933             if (suspendedPage && suspendedPage->pageIsClosedOrClosing())
2934                 suspendedPage = nullptr;
2935
2936             continueNavigationInNewProcess(navigation, WTFMove(suspendedPage), WTFMove(processForNavigation), processSwapRequestedByClient, WTFMove(data));
2937         }
2938
2939         receivedPolicyDecision(policyAction, navigation.ptr(), shouldProcessSwap ? WTF::nullopt : WTFMove(data), WTFMove(sender), shouldProcessSwap ? WillContinueLoadInNewProcess::Yes : WillContinueLoadInNewProcess::No);
2940     });
2941 }
2942
2943 void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, Optional<WebsitePoliciesData>&& websitePolicies, Ref<PolicyDecisionSender>&& sender, WillContinueLoadInNewProcess willContinueLoadInNewProcess)
2944 {
2945     if (!hasRunningProcess()) {
2946         sender->send(PolicyAction::Ignore, 0, DownloadID(), WTF::nullopt);
2947         return;
2948     }
2949
2950     auto transaction = m_pageLoadState.transaction();
2951
2952     if (action == PolicyAction::Ignore && willContinueLoadInNewProcess == WillContinueLoadInNewProcess::No && navigation && navigation->navigationID() == m_pageLoadState.pendingAPIRequest().navigationID)
2953         m_pageLoadState.clearPendingAPIRequest(transaction);
2954
2955     DownloadID downloadID = { };
2956     if (action == PolicyAction::Download) {
2957         // Create a download proxy.
2958         auto& download = m_process->processPool().createDownloadProxy(m_websiteDataStore, m_decidePolicyForResponseRequest, this);
2959         if (navigation) {
2960             download.setWasUserInitiated(navigation->wasUserInitiated());
2961             download.setRedirectChain(navigation->takeRedirectChain());
2962         }
2963
2964         downloadID = download.downloadID();
2965         handleDownloadRequest(download);
2966         m_decidePolicyForResponseRequest = { };
2967     }
2968
2969     sender->send(action, navigation ? navigation->navigationID() : 0, downloadID, WTFMove(websitePolicies));
2970 }
2971
2972 void WebPageProxy::commitProvisionalPage(FrameIdentifier frameID, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, uint32_t frameLoadType, const WebCore::CertificateInfo& certificateInfo, bool containsPluginDocument, Optional<WebCore::HasInsecureContent> forcedHasInsecureContent, const UserData& userData)
2973 {
2974     ASSERT(m_provisionalPage);
2975     RELEASE_LOG_IF_ALLOWED(Loading, "commitProvisionalPage: newPID = %i", m_provisionalPage->process().processIdentifier());
2976
2977     Optional<FrameIdentifier> mainFrameIDInPreviousProcess = m_mainFrame ? makeOptional(m_mainFrame->frameID()) : WTF::nullopt;
2978
2979     ASSERT(m_process.ptr() != &m_provisionalPage->process());
2980
2981     auto shouldDelayClosingUntilEnteringAcceleratedCompositingMode = ShouldDelayClosingUntilEnteringAcceleratedCompositingMode::No;
2982 #if PLATFORM(MAC)
2983     // On macOS, when not using UI-side compositing, we need to make sure we do not close the page in the previous process until we've
2984     // entered accelerated compositing for the new page or we will flash on navigation.
2985     if (drawingArea()->type() == DrawingAreaTypeTiledCoreAnimation)
2986         shouldDelayClosingUntilEnteringAcceleratedCompositingMode = ShouldDelayClosingUntilEnteringAcceleratedCompositingMode::Yes;
2987 #endif
2988
2989     processDidTerminate(ProcessTerminationReason::NavigationSwap);
2990
2991     m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID);
2992     auto* navigation = navigationState().navigation(m_provisionalPage->navigationID());
2993     bool didSuspendPreviousPage = navigation ? suspendCurrentPageIfPossible(*navigation, mainFrameIDInPreviousProcess, m_provisionalPage->processSwapRequestedByClient(), shouldDelayClosingUntilEnteringAcceleratedCompositingMode) : false;
2994     m_process->removeWebPage(*this, m_websiteDataStore.ptr() == &m_provisionalPage->process().websiteDataStore() ? WebProcessProxy::EndsUsingDataStore::No : WebProcessProxy::EndsUsingDataStore::Yes);
2995
2996     // There is no way we'll be able to return to the page in the previous page so close it.
2997     if (!didSuspendPreviousPage)
2998         m_process->send(Messages::WebPage::Close(), m_webPageID);
2999
3000     swapToWebProcess(m_provisionalPage->process(), m_provisionalPage->webPageID(), m_provisionalPage->takeDrawingArea(), m_provisionalPage->mainFrame());
3001
3002 #if PLATFORM(COCOA)
3003     auto accessibilityToken = m_provisionalPage->takeAccessibilityToken();
3004     if (!accessibilityToken.isEmpty())
3005         registerWebProcessAccessibilityToken({ accessibilityToken.data(), accessibilityToken.size() });
3006 #endif
3007
3008     didCommitLoadForFrame(frameID, navigationID, mimeType, frameHasCustomContentProvider, frameLoadType, certificateInfo, containsPluginDocument, forcedHasInsecureContent, userData);
3009
3010     m_provisionalPage = nullptr;
3011 }
3012
3013 void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, std::unique_ptr<SuspendedPageProxy>&& suspendedPageProxy, Ref<WebProcessProxy>&& newProcess, ProcessSwapRequestedByClient processSwapRequestedByClient, Optional<WebsitePoliciesData>&& websitePolicies)
3014 {
3015     RELEASE_LOG_IF_ALLOWED(Loading, "continueNavigationInNewProcess: newProcessPID = %i, hasSuspendedPage = %i", newProcess->processIdentifier(), !!suspendedPageProxy);
3016     LOG(Loading, "Continuing navigation %" PRIu64 " '%s' in a new web process", navigation.navigationID(), navigation.loggingString());
3017
3018     if (m_provisionalPage) {
3019         RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "continueNavigationInNewProcess: There is already a pending provisional load, cancelling it (provisonalNavigationID: %llu, navigationID: %llu)", m_provisionalPage->navigationID(), navigation.navigationID());
3020         if (m_provisionalPage->navigationID() != navigation.navigationID())
3021             m_provisionalPage->cancel();
3022         m_provisionalPage = nullptr;
3023     }
3024
3025     m_provisionalPage = makeUnique<ProvisionalPageProxy>(*this, newProcess.copyRef(), WTFMove(suspendedPageProxy), navigation.navigationID(), navigation.currentRequestIsRedirect(), navigation.currentRequest(), processSwapRequestedByClient);
3026
3027     if (auto* item = navigation.targetItem()) {
3028         LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data());
3029
3030         auto transaction = m_pageLoadState.transaction();
3031         m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), item->url() });
3032
3033         m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies));
3034         return;
3035     }
3036
3037     if (m_backForwardList->currentItem() && (navigation.lockBackForwardList() == LockBackForwardList::Yes || navigation.lockHistory() == LockHistory::Yes)) {
3038         // If WebCore is supposed to lock the history for this load, then the new process needs to know about the current history item so it can update
3039         // it instead of creating a new one.
3040         newProcess->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()), m_provisionalPage->webPageID());
3041     }
3042
3043     // FIXME: Work out timing of responding with the last policy delegate, etc
3044     ASSERT(!navigation.currentRequest().isEmpty());
3045     if (auto& substituteData = navigation.substituteData())
3046         m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), WTFMove(websitePolicies));
3047     else
3048         m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation.currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, WTFMove(websitePolicies));
3049 }
3050
3051 bool WebPageProxy::isPageOpenedByDOMShowingInitialEmptyDocument() const
3052 {
3053     return openedByDOM() && !hasCommittedAnyProvisionalLoads();
3054 }
3055
3056 // MSVC gives a redeclaration error if noreturn is used on the definition and not the declaration, while
3057 // Cocoa tests segfault if it is moved to the declaration site (even if we move the definition with it!).
3058 #if !COMPILER(MSVC)
3059 NO_RETURN_DUE_TO_ASSERT
3060 #endif
3061 void WebPageProxy::didFailToSuspendAfterProcessSwap()
3062 {
3063     // Only the SuspendedPageProxy should be getting this call.
3064     ASSERT_NOT_REACHED();
3065 }
3066
3067 #if !COMPILER(MSVC)
3068 NO_RETURN_DUE_TO_ASSERT
3069 #endif
3070 void WebPageProxy::didSuspendAfterProcessSwap()
3071 {
3072     // Only the SuspendedPageProxy should be getting this call.
3073     ASSERT_NOT_REACHED();
3074 }
3075
3076 void WebPageProxy::setUserAgent(String&& userAgent)
3077 {
3078     if (m_userAgent == userAgent)
3079         return;
3080     m_userAgent = WTFMove(userAgent);
3081
3082 #if ENABLE(SERVICE_WORKER)
3083     // We update the service worker there at the moment to be sure we use values used by actual web pages.
3084     // FIXME: Refactor this when we have a better User-Agent story.
3085     process().processPool().updateServiceWorkerUserAgent(m_userAgent);
3086 #endif
3087
3088     if (!hasRunningProcess())
3089         return;
3090     m_process->send(Messages::WebPage::SetUserAgent(m_userAgent), m_webPageID);
3091 }
3092
3093 void WebPageProxy::setApplicationNameForUserAgent(const String& applicationName)
3094 {
3095     if (m_applicationNameForUserAgent == applicationName)
3096         return;
3097
3098     m_applicationNameForUserAgent = applicationName;
3099     if (!m_customUserAgent.isEmpty())
3100         return;
3101
3102     setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3103 }
3104
3105 void WebPageProxy::setCustomUserAgent(const String& customUserAgent)
3106 {
3107     if (m_customUserAgent == customUserAgent)
3108         return;
3109
3110     m_customUserAgent = customUserAgent;
3111
3112     if (m_customUserAgent.isEmpty()) {
3113         setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3114         return;
3115     }
3116
3117     setUserAgent(String { m_customUserAgent });
3118 }
3119
3120 void WebPageProxy::resumeActiveDOMObjectsAndAnimations()
3121 {
3122     if (!hasRunningProcess() || !m_isPageSuspended)
3123         return;
3124
3125     m_isPageSuspended = false;
3126
3127     m_process->send(Messages::WebPage::ResumeActiveDOMObjectsAndAnimations(), m_webPageID);
3128 }
3129
3130 void WebPageProxy::suspendActiveDOMObjectsAndAnimations()
3131 {
3132     if (!hasRunningProcess() || m_isPageSuspended)
3133         return;
3134
3135     m_isPageSuspended = true;
3136
3137     m_process->send(Messages::WebPage::SuspendActiveDOMObjectsAndAnimations(), m_webPageID);
3138 }
3139
3140 bool WebPageProxy::supportsTextEncoding() const
3141 {
3142     // FIXME (118840): We should probably only support this for text documents, not all non-image documents.
3143     return m_mainFrame && !m_mainFrame->isDisplayingStandaloneImageDocument();
3144 }
3145
3146 void WebPageProxy::setCustomTextEncodingName(const String& encodingName)
3147 {
3148     if (m_customTextEncodingName == encodingName)
3149         return;
3150     m_customTextEncodingName = encodingName;
3151
3152     if (!hasRunningProcess())
3153         return;
3154     m_process->send(Messages::WebPage::SetCustomTextEncodingName(encodingName), m_webPageID);
3155 }
3156
3157 SessionState WebPageProxy::sessionState(WTF::Function<bool (WebBackForwardListItem&)>&& filter) const
3158 {
3159     SessionState sessionState;
3160
3161     sessionState.backForwardListState = m_backForwardList->backForwardListState(WTFMove(filter));
3162
3163     String provisionalURLString = m_pageLoadState.pendingAPIRequestURL();
3164     if (provisionalURLString.isEmpty())
3165         provisionalURLString = m_pageLoadState.provisionalURL();
3166
3167     if (!provisionalURLString.isEmpty())
3168         sessionState.provisionalURL = URL(URL(), provisionalURLString);
3169
3170     sessionState.renderTreeSize = renderTreeSize();
3171     return sessionState;
3172 }
3173
3174 RefPtr<API::Navigation> WebPageProxy::restoreFromSessionState(SessionState sessionState, bool navigate)
3175 {
3176     RELEASE_LOG_IF_ALLOWED(Loading, "restoreFromSessionState:");
3177
3178     m_sessionRestorationRenderTreeSize = 0;
3179     m_hitRenderTreeSizeThreshold = false;
3180
3181     bool hasBackForwardList = !!sessionState.backForwardListState.currentIndex;
3182
3183     if (hasBackForwardList) {
3184         // If there isn't a running process yet the RestoreSession message below is just ignored, and
3185         // session is restored when the web process is created via creation parameters which is not
3186         // considered an API request. So, we launch the initial process here before restoring the
3187         // session to ensure the session is restored in the web process via RestoreSession IPC message
3188         // which is considered an API request. See https://bugs.webkit.org/show_bug.cgi?id=198561.
3189         launchInitialProcessIfNecessary();
3190
3191         m_backForwardList->restoreFromState(WTFMove(sessionState.backForwardListState));
3192         process().send(Messages::WebPage::RestoreSession(m_backForwardList->itemStates()), m_webPageID);
3193
3194         auto transaction = m_pageLoadState.transaction();
3195         m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
3196         m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
3197
3198         // The back / forward list was restored from a sessionState so we don't want to snapshot the current
3199         // page when navigating away. Suppress navigation snapshotting until the next load has committed
3200         suppressNextAutomaticNavigationSnapshot();
3201     }
3202
3203     // FIXME: Navigating should be separate from state restoration.
3204     if (navigate) {
3205         m_sessionRestorationRenderTreeSize = sessionState.renderTreeSize;
3206         if (!m_sessionRestorationRenderTreeSize)
3207             m_hitRenderTreeSizeThreshold = true; // If we didn't get data on renderTreeSize, just don't fire the milestone.
3208
3209         if (!sessionState.provisionalURL.isNull())
3210             return loadRequest(sessionState.provisionalURL);
3211
3212         if (hasBackForwardList) {
3213             if (WebBackForwardListItem* item = m_backForwardList->currentItem())
3214                 return goToBackForwardItem(*item);
3215         }
3216     }
3217
3218     return nullptr;
3219 }
3220
3221 bool WebPageProxy::supportsTextZoom() const
3222 {
3223     // FIXME (118840): This should also return false for standalone media and plug-in documents.
3224     if (!m_mainFrame || m_mainFrame->isDisplayingStandaloneImageDocument())
3225         return false;
3226
3227     return true;
3228 }
3229  
3230 void WebPageProxy::setTextZoomFactor(double zoomFactor)
3231 {
3232     if (m_textZoomFactor == zoomFactor)
3233         return;
3234
3235     m_textZoomFactor = zoomFactor;
3236
3237     if (!hasRunningProcess())
3238         return;
3239
3240     m_process->send(Messages::WebPage::SetTextZoomFactor(m_textZoomFactor), m_webPageID);
3241 }
3242
3243 void WebPageProxy::setPageZoomFactor(double zoomFactor)
3244 {
3245     if (m_pageZoomFactor == zoomFactor)
3246         return;
3247
3248     closeOverlayedViews();
3249
3250     m_pageZoomFactor = zoomFactor;
3251
3252     if (!hasRunningProcess())
3253         return;
3254
3255     m_process->send(Messages::WebPage::SetPageZoomFactor(m_pageZoomFactor), m_webPageID);
3256 }
3257
3258 void WebPageProxy::setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor)
3259 {
3260     if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
3261         return;
3262
3263     closeOverlayedViews();
3264
3265     m_pageZoomFactor = pageZoomFactor;
3266     m_textZoomFactor = textZoomFactor;
3267
3268     if (!hasRunningProcess())
3269         return;
3270
3271     m_process->send(Messages::WebPage::SetPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor), m_webPageID);
3272 }
3273
3274 double WebPageProxy::pageZoomFactor() const
3275 {
3276     // Zoom factor for non-PDF pages persists across page loads. We maintain a separate member variable for PDF
3277     // zoom which ensures that we don't use the PDF zoom for a normal page.
3278     if (m_mainFramePluginHandlesPageScaleGesture)
3279         return m_pluginZoomFactor;
3280     return m_pageZoomFactor;
3281 }
3282
3283 double WebPageProxy::pageScaleFactor() const
3284 {
3285     // PDF documents use zoom and scale factors to size themselves appropriately in the window. We store them
3286     // separately but decide which to return based on the main frame.
3287     if (m_mainFramePluginHandlesPageScaleGesture)
3288         return m_pluginScaleFactor;
3289     return m_pageScaleFactor;
3290 }
3291
3292 void WebPageProxy::scalePage(double scale, const IntPoint& origin)
3293 {
3294     ASSERT(scale > 0);
3295
3296     m_pageScaleFactor = scale;
3297
3298     if (!hasRunningProcess())
3299         return;
3300
3301     m_process->send(Messages::WebPage::ScalePage(scale, origin), m_webPageID);
3302 }
3303
3304 void WebPageProxy::scalePageInViewCoordinates(double scale, const IntPoint& centerInViewCoordinates)
3305 {
3306     ASSERT(scale > 0);
3307
3308     m_pageScaleFactor = scale;
3309
3310     if (!hasRunningProcess())
3311         return;
3312
3313     m_process->send(Messages::WebPage::ScalePageInViewCoordinates(scale, centerInViewCoordinates), m_webPageID);
3314 }
3315
3316 void WebPageProxy::scaleView(double scale)
3317 {
3318     ASSERT(scale > 0);
3319
3320     m_viewScaleFactor = scale;
3321
3322     if (!hasRunningProcess())
3323         return;
3324
3325     m_process->send(Messages::WebPage::ScaleView(scale), m_webPageID);
3326 }
3327
3328 void WebPageProxy::setIntrinsicDeviceScaleFactor(float scaleFactor)
3329 {
3330     if (m_intrinsicDeviceScaleFactor == scaleFactor)
3331         return;
3332
3333     m_intrinsicDeviceScaleFactor = scaleFactor;
3334
3335     if (m_drawingArea)
3336         m_drawingArea->deviceScaleFactorDidChange();
3337 }
3338
3339 void WebPageProxy::windowScreenDidChange(PlatformDisplayID displayID)
3340 {
3341     if (!hasRunningProcess())
3342         return;
3343
3344     m_process->send(Messages::WebPage::WindowScreenDidChange(displayID), m_webPageID);
3345 }
3346
3347 float WebPageProxy::deviceScaleFactor() const
3348 {
3349     return m_customDeviceScaleFactor.valueOr(m_intrinsicDeviceScaleFactor);
3350 }
3351
3352 void WebPageProxy::setCustomDeviceScaleFactor(float customScaleFactor)
3353 {
3354     // FIXME: Remove this once we bump cairo requirements to support HiDPI.
3355     // https://bugs.webkit.org/show_bug.cgi?id=133378
3356 #if USE(CAIRO) && !HAVE(CAIRO_SURFACE_SET_DEVICE_SCALE)
3357     return;
3358 #endif
3359
3360     if (m_customDeviceScaleFactor && m_customDeviceScaleFactor.value() == customScaleFactor)
3361         return;
3362
3363     float oldScaleFactor = deviceScaleFactor();
3364
3365     // A value of 0 clears the customScaleFactor.
3366     if (customScaleFactor)
3367         m_customDeviceScaleFactor = customScaleFactor;
3368     else
3369         m_customDeviceScaleFactor = WTF::nullopt;
3370
3371     if (!hasRunningProcess())
3372         return;
3373
3374     if (deviceScaleFactor() != oldScaleFactor)
3375         m_drawingArea->deviceScaleFactorDidChange();
3376 }
3377
3378 void WebPageProxy::accessibilitySettingsDidChange()
3379 {
3380     if (!hasRunningProcess())
3381         return;
3382
3383     m_process->send(Messages::WebPage::AccessibilitySettingsDidChange(), m_webPageID);
3384 }
3385
3386 void WebPageProxy::setUseFixedLayout(bool fixed)
3387 {
3388     // This check is fine as the value is initialized in the web
3389     // process as part of the creation parameters.
3390     if (fixed == m_useFixedLayout)
3391         return;
3392
3393     m_useFixedLayout = fixed;
3394     if (!fixed)
3395         m_fixedLayoutSize = IntSize();
3396
3397     if (!hasRunningProcess())
3398         return;
3399
3400     m_process->send(Messages::WebPage::SetUseFixedLayout(fixed), m_webPageID);
3401 }
3402
3403 void WebPageProxy::setFixedLayoutSize(const IntSize& size)
3404 {
3405     if (size == m_fixedLayoutSize)
3406         return;
3407
3408     m_fixedLayoutSize = size;
3409
3410     if (!hasRunningProcess())
3411         return;
3412
3413     m_process->send(Messages::WebPage::SetFixedLayoutSize(size), m_webPageID);
3414 }
3415
3416 void WebPageProxy::setAlwaysShowsHorizontalScroller(bool alwaysShowsHorizontalScroller)
3417 {
3418     if (alwaysShowsHorizontalScroller == m_alwaysShowsHorizontalScroller)
3419         return;
3420
3421     m_alwaysShowsHorizontalScroller = alwaysShowsHorizontalScroller;
3422
3423     if (!hasRunningProcess())
3424         return;
3425
3426     m_process->send(Messages::WebPage::SetAlwaysShowsHorizontalScroller(alwaysShowsHorizontalScroller), m_webPageID);
3427 }
3428
3429 void WebPageProxy::setAlwaysShowsVerticalScroller(bool alwaysShowsVerticalScroller)
3430 {
3431     if (alwaysShowsVerticalScroller == m_alwaysShowsVerticalScroller)
3432         return;
3433
3434     m_alwaysShowsVerticalScroller = alwaysShowsVerticalScroller;
3435
3436     if (!hasRunningProcess())
3437         return;
3438
3439     m_process->send(Messages::WebPage::SetAlwaysShowsVerticalScroller(alwaysShowsVerticalScroller), m_webPageID);
3440 }
3441
3442 void WebPageProxy::listenForLayoutMilestones(OptionSet<WebCore::LayoutMilestone> milestones)
3443 {    
3444     if (milestones == m_observedLayoutMilestones)
3445         return;
3446
3447     m_observedLayoutMilestones = milestones;
3448
3449     if (!hasRunningProcess())
3450         return;
3451
3452     m_process->send(Messages::WebPage::ListenForLayoutMilestones(milestones), m_webPageID);
3453 }
3454
3455 void WebPageProxy::setSuppressScrollbarAnimations(bool suppressAnimations)
3456 {
3457     if (suppressAnimations == m_suppressScrollbarAnimations)
3458         return;
3459
3460     m_suppressScrollbarAnimations = suppressAnimations;
3461
3462     if (!hasRunningProcess())
3463         return;
3464
3465     m_process->send(Messages::WebPage::SetSuppressScrollbarAnimations(suppressAnimations), m_webPageID);
3466 }
3467
3468 bool WebPageProxy::rubberBandsAtLeft() const
3469 {
3470     return m_rubberBandsAtLeft;
3471 }
3472
3473 void WebPageProxy::setRubberBandsAtLeft(bool rubberBandsAtLeft)
3474 {
3475     m_rubberBandsAtLeft = rubberBandsAtLeft;
3476 }
3477
3478 bool WebPageProxy::rubberBandsAtRight() const
3479 {
3480     return m_rubberBandsAtRight;
3481 }
3482
3483 void WebPageProxy::setRubberBandsAtRight(bool rubberBandsAtRight)
3484 {
3485     m_rubberBandsAtRight = rubberBandsAtRight;
3486 }
3487
3488 bool WebPageProxy::rubberBandsAtTop() const
3489 {
3490     return m_rubberBandsAtTop;
3491 }
3492
3493 void WebPageProxy::setRubberBandsAtTop(bool rubberBandsAtTop)
3494 {
3495     m_rubberBandsAtTop = rubberBandsAtTop;
3496 }
3497
3498 bool WebPageProxy::rubberBandsAtBottom() const
3499 {
3500     return m_rubberBandsAtBottom;
3501 }
3502
3503 void WebPageProxy::setRubberBandsAtBottom(bool rubberBandsAtBottom)
3504 {
3505     m_rubberBandsAtBottom = rubberBandsAtBottom;
3506 }
3507     
3508 void WebPageProxy::setEnableVerticalRubberBanding(bool enableVerticalRubberBanding)
3509 {
3510     if (enableVerticalRubberBanding == m_enableVerticalRubberBanding)
3511         return;
3512
3513     m_enableVerticalRubberBanding = enableVerticalRubberBanding;
3514
3515     if (!hasRunningProcess())
3516         return;
3517     m_process->send(Messages::WebPage::SetEnableVerticalRubberBanding(enableVerticalRubberBanding), m_webPageID);
3518 }
3519     
3520 bool WebPageProxy::verticalRubberBandingIsEnabled() const
3521 {
3522     return m_enableVerticalRubberBanding;
3523 }
3524     
3525 void WebPageProxy::setEnableHorizontalRubberBanding(bool enableHorizontalRubberBanding)
3526 {
3527     if (enableHorizontalRubberBanding == m_enableHorizontalRubberBanding)
3528         return;
3529
3530     m_enableHorizontalRubberBanding = enableHorizontalRubberBanding;
3531
3532     if (!hasRunningProcess())
3533         return;
3534     m_process->send(Messages::WebPage::SetEnableHorizontalRubberBanding(enableHorizontalRubberBanding), m_webPageID);
3535 }
3536     
3537 bool WebPageProxy::horizontalRubberBandingIsEnabled() const
3538 {
3539     return m_enableHorizontalRubberBanding;
3540 }
3541
3542 void WebPageProxy::setBackgroundExtendsBeyondPage(bool backgroundExtendsBeyondPage)
3543 {
3544     if (backgroundExtendsBeyondPage == m_backgroundExtendsBeyondPage)
3545         return;
3546
3547     m_backgroundExtendsBeyondPage = backgroundExtendsBeyondPage;
3548
3549     if (!hasRunningProcess())
3550         return;
3551     m_process->send(Messages::WebPage::SetBackgroundExtendsBeyondPage(backgroundExtendsBeyondPage), m_webPageID);
3552 }
3553
3554 bool WebPageProxy::backgroundExtendsBeyondPage() const
3555 {
3556     return m_backgroundExtendsBeyondPage;
3557 }
3558
3559 void WebPageProxy::setPaginationMode(WebCore::Pagination::Mode mode)
3560 {