Check for navigation to app-bound domain during script evaluation
[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(), hasNavigatedAwayFromAppBoundDomain());
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, NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain, 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     loadParameters.hasNavigatedAwayFromAppBoundDomain = hasNavigatedAwayFromAppBoundDomain;
1314     maybeInitializeSandboxExtensionHandle(process, url, m_pageLoadState.resourceDirectoryURL(), loadParameters.sandboxExtensionHandle);
1315
1316     addPlatformLoadParameters(loadParameters);
1317
1318     preconnectTo(url);
1319
1320 #if HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_AUDIT_TOKEN)
1321     if (!process->isLaunching() || !url.isLocalFile())
1322         process->send(Messages::WebPage::LoadRequest(loadParameters), webPageID);
1323     else
1324         process->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(loadParameters, m_pageLoadState.resourceDirectoryURL(), m_identifier, true), webPageID);
1325 #else
1326     process->send(Messages::WebPage::LoadRequest(loadParameters), webPageID);
1327 #endif
1328     process->startResponsivenessTimer();
1329 }
1330
1331 RefPtr<API::Navigation> WebPageProxy::loadFile(const String& fileURLString, const String& resourceDirectoryURLString, API::Object* userData)
1332 {
1333     RELEASE_LOG_IF_ALLOWED(Loading, "loadFile:");
1334
1335     if (m_isClosed) {
1336         RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: page is closed");
1337         return nullptr;
1338     }
1339
1340     if (!hasRunningProcess())
1341         launchProcess({ }, ProcessLaunchReason::InitialProcess);
1342
1343     URL fileURL = URL(URL(), fileURLString);
1344     if (!fileURL.isLocalFile()) {
1345         RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: file is not local");
1346         return nullptr;
1347     }
1348
1349     URL resourceDirectoryURL;
1350     if (resourceDirectoryURLString.isNull())
1351         resourceDirectoryURL = URL({ }, "file:///"_s);
1352     else {
1353         resourceDirectoryURL = URL(URL(), resourceDirectoryURLString);
1354         if (!resourceDirectoryURL.isLocalFile()) {
1355             RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: resource URL is not local");
1356             return nullptr;
1357         }
1358     }
1359
1360     auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(fileURL), m_backForwardList->currentItem());
1361
1362     if (shouldUseForegroundPriorityForClientNavigation())
1363         navigation->setForegroundActivity(process().throttler().foregroundActivity("Client navigation"_s).moveToUniquePtr());
1364
1365     auto transaction = m_pageLoadState.transaction();
1366
1367     m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), fileURLString }, resourceDirectoryURL);
1368
1369     LoadParameters loadParameters;
1370     loadParameters.navigationID = navigation->navigationID();
1371     loadParameters.request = fileURL;
1372     loadParameters.shouldOpenExternalURLsPolicy = ShouldOpenExternalURLsPolicy::ShouldNotAllow;
1373     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1374     const bool checkAssumedReadAccessToResourceURL = false;
1375     maybeInitializeSandboxExtensionHandle(m_process, fileURL, resourceDirectoryURL, loadParameters.sandboxExtensionHandle, checkAssumedReadAccessToResourceURL);
1376     addPlatformLoadParameters(loadParameters);
1377
1378 #if HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_AUDIT_TOKEN)
1379     if (m_process->isLaunching())
1380         send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(loadParameters, resourceDirectoryURL, m_identifier, checkAssumedReadAccessToResourceURL));
1381     else
1382         send(Messages::WebPage::LoadRequest(loadParameters));
1383 #else
1384     send(Messages::WebPage::LoadRequest(loadParameters));
1385 #endif
1386     m_process->startResponsivenessTimer();
1387
1388     return navigation;
1389 }
1390
1391 RefPtr<API::Navigation> WebPageProxy::loadData(const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
1392 {
1393     RELEASE_LOG_IF_ALLOWED(Loading, "loadData:");
1394
1395     if (m_isClosed) {
1396         RELEASE_LOG_IF_ALLOWED(Loading, "loadData: page is closed");
1397         return nullptr;
1398     }
1399
1400     if (!hasRunningProcess())
1401         launchProcess({ }, ProcessLaunchReason::InitialProcess);
1402
1403     auto navigation = m_navigationState->createLoadDataNavigation(makeUnique<API::SubstituteData>(data.vector(), MIMEType, encoding, baseURL, userData));
1404
1405     if (shouldUseForegroundPriorityForClientNavigation())
1406         navigation->setForegroundActivity(process().throttler().foregroundActivity("Client navigation"_s).moveToUniquePtr());
1407
1408     loadDataWithNavigationShared(m_process.copyRef(), m_webPageID, navigation, data, MIMEType, encoding, baseURL, userData, ShouldTreatAsContinuingLoad::No, isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), WTF::nullopt, shouldOpenExternalURLsPolicy);
1409     return navigation;
1410 }
1411
1412 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, NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain, Optional<WebsitePoliciesData>&& websitePolicies, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
1413 {
1414     RELEASE_LOG_IF_ALLOWED(Loading, "loadDataWithNavigation");
1415
1416     ASSERT(!m_isClosed);
1417
1418     auto transaction = m_pageLoadState.transaction();
1419
1420     m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), !baseURL.isEmpty() ? baseURL : WTF::blankURL().string() });
1421
1422     LoadParameters loadParameters;
1423     loadParameters.navigationID = navigation.navigationID();
1424     loadParameters.data = data;
1425     loadParameters.MIMEType = MIMEType;
1426     loadParameters.encodingName = encoding;
1427     loadParameters.baseURLString = baseURL;
1428     loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::Yes;
1429     loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1430     loadParameters.websitePolicies = WTFMove(websitePolicies);
1431     loadParameters.shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
1432     loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
1433     loadParameters.hasNavigatedAwayFromAppBoundDomain = hasNavigatedAwayFromAppBoundDomain;
1434     addPlatformLoadParameters(loadParameters);
1435
1436     process->assumeReadAccessToBaseURL(*this, baseURL);
1437     process->send(Messages::WebPage::LoadData(loadParameters), webPageID);
1438     process->startResponsivenessTimer();
1439 }
1440
1441 void WebPageProxy::loadAlternateHTML(const IPC::DataReference& htmlData, const String& encoding, const URL& baseURL, const URL& unreachableURL, API::Object* userData)
1442 {
1443     RELEASE_LOG_IF_ALLOWED(Loading, "loadAlternateHTML");
1444
1445     // When the UIProcess is in the process of handling a failing provisional load, do not attempt to
1446     // start a second alternative HTML load as this will prevent the page load state from being
1447     // handled properly.
1448     if (m_isClosed || m_isLoadingAlternateHTMLStringForFailingProvisionalLoad) {
1449         RELEASE_LOG_IF_ALLOWED(Loading, "loadAlternateHTML: page is closed (or other)");
1450         return;
1451     }
1452
1453     if (!m_failingProvisionalLoadURL.isEmpty())
1454         m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = true;
1455
1456     if (!hasRunningProcess())
1457         launchProcess(RegistrableDomain { baseURL }, ProcessLaunchReason::InitialProcess);
1458
1459     auto transaction = m_pageLoadState.transaction();
1460
1461     m_pageLoadState.setPendingAPIRequest(transaction, { 0, unreachableURL });
1462     m_pageLoadState.setUnreachableURL(transaction, unreachableURL);
1463
1464     if (m_mainFrame)
1465         m_mainFrame->setUnreachableURL(unreachableURL);
1466
1467     LoadParameters loadParameters;
1468     loadParameters.navigationID = 0;
1469     loadParameters.data = htmlData;
1470     loadParameters.MIMEType = "text/html"_s;
1471     loadParameters.encodingName = encoding;
1472     loadParameters.baseURLString = baseURL;
1473     loadParameters.unreachableURLString = unreachableURL;
1474     loadParameters.provisionalLoadErrorURLString = m_failingProvisionalLoadURL;
1475     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1476     addPlatformLoadParameters(loadParameters);
1477
1478     m_process->assumeReadAccessToBaseURL(*this, baseURL);
1479     m_process->assumeReadAccessToBaseURL(*this, unreachableURL);
1480     send(Messages::WebPage::LoadAlternateHTML(loadParameters));
1481     m_process->startResponsivenessTimer();
1482 }
1483
1484 void WebPageProxy::loadWebArchiveData(API::Data* webArchiveData, API::Object* userData)
1485 {
1486     RELEASE_LOG_IF_ALLOWED(Loading, "loadWebArchiveData:");
1487
1488     if (m_isClosed) {
1489         RELEASE_LOG_IF_ALLOWED(Loading, "loadWebArchiveData: page is closed");
1490         return;
1491     }
1492
1493     if (!hasRunningProcess())
1494         launchProcess({ }, ProcessLaunchReason::InitialProcess);
1495
1496     auto transaction = m_pageLoadState.transaction();
1497     m_pageLoadState.setPendingAPIRequest(transaction, { 0, WTF::blankURL().string() });
1498
1499     LoadParameters loadParameters;
1500     loadParameters.navigationID = 0;
1501     loadParameters.data = webArchiveData->dataReference();
1502     loadParameters.MIMEType = "application/x-webarchive"_s;
1503     loadParameters.encodingName = "utf-16"_s;
1504     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1505     addPlatformLoadParameters(loadParameters);
1506
1507     send(Messages::WebPage::LoadData(loadParameters));
1508     m_process->startResponsivenessTimer();
1509 }
1510
1511 void WebPageProxy::navigateToPDFLinkWithSimulatedClick(const String& urlString, IntPoint documentPoint, IntPoint screenPoint)
1512 {
1513     RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick:");
1514
1515     if (m_isClosed) {
1516         RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick: page is closed:");
1517         return;
1518     }
1519
1520     if (WTF::protocolIsJavaScript(urlString))
1521         return;
1522
1523     if (!hasRunningProcess())
1524         launchProcess(RegistrableDomain { URL(URL(), urlString) }, ProcessLaunchReason::InitialProcess);
1525
1526     send(Messages::WebPage::NavigateToPDFLinkWithSimulatedClick(urlString, documentPoint, screenPoint));
1527     m_process->startResponsivenessTimer();
1528 }
1529
1530 void WebPageProxy::stopLoading()
1531 {
1532     RELEASE_LOG_IF_ALLOWED(Loading, "stopLoading:");
1533
1534     if (!hasRunningProcess()) {
1535         RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick: page is not valid");
1536         return;
1537     }
1538
1539     send(Messages::WebPage::StopLoading());
1540     if (m_provisionalPage) {
1541         m_provisionalPage->cancel();
1542         m_provisionalPage = nullptr;
1543     }
1544     m_process->startResponsivenessTimer();
1545 }
1546
1547 RefPtr<API::Navigation> WebPageProxy::reload(OptionSet<WebCore::ReloadOption> options)
1548 {
1549     RELEASE_LOG_IF_ALLOWED(Loading, "reload:");
1550
1551     SandboxExtension::Handle sandboxExtensionHandle;
1552
1553     String url = currentURL();
1554     if (!url.isEmpty()) {
1555         // We may not have an extension yet if back/forward list was reinstated after a WebProcess crash or a browser relaunch
1556         maybeInitializeSandboxExtensionHandle(m_process, URL(URL(), url), currentResourceDirectoryURL(), sandboxExtensionHandle);
1557     }
1558
1559     if (!hasRunningProcess())
1560         return launchProcessForReload();
1561     
1562     auto navigation = m_navigationState->createReloadNavigation();
1563
1564     if (!url.isEmpty()) {
1565         auto transaction = m_pageLoadState.transaction();
1566         m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), url });
1567     }
1568
1569     // Store decision to reload without content blockers on the navigation so that we can later set the corresponding
1570     // WebsitePolicies flag in WebPageProxy::receivedNavigationPolicyDecision().
1571     if (options.contains(WebCore::ReloadOption::DisableContentBlockers))
1572         navigation->setUserContentExtensionsEnabled(false);
1573
1574     send(Messages::WebPage::Reload(navigation->navigationID(), options.toRaw(), sandboxExtensionHandle));
1575     m_process->startResponsivenessTimer();
1576
1577 #if ENABLE(SPEECH_SYNTHESIS)
1578     resetSpeechSynthesizer();
1579 #endif
1580
1581     return navigation;
1582 }
1583
1584 void WebPageProxy::recordAutomaticNavigationSnapshot()
1585 {
1586     if (m_shouldSuppressNextAutomaticNavigationSnapshot)
1587         return;
1588
1589     if (WebBackForwardListItem* item = m_backForwardList->currentItem())
1590         recordNavigationSnapshot(*item);
1591 }
1592
1593 void WebPageProxy::recordNavigationSnapshot(WebBackForwardListItem& item)
1594 {
1595     if (!m_shouldRecordNavigationSnapshots)
1596         return;
1597
1598 #if PLATFORM(COCOA) || PLATFORM(GTK)
1599     ViewSnapshotStore::singleton().recordSnapshot(*this, item);
1600 #else
1601     UNUSED_PARAM(item);
1602 #endif
1603 }
1604
1605 RefPtr<API::Navigation> WebPageProxy::goForward()
1606 {
1607     WebBackForwardListItem* forwardItem = m_backForwardList->forwardItem();
1608     if (!forwardItem)
1609         return nullptr;
1610
1611     return goToBackForwardItem(*forwardItem, FrameLoadType::Forward);
1612 }
1613
1614 RefPtr<API::Navigation> WebPageProxy::goBack()
1615 {
1616     WebBackForwardListItem* backItem = m_backForwardList->backItem();
1617     if (!backItem)
1618         return nullptr;
1619
1620     return goToBackForwardItem(*backItem, FrameLoadType::Back);
1621 }
1622
1623 RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item)
1624 {
1625     return goToBackForwardItem(item, FrameLoadType::IndexedBackForward);
1626 }
1627
1628 RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item, FrameLoadType frameLoadType)
1629 {
1630     RELEASE_LOG_IF_ALLOWED(Loading, "goToBackForwardItem:");
1631     LOG(Loading, "WebPageProxy %p goToBackForwardItem to item URL %s", this, item.url().utf8().data());
1632
1633     if (!hasRunningProcess())
1634         return launchProcessWithItem(item);
1635
1636     RefPtr<API::Navigation> navigation;
1637     if (!m_backForwardList->currentItem()->itemIsInSameDocument(item))
1638         navigation = m_navigationState->createBackForwardNavigation(item, m_backForwardList->currentItem(), frameLoadType);
1639
1640     auto transaction = m_pageLoadState.transaction();
1641     m_pageLoadState.setPendingAPIRequest(transaction, { navigation ? navigation->navigationID() : 0, item.url() });
1642
1643     send(Messages::WebPage::GoToBackForwardItem(navigation ? navigation->navigationID() : 0, item.itemID(), frameLoadType, ShouldTreatAsContinuingLoad::No, WTF::nullopt));
1644     m_process->startResponsivenessTimer();
1645
1646     return navigation;
1647 }
1648
1649 void WebPageProxy::tryRestoreScrollPosition()
1650 {
1651     RELEASE_LOG_IF_ALLOWED(Loading, "tryRestoreScrollPosition:");
1652
1653     if (!hasRunningProcess()) {
1654         RELEASE_LOG_IF_ALLOWED(Loading, "tryRestoreScrollPosition: page is not valid");
1655         return;
1656     }
1657
1658     send(Messages::WebPage::TryRestoreScrollPosition());
1659 }
1660
1661 void WebPageProxy::didChangeBackForwardList(WebBackForwardListItem* added, Vector<Ref<WebBackForwardListItem>>&& removed)
1662 {
1663     PageClientProtector protector(pageClient());
1664
1665     if (!m_navigationClient->didChangeBackForwardList(*this, added, removed) && m_loaderClient)
1666         m_loaderClient->didChangeBackForwardList(*this, added, WTFMove(removed));
1667
1668     auto transaction = m_pageLoadState.transaction();
1669
1670     m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
1671     m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
1672 }
1673
1674 void WebPageProxy::willGoToBackForwardListItem(const BackForwardItemIdentifier& itemID, bool inBackForwardCache)
1675 {
1676     PageClientProtector protector(pageClient());
1677
1678     if (auto* item = m_backForwardList->itemForID(itemID))
1679         m_navigationClient->willGoToBackForwardListItem(*this, *item, inBackForwardCache);
1680 }
1681
1682 bool WebPageProxy::shouldKeepCurrentBackForwardListItemInList(WebBackForwardListItem& item)
1683 {
1684     PageClientProtector protector(pageClient());
1685
1686     return !m_loaderClient || m_loaderClient->shouldKeepCurrentBackForwardListItemInList(*this, item);
1687 }
1688
1689 bool WebPageProxy::canShowMIMEType(const String& mimeType)
1690 {
1691     if (MIMETypeRegistry::canShowMIMEType(mimeType))
1692         return true;
1693
1694 #if ENABLE(NETSCAPE_PLUGIN_API)
1695     String newMimeType = mimeType;
1696     PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL());
1697     if (!plugin.path.isNull() && m_preferences->pluginsEnabled())
1698         return true;
1699 #endif // ENABLE(NETSCAPE_PLUGIN_API)
1700
1701 #if PLATFORM(COCOA)
1702     // On Mac, we can show PDFs.
1703     if (MIMETypeRegistry::isPDFOrPostScriptMIMEType(mimeType) && !WebProcessPool::omitPDFSupport())
1704         return true;
1705 #endif // PLATFORM(COCOA)
1706
1707     return false;
1708 }
1709
1710 void WebPageProxy::setControlledByAutomation(bool controlled)
1711 {
1712     if (m_controlledByAutomation == controlled)
1713         return;
1714
1715     m_controlledByAutomation = controlled;
1716
1717     if (!hasRunningProcess())
1718         return;
1719
1720     send(Messages::WebPage::SetControlledByAutomation(controlled));
1721     m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation));
1722 }
1723
1724 void WebPageProxy::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type)
1725 {
1726     MESSAGE_CHECK(m_process, !targetId.isEmpty());
1727     m_inspectorController->createInspectorTarget(targetId, type);
1728 }
1729
1730 void WebPageProxy::destroyInspectorTarget(const String& targetId)
1731 {
1732     MESSAGE_CHECK(m_process, !targetId.isEmpty());
1733     m_inspectorController->destroyInspectorTarget(targetId);
1734 }
1735
1736 void WebPageProxy::sendMessageToInspectorFrontend(const String& targetId, const String& message)
1737 {
1738     m_inspectorController->sendMessageToInspectorFrontend(targetId, message);
1739 }
1740
1741 #if ENABLE(REMOTE_INSPECTOR)
1742 void WebPageProxy::setIndicating(bool indicating)
1743 {
1744     if (!hasRunningProcess())
1745         return;
1746
1747     send(Messages::WebPage::SetIndicating(indicating));
1748 }
1749
1750 bool WebPageProxy::allowsRemoteInspection() const
1751 {
1752     return m_inspectorDebuggable->remoteDebuggingAllowed();
1753 }
1754
1755 void WebPageProxy::setAllowsRemoteInspection(bool allow)
1756 {
1757     m_inspectorDebuggable->setRemoteDebuggingAllowed(allow);
1758 }
1759
1760 String WebPageProxy::remoteInspectionNameOverride() const
1761 {
1762     return m_inspectorDebuggable->nameOverride();
1763 }
1764
1765 void WebPageProxy::setRemoteInspectionNameOverride(const String& name)
1766 {
1767     m_inspectorDebuggable->setNameOverride(name);
1768 }
1769
1770 void WebPageProxy::remoteInspectorInformationDidChange()
1771 {
1772     m_inspectorDebuggable->update();
1773 }
1774 #endif
1775
1776 void WebPageProxy::setBackgroundColor(const Optional<Color>& color)
1777 {
1778     if (m_backgroundColor == color)
1779         return;
1780
1781     m_backgroundColor = color;
1782     if (hasRunningProcess())
1783         send(Messages::WebPage::SetBackgroundColor(color));
1784 }
1785
1786 void WebPageProxy::setTopContentInset(float contentInset)
1787 {
1788     if (m_topContentInset == contentInset)
1789         return;
1790
1791     m_topContentInset = contentInset;
1792
1793     if (!hasRunningProcess())
1794         return;
1795 #if PLATFORM(COCOA)
1796     MachSendRight fence = m_drawingArea->createFence();
1797
1798     auto fenceAttachment = IPC::Attachment(fence.leakSendRight(), MACH_MSG_TYPE_MOVE_SEND);
1799     send(Messages::WebPage::SetTopContentInsetFenced(contentInset, fenceAttachment));
1800 #else
1801     send(Messages::WebPage::SetTopContentInset(contentInset));
1802 #endif
1803 }
1804
1805 void WebPageProxy::setUnderlayColor(const Color& color)
1806 {
1807     if (m_underlayColor == color)
1808         return;
1809
1810     m_underlayColor = color;
1811
1812     if (hasRunningProcess())
1813         send(Messages::WebPage::SetUnderlayColor(color));
1814 }
1815
1816 void WebPageProxy::viewWillStartLiveResize()
1817 {
1818     if (!hasRunningProcess())
1819         return;
1820
1821     closeOverlayedViews();
1822     send(Messages::WebPage::ViewWillStartLiveResize());
1823 }
1824
1825 void WebPageProxy::viewWillEndLiveResize()
1826 {
1827     if (!hasRunningProcess())
1828         return;
1829     send(Messages::WebPage::ViewWillEndLiveResize());
1830 }
1831
1832 void WebPageProxy::setViewNeedsDisplay(const Region& region)
1833 {
1834     pageClient().setViewNeedsDisplay(region);
1835 }
1836
1837 void WebPageProxy::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin)
1838 {
1839     pageClient().requestScroll(scrollPosition, scrollOrigin);
1840 }
1841
1842 WebCore::FloatPoint WebPageProxy::viewScrollPosition() const
1843 {
1844     return pageClient().viewScrollPosition();
1845 }
1846
1847 void WebPageProxy::setSuppressVisibilityUpdates(bool flag)
1848 {
1849     if (m_suppressVisibilityUpdates == flag)
1850         return;
1851     m_suppressVisibilityUpdates = flag;
1852
1853     if (!m_suppressVisibilityUpdates) {
1854 #if PLATFORM(COCOA)
1855         m_activityStateChangeDispatcher->schedule();
1856 #else
1857         dispatchActivityStateChange();
1858 #endif
1859     }
1860 }
1861
1862 void WebPageProxy::updateActivityState(OptionSet<ActivityState::Flag> flagsToUpdate)
1863 {
1864     bool wasVisible = isViewVisible();
1865     m_activityState.remove(flagsToUpdate);
1866     if (flagsToUpdate & ActivityState::IsFocused && pageClient().isViewFocused())
1867         m_activityState.add(ActivityState::IsFocused);
1868     if (flagsToUpdate & ActivityState::WindowIsActive && pageClient().isViewWindowActive())
1869         m_activityState.add(ActivityState::WindowIsActive);
1870     if (flagsToUpdate & ActivityState::IsVisible) {
1871         bool isNowVisible = pageClient().isViewVisible();
1872         if (isNowVisible)
1873             m_activityState.add(ActivityState::IsVisible);
1874         if (wasVisible != isNowVisible)
1875             RELEASE_LOG_IF_ALLOWED(ViewState, "updateActivityState: view visibility state changed %d -> %d", wasVisible, isNowVisible);
1876     }
1877     if (flagsToUpdate & ActivityState::IsVisibleOrOccluded && pageClient().isViewVisibleOrOccluded())
1878         m_activityState.add(ActivityState::IsVisibleOrOccluded);
1879     if (flagsToUpdate & ActivityState::IsInWindow && pageClient().isViewInWindow())
1880         m_activityState.add(ActivityState::IsInWindow);
1881     if (flagsToUpdate & ActivityState::IsVisuallyIdle && pageClient().isVisuallyIdle())
1882         m_activityState.add(ActivityState::IsVisuallyIdle);
1883     if (flagsToUpdate & ActivityState::IsAudible && m_mediaState & MediaProducer::IsPlayingAudio && !(m_mutedState & MediaProducer::AudioIsMuted))
1884         m_activityState.add(ActivityState::IsAudible);
1885     if (flagsToUpdate & ActivityState::IsLoading && m_pageLoadState.isLoading())
1886         m_activityState.add(ActivityState::IsLoading);
1887     if (flagsToUpdate & ActivityState::IsCapturingMedia && m_mediaState & (MediaProducer::HasActiveAudioCaptureDevice | MediaProducer::HasActiveVideoCaptureDevice))
1888         m_activityState.add(ActivityState::IsCapturingMedia);
1889 }
1890
1891 void WebPageProxy::activityStateDidChange(OptionSet<ActivityState::Flag> mayHaveChanged, ActivityStateChangeDispatchMode dispatchMode, ActivityStateChangeReplyMode replyMode)
1892 {
1893     LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " activityStateDidChange - mayHaveChanged " << mayHaveChanged);
1894
1895     m_potentiallyChangedActivityStateFlags.add(mayHaveChanged);
1896     m_activityStateChangeWantsSynchronousReply = m_activityStateChangeWantsSynchronousReply || replyMode == ActivityStateChangeReplyMode::Synchronous;
1897
1898     if (m_suppressVisibilityUpdates && dispatchMode != ActivityStateChangeDispatchMode::Immediate)
1899         return;
1900
1901 #if PLATFORM(COCOA)
1902     bool isNewlyInWindow = !isInWindow() && (mayHaveChanged & ActivityState::IsInWindow) && pageClient().isViewInWindow();
1903     if (dispatchMode == ActivityStateChangeDispatchMode::Immediate || isNewlyInWindow) {
1904         dispatchActivityStateChange();
1905         return;
1906     }
1907     m_activityStateChangeDispatcher->schedule();
1908 #else
1909     UNUSED_PARAM(dispatchMode);
1910     dispatchActivityStateChange();
1911 #endif
1912 }
1913
1914 void WebPageProxy::viewDidLeaveWindow()
1915 {
1916     closeOverlayedViews();
1917 #if PLATFORM(IOS_FAMILY) && HAVE(AVKIT) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
1918     // When leaving the current page, close the video fullscreen.
1919     if (m_videoFullscreenManager && m_videoFullscreenManager->hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModeStandard))
1920         m_videoFullscreenManager->requestHideAndExitFullscreen();
1921 #endif
1922 }
1923
1924 void WebPageProxy::viewDidEnterWindow()
1925 {
1926     LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
1927     if (m_layerHostingMode != layerHostingMode) {
1928         m_layerHostingMode = layerHostingMode;
1929         send(Messages::WebPage::SetLayerHostingMode(layerHostingMode));
1930     }
1931 }
1932
1933 void WebPageProxy::dispatchActivityStateChange()
1934 {
1935 #if PLATFORM(COCOA)
1936     m_activityStateChangeDispatcher->invalidate();
1937 #endif
1938
1939     if (!hasRunningProcess())
1940         return;
1941
1942     LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " dispatchActivityStateChange - potentiallyChangedActivityStateFlags " << m_potentiallyChangedActivityStateFlags);
1943
1944     // If the visibility state may have changed, then so may the visually idle & occluded agnostic state.
1945     if (m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible)
1946         m_potentiallyChangedActivityStateFlags.add({ ActivityState::IsVisibleOrOccluded, ActivityState::IsVisuallyIdle });
1947
1948     // Record the prior view state, update the flags that may have changed,
1949     // and check which flags have actually changed.
1950     auto previousActivityState = m_activityState;
1951     updateActivityState(m_potentiallyChangedActivityStateFlags);
1952     auto changed = m_activityState ^ previousActivityState;
1953
1954     if (changed)
1955         LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " dispatchActivityStateChange: state changed from " << previousActivityState << " to " << m_activityState);
1956
1957     if ((changed & ActivityState::WindowIsActive) && isViewWindowActive())
1958         updateCurrentModifierState();
1959
1960     if ((m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible) && isViewVisible())
1961         viewIsBecomingVisible();
1962
1963     bool isNowInWindow = (changed & ActivityState::IsInWindow) && isInWindow();
1964     // We always want to wait for the Web process to reply if we've been in-window before and are coming back in-window.
1965     if (m_viewWasEverInWindow && isNowInWindow) {
1966         if (m_drawingArea->hasVisibleContent() && m_waitsForPaintAfterViewDidMoveToWindow && !m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow)
1967             m_activityStateChangeWantsSynchronousReply = true;
1968         m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow = false;
1969     }
1970
1971     // Don't wait synchronously if the view state is not visible. (This matters in particular on iOS, where a hidden page may be suspended.)
1972     if (!(m_activityState & ActivityState::IsVisible))
1973         m_activityStateChangeWantsSynchronousReply = false;
1974
1975     auto activityStateChangeID = m_activityStateChangeWantsSynchronousReply ? takeNextActivityStateChangeID() : static_cast<ActivityStateChangeID>(ActivityStateChangeAsynchronous);
1976
1977     if (changed || activityStateChangeID != ActivityStateChangeAsynchronous || !m_nextActivityStateChangeCallbacks.isEmpty())
1978         send(Messages::WebPage::SetActivityState(m_activityState, activityStateChangeID, m_nextActivityStateChangeCallbacks));
1979
1980     m_nextActivityStateChangeCallbacks.clear();
1981
1982     // This must happen after the SetActivityState message is sent, to ensure the page visibility event can fire.
1983     updateThrottleState();
1984
1985 #if ENABLE(POINTER_LOCK)
1986     if (((changed & ActivityState::IsVisible) && !isViewVisible()) || ((changed & ActivityState::WindowIsActive) && !pageClient().isViewWindowActive())
1987         || ((changed & ActivityState::IsFocused) && !(m_activityState & ActivityState::IsFocused)))
1988         requestPointerUnlock();
1989 #endif
1990
1991     if (changed & ActivityState::IsVisible) {
1992         if (isViewVisible())
1993             m_visiblePageToken = m_process->visiblePageToken();
1994         else {
1995             m_visiblePageToken = nullptr;
1996
1997             // If we've started the responsiveness timer as part of telling the web process to update the backing store
1998             // state, it might not send back a reply (since it won't paint anything if the web page is hidden) so we
1999             // stop the unresponsiveness timer here.
2000             m_process->stopResponsivenessTimer();
2001         }
2002     }
2003
2004     if (changed & ActivityState::IsInWindow) {
2005         if (isInWindow())
2006             viewDidEnterWindow();
2007         else
2008             viewDidLeaveWindow();
2009     }
2010
2011     updateBackingStoreDiscardableState();
2012
2013     if (activityStateChangeID != ActivityStateChangeAsynchronous)
2014         waitForDidUpdateActivityState(activityStateChangeID);
2015
2016     m_potentiallyChangedActivityStateFlags = { };
2017     m_activityStateChangeWantsSynchronousReply = false;
2018     m_viewWasEverInWindow |= isNowInWindow;
2019 }
2020
2021 bool WebPageProxy::isAlwaysOnLoggingAllowed() const
2022 {
2023     return sessionID().isAlwaysOnLoggingAllowed();
2024 }
2025
2026 void WebPageProxy::updateThrottleState()
2027 {
2028     bool processSuppressionEnabled = m_preferences->pageVisibilityBasedProcessSuppressionEnabled();
2029
2030     // If process suppression is not enabled take a token on the process pool to disable suppression of support processes.
2031     if (!processSuppressionEnabled)
2032         m_preventProcessSuppressionCount = m_process->processPool().processSuppressionDisabledForPageCount();
2033     else if (!m_preventProcessSuppressionCount)
2034         m_preventProcessSuppressionCount = nullptr;
2035
2036     if (m_activityState & ActivityState::IsVisuallyIdle)
2037         m_pageIsUserObservableCount = nullptr;
2038     else if (!m_pageIsUserObservableCount)
2039         m_pageIsUserObservableCount = m_process->processPool().userObservablePageCount();
2040
2041 #if PLATFORM(IOS_FAMILY)
2042     if (isViewVisible()) {
2043         if (!m_isVisibleActivity || !m_isVisibleActivity->isValid()) {
2044             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because the view is visible");
2045             m_isVisibleActivity = m_process->throttler().foregroundActivity("View is visible"_s).moveToUniquePtr();
2046         }
2047     } else if (m_isVisibleActivity) {
2048         RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because the view is no longer visible");
2049         m_isVisibleActivity = nullptr;
2050     }
2051
2052     bool isAudible = m_activityState.contains(ActivityState::IsAudible);
2053     if (isAudible) {
2054         if (!m_isAudibleActivity || !m_isAudibleActivity->isValid()) {
2055             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because we are playing audio");
2056             m_isAudibleActivity = m_process->throttler().foregroundActivity("View is playing audio"_s).moveToUniquePtr();
2057         }
2058         m_audibleActivityTimer.stop();
2059     } else if (m_isAudibleActivity) {
2060         RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess will release a foreground assertion in %g seconds because we are no longer playing audio", audibleActivityClearDelay.seconds());
2061         if (!m_audibleActivityTimer.isActive())
2062             m_audibleActivityTimer.startOneShot(audibleActivityClearDelay);
2063     }
2064
2065     bool isCapturingMedia = m_activityState.contains(ActivityState::IsCapturingMedia);
2066     if (isCapturingMedia) {
2067         if (!m_isCapturingActivity || !m_isCapturingActivity->isValid()) {
2068             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because media capture is active");
2069             m_isCapturingActivity = m_process->throttler().foregroundActivity("View is capturing media"_s).moveToUniquePtr();
2070         }
2071     } else if (m_isCapturingActivity) {
2072         RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because media capture is no longer active");
2073         m_isCapturingActivity = nullptr;
2074     }
2075
2076     if (m_alwaysRunsAtForegroundPriority) {
2077         if (!m_alwaysRunsAtForegroundPriorityActivity || !m_alwaysRunsAtForegroundPriorityActivity->isValid()) {
2078             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because m_alwaysRunsAtForegroundPriority is true");
2079             m_alwaysRunsAtForegroundPriorityActivity = m_process->throttler().foregroundActivity("View always runs at foreground priority"_s).moveToUniquePtr();
2080         }
2081     } else if (m_alwaysRunsAtForegroundPriorityActivity) {
2082         RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because m_alwaysRunsAtForegroundPriority is no longer true");
2083         m_alwaysRunsAtForegroundPriorityActivity = nullptr;
2084     }
2085 #endif
2086 }
2087
2088 #if PLATFORM(IOS_FAMILY)
2089 void WebPageProxy::clearAudibleActivity()
2090 {
2091     RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because we are no longer playing audio");
2092     m_isAudibleActivity = nullptr;
2093 }
2094 #endif
2095
2096 void WebPageProxy::updateHiddenPageThrottlingAutoIncreases()
2097 {
2098     if (!m_preferences->hiddenPageDOMTimerThrottlingAutoIncreases())
2099         m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = nullptr;
2100     else if (!m_hiddenPageDOMTimerThrottlingAutoIncreasesCount)
2101         m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = m_process->processPool().hiddenPageThrottlingAutoIncreasesCount();
2102 }
2103
2104 void WebPageProxy::layerHostingModeDidChange()
2105 {
2106     LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
2107     if (m_layerHostingMode == layerHostingMode)
2108         return;
2109
2110     m_layerHostingMode = layerHostingMode;
2111
2112     if (hasRunningProcess())
2113         send(Messages::WebPage::SetLayerHostingMode(layerHostingMode));
2114 }
2115
2116 void WebPageProxy::waitForDidUpdateActivityState(ActivityStateChangeID activityStateChangeID)
2117 {
2118     if (!hasRunningProcess())
2119         return;
2120
2121     if (m_process->state() != WebProcessProxy::State::Running)
2122         return;
2123
2124     // If we have previously timed out with no response from the WebProcess, don't block the UIProcess again until it starts responding.
2125     if (m_waitingForDidUpdateActivityState)
2126         return;
2127
2128 #if PLATFORM(IOS_FAMILY)
2129     // Hail Mary check. Should not be possible (dispatchActivityStateChange should force async if not visible,
2130     // and if visible we should be holding an assertion) - but we should never block on a suspended process.
2131     if (!m_isVisibleActivity) {
2132         ASSERT_NOT_REACHED();
2133         return;
2134     }
2135 #endif
2136
2137     m_waitingForDidUpdateActivityState = true;
2138
2139     m_drawingArea->waitForDidUpdateActivityState(activityStateChangeID);
2140 }
2141
2142 IntSize WebPageProxy::viewSize() const
2143 {
2144     return pageClient().viewSize();
2145 }
2146
2147 void WebPageProxy::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& keyboardEvent, WTF::Function<void (CallbackBase::Error)>&& callbackFunction)
2148 {
2149     if (!hasRunningProcess()) {
2150         callbackFunction(CallbackBase::Error::OwnerWasInvalidated);
2151         return;
2152     }
2153
2154     auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivity("WebPageProxy::setInitialFocus"_s));
2155     send(Messages::WebPage::SetInitialFocus(forward, isKeyboardEventValid, keyboardEvent, callbackID));
2156 }
2157
2158 void WebPageProxy::clearSelection()
2159 {
2160     if (!hasRunningProcess())
2161         return;
2162     send(Messages::WebPage::ClearSelection());
2163 }
2164
2165 void WebPageProxy::restoreSelectionInFocusedEditableElement()
2166 {
2167     if (!hasRunningProcess())
2168         return;
2169     send(Messages::WebPage::RestoreSelectionInFocusedEditableElement());
2170 }
2171
2172 void WebPageProxy::validateCommand(const String& commandName, WTF::Function<void (const String&, bool, int32_t, CallbackBase::Error)>&& callbackFunction)
2173 {
2174     if (!hasRunningProcess()) {
2175         callbackFunction(String(), false, 0, CallbackBase::Error::Unknown);
2176         return;
2177     }
2178
2179     auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivity("WebPageProxy::validateCommand"_s));
2180     send(Messages::WebPage::ValidateCommand(commandName, callbackID));
2181 }
2182
2183 void WebPageProxy::increaseListLevel()
2184 {
2185     if (!hasRunningProcess())
2186         return;
2187
2188     send(Messages::WebPage::IncreaseListLevel());
2189 }
2190
2191 void WebPageProxy::decreaseListLevel()
2192 {
2193     if (!hasRunningProcess())
2194         return;
2195
2196     send(Messages::WebPage::DecreaseListLevel());
2197 }
2198
2199 void WebPageProxy::changeListType()
2200 {
2201     if (!hasRunningProcess())
2202         return;
2203
2204     send(Messages::WebPage::ChangeListType());
2205 }
2206
2207 void WebPageProxy::setBaseWritingDirection(WritingDirection direction)
2208 {
2209     if (!hasRunningProcess())
2210         return;
2211
2212     send(Messages::WebPage::SetBaseWritingDirection(direction));
2213 }
2214
2215 void WebPageProxy::updateFontAttributesAfterEditorStateChange()
2216 {
2217     m_cachedFontAttributesAtSelectionStart.reset();
2218
2219     if (m_editorState.isMissingPostLayoutData)
2220         return;
2221
2222     if (auto fontAttributes = m_editorState.postLayoutData().fontAttributes) {
2223         m_uiClient->didChangeFontAttributes(*fontAttributes);
2224         m_cachedFontAttributesAtSelectionStart = WTFMove(fontAttributes);
2225     }
2226 }
2227
2228 void WebPageProxy::setNeedsFontAttributes(bool needsFontAttributes)
2229 {
2230     if (m_needsFontAttributes == needsFontAttributes)
2231         return;
2232
2233     m_needsFontAttributes = needsFontAttributes;
2234
2235     if (hasRunningProcess())
2236         send(Messages::WebPage::SetNeedsFontAttributes(needsFontAttributes));
2237 }
2238
2239 bool WebPageProxy::maintainsInactiveSelection() const
2240 {
2241     // Regardless of what the client wants to do, keep selections if a local Inspector is open.
2242     // Otherwise, there is no way to use the console to inspect the state of a selection.
2243     if (inspector() && inspector()->isVisible())
2244         return true;
2245
2246     return m_maintainsInactiveSelection;
2247 }
2248
2249 void WebPageProxy::setMaintainsInactiveSelection(bool newValue)
2250 {
2251     m_maintainsInactiveSelection = newValue;
2252 }
2253
2254 void WebPageProxy::scheduleFullEditorStateUpdate()
2255 {
2256     if (!hasRunningProcess())
2257         return;
2258
2259     send(Messages::WebPage::ScheduleFullEditorStateUpdate());
2260 }
2261
2262 void WebPageProxy::selectAll()
2263 {
2264     if (!hasRunningProcess())
2265         return;
2266
2267     send(Messages::WebPage::SelectAll());
2268 }
2269
2270 void WebPageProxy::executeEditCommand(const String& commandName, const String& argument, WTF::Function<void(CallbackBase::Error)>&& callbackFunction)
2271 {
2272     if (!hasRunningProcess()) {
2273         callbackFunction(CallbackBase::Error::Unknown);
2274         return;
2275     }
2276
2277     auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivity("WebPageProxy::executeEditCommand"_s));
2278     send(Messages::WebPage::ExecuteEditCommandWithCallback(commandName, argument, callbackID));
2279 }
2280     
2281 void WebPageProxy::executeEditCommand(const String& commandName, const String& argument)
2282 {
2283     static NeverDestroyed<String> ignoreSpellingCommandName(MAKE_STATIC_STRING_IMPL("ignoreSpelling"));
2284
2285     if (!hasRunningProcess())
2286         return;
2287
2288     if (commandName == ignoreSpellingCommandName)
2289         ++m_pendingLearnOrIgnoreWordMessageCount;
2290
2291     send(Messages::WebPage::ExecuteEditCommand(commandName, argument));
2292 }
2293
2294 void WebPageProxy::requestFontAttributesAtSelectionStart(Function<void(const WebCore::FontAttributes&, CallbackBase::Error)>&& callback)
2295 {
2296     if (!hasRunningProcess()) {
2297         callback({ }, CallbackBase::Error::Unknown);
2298         return;
2299     }
2300
2301     auto callbackID = m_callbacks.put(WTFMove(callback), m_process->throttler().backgroundActivity("WebPageProxy::requestFontAttributesAtSelectionStart"_s));
2302     send(Messages::WebPage::RequestFontAttributesAtSelectionStart(callbackID));
2303 }
2304
2305 void WebPageProxy::fontAttributesCallback(const WebCore::FontAttributes& attributes, CallbackID callbackID)
2306 {
2307     m_cachedFontAttributesAtSelectionStart = attributes;
2308
2309     if (auto callback = m_callbacks.take<FontAttributesCallback>(callbackID))
2310         callback->performCallbackWithReturnValue(attributes);
2311 }
2312
2313 void WebPageProxy::setEditable(bool editable)
2314 {
2315     if (editable == m_isEditable)
2316         return;
2317
2318     m_isEditable = editable;
2319
2320     if (!hasRunningProcess())
2321         return;
2322
2323     send(Messages::WebPage::SetEditable(editable));
2324 }
2325     
2326 void WebPageProxy::setMediaStreamCaptureMuted(bool muted)
2327 {
2328     if (muted)
2329         setMuted(m_mutedState | WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2330     else
2331         setMuted(m_mutedState & ~WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2332 }
2333
2334 void WebPageProxy::activateMediaStreamCaptureInPage()
2335 {
2336 #if ENABLE(MEDIA_STREAM)
2337     UserMediaProcessManager::singleton().muteCaptureMediaStreamsExceptIn(*this);
2338 #endif
2339     setMuted(m_mutedState & ~WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2340 }
2341
2342 #if !PLATFORM(IOS_FAMILY)
2343 void WebPageProxy::didCommitLayerTree(const RemoteLayerTreeTransaction&)
2344 {
2345 }
2346
2347 void WebPageProxy::layerTreeCommitComplete()
2348 {
2349 }
2350 #endif
2351
2352 #if ENABLE(DRAG_SUPPORT)
2353 void WebPageProxy::dragEntered(DragData& dragData, const String& dragStorageName)
2354 {
2355     launchInitialProcessIfNecessary();
2356     performDragControllerAction(DragControllerAction::Entered, dragData, dragStorageName, { }, { });
2357 }
2358
2359 void WebPageProxy::dragUpdated(DragData& dragData, const String& dragStorageName)
2360 {
2361     performDragControllerAction(DragControllerAction::Updated, dragData, dragStorageName, { }, { });
2362 }
2363
2364 void WebPageProxy::dragExited(DragData& dragData, const String& dragStorageName)
2365 {
2366     performDragControllerAction(DragControllerAction::Exited, dragData, dragStorageName, { }, { });
2367 }
2368
2369 void WebPageProxy::performDragOperation(DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsForUpload)
2370 {
2371     performDragControllerAction(DragControllerAction::PerformDragOperation, dragData, dragStorageName, WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionsForUpload));
2372 }
2373
2374 void WebPageProxy::performDragControllerAction(DragControllerAction action, DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsForUpload)
2375 {
2376     if (!hasRunningProcess())
2377         return;
2378 #if PLATFORM(GTK)
2379     UNUSED_PARAM(dragStorageName);
2380     UNUSED_PARAM(sandboxExtensionHandle);
2381     UNUSED_PARAM(sandboxExtensionsForUpload);
2382
2383     String url = dragData.asURL();
2384     if (!url.isEmpty())
2385         m_process->assumeReadAccessToBaseURL(*this, url);
2386
2387     ASSERT(dragData.platformData());
2388     WebSelectionData selection(*dragData.platformData());
2389     send(Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), selection, dragData.flags()));
2390 #else
2391     send(Messages::WebPage::PerformDragControllerAction(action, dragData, sandboxExtensionHandle, sandboxExtensionsForUpload));
2392 #endif
2393 }
2394
2395 void WebPageProxy::didPerformDragControllerAction(uint64_t dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect, const IntRect& editableElementRect)
2396 {
2397     MESSAGE_CHECK(m_process, dragOperation <= DragOperationDelete);
2398
2399     m_currentDragOperation = static_cast<DragOperation>(dragOperation);
2400     m_currentDragHandlingMethod = dragHandlingMethod;
2401     m_currentDragIsOverFileInput = mouseIsOverFileInput;
2402     m_currentDragNumberOfFilesToBeAccepted = numberOfItemsToBeAccepted;
2403     m_currentDragCaretEditableElementRect = editableElementRect;
2404     setDragCaretRect(insertionRect);
2405 }
2406
2407 #if PLATFORM(GTK)
2408 void WebPageProxy::startDrag(WebSelectionData&& selection, uint64_t dragOperation, const ShareableBitmap::Handle& dragImageHandle)
2409 {
2410     RefPtr<ShareableBitmap> dragImage = !dragImageHandle.isNull() ? ShareableBitmap::create(dragImageHandle) : nullptr;
2411     pageClient().startDrag(WTFMove(selection.selectionData), static_cast<WebCore::DragOperation>(dragOperation), WTFMove(dragImage));
2412
2413     didStartDrag();
2414 }
2415 #endif
2416
2417 void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t operation)
2418 {
2419     if (!hasRunningProcess())
2420         return;
2421     send(Messages::WebPage::DragEnded(clientPosition, globalPosition, operation));
2422     setDragCaretRect({ });
2423 }
2424
2425 void WebPageProxy::didPerformDragOperation(bool handled)
2426 {
2427     pageClient().didPerformDragOperation(handled);
2428 }
2429
2430 void WebPageProxy::didStartDrag()
2431 {
2432     if (hasRunningProcess())
2433         send(Messages::WebPage::DidStartDrag());
2434 }
2435     
2436 void WebPageProxy::dragCancelled()
2437 {
2438     if (hasRunningProcess())
2439         send(Messages::WebPage::DragCancelled());
2440 }
2441
2442 void WebPageProxy::didEndDragging()
2443 {
2444     resetCurrentDragInformation();
2445 }
2446
2447 void WebPageProxy::resetCurrentDragInformation()
2448 {
2449     m_currentDragOperation = WebCore::DragOperationNone;
2450     m_currentDragHandlingMethod = DragHandlingMethod::None;
2451     m_currentDragIsOverFileInput = false;
2452     m_currentDragNumberOfFilesToBeAccepted = 0;
2453     setDragCaretRect({ });
2454 }
2455
2456 #if !ENABLE(DATA_INTERACTION)
2457
2458 void WebPageProxy::setDragCaretRect(const IntRect& dragCaretRect)
2459 {
2460     m_currentDragCaretRect = dragCaretRect;
2461 }
2462
2463 #endif
2464
2465 #endif // ENABLE(DRAG_SUPPORT)
2466
2467 static bool removeOldRedundantEvent(Deque<NativeWebMouseEvent>& queue, WebEvent::Type incomingEventType)
2468 {
2469     if (incomingEventType != WebEvent::MouseMove && incomingEventType != WebEvent::MouseForceChanged)
2470         return false;
2471
2472     auto it = queue.rbegin();
2473     auto end = queue.rend();
2474
2475     // Must not remove the first event in the deque, since it is already being dispatched.
2476     if (it != end)
2477         --end;
2478
2479     for (; it != end; ++it) {
2480         auto type = it->type();
2481         if (type == incomingEventType) {
2482             queue.remove(--it.base());
2483             return true;
2484         }
2485         if (type != WebEvent::MouseMove && type != WebEvent::MouseForceChanged)
2486             break;
2487     }
2488     return false;
2489 }
2490
2491 void WebPageProxy::handleMouseEvent(const NativeWebMouseEvent& event)
2492 {
2493     if (!hasRunningProcess())
2494         return;
2495
2496 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2497     if (m_scrollingCoordinatorProxy)
2498         m_scrollingCoordinatorProxy->handleMouseEvent(platform(event));
2499 #endif
2500
2501     // If we receive multiple mousemove or mouseforcechanged events and the most recent mousemove or mouseforcechanged event
2502     // (respectively) has not yet been sent to WebProcess for processing, remove the pending mouse event and insert the new
2503     // event in the queue.
2504     bool didRemoveEvent = removeOldRedundantEvent(m_mouseEventQueue, event.type());
2505     m_mouseEventQueue.append(event);
2506
2507 #if LOG_DISABLED
2508     UNUSED_PARAM(didRemoveEvent);
2509 #else
2510     LOG(MouseHandling, "UIProcess: %s mouse event %s (queue size %zu)", didRemoveEvent ? "replaced" : "enqueued", webMouseEventTypeString(event.type()), m_mouseEventQueue.size());
2511 #endif
2512
2513     if (m_mouseEventQueue.size() == 1) // Otherwise, called from DidReceiveEvent message handler.
2514         processNextQueuedMouseEvent();
2515 }
2516     
2517 void WebPageProxy::processNextQueuedMouseEvent()
2518 {
2519     if (!hasRunningProcess())
2520         return;
2521
2522     ASSERT(!m_mouseEventQueue.isEmpty());
2523
2524     const NativeWebMouseEvent& event = m_mouseEventQueue.first();
2525
2526     if (pageClient().windowIsFrontWindowUnderMouse(event))
2527         setToolTip(String());
2528
2529     WebEvent::Type eventType = event.type();
2530     if (eventType == WebEvent::MouseDown || eventType == WebEvent::MouseForceChanged || eventType == WebEvent::MouseForceDown)
2531         m_process->startResponsivenessTimer(WebProcessProxy::UseLazyStop::Yes);
2532     else if (eventType != WebEvent::MouseMove) {
2533         // NOTE: This does not start the responsiveness timer because mouse move should not indicate interaction.
2534         m_process->startResponsivenessTimer();
2535     }
2536
2537     LOG(MouseHandling, "UIProcess: sent mouse event %s (queue size %zu)", webMouseEventTypeString(eventType), m_mouseEventQueue.size());
2538     send(Messages::WebPage::MouseEvent(event));
2539 }
2540
2541 void WebPageProxy::doAfterProcessingAllPendingMouseEvents(WTF::Function<void ()>&& action)
2542 {
2543     if (!isProcessingMouseEvents()) {
2544         action();
2545         return;
2546     }
2547
2548     m_callbackHandlersAfterProcessingPendingMouseEvents.append(WTFMove(action));
2549 }
2550
2551 void WebPageProxy::didFinishProcessingAllPendingMouseEvents()
2552 {
2553     flushPendingMouseEventCallbacks();
2554 }
2555
2556 void WebPageProxy::flushPendingMouseEventCallbacks()
2557 {
2558     for (auto& callback : m_callbackHandlersAfterProcessingPendingMouseEvents)
2559         callback();
2560
2561     m_callbackHandlersAfterProcessingPendingMouseEvents.clear();
2562 }
2563
2564 #if MERGE_WHEEL_EVENTS
2565 static bool canCoalesce(const WebWheelEvent& a, const WebWheelEvent& b)
2566 {
2567     if (a.position() != b.position())
2568         return false;
2569     if (a.globalPosition() != b.globalPosition())
2570         return false;
2571     if (a.modifiers() != b.modifiers())
2572         return false;
2573     if (a.granularity() != b.granularity())
2574         return false;
2575 #if PLATFORM(COCOA)
2576     if (a.phase() != b.phase())
2577         return false;
2578     if (a.momentumPhase() != b.momentumPhase())
2579         return false;
2580     if (a.hasPreciseScrollingDeltas() != b.hasPreciseScrollingDeltas())
2581         return false;
2582 #endif
2583
2584     return true;
2585 }
2586
2587 static WebWheelEvent coalesce(const WebWheelEvent& a, const WebWheelEvent& b)
2588 {
2589     ASSERT(canCoalesce(a, b));
2590
2591     FloatSize mergedDelta = a.delta() + b.delta();
2592     FloatSize mergedWheelTicks = a.wheelTicks() + b.wheelTicks();
2593
2594 #if PLATFORM(COCOA)
2595     FloatSize mergedUnacceleratedScrollingDelta = a.unacceleratedScrollingDelta() + b.unacceleratedScrollingDelta();
2596
2597     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());
2598 #else
2599     return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.modifiers(), b.timestamp());
2600 #endif
2601 }
2602 #endif // MERGE_WHEEL_EVENTS
2603
2604 static WebWheelEvent coalescedWheelEvent(Deque<NativeWebWheelEvent>& queue, Vector<NativeWebWheelEvent>& coalescedEvents)
2605 {
2606     ASSERT(!queue.isEmpty());
2607     ASSERT(coalescedEvents.isEmpty());
2608
2609 #if MERGE_WHEEL_EVENTS
2610     NativeWebWheelEvent firstEvent = queue.takeFirst();
2611     coalescedEvents.append(firstEvent);
2612
2613     WebWheelEvent event = firstEvent;
2614     while (!queue.isEmpty() && canCoalesce(event, queue.first())) {
2615         NativeWebWheelEvent firstEvent = queue.takeFirst();
2616         coalescedEvents.append(firstEvent);
2617         event = coalesce(event, firstEvent);
2618     }
2619
2620     return event;
2621 #else
2622     while (!queue.isEmpty())
2623         coalescedEvents.append(queue.takeFirst());
2624     return coalescedEvents.last();
2625 #endif
2626 }
2627
2628 void WebPageProxy::handleWheelEvent(const NativeWebWheelEvent& event)
2629 {
2630 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2631     if (m_scrollingCoordinatorProxy && m_scrollingCoordinatorProxy->handleWheelEvent(platform(event)))
2632         return;
2633 #endif
2634
2635     if (!hasRunningProcess())
2636         return;
2637
2638     closeOverlayedViews();
2639
2640     if (!m_currentlyProcessedWheelEvents.isEmpty()) {
2641         m_wheelEventQueue.append(event);
2642         if (!shouldProcessWheelEventNow(event))
2643             return;
2644         // The queue has too many wheel events, so push a new event.
2645     }
2646
2647     if (!m_wheelEventQueue.isEmpty()) {
2648         processNextQueuedWheelEvent();
2649         return;
2650     }
2651
2652     auto coalescedWheelEvent = makeUnique<Vector<NativeWebWheelEvent>>();
2653     coalescedWheelEvent->append(event);
2654     m_currentlyProcessedWheelEvents.append(WTFMove(coalescedWheelEvent));
2655     sendWheelEvent(event);
2656 }
2657
2658 void WebPageProxy::processNextQueuedWheelEvent()
2659 {
2660     auto nextCoalescedEvent = makeUnique<Vector<NativeWebWheelEvent>>();
2661     WebWheelEvent nextWheelEvent = coalescedWheelEvent(m_wheelEventQueue, *nextCoalescedEvent.get());
2662     m_currentlyProcessedWheelEvents.append(WTFMove(nextCoalescedEvent));
2663     sendWheelEvent(nextWheelEvent);
2664 }
2665
2666 void WebPageProxy::sendWheelEvent(const WebWheelEvent& event)
2667 {
2668     send(
2669         Messages::EventDispatcher::WheelEvent(
2670             m_webPageID,
2671             event,
2672             shouldUseImplicitRubberBandControl() ? !m_backForwardList->backItem() : rubberBandsAtLeft(),
2673             shouldUseImplicitRubberBandControl() ? !m_backForwardList->forwardItem() : rubberBandsAtRight(),
2674             rubberBandsAtTop(),
2675             rubberBandsAtBottom()
2676         ), 0);
2677
2678     // Manually ping the web process to check for responsiveness since our wheel
2679     // event will dispatch to a non-main thread, which always responds.
2680     m_process->isResponsiveWithLazyStop();
2681 }
2682
2683 bool WebPageProxy::shouldProcessWheelEventNow(const WebWheelEvent& event) const
2684 {
2685 #if PLATFORM(GTK)
2686     // Don't queue events representing a non-trivial scrolling phase to
2687     // avoid having them trapped in the queue, potentially preventing a
2688     // scrolling session to beginning or end correctly.
2689     // This is only needed by platforms whose WebWheelEvent has this phase
2690     // information (Cocoa and GTK+) but Cocoa was fine without it.
2691     if (event.phase() == WebWheelEvent::Phase::PhaseNone
2692         || event.phase() == WebWheelEvent::Phase::PhaseChanged
2693         || event.momentumPhase() == WebWheelEvent::Phase::PhaseNone
2694         || event.momentumPhase() == WebWheelEvent::Phase::PhaseChanged)
2695         return true;
2696 #else
2697     UNUSED_PARAM(event);
2698 #endif
2699     if (m_wheelEventQueue.size() >= wheelEventQueueSizeThreshold)
2700         return true;
2701     return false;
2702 }
2703
2704 bool WebPageProxy::hasQueuedKeyEvent() const
2705 {
2706     return !m_keyEventQueue.isEmpty();
2707 }
2708
2709 const NativeWebKeyboardEvent& WebPageProxy::firstQueuedKeyEvent() const
2710 {
2711     return m_keyEventQueue.first();
2712 }
2713
2714 void WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event)
2715 {
2716     if (!hasRunningProcess())
2717         return;
2718     
2719     LOG(KeyHandling, "WebPageProxy::handleKeyboardEvent: %s", webKeyboardEventTypeString(event.type()));
2720
2721     m_keyEventQueue.append(event);
2722
2723     m_process->startResponsivenessTimer(event.type() == WebEvent::KeyDown ? WebProcessProxy::UseLazyStop::Yes : WebProcessProxy::UseLazyStop::No);
2724
2725     if (m_keyEventQueue.size() == 1) { // Otherwise, sent from DidReceiveEvent message handler.
2726         LOG(KeyHandling, " UI process: sent keyEvent from handleKeyboardEvent");
2727         send(Messages::WebPage::KeyEvent(event));
2728     }
2729 }
2730
2731 WebPreferencesStore WebPageProxy::preferencesStore() const
2732 {
2733     if (m_configurationPreferenceValues.isEmpty())
2734         return m_preferences->store();
2735
2736     WebPreferencesStore store = m_preferences->store();
2737     for (const auto& preference : m_configurationPreferenceValues)
2738         store.m_values.set(preference.key, preference.value);
2739
2740     return store;
2741 }
2742
2743 #if ENABLE(NETSCAPE_PLUGIN_API)
2744 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)
2745 {
2746     PageClientProtector protector(pageClient());
2747
2748     MESSAGE_CHECK_URL(m_process, urlString);
2749
2750     URL pluginURL = URL { URL(), urlString };
2751     String newMimeType = mimeType.convertToASCIILowercase();
2752
2753     PluginData::AllowedPluginTypes allowedPluginTypes = allowOnlyApplicationPlugins ? PluginData::OnlyApplicationPlugins : PluginData::AllPlugins;
2754
2755     URL pageURL = URL { URL(), pageURLString };
2756     if (!m_process->processPool().pluginInfoStore().isSupportedPlugin(mimeType, pluginURL, frameURLString, pageURL)) {
2757         reply(0, newMimeType, PluginModuleLoadNormally, { }, true);
2758         return;
2759     }
2760
2761     PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, pluginURL, allowedPluginTypes);
2762     if (!plugin.path) {
2763         reply(0, newMimeType, PluginModuleLoadNormally, { }, false);
2764         return;
2765     }
2766
2767     uint32_t pluginLoadPolicy = PluginInfoStore::defaultLoadPolicyForPlugin(plugin);
2768
2769 #if PLATFORM(COCOA)
2770     auto pluginInformation = createPluginInformationDictionary(plugin, frameURLString, String(), pageURLString, String(), String());
2771 #endif
2772
2773     auto findPluginCompletion = [processType, reply = WTFMove(reply), newMimeType = WTFMove(newMimeType), plugin = WTFMove(plugin)] (uint32_t pluginLoadPolicy, const String& unavailabilityDescription) mutable {
2774         PluginProcessSandboxPolicy pluginProcessSandboxPolicy = PluginProcessSandboxPolicyNormal;
2775         switch (pluginLoadPolicy) {
2776         case PluginModuleLoadNormally:
2777             pluginProcessSandboxPolicy = PluginProcessSandboxPolicyNormal;
2778             break;
2779         case PluginModuleLoadUnsandboxed:
2780             pluginProcessSandboxPolicy = PluginProcessSandboxPolicyUnsandboxed;
2781             break;
2782
2783         case PluginModuleBlockedForSecurity:
2784         case PluginModuleBlockedForCompatibility:
2785             reply(0, newMimeType, pluginLoadPolicy, unavailabilityDescription, false);
2786             return;
2787         }
2788
2789         reply(PluginProcessManager::singleton().pluginProcessToken(plugin, static_cast<PluginProcessType>(processType), pluginProcessSandboxPolicy), newMimeType, pluginLoadPolicy, unavailabilityDescription, false);
2790     };
2791
2792 #if PLATFORM(COCOA)
2793     m_navigationClient->decidePolicyForPluginLoad(*this, static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy), pluginInformation.get(), WTFMove(findPluginCompletion));
2794 #else
2795     findPluginCompletion(pluginLoadPolicy, { });
2796 #endif
2797 }
2798
2799 #endif // ENABLE(NETSCAPE_PLUGIN_API)
2800
2801 #if ENABLE(TOUCH_EVENTS)
2802
2803 static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b)
2804 {
2805     if (static_cast<uintptr_t>(b) > static_cast<uintptr_t>(a))
2806         return b;
2807     return a;
2808 }
2809
2810 void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent)
2811 {
2812 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2813     const EventNames& names = eventNames();
2814     for (auto& touchPoint : touchStartEvent.touchPoints()) {
2815         IntPoint location = touchPoint.location();
2816         auto updateTrackingType = [this, location](TrackingType& trackingType, const AtomString& eventName) {
2817             if (trackingType == TrackingType::Synchronous)
2818                 return;
2819
2820             TrackingType trackingTypeForLocation = m_scrollingCoordinatorProxy->eventTrackingTypeForPoint(eventName, location);
2821
2822             trackingType = mergeTrackingTypes(trackingType, trackingTypeForLocation);
2823         };
2824         updateTrackingType(m_touchAndPointerEventTracking.touchForceChangedTracking, names.touchforcechangeEvent);
2825         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.touchstartEvent);
2826         updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.touchmoveEvent);
2827         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.touchendEvent);
2828         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointeroverEvent);
2829         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointerenterEvent);
2830         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointerdownEvent);
2831         updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.pointermoveEvent);
2832         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointerupEvent);
2833         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointeroutEvent);
2834         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointerleaveEvent);
2835         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.mousedownEvent);
2836         updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.mousemoveEvent);
2837         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.mouseupEvent);
2838     }
2839 #else
2840     UNUSED_PARAM(touchStartEvent);
2841     m_touchAndPointerEventTracking.touchForceChangedTracking = TrackingType::Synchronous;
2842     m_touchAndPointerEventTracking.touchStartTracking = TrackingType::Synchronous;
2843     m_touchAndPointerEventTracking.touchMoveTracking = TrackingType::Synchronous;
2844     m_touchAndPointerEventTracking.touchEndTracking = TrackingType::Synchronous;
2845 #endif // ENABLE(ASYNC_SCROLLING)
2846 }
2847
2848 TrackingType WebPageProxy::touchEventTrackingType(const WebTouchEvent& touchStartEvent) const
2849 {
2850     // We send all events if any type is needed, we just do it asynchronously for the types that are not tracked.
2851     //
2852     // Touch events define a sequence with strong dependencies. For example, we can expect
2853     // a TouchMove to only appear after a TouchStart, and the ids of the touch points is consistent between
2854     // the two.
2855     //
2856     // WebCore should not have to set up its state correctly after some events were dismissed.
2857     // For example, we don't want to send a TouchMoved without a TouchPressed.
2858     // We send everything, WebCore updates its internal state and dispatch what is needed to the page.
2859     TrackingType globalTrackingType = m_touchAndPointerEventTracking.isTrackingAnything() ? TrackingType::Asynchronous : TrackingType::NotTracking;
2860
2861     globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchForceChangedTracking);
2862     for (auto& touchPoint : touchStartEvent.touchPoints()) {
2863         switch (touchPoint.state()) {
2864         case WebPlatformTouchPoint::TouchReleased:
2865             globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchEndTracking);
2866             break;
2867         case WebPlatformTouchPoint::TouchPressed:
2868             globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchStartTracking);
2869             break;
2870         case WebPlatformTouchPoint::TouchMoved:
2871         case WebPlatformTouchPoint::TouchStationary:
2872             globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchMoveTracking);
2873             break;
2874         case WebPlatformTouchPoint::TouchCancelled:
2875             globalTrackingType = mergeTrackingTypes(globalTrackingType, TrackingType::Asynchronous);
2876             break;
2877         }
2878     }
2879
2880     return globalTrackingType;
2881 }
2882
2883 #endif
2884
2885 #if ENABLE(MAC_GESTURE_EVENTS)
2886 void WebPageProxy::handleGestureEvent(const NativeWebGestureEvent& event)
2887 {
2888     if (!hasRunningProcess())
2889         return;
2890
2891     m_gestureEventQueue.append(event);
2892     // FIXME: Consider doing some coalescing here.
2893
2894     m_process->startResponsivenessTimer((event.type() == WebEvent::GestureStart || event.type() == WebEvent::GestureChange) ? WebProcessProxy::UseLazyStop::Yes : WebProcessProxy::UseLazyStop::No);
2895
2896     send(Messages::EventDispatcher::GestureEvent(m_webPageID, event), 0);
2897 }
2898 #endif
2899
2900 #if ENABLE(IOS_TOUCH_EVENTS)
2901 void WebPageProxy::handlePreventableTouchEvent(NativeWebTouchEvent& event)
2902 {
2903     if (!hasRunningProcess())
2904         return;
2905
2906     TraceScope scope(SyncTouchEventStart, SyncTouchEventEnd);
2907
2908     updateTouchEventTracking(event);
2909
2910     auto handleAllTouchPointsReleased = WTF::makeScopeExit([&] {
2911         if (!event.allTouchPointsAreReleased())
2912             return;
2913
2914         m_touchAndPointerEventTracking.reset();
2915         didReleaseAllTouchPoints();
2916     });
2917
2918     TrackingType touchEventsTrackingType = touchEventTrackingType(event);
2919     if (touchEventsTrackingType == TrackingType::NotTracking) {
2920         if (!isHandlingPreventableTouchStart())
2921             pageClient().doneDeferringNativeGestures(false);
2922         return;
2923     }
2924
2925     if (touchEventsTrackingType == TrackingType::Asynchronous) {
2926         // We can end up here if a native gesture has not started but the event handlers are passive.
2927         //
2928         // The client of WebPageProxy asks the event to be sent synchronously since the touch event
2929         // can prevent a native gesture.
2930         // But, here we know that all events handlers that can handle this events are passive.
2931         // We can use asynchronous dispatch and pretend to the client that the page does nothing with the events.
2932         event.setCanPreventNativeGestures(false);
2933         handleUnpreventableTouchEvent(event);
2934         didReceiveEvent(event.type(), false);
2935         if (!isHandlingPreventableTouchStart())
2936             pageClient().doneDeferringNativeGestures(false);
2937         return;
2938     }
2939
2940     if (event.type() == WebEvent::TouchStart) {
2941         ++m_handlingPreventableTouchStartCount;
2942         Function<void(bool, CallbackBase::Error)> completionHandler = [this, protectedThis = makeRef(*this), event](bool handled, CallbackBase::Error error) {
2943             ASSERT(m_handlingPreventableTouchStartCount);
2944             if (m_handlingPreventableTouchStartCount)
2945                 --m_handlingPreventableTouchStartCount;
2946
2947             bool handledOrFailedWithError = handled || error != CallbackBase::Error::None || m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart;
2948             if (!isHandlingPreventableTouchStart())
2949                 m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart = false;
2950
2951             if (error == CallbackBase::Error::ProcessExited)
2952                 return;
2953
2954             didReceiveEvent(event.type(), handledOrFailedWithError);
2955             pageClient().doneWithTouchEvent(event, handledOrFailedWithError);
2956             if (!isHandlingPreventableTouchStart())
2957                 pageClient().doneDeferringNativeGestures(handledOrFailedWithError);
2958         };
2959
2960         auto callbackID = m_callbacks.put(WTFMove(completionHandler), m_process->throttler().backgroundActivity("WebPageProxy::handlePreventableTouchEvent"_s));
2961         send(Messages::EventDispatcher::TouchEvent(m_webPageID, event, callbackID), 0);
2962         return;
2963     }
2964
2965     m_process->startResponsivenessTimer();
2966     bool handled = false;
2967     bool replyReceived = sendSync(Messages::WebPage::TouchEventSync(event), Messages::WebPage::TouchEventSync::Reply(handled), 1_s, IPC::SendSyncOption::ForceDispatchWhenDestinationIsWaitingForUnboundedSyncReply);
2968     // 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.
2969     if (!replyReceived)
2970         handled = true;
2971     didReceiveEvent(event.type(), handled);
2972     pageClient().doneWithTouchEvent(event, handled);
2973     if (!isHandlingPreventableTouchStart())
2974         pageClient().doneDeferringNativeGestures(handled);
2975     else if (handled)
2976         m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart = true;
2977     m_process->stopResponsivenessTimer();
2978 }
2979
2980 void WebPageProxy::resetPotentialTapSecurityOrigin()
2981 {
2982     if (!hasRunningProcess())
2983         return;
2984
2985     send(Messages::WebPage::ResetPotentialTapSecurityOrigin());
2986 }
2987
2988 void WebPageProxy::handleUnpreventableTouchEvent(const NativeWebTouchEvent& event)
2989 {
2990     if (!hasRunningProcess())
2991         return;
2992
2993     TrackingType touchEventsTrackingType = touchEventTrackingType(event);
2994     if (touchEventsTrackingType == TrackingType::NotTracking)
2995         return;
2996
2997     send(Messages::EventDispatcher::TouchEvent(m_webPageID, event, WTF::nullopt), 0);
2998
2999     if (event.allTouchPointsAreReleased()) {
3000         m_touchAndPointerEventTracking.reset();
3001         didReleaseAllTouchPoints();
3002     }
3003 }
3004
3005 #elif ENABLE(TOUCH_EVENTS)
3006 void WebPageProxy::handleTouchEvent(const NativeWebTouchEvent& event)
3007 {
3008     if (!hasRunningProcess())
3009         return;
3010
3011     updateTouchEventTracking(event);
3012
3013     if (touchEventTrackingType(event) == TrackingType::NotTracking)
3014         return;
3015
3016     // If the page is suspended, which should be the case during panning, pinching
3017     // and animation on the page itself (kinetic scrolling, tap to zoom) etc, then
3018     // we do not send any of the events to the page even if is has listeners.
3019     if (!m_isPageSuspended) {
3020         m_touchEventQueue.append(event);
3021         m_process->startResponsivenessTimer();
3022         send(Messages::WebPage::TouchEvent(event));
3023     } else {
3024         if (m_touchEventQueue.isEmpty()) {
3025             bool isEventHandled = false;
3026             pageClient().doneWithTouchEvent(event, isEventHandled);
3027         } else {
3028             // We attach the incoming events to the newest queued event so that all
3029             // the events are delivered in the correct order when the event is dequed.
3030             QueuedTouchEvents& lastEvent = m_touchEventQueue.last();
3031             lastEvent.deferredTouchEvents.append(event);
3032         }
3033     }
3034
3035     if (event.allTouchPointsAreReleased()) {
3036         m_touchAndPointerEventTracking.reset();
3037         didReleaseAllTouchPoints();
3038     }
3039 }
3040 #endif // ENABLE(TOUCH_EVENTS)
3041
3042 #if ENABLE(POINTER_EVENTS)
3043 void WebPageProxy::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint)
3044 {
3045     send(Messages::WebPage::CancelPointer(pointerId, documentPoint));
3046 }
3047
3048 void WebPageProxy::touchWithIdentifierWasRemoved(WebCore::PointerID pointerId)
3049 {
3050     send(Messages::WebPage::TouchWithIdentifierWasRemoved(pointerId));
3051 }
3052 #endif
3053
3054 void WebPageProxy::scrollBy(ScrollDirection direction, ScrollGranularity granularity)
3055 {
3056     if (!hasRunningProcess())
3057         return;
3058
3059     send(Messages::WebPage::ScrollBy(direction, granularity));
3060 }
3061
3062 void WebPageProxy::centerSelectionInVisibleArea()
3063 {
3064     if (!hasRunningProcess())
3065         return;
3066
3067     send(Messages::WebPage::CenterSelectionInVisibleArea());
3068 }
3069
3070 class WebPageProxy::PolicyDecisionSender : public RefCounted<PolicyDecisionSender> {
3071 public:
3072     using SendFunction = CompletionHandler<void(PolicyDecision&&)>;
3073
3074     static Ref<PolicyDecisionSender> create(PolicyCheckIdentifier identifier, SendFunction&& sendFunction)
3075     {
3076         return adoptRef(*new PolicyDecisionSender(identifier, WTFMove(sendFunction)));
3077     }
3078
3079     void send(PolicyDecision&& policyDecision)
3080     {
3081         if (m_sendFunction)
3082             m_sendFunction(WTFMove(policyDecision));
3083     }
3084
3085     PolicyCheckIdentifier identifier() { return m_identifier; }
3086     
3087 private:
3088     PolicyDecisionSender(PolicyCheckIdentifier identifier, SendFunction sendFunction)
3089         : m_sendFunction(WTFMove(sendFunction))
3090         , m_identifier(identifier)
3091         { }
3092
3093     SendFunction m_sendFunction;
3094     PolicyCheckIdentifier m_identifier;
3095 };
3096
3097
3098 bool WebPageProxy::isAppBoundDomain(const WebCore::RegistrableDomain& domain) const
3099 {
3100     WEB_PAGE_PROXY_ADDITIONS
3101     return true;
3102 }
3103
3104 bool WebPageProxy::isAppBoundDomain(const URL& url) const
3105 {
3106     return isAppBoundDomain(RegistrableDomain(url));
3107 }
3108
3109 void WebPageProxy::setIsNavigatingToAppBoundDomain(bool isMainFrame, const URL& requestURL)
3110 {
3111     if (m_preferences->isInAppBrowserPrivacyEnabled() && isMainFrame) {
3112         if (!isAppBoundDomain(requestURL)) {
3113             m_configuration->setWebViewCategory(WebViewCategory::InAppBrowser);
3114             m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::No;
3115             m_hasNavigatedAwayFromAppBoundDomain = NavigatedAwayFromAppBoundDomain::Yes;
3116             return;
3117         }
3118         m_configuration->setWebViewCategory(WebViewCategory::AppBoundDomain);
3119         m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::Yes;
3120     }
3121 }
3122
3123 void WebPageProxy::setIsNavigatingToAppBoundDomainTesting(bool isNavigatingToAppBoundDomain, CompletionHandler<void()>&& completionHandler)
3124 {
3125     sendWithAsyncReply(Messages::WebPage::SetIsNavigatingToAppBoundDomainTesting(isNavigatingToAppBoundDomain), WTFMove(completionHandler));
3126 }
3127
3128 void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, API::Navigation* navigation, ProcessSwapRequestedByClient processSwapRequestedByClient, WebFrameProxy& frame, API::WebsitePolicies* policies, Ref<PolicyDecisionSender>&& sender)
3129 {
3130     Ref<WebsiteDataStore> websiteDataStore = m_websiteDataStore.copyRef();
3131     Optional<WebsitePoliciesData> data;
3132     if (policies) {
3133         data = policies->data();
3134         if (policies->websiteDataStore() && policies->websiteDataStore() != websiteDataStore.ptr()) {
3135             websiteDataStore = *policies->websiteDataStore();
3136             processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
3137         }
3138     }
3139
3140     if (navigation && !navigation->userContentExtensionsEnabled()) {
3141         if (!data)
3142             data = WebsitePoliciesData { };
3143         data->contentBlockersEnabled = false;
3144     }
3145
3146 #if ENABLE(DEVICE_ORIENTATION)
3147     if (navigation && (!data || data->deviceOrientationAndMotionAccessState == WebCore::DeviceOrientationOrMotionPermissionState::Prompt)) {
3148         auto deviceOrientationPermission = websiteDataStore->deviceOrientationAndMotionAccessController().cachedDeviceOrientationPermission(SecurityOriginData::fromURL(navigation->currentRequest().url()));
3149         if (deviceOrientationPermission != WebCore::DeviceOrientationOrMotionPermissionState::Prompt) {
3150             if (!data)
3151                 data = WebsitePoliciesData { };
3152             data->deviceOrientationAndMotionAccessState = deviceOrientationPermission;
3153         }
3154     }
3155 #endif
3156
3157 #if PLATFORM(COCOA)
3158     static const bool forceDownloadFromDownloadAttribute = false;
3159 #else
3160     static const bool forceDownloadFromDownloadAttribute = true;
3161 #endif
3162     if (policyAction == PolicyAction::Use && navigation && (navigation->isSystemPreview() || (forceDownloadFromDownloadAttribute && navigation->shouldPerformDownload())))
3163         policyAction = PolicyAction::Download;
3164
3165     if (policyAction != PolicyAction::Use || !frame.isMainFrame() || !navigation) {
3166         receivedPolicyDecision(policyAction, navigation, WTFMove(data), WTFMove(sender));
3167         return;
3168     }
3169
3170     Ref<WebProcessProxy> sourceProcess = process();
3171     URL sourceURL = URL { URL(), pageLoadState().url() };
3172     if (auto* provisionalPage = provisionalPageProxy()) {
3173         if (provisionalPage->navigationID() == navigation->navigationID()) {
3174             sourceProcess = provisionalPage->process();
3175             sourceURL = provisionalPage->provisionalURL();
3176         }
3177     }
3178
3179     process().processPool().processForNavigation(*this, *navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, WTFMove(websiteDataStore), [this, protectedThis = makeRef(*this), policyAction, navigation = makeRef(*navigation), sourceProcess = sourceProcess.copyRef(),
3180         data = WTFMove(data), sender = WTFMove(sender), processSwapRequestedByClient] (Ref<WebProcessProxy>&& processForNavigation, SuspendedPageProxy* destinationSuspendedPage, const String& reason) mutable {
3181         // If the navigation has been destroyed, then no need to proceed.
3182         if (isClosed() || !navigationState().hasNavigation(navigation->navigationID())) {
3183             receivedPolicyDecision(policyAction, navigation.ptr(), WTFMove(data), WTFMove(sender));
3184             return;
3185         }
3186
3187         bool shouldProcessSwap = processForNavigation.ptr() != sourceProcess.ptr();
3188         if (shouldProcessSwap) {
3189             policyAction = PolicyAction::StopAllLoads;
3190             RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "decidePolicyForNavigationAction, swapping process %i with process %i for navigation, reason: %" PUBLIC_LOG_STRING, processIdentifier(), processForNavigation->processIdentifier(), reason.utf8().data());
3191             LOG(ProcessSwapping, "(ProcessSwapping) Switching from process %i to new process (%i) for navigation %" PRIu64 " '%s'", processIdentifier(), processForNavigation->processIdentifier(), navigation->navigationID(), navigation->loggingString());
3192         } else
3193             RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "decidePolicyForNavigationAction: keep using process %i for navigation, reason: %" PUBLIC_LOG_STRING, processIdentifier(), reason.utf8().data());
3194
3195         if (shouldProcessSwap) {
3196             // Make sure the process to be used for the navigation does not get shutDown now due to destroying SuspendedPageProxy or ProvisionalPageProxy objects.
3197             auto preventNavigationProcessShutdown = processForNavigation->makeScopePreventingShutdown();
3198
3199             ASSERT(!destinationSuspendedPage || navigation->targetItem());
3200             auto suspendedPage = destinationSuspendedPage ? backForwardCache().takeSuspendedPage(*navigation->targetItem()) : nullptr;
3201             ASSERT(suspendedPage.get() == destinationSuspendedPage);
3202             if (suspendedPage && suspendedPage->pageIsClosedOrClosing())
3203                 suspendedPage = nullptr;
3204
3205             continueNavigationInNewProcess(navigation, WTFMove(suspendedPage), WTFMove(processForNavigation), processSwapRequestedByClient, WTFMove(data));
3206         }
3207
3208         receivedPolicyDecision(policyAction, navigation.ptr(), shouldProcessSwap ? WTF::nullopt : WTFMove(data), WTFMove(sender), shouldProcessSwap ? WillContinueLoadInNewProcess::Yes : WillContinueLoadInNewProcess::No);
3209     });
3210 }
3211
3212 void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, Optional<WebsitePoliciesData>&& websitePolicies, Ref<PolicyDecisionSender>&& sender, WillContinueLoadInNewProcess willContinueLoadInNewProcess)
3213 {
3214     if (!hasRunningProcess()) {
3215         sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), PolicyAction::Ignore, 0, DownloadID(), WTF::nullopt });
3216         return;
3217     }
3218
3219     auto transaction = m_pageLoadState.transaction();
3220
3221     if (action == PolicyAction::Ignore && willContinueLoadInNewProcess == WillContinueLoadInNewProcess::No && navigation && navigation->navigationID() == m_pageLoadState.pendingAPIRequest().navigationID)
3222         m_pageLoadState.clearPendingAPIRequest(transaction);
3223
3224     DownloadID downloadID = { };
3225     if (action == PolicyAction::Download) {
3226         // Create a download proxy.
3227         auto& download = m_process->processPool().createDownloadProxy(m_websiteDataStore, m_decidePolicyForResponseRequest, this, navigation ? navigation->originatingFrameInfo() : FrameInfoData { });
3228         if (navigation) {
3229             download.setWasUserInitiated(navigation->wasUserInitiated());
3230             download.setRedirectChain(navigation->takeRedirectChain());
3231         }
3232
3233         downloadID = download.downloadID();
3234         handleDownloadRequest(download);
3235         m_decidePolicyForResponseRequest = { };
3236     }
3237
3238     sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), action, navigation ? navigation->navigationID() : 0, downloadID, WTFMove(websitePolicies) });
3239 }
3240
3241 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)
3242 {
3243     ASSERT(m_provisionalPage);
3244     RELEASE_LOG_IF_ALLOWED(Loading, "commitProvisionalPage: newPID = %i", m_provisionalPage->process().processIdentifier());
3245
3246     Optional<FrameIdentifier> mainFrameIDInPreviousProcess = m_mainFrame ? makeOptional(m_mainFrame->frameID()) : WTF::nullopt;
3247
3248     ASSERT(m_process.ptr() != &m_provisionalPage->process());
3249
3250     auto shouldDelayClosingUntilEnteringAcceleratedCompositingMode = ShouldDelayClosingUntilEnteringAcceleratedCompositingMode::No;
3251 #if PLATFORM(MAC)
3252     // 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
3253     // entered accelerated compositing for the new page or we will flash on navigation.
3254     if (drawingArea()->type() == DrawingAreaTypeTiledCoreAnimation)
3255         shouldDelayClosingUntilEnteringAcceleratedCompositingMode = ShouldDelayClosingUntilEnteringAcceleratedCompositingMode::Yes;
3256 #endif
3257
3258     if (m_isLayerTreeFrozenDueToSwipeAnimation)
3259         send(Messages::WebPage::UnfreezeLayerTreeDueToSwipeAnimation());
3260
3261     processDidTerminate(ProcessTerminationReason::NavigationSwap);
3262
3263     m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID);
3264     auto* navigation = navigationState().navigation(m_provisionalPage->navigationID());
3265     bool didSuspendPreviousPage = navigation ? suspendCurrentPageIfPossible(*navigation, mainFrameIDInPreviousProcess, m_provisionalPage->processSwapRequestedByClient(), shouldDelayClosingUntilEnteringAcceleratedCompositingMode) : false;
3266     m_process->removeWebPage(*this, m_websiteDataStore.ptr() == &m_provisionalPage->process().websiteDataStore() ? WebProcessProxy::EndsUsingDataStore::No : WebProcessProxy::EndsUsingDataStore::Yes);
3267
3268     // There is no way we'll be able to return to the page in the previous page so close it.
3269     if (!didSuspendPreviousPage)
3270         send(Messages::WebPage::Close());
3271
3272     const auto oldWebPageID = m_webPageID;
3273     swapToProvisionalPage(std::exchange(m_provisionalPage, nullptr));
3274
3275     didCommitLoadForFrame(frameID, navigationID, mimeType, frameHasCustomContentProvider, frameLoadType, certificateInfo, usedLegacyTLS, containsPluginDocument, forcedHasInsecureContent, userData);
3276
3277     m_inspectorController->didCommitProvisionalPage(oldWebPageID, m_webPageID);
3278 }
3279
3280 void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, std::unique_ptr<SuspendedPageProxy>&& suspendedPage, Ref<WebProcessProxy>&& newProcess, ProcessSwapRequestedByClient processSwapRequestedByClient, Optional<WebsitePoliciesData>&& websitePolicies)
3281 {
3282     RELEASE_LOG_IF_ALLOWED(Loading, "continueNavigationInNewProcess: newProcessPID = %i, hasSuspendedPage = %i", newProcess->processIdentifier(), !!suspendedPage);
3283     LOG(Loading, "Continuing navigation %" PRIu64 " '%s' in a new web process", navigation.navigationID(), navigation.loggingString());
3284     RELEASE_ASSERT(!newProcess->isInProcessCache());
3285
3286     if (m_provisionalPage) {
3287         RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "continueNavigationInNewProcess: There is already a pending provisional load, cancelling it (provisonalNavigationID: %llu, navigationID: %llu)", m_provisionalPage->navigationID(), navigation.navigationID());
3288         if (m_provisionalPage->navigationID() != navigation.navigationID())
3289             m_provisionalPage->cancel();
3290         m_provisionalPage = nullptr;
3291     }
3292
3293     m_provisionalPage = makeUnique<ProvisionalPageProxy>(*this, WTFMove(newProcess), WTFMove(suspendedPage), navigation.navigationID(), navigation.currentRequestIsRedirect(), navigation.currentRequest(), processSwapRequestedByClient);
3294
3295     auto continuation = [this, protectedThis = makeRef(*this), navigation = makeRef(navigation), websitePolicies = WTFMove(websitePolicies)]() mutable {
3296         if (auto* item = navigation->targetItem()) {
3297             LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data());
3298
3299             auto transaction = m_pageLoadState.transaction();
3300             m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), item->url() });
3301
3302             m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies));
3303             return;
3304         }
3305
3306         if (m_backForwardList->currentItem() && (navigation->lockBackForwardList() == LockBackForwardList::Yes || navigation->lockHistory() == LockHistory::Yes)) {
3307             // 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
3308             // it instead of creating a new one.
3309             m_provisionalPage->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()));
3310         }
3311
3312         // FIXME: Work out timing of responding with the last policy delegate, etc
3313         ASSERT(!navigation->currentRequest().isEmpty());
3314         if (auto& substituteData = navigation->substituteData())
3315             m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), WTFMove(websitePolicies));
3316         else
3317             m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation->currentRequest() }, nullptr, isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), WTFMove(websitePolicies));
3318     };
3319     if (m_inspectorController->shouldPauseLoading(*m_provisionalPage))
3320         m_inspectorController->setContinueLoadingCallback(*m_provisionalPage, WTFMove(continuation));
3321     else
3322         continuation();
3323 }
3324
3325 bool WebPageProxy::isPageOpenedByDOMShowingInitialEmptyDocument() const
3326 {
3327     return openedByDOM() && !hasCommittedAnyProvisionalLoads();
3328 }
3329
3330 // MSVC gives a redeclaration error if noreturn is used on the definition and not the declaration, while
3331 // Cocoa tests segfault if it is moved to the declaration site (even if we move the definition with it!).
3332 #if !COMPILER(MSVC)
3333 NO_RETURN_DUE_TO_ASSERT
3334 #endif
3335 void WebPageProxy::didFailToSuspendAfterProcessSwap()
3336 {
3337     // Only the SuspendedPageProxy should be getting this call.
3338     ASSERT_NOT_REACHED();
3339 }
3340
3341 #if !COMPILER(MSVC)
3342 NO_RETURN_DUE_TO_ASSERT
3343 #endif
3344 void WebPageProxy::didSuspendAfterProcessSwap()
3345 {
3346     // Only the SuspendedPageProxy should be getting this call.
3347     ASSERT_NOT_REACHED();
3348 }
3349
3350 void WebPageProxy::setUserAgent(String&& userAgent)
3351 {
3352     if (m_userAgent == userAgent)
3353         return;
3354     m_userAgent = WTFMove(userAgent);
3355
3356 #if ENABLE(SERVICE_WORKER)
3357     // We update the service worker there at the moment to be sure we use values used by actual web pages.
3358     // FIXME: Refactor this when we have a better User-Agent story.
3359     process().processPool().updateServiceWorkerUserAgent(m_userAgent);
3360 #endif
3361
3362     if (!hasRunningProcess())
3363         return;
3364     send(Messages::WebPage::SetUserAgent(m_userAgent));
3365 }
3366
3367 void WebPageProxy::setApplicationNameForUserAgent(const String& applicationName)
3368 {
3369     if (m_applicationNameForUserAgent == applicationName)
3370         return;
3371
3372     m_applicationNameForUserAgent = applicationName;
3373     if (!m_customUserAgent.isEmpty())
3374         return;
3375
3376     setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3377 }
3378
3379 void WebPageProxy::setCustomUserAgent(const String& customUserAgent)
3380 {
3381     if (m_customUserAgent == customUserAgent)
3382         return;
3383
3384     m_customUserAgent = customUserAgent;
3385
3386     if (m_customUserAgent.isEmpty()) {
3387         setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3388         return;
3389     }
3390
3391     setUserAgent(String { m_customUserAgent });
3392 }
3393
3394 void WebPageProxy::resumeActiveDOMObjectsAndAnimations()
3395 {
3396     if (!hasRunningProcess() || !m_isPageSuspended)
3397         return;
3398
3399     m_isPageSuspended = false;
3400
3401     send(Messages::WebPage::ResumeActiveDOMObjectsAndAnimations());
3402 }
3403
3404 void WebPageProxy::suspendActiveDOMObjectsAndAnimations()
3405 {
3406     if (!hasRunningProcess() || m_isPageSuspended)
3407         return;
3408
3409     m_isPageSuspended = true;
3410
3411     send(Messages::WebPage::SuspendActiveDOMObjectsAndAnimations());
3412 }
3413
3414 bool WebPageProxy::supportsTextEncoding() const
3415 {
3416     // FIXME (118840): We should probably only support this for text documents, not all non-image documents.
3417     return m_mainFrame && !m_mainFrame->isDisplayingStandaloneImageDocument();
3418 }
3419
3420 void WebPageProxy::setCustomTextEncodingName(const String& encodingName)
3421 {
3422     if (m_customTextEncodingName == encodingName)
3423         return;
3424     m_customTextEncodingName = encodingName;
3425
3426     if (!hasRunningProcess())
3427         return;
3428     send(Messages::WebPage::SetCustomTextEncodingName(encodingName));
3429 }
3430
3431 SessionState WebPageProxy::sessionState(WTF::Function<bool (WebBackForwardListItem&)>&& filter) const
3432 {
3433     SessionState sessionState;
3434
3435     sessionState.backForwardListState = m_backForwardList->backForwardListState(WTFMove(filter));
3436
3437     String provisionalURLString = m_pageLoadState.pendingAPIRequestURL();
3438     if (provisionalURLString.isEmpty())
3439         provisionalURLString = m_pageLoadState.provisionalURL();
3440
3441     if (!provisionalURLString.isEmpty())
3442         sessionState.provisionalURL = URL(URL(), provisionalURLString);
3443
3444     sessionState.renderTreeSize = renderTreeSize();
3445     return sessionState;
3446 }
3447
3448 RefPtr<API::Navigation> WebPageProxy::restoreFromSessionState(SessionState sessionState, bool navigate)
3449 {
3450     RELEASE_LOG_IF_ALLOWED(Loading, "restoreFromSessionState:");
3451
3452     m_sessionRestorationRenderTreeSize = 0;
3453     m_hitRenderTreeSizeThreshold = false;
3454
3455     bool hasBackForwardList = !!sessionState.backForwardListState.currentIndex;
3456
3457     if (hasBackForwardList) {
3458         // If there isn't a running process yet the RestoreSession message below is just ignored, and
3459         // session is restored when the web process is created via creation parameters which is not
3460         // considered an API request. So, we launch the initial process here before restoring the
3461         // session to ensure the session is restored in the web process via RestoreSession IPC message
3462         // which is considered an API request. See https://bugs.webkit.org/show_bug.cgi?id=198561.
3463         launchInitialProcessIfNecessary();
3464
3465         m_backForwardList->restoreFromState(WTFMove(sessionState.backForwardListState));
3466         send(Messages::WebPage::RestoreSession(m_backForwardList->itemStates()));
3467
3468         auto transaction = m_pageLoadState.transaction();
3469         m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
3470         m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
3471
3472         // The back / forward list was restored from a sessionState so we don't want to snapshot the current
3473         // page when navigating away. Suppress navigation snapshotting until the next load has committed
3474         suppressNextAutomaticNavigationSnapshot();
3475     }
3476
3477     // FIXME: Navigating should be separate from state restoration.
3478     if (navigate) {
3479         m_sessionRestorationRenderTreeSize = sessionState.renderTreeSize;
3480         if (!m_sessionRestorationRenderTreeSize)
3481             m_hitRenderTreeSizeThreshold = true; // If we didn't get data on renderTreeSize, just don't fire the milestone.
3482
3483         if (!sessionState.provisionalURL.isNull())
3484             return loadRequest(sessionState.provisionalURL);
3485
3486         if (hasBackForwardList) {
3487             if (WebBackForwardListItem* item = m_backForwardList->currentItem())
3488                 return goToBackForwardItem(*item);
3489         }
3490     }
3491
3492     return nullptr;
3493 }
3494
3495 bool WebPageProxy::supportsTextZoom() const
3496 {
3497     // FIXME (118840): This should also return false for standalone media and plug-in documents.
3498     if (!m_mainFrame || m_mainFrame->isDisplayingStandaloneImageDocument())
3499         return false;
3500
3501     return true;
3502 }
3503  
3504 void WebPageProxy::setTextZoomFactor(double zoomFactor)
3505 {
3506     if (m_textZoomFactor == zoomFactor)
3507         return;
3508
3509     m_textZoomFactor = zoomFactor;
3510
3511     if (!hasRunningProcess())
3512         return;
3513
3514     send(Messages::WebPage::SetTextZoomFactor(m_textZoomFactor));
3515 }
3516
3517 void WebPageProxy::setPageZoomFactor(double zoomFactor)
3518 {
3519     if (m_pageZoomFactor == zoomFactor)
3520         return;
3521
3522     closeOverlayedViews();
3523
3524     m_pageZoomFactor = zoomFactor;
3525
3526     if (!hasRunningProcess())
3527         return;
3528
3529     send(Messages::WebPage::SetPageZoomFactor(m_pageZoomFactor));