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