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