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