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