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