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