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