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