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