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