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