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