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