Use ObjectIdentifier<FrameIdentifierType> for frameIDs
[WebKit.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<FrameIdentifier> 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 PLATFORM(MAC) && HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_PID)
1080     if (SandboxExtension::createHandleForReadByPid("/", processIdentifier(), sandboxExtensionHandle)) {
1081 #else
1082     if (SandboxExtension::createHandle("/", SandboxExtension::Type::ReadOnly, sandboxExtensionHandle)) {
1083 #endif
1084         willAcquireUniversalFileReadSandboxExtension(process);
1085         return;
1086     }
1087
1088 #if PLATFORM(COCOA)
1089     if (!linkedOnOrAfter(SDKVersion::FirstWithoutUnconditionalUniversalSandboxExtension))
1090         willAcquireUniversalFileReadSandboxExtension(process);
1091 #endif
1092
1093     // We failed to issue an universal file read access sandbox, fall back to issuing one for the base URL instead.
1094     auto baseURL = URL(URL(), url.baseAsString());
1095     auto basePath = baseURL.fileSystemPath();
1096     if (basePath.isNull())
1097         return;
1098 #if PLATFORM(MAC) && HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_PID)
1099     if (SandboxExtension::createHandleForReadByPid(basePath, processIdentifier(), sandboxExtensionHandle))
1100 #else
1101     if (SandboxExtension::createHandle(basePath, SandboxExtension::Type::ReadOnly, sandboxExtensionHandle))
1102 #endif
1103         m_process->assumeReadAccessToBaseURL(*this, baseURL);
1104 }
1105
1106 #if !PLATFORM(COCOA)
1107 void WebPageProxy::addPlatformLoadParameters(LoadParameters&)
1108 {
1109 }
1110 #endif
1111
1112 WebProcessProxy& WebPageProxy::ensureRunningProcess()
1113 {
1114     if (!hasRunningProcess())
1115         launchProcess({ });
1116
1117     return m_process;
1118 }
1119
1120 RefPtr<API::Navigation> WebPageProxy::loadRequest(ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData)
1121 {
1122     if (m_isClosed)
1123         return nullptr;
1124
1125     RELEASE_LOG_IF_ALLOWED(Loading, "loadRequest: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1126
1127     if (!hasRunningProcess())
1128         launchProcess(RegistrableDomain { request.url() });
1129
1130     auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem());
1131     loadRequestWithNavigationShared(m_process.copyRef(), navigation.get(), WTFMove(request), shouldOpenExternalURLsPolicy, userData, ShouldTreatAsContinuingLoad::No);
1132     return navigation;
1133 }
1134
1135 void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& process, API::Navigation& navigation, ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& websitePolicies)
1136 {
1137     ASSERT(!m_isClosed);
1138
1139     RELEASE_LOG_IF_ALLOWED(Loading, "loadRequestWithNavigation: webPID = %i, pageID = %" PRIu64, process->processIdentifier(), m_pageID.toUInt64());
1140
1141     auto transaction = m_pageLoadState.transaction();
1142
1143     auto url = request.url();
1144     if (shouldTreatAsContinuingLoad != ShouldTreatAsContinuingLoad::Yes)
1145         m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), url });
1146
1147     LoadParameters loadParameters;
1148     loadParameters.navigationID = navigation.navigationID();
1149     loadParameters.request = WTFMove(request);
1150     loadParameters.shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
1151     loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1152     loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::Yes;
1153     loadParameters.websitePolicies = WTFMove(websitePolicies);
1154     loadParameters.lockHistory = navigation.lockHistory();
1155     loadParameters.lockBackForwardList = navigation.lockBackForwardList();
1156     loadParameters.clientRedirectSourceForHistory = navigation.clientRedirectSourceForHistory();
1157     maybeInitializeSandboxExtensionHandle(process, url, m_pageLoadState.resourceDirectoryURL(), loadParameters.sandboxExtensionHandle);
1158
1159     addPlatformLoadParameters(loadParameters);
1160
1161     process->send(Messages::WebPage::LoadRequest(loadParameters), m_pageID);
1162     process->responsivenessTimer().start();
1163 }
1164
1165 RefPtr<API::Navigation> WebPageProxy::loadFile(const String& fileURLString, const String& resourceDirectoryURLString, API::Object* userData)
1166 {
1167     RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1168
1169     if (m_isClosed) {
1170         RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: page is closed: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1171         return nullptr;
1172     }
1173
1174     if (!hasRunningProcess())
1175         launchProcess({ });
1176
1177     URL fileURL = URL(URL(), fileURLString);
1178     if (!fileURL.isLocalFile()) {
1179         RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: file is not local: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1180         return nullptr;
1181     }
1182
1183     URL resourceDirectoryURL;
1184     if (resourceDirectoryURLString.isNull())
1185         resourceDirectoryURL = URL({ }, "file:///"_s);
1186     else {
1187         resourceDirectoryURL = URL(URL(), resourceDirectoryURLString);
1188         if (!resourceDirectoryURL.isLocalFile()) {
1189             RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: resource URL is not local: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1190             return nullptr;
1191         }
1192     }
1193
1194     auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(fileURL), m_backForwardList->currentItem());
1195
1196     auto transaction = m_pageLoadState.transaction();
1197
1198     m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), fileURLString }, resourceDirectoryURL);
1199
1200     String resourceDirectoryPath = resourceDirectoryURL.fileSystemPath();
1201
1202     LoadParameters loadParameters;
1203     loadParameters.navigationID = navigation->navigationID();
1204     loadParameters.request = fileURL;
1205     loadParameters.shouldOpenExternalURLsPolicy = ShouldOpenExternalURLsPolicy::ShouldNotAllow;
1206     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1207     SandboxExtension::createHandle(resourceDirectoryPath, SandboxExtension::Type::ReadOnly, loadParameters.sandboxExtensionHandle);
1208     addPlatformLoadParameters(loadParameters);
1209
1210     m_process->assumeReadAccessToBaseURL(*this, resourceDirectoryURL);
1211     m_process->send(Messages::WebPage::LoadRequest(loadParameters), m_pageID);
1212     m_process->responsivenessTimer().start();
1213
1214     return navigation;
1215 }
1216
1217 RefPtr<API::Navigation> WebPageProxy::loadData(const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
1218 {
1219     RELEASE_LOG_IF_ALLOWED(Loading, "loadData: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1220
1221     if (m_isClosed) {
1222         RELEASE_LOG_IF_ALLOWED(Loading, "loadData: page is closed: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1223         return nullptr;
1224     }
1225
1226     if (!hasRunningProcess())
1227         launchProcess({ });
1228
1229     auto navigation = m_navigationState->createLoadDataNavigation(std::make_unique<API::SubstituteData>(data.vector(), MIMEType, encoding, baseURL, userData));
1230     loadDataWithNavigationShared(m_process.copyRef(), navigation, data, MIMEType, encoding, baseURL, userData, ShouldTreatAsContinuingLoad::No, WTF::nullopt, shouldOpenExternalURLsPolicy);
1231     return navigation;
1232 }
1233
1234 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)
1235 {
1236     RELEASE_LOG_IF_ALLOWED(Loading, "loadDataWithNavigation: webPID = %i, pageID = %" PRIu64, process->processIdentifier(), m_pageID.toUInt64());
1237
1238     ASSERT(!m_isClosed);
1239
1240     auto transaction = m_pageLoadState.transaction();
1241
1242     m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), !baseURL.isEmpty() ? baseURL : WTF::blankURL().string() });
1243
1244     LoadParameters loadParameters;
1245     loadParameters.navigationID = navigation.navigationID();
1246     loadParameters.data = data;
1247     loadParameters.MIMEType = MIMEType;
1248     loadParameters.encodingName = encoding;
1249     loadParameters.baseURLString = baseURL;
1250     loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::Yes;
1251     loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1252     loadParameters.websitePolicies = WTFMove(websitePolicies);
1253     loadParameters.shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
1254     addPlatformLoadParameters(loadParameters);
1255
1256     process->assumeReadAccessToBaseURL(*this, baseURL);
1257     process->send(Messages::WebPage::LoadData(loadParameters), m_pageID);
1258     process->responsivenessTimer().start();
1259 }
1260
1261 void WebPageProxy::loadAlternateHTML(const IPC::DataReference& htmlData, const String& encoding, const URL& baseURL, const URL& unreachableURL, API::Object* userData)
1262 {
1263     RELEASE_LOG_IF_ALLOWED(Loading, "loadAlternateHTML: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1264
1265     // When the UIProcess is in the process of handling a failing provisional load, do not attempt to
1266     // start a second alternative HTML load as this will prevent the page load state from being
1267     // handled properly.
1268     if (m_isClosed || m_isLoadingAlternateHTMLStringForFailingProvisionalLoad) {
1269         RELEASE_LOG_IF_ALLOWED(Loading, "loadAlternateHTML: page is closed (or other): webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1270         return;
1271     }
1272
1273     if (!m_failingProvisionalLoadURL.isEmpty())
1274         m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = true;
1275
1276     if (!hasRunningProcess())
1277         launchProcess(RegistrableDomain { baseURL });
1278
1279     auto transaction = m_pageLoadState.transaction();
1280
1281     m_pageLoadState.setPendingAPIRequest(transaction, { 0, unreachableURL });
1282     m_pageLoadState.setUnreachableURL(transaction, unreachableURL);
1283
1284     if (m_mainFrame)
1285         m_mainFrame->setUnreachableURL(unreachableURL);
1286
1287     LoadParameters loadParameters;
1288     loadParameters.navigationID = 0;
1289     loadParameters.data = htmlData;
1290     loadParameters.MIMEType = "text/html"_s;
1291     loadParameters.encodingName = encoding;
1292     loadParameters.baseURLString = baseURL;
1293     loadParameters.unreachableURLString = unreachableURL;
1294     loadParameters.provisionalLoadErrorURLString = m_failingProvisionalLoadURL;
1295     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1296     addPlatformLoadParameters(loadParameters);
1297
1298     m_process->assumeReadAccessToBaseURL(*this, baseURL);
1299     m_process->assumeReadAccessToBaseURL(*this, unreachableURL);
1300     m_process->send(Messages::WebPage::LoadAlternateHTML(loadParameters), m_pageID);
1301     m_process->responsivenessTimer().start();
1302 }
1303
1304 void WebPageProxy::loadWebArchiveData(API::Data* webArchiveData, API::Object* userData)
1305 {
1306     RELEASE_LOG_IF_ALLOWED(Loading, "loadWebArchiveData: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1307
1308     if (m_isClosed) {
1309         RELEASE_LOG_IF_ALLOWED(Loading, "loadWebArchiveData: page is closed: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1310         return;
1311     }
1312
1313     if (!hasRunningProcess())
1314         launchProcess({ });
1315
1316     auto transaction = m_pageLoadState.transaction();
1317     m_pageLoadState.setPendingAPIRequest(transaction, { 0, WTF::blankURL().string() });
1318
1319     LoadParameters loadParameters;
1320     loadParameters.navigationID = 0;
1321     loadParameters.data = webArchiveData->dataReference();
1322     loadParameters.MIMEType = "application/x-webarchive"_s;
1323     loadParameters.encodingName = "utf-16"_s;
1324     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1325     addPlatformLoadParameters(loadParameters);
1326
1327     m_process->send(Messages::WebPage::LoadData(loadParameters), m_pageID);
1328     m_process->responsivenessTimer().start();
1329 }
1330
1331 void WebPageProxy::navigateToPDFLinkWithSimulatedClick(const String& urlString, IntPoint documentPoint, IntPoint screenPoint)
1332 {
1333     RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1334
1335     if (m_isClosed) {
1336         RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick: page is closed: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1337         return;
1338     }
1339
1340     if (WTF::protocolIsJavaScript(urlString))
1341         return;
1342
1343     if (!hasRunningProcess())
1344         launchProcess(RegistrableDomain { URL(URL(), urlString) });
1345
1346     m_process->send(Messages::WebPage::NavigateToPDFLinkWithSimulatedClick(urlString, documentPoint, screenPoint), m_pageID);
1347     m_process->responsivenessTimer().start();
1348 }
1349
1350 void WebPageProxy::stopLoading()
1351 {
1352     RELEASE_LOG_IF_ALLOWED(Loading, "stopLoading: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1353
1354     if (!hasRunningProcess()) {
1355         RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick: page is not valid: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1356         return;
1357     }
1358
1359     m_process->send(Messages::WebPage::StopLoading(), m_pageID);
1360     if (m_provisionalPage) {
1361         m_provisionalPage->cancel();
1362         m_provisionalPage = nullptr;
1363     }
1364     m_process->responsivenessTimer().start();
1365 }
1366
1367 RefPtr<API::Navigation> WebPageProxy::reload(OptionSet<WebCore::ReloadOption> options)
1368 {
1369     RELEASE_LOG_IF_ALLOWED(Loading, "reload: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1370
1371     SandboxExtension::Handle sandboxExtensionHandle;
1372
1373     String url = currentURL();
1374     if (!url.isEmpty()) {
1375         // We may not have an extension yet if back/forward list was reinstated after a WebProcess crash or a browser relaunch
1376         maybeInitializeSandboxExtensionHandle(m_process, URL(URL(), url), currentResourceDirectoryURL(), sandboxExtensionHandle);
1377     }
1378
1379     if (!hasRunningProcess())
1380         return launchProcessForReload();
1381     
1382     auto navigation = m_navigationState->createReloadNavigation();
1383
1384     if (!url.isEmpty()) {
1385         auto transaction = m_pageLoadState.transaction();
1386         m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), url });
1387     }
1388
1389     // Store decision to reload without content blockers on the navigation so that we can later set the corresponding
1390     // WebsitePolicies flag in WebPageProxy::receivedNavigationPolicyDecision().
1391     if (options.contains(WebCore::ReloadOption::DisableContentBlockers))
1392         navigation->setUserContentExtensionsEnabled(false);
1393
1394     m_process->send(Messages::WebPage::Reload(navigation->navigationID(), options.toRaw(), sandboxExtensionHandle), m_pageID);
1395     m_process->responsivenessTimer().start();
1396
1397 #if ENABLE(SPEECH_SYNTHESIS)
1398     resetSpeechSynthesizer();
1399 #endif
1400
1401     return navigation;
1402 }
1403
1404 void WebPageProxy::recordAutomaticNavigationSnapshot()
1405 {
1406     if (m_shouldSuppressNextAutomaticNavigationSnapshot)
1407         return;
1408
1409     if (WebBackForwardListItem* item = m_backForwardList->currentItem())
1410         recordNavigationSnapshot(*item);
1411 }
1412
1413 void WebPageProxy::recordNavigationSnapshot(WebBackForwardListItem& item)
1414 {
1415     if (!m_shouldRecordNavigationSnapshots)
1416         return;
1417
1418 #if PLATFORM(COCOA) || PLATFORM(GTK)
1419     ViewSnapshotStore::singleton().recordSnapshot(*this, item);
1420 #else
1421     UNUSED_PARAM(item);
1422 #endif
1423 }
1424
1425 RefPtr<API::Navigation> WebPageProxy::goForward()
1426 {
1427     WebBackForwardListItem* forwardItem = m_backForwardList->forwardItem();
1428     if (!forwardItem)
1429         return nullptr;
1430
1431     return goToBackForwardItem(*forwardItem, FrameLoadType::Forward);
1432 }
1433
1434 RefPtr<API::Navigation> WebPageProxy::goBack()
1435 {
1436     WebBackForwardListItem* backItem = m_backForwardList->backItem();
1437     if (!backItem)
1438         return nullptr;
1439
1440     return goToBackForwardItem(*backItem, FrameLoadType::Back);
1441 }
1442
1443 RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item)
1444 {
1445     return goToBackForwardItem(item, FrameLoadType::IndexedBackForward);
1446 }
1447
1448 RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item, FrameLoadType frameLoadType)
1449 {
1450     RELEASE_LOG_IF_ALLOWED(Loading, "goToBackForwardItem: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1451     LOG(Loading, "WebPageProxy %p goToBackForwardItem to item URL %s", this, item.url().utf8().data());
1452
1453     if (!hasRunningProcess())
1454         return launchProcessWithItem(item);
1455
1456     RefPtr<API::Navigation> navigation;
1457     if (!m_backForwardList->currentItem()->itemIsInSameDocument(item))
1458         navigation = m_navigationState->createBackForwardNavigation(item, m_backForwardList->currentItem(), frameLoadType);
1459
1460     auto transaction = m_pageLoadState.transaction();
1461     m_pageLoadState.setPendingAPIRequest(transaction, { navigation ? navigation->navigationID() : 0, item.url() });
1462
1463     m_process->send(Messages::WebPage::GoToBackForwardItem(navigation ? navigation->navigationID() : 0, item.itemID(), frameLoadType, ShouldTreatAsContinuingLoad::No, WTF::nullopt), m_pageID);
1464     m_process->responsivenessTimer().start();
1465
1466     return navigation;
1467 }
1468
1469 void WebPageProxy::tryRestoreScrollPosition()
1470 {
1471     RELEASE_LOG_IF_ALLOWED(Loading, "tryRestoreScrollPosition: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1472
1473     if (!hasRunningProcess()) {
1474         RELEASE_LOG_IF_ALLOWED(Loading, "tryRestoreScrollPosition: page is not valid: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
1475         return;
1476     }
1477
1478     m_process->send(Messages::WebPage::TryRestoreScrollPosition(), m_pageID);
1479 }
1480
1481 void WebPageProxy::didChangeBackForwardList(WebBackForwardListItem* added, Vector<Ref<WebBackForwardListItem>>&& removed)
1482 {
1483     PageClientProtector protector(pageClient());
1484
1485     if (!m_navigationClient->didChangeBackForwardList(*this, added, removed) && m_loaderClient)
1486         m_loaderClient->didChangeBackForwardList(*this, added, WTFMove(removed));
1487
1488     auto transaction = m_pageLoadState.transaction();
1489
1490     m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
1491     m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
1492 }
1493
1494 void WebPageProxy::willGoToBackForwardListItem(const BackForwardItemIdentifier& itemID, bool inPageCache)
1495 {
1496     PageClientProtector protector(pageClient());
1497
1498     if (auto* item = m_backForwardList->itemForID(itemID))
1499         m_navigationClient->willGoToBackForwardListItem(*this, *item, inPageCache);
1500 }
1501
1502 bool WebPageProxy::shouldKeepCurrentBackForwardListItemInList(WebBackForwardListItem& item)
1503 {
1504     PageClientProtector protector(pageClient());
1505
1506     return !m_loaderClient || m_loaderClient->shouldKeepCurrentBackForwardListItemInList(*this, item);
1507 }
1508
1509 bool WebPageProxy::canShowMIMEType(const String& mimeType)
1510 {
1511     if (MIMETypeRegistry::canShowMIMEType(mimeType))
1512         return true;
1513
1514 #if ENABLE(NETSCAPE_PLUGIN_API)
1515     String newMimeType = mimeType;
1516     PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL());
1517     if (!plugin.path.isNull() && m_preferences->pluginsEnabled())
1518         return true;
1519 #endif // ENABLE(NETSCAPE_PLUGIN_API)
1520
1521 #if PLATFORM(COCOA)
1522     // On Mac, we can show PDFs.
1523     if (MIMETypeRegistry::isPDFOrPostScriptMIMEType(mimeType) && !WebProcessPool::omitPDFSupport())
1524         return true;
1525 #endif // PLATFORM(COCOA)
1526
1527     return false;
1528 }
1529
1530 void WebPageProxy::setControlledByAutomation(bool controlled)
1531 {
1532     if (m_controlledByAutomation == controlled)
1533         return;
1534
1535     m_controlledByAutomation = controlled;
1536
1537     if (!hasRunningProcess())
1538         return;
1539
1540     m_process->send(Messages::WebPage::SetControlledByAutomation(controlled), m_pageID);
1541     m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation));
1542 }
1543
1544 void WebPageProxy::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type)
1545 {
1546     m_inspectorController->createInspectorTarget(targetId, type);
1547 }
1548
1549 void WebPageProxy::destroyInspectorTarget(const String& targetId)
1550 {
1551     m_inspectorController->destroyInspectorTarget(targetId);
1552 }
1553
1554 void WebPageProxy::sendMessageToInspectorFrontend(const String& targetId, const String& message)
1555 {
1556     m_inspectorController->sendMessageToInspectorFrontend(targetId, message);
1557 }
1558
1559 #if ENABLE(REMOTE_INSPECTOR)
1560 void WebPageProxy::setIndicating(bool indicating)
1561 {
1562     if (!hasRunningProcess())
1563         return;
1564
1565     m_process->send(Messages::WebPage::SetIndicating(indicating), m_pageID);
1566 }
1567
1568 bool WebPageProxy::allowsRemoteInspection() const
1569 {
1570     return m_inspectorDebuggable->remoteDebuggingAllowed();
1571 }
1572
1573 void WebPageProxy::setAllowsRemoteInspection(bool allow)
1574 {
1575     m_inspectorDebuggable->setRemoteDebuggingAllowed(allow);
1576 }
1577
1578 String WebPageProxy::remoteInspectionNameOverride() const
1579 {
1580     return m_inspectorDebuggable->nameOverride();
1581 }
1582
1583 void WebPageProxy::setRemoteInspectionNameOverride(const String& name)
1584 {
1585     m_inspectorDebuggable->setNameOverride(name);
1586 }
1587
1588 void WebPageProxy::remoteInspectorInformationDidChange()
1589 {
1590     m_inspectorDebuggable->update();
1591 }
1592 #endif
1593
1594 void WebPageProxy::clearInspectorTargets()
1595 {
1596     m_inspectorController->clearTargets();
1597 }
1598
1599 void WebPageProxy::createInspectorTargets()
1600 {
1601     String pageTargetId = makeString("page-", m_pageID.toUInt64());
1602     m_inspectorController->createInspectorTarget(pageTargetId, Inspector::InspectorTargetType::Page);
1603 }
1604
1605 void WebPageProxy::setBackgroundColor(const Optional<Color>& color)
1606 {
1607     if (m_backgroundColor == color)
1608         return;
1609
1610     m_backgroundColor = color;
1611     if (hasRunningProcess())
1612         m_process->send(Messages::WebPage::SetBackgroundColor(color), m_pageID);
1613 }
1614
1615 void WebPageProxy::setTopContentInset(float contentInset)
1616 {
1617     if (m_topContentInset == contentInset)
1618         return;
1619
1620     m_topContentInset = contentInset;
1621
1622     if (!hasRunningProcess())
1623         return;
1624 #if PLATFORM(COCOA)
1625     MachSendRight fence = m_drawingArea->createFence();
1626
1627     auto fenceAttachment = IPC::Attachment(fence.leakSendRight(), MACH_MSG_TYPE_MOVE_SEND);
1628     m_process->send(Messages::WebPage::SetTopContentInsetFenced(contentInset, fenceAttachment), m_pageID);
1629 #else
1630     m_process->send(Messages::WebPage::SetTopContentInset(contentInset), m_pageID);
1631 #endif
1632 }
1633
1634 void WebPageProxy::setUnderlayColor(const Color& color)
1635 {
1636     if (m_underlayColor == color)
1637         return;
1638
1639     m_underlayColor = color;
1640
1641     if (hasRunningProcess())
1642         m_process->send(Messages::WebPage::SetUnderlayColor(color), m_pageID);
1643 }
1644
1645 void WebPageProxy::viewWillStartLiveResize()
1646 {
1647     if (!hasRunningProcess())
1648         return;
1649
1650     closeOverlayedViews();
1651     m_process->send(Messages::WebPage::ViewWillStartLiveResize(), m_pageID);
1652 }
1653
1654 void WebPageProxy::viewWillEndLiveResize()
1655 {
1656     if (!hasRunningProcess())
1657         return;
1658     m_process->send(Messages::WebPage::ViewWillEndLiveResize(), m_pageID);
1659 }
1660
1661 void WebPageProxy::setViewNeedsDisplay(const Region& region)
1662 {
1663     pageClient().setViewNeedsDisplay(region);
1664 }
1665
1666 void WebPageProxy::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin)
1667 {
1668     pageClient().requestScroll(scrollPosition, scrollOrigin);
1669 }
1670
1671 WebCore::FloatPoint WebPageProxy::viewScrollPosition() const
1672 {
1673     return pageClient().viewScrollPosition();
1674 }
1675
1676 void WebPageProxy::setSuppressVisibilityUpdates(bool flag)
1677 {
1678     if (m_suppressVisibilityUpdates == flag)
1679         return;
1680     m_suppressVisibilityUpdates = flag;
1681
1682     if (!m_suppressVisibilityUpdates) {
1683 #if PLATFORM(COCOA)
1684         m_activityStateChangeDispatcher->schedule();
1685 #else
1686         dispatchActivityStateChange();
1687 #endif
1688     }
1689 }
1690
1691 void WebPageProxy::updateActivityState(OptionSet<ActivityState::Flag> flagsToUpdate)
1692 {
1693     m_activityState.remove(flagsToUpdate);
1694     if (flagsToUpdate & ActivityState::IsFocused && pageClient().isViewFocused())
1695         m_activityState.add(ActivityState::IsFocused);
1696     if (flagsToUpdate & ActivityState::WindowIsActive && pageClient().isViewWindowActive())
1697         m_activityState.add(ActivityState::WindowIsActive);
1698     if (flagsToUpdate & ActivityState::IsVisible && pageClient().isViewVisible())
1699         m_activityState.add(ActivityState::IsVisible);
1700     if (flagsToUpdate & ActivityState::IsVisibleOrOccluded && pageClient().isViewVisibleOrOccluded())
1701         m_activityState.add(ActivityState::IsVisibleOrOccluded);
1702     if (flagsToUpdate & ActivityState::IsInWindow && pageClient().isViewInWindow())
1703         m_activityState.add(ActivityState::IsInWindow);
1704     if (flagsToUpdate & ActivityState::IsVisuallyIdle && pageClient().isVisuallyIdle())
1705         m_activityState.add(ActivityState::IsVisuallyIdle);
1706     if (flagsToUpdate & ActivityState::IsAudible && m_mediaState & MediaProducer::IsPlayingAudio && !(m_mutedState & MediaProducer::AudioIsMuted))
1707         m_activityState.add(ActivityState::IsAudible);
1708     if (flagsToUpdate & ActivityState::IsLoading && m_pageLoadState.isLoading())
1709         m_activityState.add(ActivityState::IsLoading);
1710     if (flagsToUpdate & ActivityState::IsCapturingMedia && m_mediaState & (MediaProducer::HasActiveAudioCaptureDevice | MediaProducer::HasActiveVideoCaptureDevice))
1711         m_activityState.add(ActivityState::IsCapturingMedia);
1712 }
1713
1714 void WebPageProxy::activityStateDidChange(OptionSet<ActivityState::Flag> mayHaveChanged, bool wantsSynchronousReply, ActivityStateChangeDispatchMode dispatchMode)
1715 {
1716     LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << pageID() << " activityStateDidChange - mayHaveChanged " << mayHaveChanged);
1717
1718     m_potentiallyChangedActivityStateFlags.add(mayHaveChanged);
1719     m_activityStateChangeWantsSynchronousReply = m_activityStateChangeWantsSynchronousReply || wantsSynchronousReply;
1720
1721     if (m_suppressVisibilityUpdates && dispatchMode != ActivityStateChangeDispatchMode::Immediate)
1722         return;
1723
1724 #if PLATFORM(COCOA)
1725     bool isNewlyInWindow = !isInWindow() && (mayHaveChanged & ActivityState::IsInWindow) && pageClient().isViewInWindow();
1726     if (dispatchMode == ActivityStateChangeDispatchMode::Immediate || isNewlyInWindow) {
1727         dispatchActivityStateChange();
1728         return;
1729     }
1730     m_activityStateChangeDispatcher->schedule();
1731 #else
1732     UNUSED_PARAM(dispatchMode);
1733     dispatchActivityStateChange();
1734 #endif
1735 }
1736
1737 void WebPageProxy::viewDidLeaveWindow()
1738 {
1739     closeOverlayedViews();
1740 #if PLATFORM(IOS_FAMILY) && HAVE(AVKIT) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
1741     // When leaving the current page, close the video fullscreen.
1742     if (m_videoFullscreenManager && m_videoFullscreenManager->hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModeStandard))
1743         m_videoFullscreenManager->requestHideAndExitFullscreen();
1744 #endif
1745 }
1746
1747 void WebPageProxy::viewDidEnterWindow()
1748 {
1749     LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
1750     if (m_layerHostingMode != layerHostingMode) {
1751         m_layerHostingMode = layerHostingMode;
1752         m_process->send(Messages::WebPage::SetLayerHostingMode(layerHostingMode), m_pageID);
1753     }
1754 }
1755
1756 void WebPageProxy::dispatchActivityStateChange()
1757 {
1758 #if PLATFORM(COCOA)
1759     m_activityStateChangeDispatcher->invalidate();
1760 #endif
1761
1762     if (!hasRunningProcess())
1763         return;
1764
1765     LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << pageID() << " dispatchActivityStateChange - potentiallyChangedActivityStateFlags " << m_potentiallyChangedActivityStateFlags);
1766
1767     // If the visibility state may have changed, then so may the visually idle & occluded agnostic state.
1768     if (m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible)
1769         m_potentiallyChangedActivityStateFlags.add({ ActivityState::IsVisibleOrOccluded, ActivityState::IsVisuallyIdle });
1770
1771     // Record the prior view state, update the flags that may have changed,
1772     // and check which flags have actually changed.
1773     auto previousActivityState = m_activityState;
1774     updateActivityState(m_potentiallyChangedActivityStateFlags);
1775     auto changed = m_activityState ^ previousActivityState;
1776
1777     if (changed)
1778         LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << pageID() << " dispatchActivityStateChange: state changed from " << previousActivityState << " to " << m_activityState);
1779
1780     if ((changed & ActivityState::WindowIsActive) && isViewWindowActive())
1781         updateCurrentModifierState();
1782
1783     if ((m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible) && isViewVisible())
1784         viewIsBecomingVisible();
1785
1786     bool isNowInWindow = (changed & ActivityState::IsInWindow) && isInWindow();
1787     // We always want to wait for the Web process to reply if we've been in-window before and are coming back in-window.
1788     if (m_viewWasEverInWindow && isNowInWindow) {
1789         if (m_drawingArea->hasVisibleContent() && m_waitsForPaintAfterViewDidMoveToWindow && !m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow)
1790             m_activityStateChangeWantsSynchronousReply = true;
1791         m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow = false;
1792     }
1793
1794     // Don't wait synchronously if the view state is not visible. (This matters in particular on iOS, where a hidden page may be suspended.)
1795     if (!(m_activityState & ActivityState::IsVisible))
1796         m_activityStateChangeWantsSynchronousReply = false;
1797
1798     auto activityStateChangeID = m_activityStateChangeWantsSynchronousReply ? takeNextActivityStateChangeID() : static_cast<ActivityStateChangeID>(ActivityStateChangeAsynchronous);
1799
1800     if (changed || activityStateChangeID != ActivityStateChangeAsynchronous || !m_nextActivityStateChangeCallbacks.isEmpty())
1801         m_process->send(Messages::WebPage::SetActivityState(m_activityState, activityStateChangeID, m_nextActivityStateChangeCallbacks), m_pageID);
1802
1803     m_nextActivityStateChangeCallbacks.clear();
1804
1805     // This must happen after the SetActivityState message is sent, to ensure the page visibility event can fire.
1806     updateThrottleState();
1807
1808 #if ENABLE(POINTER_LOCK)
1809     if (((changed & ActivityState::IsVisible) && !isViewVisible()) || ((changed & ActivityState::WindowIsActive) && !pageClient().isViewWindowActive())
1810         || ((changed & ActivityState::IsFocused) && !(m_activityState & ActivityState::IsFocused)))
1811         requestPointerUnlock();
1812 #endif
1813
1814     if (changed & ActivityState::IsVisible) {
1815         if (isViewVisible())
1816             m_visiblePageToken = m_process->visiblePageToken();
1817         else {
1818             m_visiblePageToken = nullptr;
1819
1820             // If we've started the responsiveness timer as part of telling the web process to update the backing store
1821             // state, it might not send back a reply (since it won't paint anything if the web page is hidden) so we
1822             // stop the unresponsiveness timer here.
1823             m_process->responsivenessTimer().stop();
1824         }
1825     }
1826
1827     if (changed & ActivityState::IsInWindow) {
1828         if (isInWindow())
1829             viewDidEnterWindow();
1830         else
1831             viewDidLeaveWindow();
1832     }
1833
1834     updateBackingStoreDiscardableState();
1835
1836     if (activityStateChangeID != ActivityStateChangeAsynchronous)
1837         waitForDidUpdateActivityState(activityStateChangeID);
1838
1839     m_potentiallyChangedActivityStateFlags = { };
1840     m_activityStateChangeWantsSynchronousReply = false;
1841     m_viewWasEverInWindow |= isNowInWindow;
1842 }
1843
1844 bool WebPageProxy::isAlwaysOnLoggingAllowed() const
1845 {
1846     return sessionID().isAlwaysOnLoggingAllowed();
1847 }
1848
1849 void WebPageProxy::updateThrottleState()
1850 {
1851     bool processSuppressionEnabled = m_preferences->pageVisibilityBasedProcessSuppressionEnabled();
1852
1853     // If process suppression is not enabled take a token on the process pool to disable suppression of support processes.
1854     if (!processSuppressionEnabled)
1855         m_preventProcessSuppressionCount = m_process->processPool().processSuppressionDisabledForPageCount();
1856     else if (!m_preventProcessSuppressionCount)
1857         m_preventProcessSuppressionCount = nullptr;
1858
1859     if (m_activityState & ActivityState::IsVisuallyIdle)
1860         m_pageIsUserObservableCount = nullptr;
1861     else if (!m_pageIsUserObservableCount)
1862         m_pageIsUserObservableCount = m_process->processPool().userObservablePageCount();
1863
1864 #if PLATFORM(IOS_FAMILY)
1865     bool isCapturingMedia = m_activityState.contains(ActivityState::IsCapturingMedia);
1866     bool isAudible = m_activityState.contains(ActivityState::IsAudible);
1867     if (!isViewVisible() && !m_alwaysRunsAtForegroundPriority && !isCapturingMedia && !isAudible) {
1868         if (m_activityToken) {
1869             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because the view is no longer visible");
1870             m_activityToken = nullptr;
1871         }
1872     } else if (!m_activityToken) {
1873         if (isViewVisible())
1874             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because the view is visible");
1875         else if (isAudible)
1876             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because we are playing audio");
1877         else if (isCapturingMedia)
1878             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because media capture is active");
1879         else
1880             RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion even though the view is not visible because m_alwaysRunsAtForegroundPriority is true");
1881         m_activityToken = m_process->throttler().foregroundActivityToken();
1882     }
1883 #endif
1884 }
1885
1886 void WebPageProxy::updateHiddenPageThrottlingAutoIncreases()
1887 {
1888     if (!m_preferences->hiddenPageDOMTimerThrottlingAutoIncreases())
1889         m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = nullptr;
1890     else if (!m_hiddenPageDOMTimerThrottlingAutoIncreasesCount)
1891         m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = m_process->processPool().hiddenPageThrottlingAutoIncreasesCount();
1892 }
1893
1894 void WebPageProxy::layerHostingModeDidChange()
1895 {
1896     LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
1897     if (m_layerHostingMode == layerHostingMode)
1898         return;
1899
1900     m_layerHostingMode = layerHostingMode;
1901
1902     if (hasRunningProcess())
1903         m_process->send(Messages::WebPage::SetLayerHostingMode(layerHostingMode), m_pageID);
1904 }
1905
1906 void WebPageProxy::waitForDidUpdateActivityState(ActivityStateChangeID activityStateChangeID)
1907 {
1908     if (!hasRunningProcess())
1909         return;
1910
1911     if (m_process->state() != WebProcessProxy::State::Running)
1912         return;
1913
1914     // If we have previously timed out with no response from the WebProcess, don't block the UIProcess again until it starts responding.
1915     if (m_waitingForDidUpdateActivityState)
1916         return;
1917
1918 #if PLATFORM(IOS_FAMILY)
1919     // Hail Mary check. Should not be possible (dispatchActivityStateChange should force async if not visible,
1920     // and if visible we should be holding an assertion) - but we should never block on a suspended process.
1921     if (!m_activityToken) {
1922         ASSERT_NOT_REACHED();
1923         return;
1924     }
1925 #endif
1926
1927     m_waitingForDidUpdateActivityState = true;
1928
1929     m_drawingArea->waitForDidUpdateActivityState(activityStateChangeID);
1930 }
1931
1932 IntSize WebPageProxy::viewSize() const
1933 {
1934     return pageClient().viewSize();
1935 }
1936
1937 void WebPageProxy::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& keyboardEvent, WTF::Function<void (CallbackBase::Error)>&& callbackFunction)
1938 {
1939     if (!hasRunningProcess()) {
1940         callbackFunction(CallbackBase::Error::OwnerWasInvalidated);
1941         return;
1942     }
1943
1944     auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
1945     m_process->send(Messages::WebPage::SetInitialFocus(forward, isKeyboardEventValid, keyboardEvent, callbackID), m_pageID);
1946 }
1947
1948 void WebPageProxy::clearSelection()
1949 {
1950     if (!hasRunningProcess())
1951         return;
1952     m_process->send(Messages::WebPage::ClearSelection(), m_pageID);
1953 }
1954
1955 void WebPageProxy::restoreSelectionInFocusedEditableElement()
1956 {
1957     if (!hasRunningProcess())
1958         return;
1959     m_process->send(Messages::WebPage::RestoreSelectionInFocusedEditableElement(), m_pageID);
1960 }
1961
1962 void WebPageProxy::validateCommand(const String& commandName, WTF::Function<void (const String&, bool, int32_t, CallbackBase::Error)>&& callbackFunction)
1963 {
1964     if (!hasRunningProcess()) {
1965         callbackFunction(String(), false, 0, CallbackBase::Error::Unknown);
1966         return;
1967     }
1968
1969     auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
1970     m_process->send(Messages::WebPage::ValidateCommand(commandName, callbackID), m_pageID);
1971 }
1972
1973 void WebPageProxy::increaseListLevel()
1974 {
1975     if (!hasRunningProcess())
1976         return;
1977
1978     m_process->send(Messages::WebPage::IncreaseListLevel(), m_pageID);
1979 }
1980
1981 void WebPageProxy::decreaseListLevel()
1982 {
1983     if (!hasRunningProcess())
1984         return;
1985
1986     m_process->send(Messages::WebPage::DecreaseListLevel(), m_pageID);
1987 }
1988
1989 void WebPageProxy::changeListType()
1990 {
1991     if (!hasRunningProcess())
1992         return;
1993
1994     m_process->send(Messages::WebPage::ChangeListType(), m_pageID);
1995 }
1996
1997 void WebPageProxy::setBaseWritingDirection(WritingDirection direction)
1998 {
1999     if (!hasRunningProcess())
2000         return;
2001
2002     m_process->send(Messages::WebPage::SetBaseWritingDirection(direction), m_pageID);
2003 }
2004
2005 void WebPageProxy::updateFontAttributesAfterEditorStateChange()
2006 {
2007     m_cachedFontAttributesAtSelectionStart.reset();
2008
2009     if (m_editorState.isMissingPostLayoutData)
2010         return;
2011
2012     if (auto fontAttributes = m_editorState.postLayoutData().fontAttributes) {
2013         m_uiClient->didChangeFontAttributes(*fontAttributes);
2014         m_cachedFontAttributesAtSelectionStart = WTFMove(fontAttributes);
2015     }
2016 }
2017
2018 void WebPageProxy::setNeedsFontAttributes(bool needsFontAttributes)
2019 {
2020     if (m_needsFontAttributes == needsFontAttributes)
2021         return;
2022
2023     m_needsFontAttributes = needsFontAttributes;
2024
2025     if (hasRunningProcess())
2026         m_process->send(Messages::WebPage::SetNeedsFontAttributes(needsFontAttributes), m_pageID);
2027 }
2028
2029 bool WebPageProxy::maintainsInactiveSelection() const
2030 {
2031     // Regardless of what the client wants to do, keep selections if a local Inspector is open.
2032     // Otherwise, there is no way to use the console to inspect the state of a selection.
2033     if (inspector() && inspector()->isVisible())
2034         return true;
2035
2036     return m_maintainsInactiveSelection;
2037 }
2038
2039 void WebPageProxy::setMaintainsInactiveSelection(bool newValue)
2040 {
2041     m_maintainsInactiveSelection = newValue;
2042 }
2043
2044 void WebPageProxy::scheduleFullEditorStateUpdate()
2045 {
2046     if (!hasRunningProcess())
2047         return;
2048
2049     m_process->send(Messages::WebPage::ScheduleFullEditorStateUpdate(), m_pageID);
2050 }
2051
2052 void WebPageProxy::selectAll()
2053 {
2054     if (!hasRunningProcess())
2055         return;
2056
2057     m_process->send(Messages::WebPage::SelectAll(), m_pageID);
2058 }
2059
2060 void WebPageProxy::executeEditCommand(const String& commandName, const String& argument, WTF::Function<void(CallbackBase::Error)>&& callbackFunction)
2061 {
2062     if (!hasRunningProcess()) {
2063         callbackFunction(CallbackBase::Error::Unknown);
2064         return;
2065     }
2066
2067     auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
2068     m_process->send(Messages::WebPage::ExecuteEditCommandWithCallback(commandName, argument, callbackID), m_pageID);
2069 }
2070     
2071 void WebPageProxy::executeEditCommand(const String& commandName, const String& argument)
2072 {
2073     static NeverDestroyed<String> ignoreSpellingCommandName(MAKE_STATIC_STRING_IMPL("ignoreSpelling"));
2074
2075     if (!hasRunningProcess())
2076         return;
2077
2078     if (commandName == ignoreSpellingCommandName)
2079         ++m_pendingLearnOrIgnoreWordMessageCount;
2080
2081     m_process->send(Messages::WebPage::ExecuteEditCommand(commandName, argument), m_pageID);
2082 }
2083
2084 void WebPageProxy::requestFontAttributesAtSelectionStart(Function<void(const WebCore::FontAttributes&, CallbackBase::Error)>&& callback)
2085 {
2086     if (!hasRunningProcess()) {
2087         callback({ }, CallbackBase::Error::Unknown);
2088         return;
2089     }
2090
2091     auto callbackID = m_callbacks.put(WTFMove(callback), m_process->throttler().backgroundActivityToken());
2092     m_process->send(Messages::WebPage::RequestFontAttributesAtSelectionStart(callbackID), m_pageID);
2093 }
2094
2095 void WebPageProxy::fontAttributesCallback(const WebCore::FontAttributes& attributes, CallbackID callbackID)
2096 {
2097     m_cachedFontAttributesAtSelectionStart = attributes;
2098
2099     if (auto callback = m_callbacks.take<FontAttributesCallback>(callbackID))
2100         callback->performCallbackWithReturnValue(attributes);
2101 }
2102
2103 void WebPageProxy::setEditable(bool editable)
2104 {
2105     if (editable == m_isEditable)
2106         return;
2107
2108     m_isEditable = editable;
2109
2110     if (!hasRunningProcess())
2111         return;
2112
2113     m_process->send(Messages::WebPage::SetEditable(editable), m_pageID);
2114 }
2115     
2116 void WebPageProxy::setMediaStreamCaptureMuted(bool muted)
2117 {
2118     if (muted)
2119         setMuted(m_mutedState | WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2120     else
2121         setMuted(m_mutedState & ~WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2122 }
2123
2124 void WebPageProxy::activateMediaStreamCaptureInPage()
2125 {
2126 #if ENABLE(MEDIA_STREAM)
2127     UserMediaProcessManager::singleton().muteCaptureMediaStreamsExceptIn(*this);
2128 #endif
2129     setMuted(m_mutedState & ~WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2130 }
2131
2132 #if !PLATFORM(IOS_FAMILY)
2133 void WebPageProxy::didCommitLayerTree(const RemoteLayerTreeTransaction&)
2134 {
2135 }
2136
2137 void WebPageProxy::layerTreeCommitComplete()
2138 {
2139 }
2140 #endif
2141
2142 #if ENABLE(DRAG_SUPPORT)
2143 void WebPageProxy::dragEntered(DragData& dragData, const String& dragStorageName)
2144 {
2145     performDragControllerAction(DragControllerAction::Entered, dragData, dragStorageName, { }, { });
2146 }
2147
2148 void WebPageProxy::dragUpdated(DragData& dragData, const String& dragStorageName)
2149 {
2150     performDragControllerAction(DragControllerAction::Updated, dragData, dragStorageName, { }, { });
2151 }
2152
2153 void WebPageProxy::dragExited(DragData& dragData, const String& dragStorageName)
2154 {
2155     performDragControllerAction(DragControllerAction::Exited, dragData, dragStorageName, { }, { });
2156 }
2157
2158 void WebPageProxy::performDragOperation(DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsForUpload)
2159 {
2160     performDragControllerAction(DragControllerAction::PerformDragOperation, dragData, dragStorageName, WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionsForUpload));
2161 }
2162
2163 void WebPageProxy::performDragControllerAction(DragControllerAction action, DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsForUpload)
2164 {
2165     if (!hasRunningProcess())
2166         return;
2167 #if PLATFORM(GTK)
2168     UNUSED_PARAM(dragStorageName);
2169     UNUSED_PARAM(sandboxExtensionHandle);
2170     UNUSED_PARAM(sandboxExtensionsForUpload);
2171
2172     String url = dragData.asURL();
2173     if (!url.isEmpty())
2174         m_process->assumeReadAccessToBaseURL(*this, url);
2175
2176     ASSERT(dragData.platformData());
2177     WebSelectionData selection(*dragData.platformData());
2178     m_process->send(Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), selection, dragData.flags()), m_pageID);
2179 #else
2180     m_process->send(Messages::WebPage::PerformDragControllerAction(action, dragData, sandboxExtensionHandle, sandboxExtensionsForUpload), m_pageID);
2181 #endif
2182 }
2183
2184 void WebPageProxy::didPerformDragControllerAction(uint64_t dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect, const IntRect& editableElementRect)
2185 {
2186     MESSAGE_CHECK(m_process, dragOperation <= DragOperationDelete);
2187
2188     m_currentDragOperation = static_cast<DragOperation>(dragOperation);
2189     m_currentDragHandlingMethod = dragHandlingMethod;
2190     m_currentDragIsOverFileInput = mouseIsOverFileInput;
2191     m_currentDragNumberOfFilesToBeAccepted = numberOfItemsToBeAccepted;
2192     m_currentDragCaretEditableElementRect = editableElementRect;
2193     setDragCaretRect(insertionRect);
2194 }
2195
2196 #if PLATFORM(GTK)
2197 void WebPageProxy::startDrag(WebSelectionData&& selection, uint64_t dragOperation, const ShareableBitmap::Handle& dragImageHandle)
2198 {
2199     RefPtr<ShareableBitmap> dragImage = !dragImageHandle.isNull() ? ShareableBitmap::create(dragImageHandle) : nullptr;
2200     pageClient().startDrag(WTFMove(selection.selectionData), static_cast<WebCore::DragOperation>(dragOperation), WTFMove(dragImage));
2201
2202     didStartDrag();
2203 }
2204 #endif
2205
2206 void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t operation)
2207 {
2208     if (!hasRunningProcess())
2209         return;
2210     m_process->send(Messages::WebPage::DragEnded(clientPosition, globalPosition, operation), m_pageID);
2211     setDragCaretRect({ });
2212 }
2213
2214 void WebPageProxy::didPerformDragOperation(bool handled)
2215 {
2216     pageClient().didPerformDragOperation(handled);
2217 }
2218
2219 void WebPageProxy::didStartDrag()
2220 {
2221     if (hasRunningProcess())
2222         m_process->send(Messages::WebPage::DidStartDrag(), m_pageID);
2223 }
2224     
2225 void WebPageProxy::dragCancelled()
2226 {
2227     if (hasRunningProcess())
2228         m_process->send(Messages::WebPage::DragCancelled(), m_pageID);
2229 }
2230
2231 void WebPageProxy::didEndDragging()
2232 {
2233     resetCurrentDragInformation();
2234 }
2235
2236 void WebPageProxy::resetCurrentDragInformation()
2237 {
2238     m_currentDragOperation = WebCore::DragOperationNone;
2239     m_currentDragHandlingMethod = DragHandlingMethod::None;
2240     m_currentDragIsOverFileInput = false;
2241     m_currentDragNumberOfFilesToBeAccepted = 0;
2242     setDragCaretRect({ });
2243 }
2244
2245 #if !ENABLE(DATA_INTERACTION)
2246
2247 void WebPageProxy::setDragCaretRect(const IntRect& dragCaretRect)
2248 {
2249     m_currentDragCaretRect = dragCaretRect;
2250 }
2251
2252 #endif
2253
2254 #endif // ENABLE(DRAG_SUPPORT)
2255
2256 static bool removeOldRedundantEvent(Deque<NativeWebMouseEvent>& queue, WebEvent::Type incomingEventType)
2257 {
2258     if (incomingEventType != WebEvent::MouseMove && incomingEventType != WebEvent::MouseForceChanged)
2259         return false;
2260
2261     auto it = queue.rbegin();
2262     auto end = queue.rend();
2263
2264     // Must not remove the first event in the deque, since it is already being dispatched.
2265     if (it != end)
2266         --end;
2267
2268     for (; it != end; ++it) {
2269         auto type = it->type();
2270         if (type == incomingEventType) {
2271             queue.remove(--it.base());
2272             return true;
2273         }
2274         if (type != WebEvent::MouseMove && type != WebEvent::MouseForceChanged)
2275             break;
2276     }
2277     return false;
2278 }
2279
2280 void WebPageProxy::handleMouseEvent(const NativeWebMouseEvent& event)
2281 {
2282     if (!hasRunningProcess())
2283         return;
2284
2285 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2286     if (m_scrollingCoordinatorProxy)
2287         m_scrollingCoordinatorProxy->handleMouseEvent(platform(event));
2288 #endif
2289
2290     // If we receive multiple mousemove or mouseforcechanged events and the most recent mousemove or mouseforcechanged event
2291     // (respectively) has not yet been sent to WebProcess for processing, remove the pending mouse event and insert the new
2292     // event in the queue.
2293     bool didRemoveEvent = removeOldRedundantEvent(m_mouseEventQueue, event.type());
2294     m_mouseEventQueue.append(event);
2295
2296 #if LOG_DISABLED
2297     UNUSED_PARAM(didRemoveEvent);
2298 #else
2299     LOG(MouseHandling, "UIProcess: %s mouse event %s (queue size %zu)", didRemoveEvent ? "replaced" : "enqueued", webMouseEventTypeString(event.type()), m_mouseEventQueue.size());
2300 #endif
2301
2302     if (m_mouseEventQueue.size() == 1) // Otherwise, called from DidReceiveEvent message handler.
2303         processNextQueuedMouseEvent();
2304 }
2305     
2306 void WebPageProxy::processNextQueuedMouseEvent()
2307 {
2308     if (!hasRunningProcess())
2309         return;
2310
2311     ASSERT(!m_mouseEventQueue.isEmpty());
2312
2313     const NativeWebMouseEvent& event = m_mouseEventQueue.first();
2314
2315     if (pageClient().windowIsFrontWindowUnderMouse(event))
2316         setToolTip(String());
2317
2318     WebEvent::Type eventType = event.type();
2319     if (eventType == WebEvent::MouseDown || eventType == WebEvent::MouseForceChanged || eventType == WebEvent::MouseForceDown)
2320         m_process->responsivenessTimer().startWithLazyStop();
2321     else if (eventType != WebEvent::MouseMove) {
2322         // NOTE: This does not start the responsiveness timer because mouse move should not indicate interaction.
2323         m_process->responsivenessTimer().start();
2324     }
2325
2326     LOG(MouseHandling, "UIProcess: sent mouse event %s (queue size %zu)", webMouseEventTypeString(eventType), m_mouseEventQueue.size());
2327     m_process->send(Messages::WebPage::MouseEvent(event), m_pageID);
2328 }
2329
2330 #if MERGE_WHEEL_EVENTS
2331 static bool canCoalesce(const WebWheelEvent& a, const WebWheelEvent& b)
2332 {
2333     if (a.position() != b.position())
2334         return false;
2335     if (a.globalPosition() != b.globalPosition())
2336         return false;
2337     if (a.modifiers() != b.modifiers())
2338         return false;
2339     if (a.granularity() != b.granularity())
2340         return false;
2341 #if PLATFORM(COCOA)
2342     if (a.phase() != b.phase())
2343         return false;
2344     if (a.momentumPhase() != b.momentumPhase())
2345         return false;
2346     if (a.hasPreciseScrollingDeltas() != b.hasPreciseScrollingDeltas())
2347         return false;
2348 #endif
2349
2350     return true;
2351 }
2352
2353 static WebWheelEvent coalesce(const WebWheelEvent& a, const WebWheelEvent& b)
2354 {
2355     ASSERT(canCoalesce(a, b));
2356
2357     FloatSize mergedDelta = a.delta() + b.delta();
2358     FloatSize mergedWheelTicks = a.wheelTicks() + b.wheelTicks();
2359
2360 #if PLATFORM(COCOA)
2361     FloatSize mergedUnacceleratedScrollingDelta = a.unacceleratedScrollingDelta() + b.unacceleratedScrollingDelta();
2362
2363     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());
2364 #else
2365     return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.modifiers(), b.timestamp());
2366 #endif
2367 }
2368 #endif // MERGE_WHEEL_EVENTS
2369
2370 static WebWheelEvent coalescedWheelEvent(Deque<NativeWebWheelEvent>& queue, Vector<NativeWebWheelEvent>& coalescedEvents)
2371 {
2372     ASSERT(!queue.isEmpty());
2373     ASSERT(coalescedEvents.isEmpty());
2374
2375 #if MERGE_WHEEL_EVENTS
2376     NativeWebWheelEvent firstEvent = queue.takeFirst();
2377     coalescedEvents.append(firstEvent);
2378
2379     WebWheelEvent event = firstEvent;
2380     while (!queue.isEmpty() && canCoalesce(event, queue.first())) {
2381         NativeWebWheelEvent firstEvent = queue.takeFirst();
2382         coalescedEvents.append(firstEvent);
2383         event = coalesce(event, firstEvent);
2384     }
2385
2386     return event;
2387 #else
2388     while (!queue.isEmpty())
2389         coalescedEvents.append(queue.takeFirst());
2390     return coalescedEvents.last();
2391 #endif
2392 }
2393
2394 void WebPageProxy::handleWheelEvent(const NativeWebWheelEvent& event)
2395 {
2396 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2397     if (m_scrollingCoordinatorProxy && m_scrollingCoordinatorProxy->handleWheelEvent(platform(event)))
2398         return;
2399 #endif
2400
2401     if (!hasRunningProcess())
2402         return;
2403
2404     closeOverlayedViews();
2405
2406     if (!m_currentlyProcessedWheelEvents.isEmpty()) {
2407         m_wheelEventQueue.append(event);
2408         if (!shouldProcessWheelEventNow(event))
2409             return;
2410         // The queue has too many wheel events, so push a new event.
2411     }
2412
2413     if (!m_wheelEventQueue.isEmpty()) {
2414         processNextQueuedWheelEvent();
2415         return;
2416     }
2417
2418     auto coalescedWheelEvent = std::make_unique<Vector<NativeWebWheelEvent>>();
2419     coalescedWheelEvent->append(event);
2420     m_currentlyProcessedWheelEvents.append(WTFMove(coalescedWheelEvent));
2421     sendWheelEvent(event);
2422 }
2423
2424 void WebPageProxy::processNextQueuedWheelEvent()
2425 {
2426     auto nextCoalescedEvent = std::make_unique<Vector<NativeWebWheelEvent>>();
2427     WebWheelEvent nextWheelEvent = coalescedWheelEvent(m_wheelEventQueue, *nextCoalescedEvent.get());
2428     m_currentlyProcessedWheelEvents.append(WTFMove(nextCoalescedEvent));
2429     sendWheelEvent(nextWheelEvent);
2430 }
2431
2432 void WebPageProxy::sendWheelEvent(const WebWheelEvent& event)
2433 {
2434     m_process->send(
2435         Messages::EventDispatcher::WheelEvent(
2436             m_pageID,
2437             event,
2438             shouldUseImplicitRubberBandControl() ? !m_backForwardList->backItem() : rubberBandsAtLeft(),
2439             shouldUseImplicitRubberBandControl() ? !m_backForwardList->forwardItem() : rubberBandsAtRight(),
2440             rubberBandsAtTop(),
2441             rubberBandsAtBottom()
2442         ), 0);
2443
2444     // Manually ping the web process to check for responsiveness since our wheel
2445     // event will dispatch to a non-main thread, which always responds.
2446     m_process->isResponsiveWithLazyStop();
2447 }
2448
2449 bool WebPageProxy::shouldProcessWheelEventNow(const WebWheelEvent& event) const
2450 {
2451 #if PLATFORM(GTK)
2452     // Don't queue events representing a non-trivial scrolling phase to
2453     // avoid having them trapped in the queue, potentially preventing a
2454     // scrolling session to beginning or end correctly.
2455     // This is only needed by platforms whose WebWheelEvent has this phase
2456     // information (Cocoa and GTK+) but Cocoa was fine without it.
2457     if (event.phase() == WebWheelEvent::Phase::PhaseNone
2458         || event.phase() == WebWheelEvent::Phase::PhaseChanged
2459         || event.momentumPhase() == WebWheelEvent::Phase::PhaseNone
2460         || event.momentumPhase() == WebWheelEvent::Phase::PhaseChanged)
2461         return true;
2462 #else
2463     UNUSED_PARAM(event);
2464 #endif
2465     if (m_wheelEventQueue.size() >= wheelEventQueueSizeThreshold)
2466         return true;
2467     return false;
2468 }
2469
2470 void WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event)
2471 {
2472     if (!hasRunningProcess())
2473         return;
2474     
2475     LOG(KeyHandling, "WebPageProxy::handleKeyboardEvent: %s", webKeyboardEventTypeString(event.type()));
2476
2477     m_keyEventQueue.append(event);
2478
2479     ResponsivenessTimer& responsivenessTimer = m_process->responsivenessTimer();
2480     if (event.type() == WebEvent::KeyDown)
2481         responsivenessTimer.startWithLazyStop();
2482     else
2483         responsivenessTimer.start();
2484
2485     if (m_keyEventQueue.size() == 1) { // Otherwise, sent from DidReceiveEvent message handler.
2486         LOG(KeyHandling, " UI process: sent keyEvent from handleKeyboardEvent");
2487         m_process->send(Messages::WebPage::KeyEvent(event), m_pageID);
2488     }
2489 }
2490
2491 WebPreferencesStore WebPageProxy::preferencesStore() const
2492 {
2493     if (m_configurationPreferenceValues.isEmpty())
2494         return m_preferences->store();
2495
2496     WebPreferencesStore store = m_preferences->store();
2497     for (const auto& preference : m_configurationPreferenceValues)
2498         store.m_values.set(preference.key, preference.value);
2499
2500     return store;
2501 }
2502
2503 #if ENABLE(NETSCAPE_PLUGIN_API)
2504 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)
2505 {
2506     PageClientProtector protector(pageClient());
2507
2508     MESSAGE_CHECK_URL(m_process, urlString);
2509
2510     URL pluginURL = URL { URL(), urlString };
2511     String newMimeType = mimeType.convertToASCIILowercase();
2512
2513     PluginData::AllowedPluginTypes allowedPluginTypes = allowOnlyApplicationPlugins ? PluginData::OnlyApplicationPlugins : PluginData::AllPlugins;
2514
2515     URL pageURL = URL { URL(), pageURLString };
2516     if (!m_process->processPool().pluginInfoStore().isSupportedPlugin(mimeType, pluginURL, frameURLString, pageURL)) {
2517         reply(0, newMimeType, PluginModuleLoadNormally, { }, true);
2518         return;
2519     }
2520
2521     PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, pluginURL, allowedPluginTypes);
2522     if (!plugin.path) {
2523         reply(0, newMimeType, PluginModuleLoadNormally, { }, false);
2524         return;
2525     }
2526
2527     uint32_t pluginLoadPolicy = PluginInfoStore::defaultLoadPolicyForPlugin(plugin);
2528
2529 #if PLATFORM(COCOA)
2530     auto pluginInformation = createPluginInformationDictionary(plugin, frameURLString, String(), pageURLString, String(), String());
2531 #endif
2532
2533     auto findPluginCompletion = [processType, reply = WTFMove(reply), newMimeType = WTFMove(newMimeType), plugin = WTFMove(plugin)] (uint32_t pluginLoadPolicy, const String& unavailabilityDescription) mutable {
2534         PluginProcessSandboxPolicy pluginProcessSandboxPolicy = PluginProcessSandboxPolicyNormal;
2535         switch (pluginLoadPolicy) {
2536         case PluginModuleLoadNormally:
2537             pluginProcessSandboxPolicy = PluginProcessSandboxPolicyNormal;
2538             break;
2539         case PluginModuleLoadUnsandboxed:
2540             pluginProcessSandboxPolicy = PluginProcessSandboxPolicyUnsandboxed;
2541             break;
2542
2543         case PluginModuleBlockedForSecurity:
2544         case PluginModuleBlockedForCompatibility:
2545             reply(0, newMimeType, pluginLoadPolicy, unavailabilityDescription, false);
2546             return;
2547         }
2548
2549         reply(PluginProcessManager::singleton().pluginProcessToken(plugin, static_cast<PluginProcessType>(processType), pluginProcessSandboxPolicy), newMimeType, pluginLoadPolicy, unavailabilityDescription, false);
2550     };
2551
2552 #if PLATFORM(COCOA)
2553     m_navigationClient->decidePolicyForPluginLoad(*this, static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy), pluginInformation.get(), WTFMove(findPluginCompletion));
2554 #else
2555     findPluginCompletion(pluginLoadPolicy, { });
2556 #endif
2557 }
2558
2559 #endif // ENABLE(NETSCAPE_PLUGIN_API)
2560
2561 #if ENABLE(TOUCH_EVENTS)
2562
2563 static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b)
2564 {
2565     if (static_cast<uintptr_t>(b) > static_cast<uintptr_t>(a))
2566         return b;
2567     return a;
2568 }
2569
2570 void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent)
2571 {
2572 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2573     const EventNames& names = eventNames();
2574     for (auto& touchPoint : touchStartEvent.touchPoints()) {
2575         IntPoint location = touchPoint.location();
2576         auto updateTrackingType = [this, location](TrackingType& trackingType, const AtomString& eventName) {
2577             if (trackingType == TrackingType::Synchronous)
2578                 return;
2579
2580             TrackingType trackingTypeForLocation = m_scrollingCoordinatorProxy->eventTrackingTypeForPoint(eventName, location);
2581
2582             trackingType = mergeTrackingTypes(trackingType, trackingTypeForLocation);
2583         };
2584         updateTrackingType(m_touchAndPointerEventTracking.touchForceChangedTracking, names.touchforcechangeEvent);
2585         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.touchstartEvent);
2586         updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.touchmoveEvent);
2587         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.touchendEvent);
2588         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointeroverEvent);
2589         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointerenterEvent);
2590         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointerdownEvent);
2591         updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.pointermoveEvent);
2592         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointerupEvent);
2593         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointeroutEvent);
2594         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointerleaveEvent);
2595         updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.mousedownEvent);
2596         updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.mousemoveEvent);
2597         updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.mouseupEvent);
2598     }
2599 #else
2600     UNUSED_PARAM(touchStartEvent);
2601     m_touchAndPointerEventTracking.touchForceChangedTracking = TrackingType::Synchronous;
2602     m_touchAndPointerEventTracking.touchStartTracking = TrackingType::Synchronous;
2603     m_touchAndPointerEventTracking.touchMoveTracking = TrackingType::Synchronous;
2604     m_touchAndPointerEventTracking.touchEndTracking = TrackingType::Synchronous;
2605 #endif // ENABLE(ASYNC_SCROLLING)
2606 }
2607
2608 TrackingType WebPageProxy::touchEventTrackingType(const WebTouchEvent& touchStartEvent) const
2609 {
2610     // We send all events if any type is needed, we just do it asynchronously for the types that are not tracked.
2611     //
2612     // Touch events define a sequence with strong dependencies. For example, we can expect
2613     // a TouchMove to only appear after a TouchStart, and the ids of the touch points is consistent between
2614     // the two.
2615     //
2616     // WebCore should not have to set up its state correctly after some events were dismissed.
2617     // For example, we don't want to send a TouchMoved without a TouchPressed.
2618     // We send everything, WebCore updates its internal state and dispatch what is needed to the page.
2619     TrackingType globalTrackingType = m_touchAndPointerEventTracking.isTrackingAnything() ? TrackingType::Asynchronous : TrackingType::NotTracking;
2620
2621     globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchForceChangedTracking);
2622     for (auto& touchPoint : touchStartEvent.touchPoints()) {
2623         switch (touchPoint.state()) {
2624         case WebPlatformTouchPoint::TouchReleased:
2625             globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchEndTracking);
2626             break;
2627         case WebPlatformTouchPoint::TouchPressed:
2628             globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchStartTracking);
2629             break;
2630         case WebPlatformTouchPoint::TouchMoved:
2631         case WebPlatformTouchPoint::TouchStationary:
2632             globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchMoveTracking);
2633             break;
2634         case WebPlatformTouchPoint::TouchCancelled:
2635             globalTrackingType = mergeTrackingTypes(globalTrackingType, TrackingType::Asynchronous);
2636             break;
2637         }
2638     }
2639
2640     return globalTrackingType;
2641 }
2642
2643 #endif
2644
2645 #if ENABLE(MAC_GESTURE_EVENTS)
2646 void WebPageProxy::handleGestureEvent(const NativeWebGestureEvent& event)
2647 {
2648     if (!hasRunningProcess())
2649         return;
2650
2651     m_gestureEventQueue.append(event);
2652     // FIXME: Consider doing some coalescing here.
2653
2654     ResponsivenessTimer& responsivenessTimer = m_process->responsivenessTimer();
2655     if (event.type() == WebEvent::GestureStart || event.type() == WebEvent::GestureChange)
2656         responsivenessTimer.startWithLazyStop();
2657     else
2658         responsivenessTimer.start();
2659
2660     m_process->send(Messages::EventDispatcher::GestureEvent(m_pageID, event), 0);
2661 }
2662 #endif
2663
2664 #if ENABLE(IOS_TOUCH_EVENTS)
2665 void WebPageProxy::handleTouchEventSynchronously(NativeWebTouchEvent& event)
2666 {
2667     if (!hasRunningProcess())
2668         return;
2669
2670     TraceScope scope(SyncTouchEventStart, SyncTouchEventEnd);
2671
2672     updateTouchEventTracking(event);
2673
2674     TrackingType touchEventsTrackingType = touchEventTrackingType(event);
2675     if (touchEventsTrackingType == TrackingType::NotTracking)
2676         return;
2677
2678     if (touchEventsTrackingType == TrackingType::Asynchronous) {
2679         // We can end up here if a native gesture has not started but the event handlers are passive.
2680         //
2681         // The client of WebPageProxy asks the event to be sent synchronously since the touch event
2682         // can prevent a native gesture.
2683         // But, here we know that all events handlers that can handle this events are passive.
2684         // We can use asynchronous dispatch and pretend to the client that the page does nothing with the events.
2685         event.setCanPreventNativeGestures(false);
2686         handleTouchEventAsynchronously(event);
2687         didReceiveEvent(event.type(), false);
2688         return;
2689     }
2690
2691     m_process->responsivenessTimer().start();
2692     bool handled = false;
2693     bool replyReceived = m_process->sendSync(Messages::WebPage::TouchEventSync(event), Messages::WebPage::TouchEventSync::Reply(handled), m_pageID, 1_s, IPC::SendSyncOption::ForceDispatchWhenDestinationIsWaitingForUnboundedSyncReply);
2694     // 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.
2695     if (!replyReceived)
2696         handled = true;
2697     didReceiveEvent(event.type(), handled);
2698     pageClient().doneWithTouchEvent(event, handled);
2699     m_process->responsivenessTimer().stop();
2700
2701     if (event.allTouchPointsAreReleased()) {
2702         m_touchAndPointerEventTracking.reset();
2703         didReleaseAllTouchPoints();
2704     }
2705 }
2706
2707 void WebPageProxy::resetPotentialTapSecurityOrigin()
2708 {
2709     if (!hasRunningProcess())
2710         return;
2711
2712     m_process->send(Messages::WebPage::ResetPotentialTapSecurityOrigin(), m_pageID);
2713 }
2714
2715 void WebPageProxy::handleTouchEventAsynchronously(const NativeWebTouchEvent& event)
2716 {
2717     if (!hasRunningProcess())
2718         return;
2719
2720     TrackingType touchEventsTrackingType = touchEventTrackingType(event);
2721     if (touchEventsTrackingType == TrackingType::NotTracking)
2722         return;
2723
2724     m_process->send(Messages::EventDispatcher::TouchEvent(m_pageID, event), 0);
2725
2726     if (event.allTouchPointsAreReleased()) {
2727         m_touchAndPointerEventTracking.reset();
2728         didReleaseAllTouchPoints();
2729     }
2730 }
2731
2732 #elif ENABLE(TOUCH_EVENTS)
2733 void WebPageProxy::handleTouchEvent(const NativeWebTouchEvent& event)
2734 {
2735     if (!hasRunningProcess())
2736         return;
2737
2738     updateTouchEventTracking(event);
2739
2740     if (touchEventTrackingType(event) == TrackingType::NotTracking)
2741         return;
2742
2743     // If the page is suspended, which should be the case during panning, pinching
2744     // and animation on the page itself (kinetic scrolling, tap to zoom) etc, then
2745     // we do not send any of the events to the page even if is has listeners.
2746     if (!m_isPageSuspended) {
2747         m_touchEventQueue.append(event);
2748         m_process->responsivenessTimer().start();
2749         m_process->send(Messages::WebPage::TouchEvent(event), m_pageID);
2750     } else {
2751         if (m_touchEventQueue.isEmpty()) {
2752             bool isEventHandled = false;
2753             pageClient().doneWithTouchEvent(event, isEventHandled);
2754         } else {
2755             // We attach the incoming events to the newest queued event so that all
2756             // the events are delivered in the correct order when the event is dequed.
2757             QueuedTouchEvents& lastEvent = m_touchEventQueue.last();
2758             lastEvent.deferredTouchEvents.append(event);
2759         }
2760     }
2761
2762     if (event.allTouchPointsAreReleased()) {
2763         m_touchAndPointerEventTracking.reset();
2764         didReleaseAllTouchPoints();
2765     }
2766 }
2767 #endif // ENABLE(TOUCH_EVENTS)
2768
2769 #if ENABLE(POINTER_EVENTS)
2770 void WebPageProxy::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint)
2771 {
2772     m_process->send(Messages::WebPage::CancelPointer(pointerId, documentPoint), m_pageID);
2773 }
2774
2775 void WebPageProxy::touchWithIdentifierWasRemoved(WebCore::PointerID pointerId)
2776 {
2777     m_process->send(Messages::WebPage::TouchWithIdentifierWasRemoved(pointerId), m_pageID);
2778 }
2779 #endif
2780
2781 void WebPageProxy::scrollBy(ScrollDirection direction, ScrollGranularity granularity)
2782 {
2783     if (!hasRunningProcess())
2784         return;
2785
2786     m_process->send(Messages::WebPage::ScrollBy(direction, granularity), m_pageID);
2787 }
2788
2789 void WebPageProxy::centerSelectionInVisibleArea()
2790 {
2791     if (!hasRunningProcess())
2792         return;
2793
2794     m_process->send(Messages::WebPage::CenterSelectionInVisibleArea(), m_pageID);
2795 }
2796
2797 class WebPageProxy::PolicyDecisionSender : public RefCounted<PolicyDecisionSender> {
2798 public:
2799     using SendFunction = CompletionHandler<void(PolicyCheckIdentifier, PolicyAction, uint64_t newNavigationID, DownloadID, Optional<WebsitePoliciesData>)>;
2800
2801     static Ref<PolicyDecisionSender> create(PolicyCheckIdentifier identifier, SendFunction&& sendFunction)
2802     {
2803         return adoptRef(*new PolicyDecisionSender(identifier, WTFMove(sendFunction)));
2804     }
2805
2806     template<typename... Args> void send(Args... args)
2807     {
2808         if (m_sendFunction)
2809             m_sendFunction(m_identifier, std::forward<Args>(args)...);
2810     }
2811 private:
2812     PolicyDecisionSender(PolicyCheckIdentifier identifier, SendFunction sendFunction)
2813         : m_sendFunction(WTFMove(sendFunction))
2814         , m_identifier(identifier)
2815         { }
2816
2817     SendFunction m_sendFunction;
2818     PolicyCheckIdentifier m_identifier;
2819 };
2820
2821 void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, API::Navigation* navigation, ProcessSwapRequestedByClient processSwapRequestedByClient, WebFrameProxy& frame, API::WebsitePolicies* policies, Ref<PolicyDecisionSender>&& sender)
2822 {
2823     Ref<WebsiteDataStore> websiteDataStore = m_websiteDataStore.copyRef();
2824     Optional<WebsitePoliciesData> data;
2825     if (policies) {
2826         data = policies->data();
2827         if (policies->websiteDataStore() && &policies->websiteDataStore()->websiteDataStore() != websiteDataStore.ptr()) {
2828             websiteDataStore = policies->websiteDataStore()->websiteDataStore();
2829             processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
2830         }
2831     }
2832
2833     if (navigation && !navigation->userContentExtensionsEnabled()) {
2834         if (!data)
2835             data = WebsitePoliciesData { };
2836         data->contentBlockersEnabled = false;
2837     }
2838
2839 #if ENABLE(DEVICE_ORIENTATION)
2840     if (navigation && (!data || data->deviceOrientationAndMotionAccessState == WebCore::DeviceOrientationOrMotionPermissionState::Prompt)) {
2841         auto deviceOrientationPermission = websiteDataStore->deviceOrientationAndMotionAccessController().cachedDeviceOrientationPermission(SecurityOriginData::fromURL(navigation->currentRequest().url()));
2842         if (deviceOrientationPermission != WebCore::DeviceOrientationOrMotionPermissionState::Prompt) {
2843             if (!data)
2844                 data = WebsitePoliciesData { };
2845             data->deviceOrientationAndMotionAccessState = deviceOrientationPermission;
2846         }
2847     }
2848 #endif
2849
2850 #if PLATFORM(COCOA)
2851     static const bool forceDownloadFromDownloadAttribute = false;
2852 #else
2853     static const bool forceDownloadFromDownloadAttribute = true;
2854 #endif
2855     if (policyAction == PolicyAction::Use && navigation && (navigation->isSystemPreview() || (forceDownloadFromDownloadAttribute && navigation->shouldPerformDownload())))
2856         policyAction = PolicyAction::Download;
2857
2858     if (policyAction != PolicyAction::Use || !frame.isMainFrame() || !navigation) {
2859         receivedPolicyDecision(policyAction, navigation, WTFMove(data), WTFMove(sender));
2860         return;
2861     }
2862
2863     Ref<WebProcessProxy> sourceProcess = process();
2864     URL sourceURL = URL { URL(), pageLoadState().url() };
2865     if (auto* provisionalPage = provisionalPageProxy()) {
2866         if (provisionalPage->navigationID() == navigation->navigationID()) {
2867             sourceProcess = provisionalPage->process();
2868             sourceURL = provisionalPage->provisionalURL();
2869         }
2870     }
2871
2872     process().processPool().processForNavigation(*this, *navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, WTFMove(websiteDataStore), [this, protectedThis = makeRef(*this), policyAction, navigation = makeRef(*navigation), sourceProcess = sourceProcess.copyRef(),
2873         data = WTFMove(data), sender = WTFMove(sender), processSwapRequestedByClient] (Ref<WebProcessProxy>&& processForNavigation, SuspendedPageProxy* destinationSuspendedPage, const String& reason) mutable {
2874         // If the navigation has been destroyed, then no need to proceed.
2875         if (isClosed() || !navigationState().hasNavigation(navigation->navigationID())) {
2876             receivedPolicyDecision(policyAction, navigation.ptr(), WTFMove(data), WTFMove(sender));
2877             return;
2878         }
2879
2880         bool shouldProcessSwap = processForNavigation.ptr() != sourceProcess.ptr();
2881         if (shouldProcessSwap) {
2882             policyAction = PolicyAction::StopAllLoads;
2883             RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "decidePolicyForNavigationAction, swapping process %i with process %i for navigation, reason: %{public}s", processIdentifier(), processForNavigation->processIdentifier(), reason.utf8().data());
2884             LOG(ProcessSwapping, "(ProcessSwapping) Switching from process %i to new process (%i) for navigation %" PRIu64 " '%s'", processIdentifier(), processForNavigation->processIdentifier(), navigation->navigationID(), navigation->loggingString());
2885         } else
2886             RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "decidePolicyForNavigationAction: keep using process %i for navigation, reason: %{public}s", processIdentifier(), reason.utf8().data());
2887
2888         if (shouldProcessSwap) {
2889             // FIXME: Architecturally we do not currently support multiple WebPage's with the same ID in a given WebProcess.
2890             // In the case where the destination WebProcess has a SuspendedPageProxy for this WebPage, we should have thrown
2891             // it away to support WebProcess re-use.
2892             ASSERT(destinationSuspendedPage || !process().processPool().hasSuspendedPageFor(processForNavigation, *this));
2893
2894             auto suspendedPage = destinationSuspendedPage ? process().processPool().takeSuspendedPage(*destinationSuspendedPage) : nullptr;
2895             if (suspendedPage && suspendedPage->pageIsClosedOrClosing())
2896                 suspendedPage = nullptr;
2897
2898             continueNavigationInNewProcess(navigation, WTFMove(suspendedPage), WTFMove(processForNavigation), processSwapRequestedByClient, WTFMove(data));
2899         }
2900
2901         receivedPolicyDecision(policyAction, navigation.ptr(), shouldProcessSwap ? WTF::nullopt : WTFMove(data), WTFMove(sender), shouldProcessSwap ? WillContinueLoadInNewProcess::Yes : WillContinueLoadInNewProcess::No);
2902     });
2903 }
2904
2905 void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, Optional<WebsitePoliciesData>&& websitePolicies, Ref<PolicyDecisionSender>&& sender, WillContinueLoadInNewProcess willContinueLoadInNewProcess)
2906 {
2907     if (!hasRunningProcess()) {
2908         sender->send(PolicyAction::Ignore, 0, DownloadID(), WTF::nullopt);
2909         return;
2910     }
2911
2912     auto transaction = m_pageLoadState.transaction();
2913
2914     if (action == PolicyAction::Ignore && willContinueLoadInNewProcess == WillContinueLoadInNewProcess::No && navigation && navigation->navigationID() == m_pageLoadState.pendingAPIRequest().navigationID)
2915         m_pageLoadState.clearPendingAPIRequest(transaction);
2916
2917     DownloadID downloadID = { };
2918     if (action == PolicyAction::Download) {
2919         // Create a download proxy.
2920         auto& download = m_process->processPool().createDownloadProxy(m_decidePolicyForResponseRequest, this);
2921         if (navigation) {
2922             download.setWasUserInitiated(navigation->wasUserInitiated());
2923             download.setRedirectChain(navigation->takeRedirectChain());
2924         }
2925
2926         downloadID = download.downloadID();
2927         handleDownloadRequest(download);
2928         m_decidePolicyForResponseRequest = { };
2929     }
2930
2931     sender->send(action, navigation ? navigation->navigationID() : 0, downloadID, WTFMove(websitePolicies));
2932 }
2933
2934 void WebPageProxy::commitProvisionalPage(FrameIdentifier 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)
2935 {
2936     ASSERT(m_provisionalPage);
2937     RELEASE_LOG_IF_ALLOWED(Loading, "commitProvisionalPage: previousPID = %i, newPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_provisionalPage->process().processIdentifier(), m_pageID.toUInt64());
2938
2939     Optional<FrameIdentifier> mainFrameIDInPreviousProcess = m_mainFrame ? makeOptional(m_mainFrame->frameID()) : WTF::nullopt;
2940
2941     ASSERT(m_process.ptr() != &m_provisionalPage->process());
2942
2943     auto shouldDelayClosingUntilEnteringAcceleratedCompositingMode = ShouldDelayClosingUntilEnteringAcceleratedCompositingMode::No;
2944 #if PLATFORM(MAC)
2945     // 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
2946     // entered accelerated compositing for the new page or we will flash on navigation.
2947     if (drawingArea()->type() == DrawingAreaTypeTiledCoreAnimation)
2948         shouldDelayClosingUntilEnteringAcceleratedCompositingMode = ShouldDelayClosingUntilEnteringAcceleratedCompositingMode::Yes;
2949 #endif
2950
2951     processDidTerminate(ProcessTerminationReason::NavigationSwap);
2952
2953     m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
2954     auto* navigation = navigationState().navigation(m_provisionalPage->navigationID());
2955     bool didSuspendPreviousPage = navigation ? suspendCurrentPageIfPossible(*navigation, mainFrameIDInPreviousProcess, m_provisionalPage->processSwapRequestedByClient(), shouldDelayClosingUntilEnteringAcceleratedCompositingMode) : false;
2956     m_process->removeWebPage(*this, m_websiteDataStore.ptr() == &m_provisionalPage->process().websiteDataStore() ? WebProcessProxy::EndsUsingDataStore::No : WebProcessProxy::EndsUsingDataStore::Yes);
2957
2958     // There is no way we'll be able to return to the page in the previous page so close it.
2959     if (!didSuspendPreviousPage)
2960         m_process->send(Messages::WebPage::Close(), pageID());
2961
2962     swapToWebProcess(m_provisionalPage->process(), m_provisionalPage->takeDrawingArea(), m_provisionalPage->mainFrame());
2963
2964 #if PLATFORM(COCOA)
2965     auto accessibilityToken = m_provisionalPage->takeAccessibilityToken();
2966     if (!accessibilityToken.isEmpty())
2967         registerWebProcessAccessibilityToken({ accessibilityToken.data(), accessibilityToken.size() });
2968 #endif
2969
2970     didCommitLoadForFrame(frameID, navigationID, mimeType, frameHasCustomContentProvider, frameLoadType, certificateInfo, containsPluginDocument, forcedHasInsecureContent, userData);
2971
2972     m_provisionalPage = nullptr;
2973 }
2974
2975 void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, std::unique_ptr<SuspendedPageProxy>&& suspendedPageProxy, Ref<WebProcessProxy>&& newProcess, ProcessSwapRequestedByClient processSwapRequestedByClient, Optional<WebsitePoliciesData>&& websitePolicies)
2976 {
2977     RELEASE_LOG_IF_ALLOWED(Loading, "continueNavigationInNewProcess: webPID = %i, pageID = %" PRIu64 ", newProcessPID = %i, hasSuspendedPage = %i", m_process->processIdentifier(), m_pageID.toUInt64(), newProcess->processIdentifier(), !!suspendedPageProxy);
2978     LOG(Loading, "Continuing navigation %" PRIu64 " '%s' in a new web process", navigation.navigationID(), navigation.loggingString());
2979
2980     if (m_provisionalPage) {
2981         RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "continueNavigationInNewProcess: There is already a pending provisional load, cancelling it (provisonalNavigationID: %llu, navigationID: %llu)", m_provisionalPage->navigationID(), navigation.navigationID());
2982         if (m_provisionalPage->navigationID() != navigation.navigationID())
2983             m_provisionalPage->cancel();
2984         m_provisionalPage = nullptr;
2985     }
2986
2987     m_provisionalPage = std::make_unique<ProvisionalPageProxy>(*this, newProcess.copyRef(), WTFMove(suspendedPageProxy), navigation.navigationID(), navigation.currentRequestIsRedirect(), navigation.currentRequest(), processSwapRequestedByClient);
2988
2989     if (auto* item = navigation.targetItem()) {
2990         LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data());
2991
2992         auto transaction = m_pageLoadState.transaction();
2993         m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), item->url() });
2994
2995         m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies));
2996         return;
2997     }
2998
2999     if (m_backForwardList->currentItem() && (navigation.lockBackForwardList() == LockBackForwardList::Yes || navigation.lockHistory() == LockHistory::Yes)) {
3000         // 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
3001         // it instead of creating a new one.
3002         newProcess->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()), m_pageID);
3003     }
3004
3005     // FIXME: Work out timing of responding with the last policy delegate, etc
3006     ASSERT(!navigation.currentRequest().isEmpty());
3007     if (auto& substituteData = navigation.substituteData())
3008         m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), WTFMove(websitePolicies));
3009     else
3010         m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation.currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, WTFMove(websitePolicies));
3011 }
3012
3013 bool WebPageProxy::isPageOpenedByDOMShowingInitialEmptyDocument() const
3014 {
3015     return openedByDOM() && !hasCommittedAnyProvisionalLoads();
3016 }
3017
3018 // MSVC gives a redeclaration error if noreturn is used on the definition and not the declaration, while
3019 // Cocoa tests segfault if it is moved to the declaration site (even if we move the definition with it!).
3020 #if !COMPILER(MSVC)
3021 NO_RETURN_DUE_TO_ASSERT
3022 #endif
3023 void WebPageProxy::didFailToSuspendAfterProcessSwap()
3024 {
3025     // Only the SuspendedPageProxy should be getting this call.
3026     ASSERT_NOT_REACHED();
3027 }
3028
3029 #if !COMPILER(MSVC)
3030 NO_RETURN_DUE_TO_ASSERT
3031 #endif
3032 void WebPageProxy::didSuspendAfterProcessSwap()
3033 {
3034     // Only the SuspendedPageProxy should be getting this call.
3035     ASSERT_NOT_REACHED();
3036 }
3037
3038 void WebPageProxy::setUserAgent(String&& userAgent)
3039 {
3040     if (m_userAgent == userAgent)
3041         return;
3042     m_userAgent = WTFMove(userAgent);
3043
3044 #if ENABLE(SERVICE_WORKER)
3045     // We update the service worker there at the moment to be sure we use values used by actual web pages.
3046     // FIXME: Refactor this when we have a better User-Agent story.
3047     process().processPool().updateServiceWorkerUserAgent(m_userAgent);
3048 #endif
3049
3050     if (!hasRunningProcess())
3051         return;
3052     m_process->send(Messages::WebPage::SetUserAgent(m_userAgent), m_pageID);
3053 }
3054
3055 void WebPageProxy::setApplicationNameForUserAgent(const String& applicationName)
3056 {
3057     if (m_applicationNameForUserAgent == applicationName)
3058         return;
3059
3060     m_applicationNameForUserAgent = applicationName;
3061     if (!m_customUserAgent.isEmpty())
3062         return;
3063
3064     setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3065 }
3066
3067 void WebPageProxy::setCustomUserAgent(const String& customUserAgent)
3068 {
3069     if (m_customUserAgent == customUserAgent)
3070         return;
3071
3072     m_customUserAgent = customUserAgent;
3073
3074     if (m_customUserAgent.isEmpty()) {
3075         setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3076         return;
3077     }
3078
3079     setUserAgent(String { m_customUserAgent });
3080 }
3081
3082 void WebPageProxy::resumeActiveDOMObjectsAndAnimations()
3083 {
3084     if (!hasRunningProcess() || !m_isPageSuspended)
3085         return;
3086
3087     m_isPageSuspended = false;
3088
3089     m_process->send(Messages::WebPage::ResumeActiveDOMObjectsAndAnimations(), m_pageID);
3090 }
3091
3092 void WebPageProxy::suspendActiveDOMObjectsAndAnimations()
3093 {
3094     if (!hasRunningProcess() || m_isPageSuspended)
3095         return;
3096
3097     m_isPageSuspended = true;
3098
3099     m_process->send(Messages::WebPage::SuspendActiveDOMObjectsAndAnimations(), m_pageID);
3100 }
3101
3102 bool WebPageProxy::supportsTextEncoding() const
3103 {
3104     // FIXME (118840): We should probably only support this for text documents, not all non-image documents.
3105     return m_mainFrame && !m_mainFrame->isDisplayingStandaloneImageDocument();
3106 }
3107
3108 void WebPageProxy::setCustomTextEncodingName(const String& encodingName)
3109 {
3110     if (m_customTextEncodingName == encodingName)
3111         return;
3112     m_customTextEncodingName = encodingName;
3113
3114     if (!hasRunningProcess())
3115         return;
3116     m_process->send(Messages::WebPage::SetCustomTextEncodingName(encodingName), m_pageID);
3117 }
3118
3119 SessionState WebPageProxy::sessionState(WTF::Function<bool (WebBackForwardListItem&)>&& filter) const
3120 {
3121     SessionState sessionState;
3122
3123     sessionState.backForwardListState = m_backForwardList->backForwardListState(WTFMove(filter));
3124
3125     String provisionalURLString = m_pageLoadState.pendingAPIRequestURL();
3126     if (provisionalURLString.isEmpty())
3127         provisionalURLString = m_pageLoadState.provisionalURL();
3128
3129     if (!provisionalURLString.isEmpty())
3130         sessionState.provisionalURL = URL(URL(), provisionalURLString);
3131
3132     sessionState.renderTreeSize = renderTreeSize();
3133     return sessionState;
3134 }
3135
3136 RefPtr<API::Navigation> WebPageProxy::restoreFromSessionState(SessionState sessionState, bool navigate)
3137 {
3138     RELEASE_LOG_IF_ALLOWED(Loading, "restoreFromSessionState: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID.toUInt64());
3139
3140     m_sessionRestorationRenderTreeSize = 0;
3141     m_hitRenderTreeSizeThreshold = false;
3142
3143     bool hasBackForwardList = !!sessionState.backForwardListState.currentIndex;
3144
3145     if (hasBackForwardList) {
3146         // If there isn't a running process yet the RestoreSession message below is just ignored, and
3147         // session is restored when the web process is created via creation parameters which is not
3148         // considered an API request. So, we launch the initial process here before restoring the
3149         // session to ensure the session is restored in the web process via RestoreSession IPC message
3150         // which is considered an API request. See https://bugs.webkit.org/show_bug.cgi?id=198561.
3151         launchInitialProcessIfNecessary();
3152
3153         m_backForwardList->restoreFromState(WTFMove(sessionState.backForwardListState));
3154         process().send(Messages::WebPage::RestoreSession(m_backForwardList->itemStates()), m_pageID);
3155
3156         auto transaction = m_pageLoadState.transaction();
3157         m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
3158         m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
3159
3160         // The back / forward list was restored from a sessionState so we don't want to snapshot the current
3161         // page when navigating away. Suppress navigation snapshotting until the next load has committed
3162         suppressNextAutomaticNavigationSnapshot();
3163     }
3164
3165     // FIXME: Navigating should be separate from state restoration.
3166     if (navigate) {
3167         m_sessionRestorationRenderTreeSize = sessionState.renderTreeSize;
3168         if (!m_sessionRestorationRenderTreeSize)
3169             m_hitRenderTreeSizeThreshold = true; // If we didn't get data on renderTreeSize, just don't fire the milestone.
3170
3171         if (!sessionState.provisionalURL.isNull())
3172             return loadRequest(sessionState.provisionalURL);
3173
3174         if (hasBackForwardList) {
3175             if (WebBackForwardListItem* item = m_backForwardList->currentItem())
3176                 return goToBackForwardItem(*item);
3177         }
3178     }
3179
3180     return nullptr;
3181 }
3182
3183 bool WebPageProxy::supportsTextZoom() const
3184 {
3185     // FIXME (118840): This should also return false for standalone media and plug-in documents.
3186     if (!m_mainFrame || m_mainFrame->isDisplayingStandaloneImageDocument())
3187         return false;
3188
3189     return true;
3190 }
3191  
3192 void WebPageProxy::setTextZoomFactor(double zoomFactor)
3193 {
3194     if (m_textZoomFactor == zoomFactor)
3195         return;
3196
3197     m_textZoomFactor = zoomFactor;
3198
3199     if (!hasRunningProcess())
3200         return;
3201
3202     m_process->send(Messages::WebPage::SetTextZoomFactor(m_textZoomFactor), m_pageID); 
3203 }
3204
3205 void WebPageProxy::setPageZoomFactor(double zoomFactor)
3206 {
3207     if (m_pageZoomFactor == zoomFactor)
3208         return;
3209
3210     closeOverlayedViews();
3211
3212     m_pageZoomFactor = zoomFactor;
3213
3214     if (!hasRunningProcess())
3215         return;
3216
3217     m_process->send(Messages::WebPage::SetPageZoomFactor(m_pageZoomFactor), m_pageID); 
3218 }
3219
3220 void WebPageProxy::setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor)
3221 {
3222     if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
3223         return;
3224
3225     closeOverlayedViews();
3226
3227     m_pageZoomFactor = pageZoomFactor;
3228     m_textZoomFactor = textZoomFactor;
3229
3230     if (!hasRunningProcess())
3231         return;
3232
3233     m_process->send(Messages::WebPage::SetPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor), m_pageID); 
3234 }
3235
3236 double WebPageProxy::pageZoomFactor() const
3237 {
3238     // Zoom factor for non-PDF pages persists across page loads. We maintain a separate member variable for PDF
3239     // zoom which ensures that we don't use the PDF zoom for a normal page.
3240     if (m_mainFramePluginHandlesPageScaleGesture)
3241         return m_pluginZoomFactor;
3242     return m_pageZoomFactor;
3243 }
3244
3245 double WebPageProxy::pageScaleFactor() const
3246 {
3247     // PDF documents use zoom and scale factors to size themselves appropriately in the window. We store them
3248     // separately but decide which to return based on the main frame.
3249     if (m_mainFramePluginHandlesPageScaleGesture)
3250         return m_pluginScaleFactor;
3251     return m_pageScaleFactor;
3252 }
3253
3254 void WebPageProxy::scalePage(double scale, const IntPoint& origin)
3255 {
3256     ASSERT(scale > 0);
3257
3258     m_pageScaleFactor = scale;
3259
3260     if (!hasRunningProcess())
3261         return;
3262
3263     m_process->send(Messages::WebPage::ScalePage(scale, origin), m_pageID);
3264 }
3265
3266 void WebPageProxy::scalePageInViewCoordinates(double scale, const IntPoint& centerInViewCoordinates)
3267 {
3268     ASSERT(scale > 0);
3269
3270     m_pageScaleFactor = scale;
3271
3272     if (!hasRunningProcess())
3273         return;
3274
3275     m_process->send(Messages::WebPage::ScalePageInViewCoordinates(scale, centerInViewCoordinates), m_pageID);
3276 }
3277
3278 void WebPageProxy::scaleView(double scale)
3279 {
3280     ASSERT(scale > 0);
3281
3282     m_viewScaleFactor = scale;
3283
3284     if (!hasRunningProcess())
3285         return;
3286
3287     m_process->send(Messages::WebPage::ScaleView(scale), m_pageID);
3288 }
3289
3290 void WebPageProxy::setIntrinsicDeviceScaleFactor(float scaleFactor)
3291 {
3292     if (m_intrinsicDeviceScaleFactor == scaleFactor)
3293         return;
3294
3295     m_intrinsicDeviceScaleFactor = scaleFactor;
3296
3297     if (m_drawingArea)
3298         m_drawingArea->deviceScaleFactorDidChange();
3299 }
3300
3301 void WebPageProxy::windowScreenDidChange(PlatformDisplayID displayID)
3302 {
3303     if (!hasRunningProcess())
3304         return;
3305
3306     m_process->send(Messages::WebPage::WindowScreenDidChange(displayID), m_pageID);
3307 }
3308
3309 float WebPageProxy::deviceScaleFactor() const
3310 {
3311     return m_customDeviceScaleFactor.valueOr(m_intrinsicDeviceScaleFactor);
3312 }
3313
3314 void WebPageProxy::setCustomDeviceScaleFactor(float customScaleFactor)
3315 {
3316     // FIXME: Remove this once we bump cairo requirements to support HiDPI.
3317     // https://bugs.webkit.org/show_bug.cgi?id=133378
3318 #if USE(CAIRO) && !HAVE(CAIRO_SURFACE_SET_DEVICE_SCALE)
3319     return;
3320 #endif
3321
3322     if (m_customDeviceScaleFactor && m_customDeviceScaleFactor.value() == customScaleFactor)
3323         return;
3324
3325     float oldScaleFactor = deviceScaleFactor();
3326
3327     // A value of 0 clears the customScaleFactor.
3328     if (customScaleFactor)
3329         m_customDeviceScaleFactor = customScaleFactor;
3330     else
3331         m_customDeviceScaleFactor = WTF::nullopt;
3332
3333     if (!hasRunningProcess())
3334         return;
3335
3336     if (deviceScaleFactor() != oldScaleFactor)
3337         m_drawingArea->deviceScaleFactorDidChange();
3338 }
3339
3340 void WebPageProxy::accessibilitySettingsDidChange()
3341 {
3342     if (!hasRunningProcess())
3343         return;
3344
3345     m_process->send(Messages::WebPage::AccessibilitySettingsDidChange(), m_pageID);
3346 }
3347
3348 void WebPageProxy::setUseFixedLayout(bool fixed)
3349 {
3350     // This check is fine as the value is initialized in the web
3351     // process as part of the creation parameters.
3352     if (fixed == m_useFixedLayout)
3353         return;
3354
3355     m_useFixedLayout = fixed;
3356     if (!fixed)
3357         m_fixedLayoutSize = IntSize();
3358
3359     if (!hasRunningProcess())
3360         return;
3361
3362     m_process->send(Messages::WebPage::SetUseFixedLayout(fixed), m_pageID);
3363 }
3364
3365 void WebPageProxy::setFixedLayoutSize(const IntSize& size)
3366 {
3367     if (size == m_fixedLayoutSize)
3368         return;
3369
3370     m_fixedLayoutSize = size;
3371
3372     if (!hasRunningProcess())
3373         return;
3374
3375     m_process->send(Messages::WebPage::SetFixedLayoutSize(size), m_pageID);
3376 }
3377
3378 void WebPageProxy::setAlwaysShowsHorizontalScroller(bool alwaysShowsHorizontalScroller)
3379 {
3380     if (alwaysShowsHorizontalScroller == m_alwaysShowsHorizontalScroller)
3381         return;
3382
3383     m_alwaysShowsHorizontalScroller = alwaysShowsHorizontalScroller;
3384
3385     if (!hasRunningProcess())
3386         return;
3387
3388     m_process->send(Messages::WebPage::SetAlwaysShowsHorizontalScroller(alwaysShowsHorizontalScroller), m_pageID);
3389 }
3390
3391 void WebPageProxy::setAlwaysShowsVerticalScroller(bool alwaysShowsVerticalScroller)
3392 {
3393     if (alwaysShowsVerticalScroller == m_alwaysShowsVerticalScroller)
3394         return;
3395
3396     m_alwaysShowsVerticalScroller = alwaysShowsVerticalScroller;
3397
3398     if (!hasRunningProcess())
3399         return;
3400
3401     m_process->send(Messages::WebPage::SetAlwaysShowsVerticalScroller(alwaysShowsVerticalScroller), m_pageID);
3402 }
3403
3404 void WebPageProxy::listenForLayoutMilestones(OptionSet<WebCore::LayoutMilestone> milestones)
3405 {    
3406     if (milestones == m_observedLayoutMilestones)
3407         return;
3408
3409     m_observedLayoutMilestones = milestones;
3410
3411     if (!hasRunningProcess())
3412         return;
3413
3414     m_process->send(Messages::WebPage::ListenForLayoutMilestones(milestones), m_pageID);
3415 }
3416
3417 void WebPageProxy::setSuppressScrollbarAnimations(bool suppressAnimations)
3418 {
3419     if (suppressAnimations == m_suppressScrollbarAnimations)
3420         return;
3421
3422     m_suppressScrollbarAnimations = suppressAnimations;
3423
3424     if (!hasRunningProcess())
3425         return;
3426
3427     m_process->send(Messages::WebPage::SetSuppressScrollbarAnimations(suppressAnimations), m_pageID);
3428 }
3429
3430 bool WebPageProxy::rubberBandsAtLeft() const
3431 {
3432     return m_rubberBandsAtLeft;
3433 }
3434
3435 void WebPageProxy::setRubberBandsAtLeft(bool rubberBandsAtLeft)
3436 {
3437     m_rubberBandsAtLeft = rubberBandsAtLeft;
3438 }
3439
3440 bool WebPageProxy::rubberBandsAtRight() const
3441 {
3442     return m_rubberBandsAtRight;
3443 }
3444
3445 void WebPageProxy::setRubberBandsAtRight(bool rubberBandsAtRight)
3446 {
3447     m_rubberBandsAtRight = rubberBandsAtRight;
3448 }
3449
3450 bool WebPageProxy::rubberBandsAtTop() const
3451 {
3452     return m_rubberBandsAtTop;
3453 }
3454
3455 void WebPageProxy::setRubberBandsAtTop(bool rubberBandsAtTop)
3456 {
3457     m_rubberBandsAtTop = rubberBandsAtTop;
3458 }
3459
3460 bool WebPageProxy::rubberBandsAtBottom() const
3461 {
3462     return m_rubberBandsAtBottom;
3463 }
3464
3465 void WebPageProxy::setRubberBandsAtBottom(bool rubberBandsAtBottom)
3466 {
3467     m_rubberBandsAtBottom = rubberBandsAtBottom;
3468 }
3469     
3470 void WebPageProxy::setEnableVerticalRubberBanding(bool enableVerticalRubberBanding)
3471 {
3472     if (enableVerticalRubberBanding == m_enableVerticalRubberBanding)
3473         return;
3474
3475     m_enableVerticalRubberBanding = enableVerticalRubberBanding;
3476
3477     if (!hasRunningProcess())
3478         return;
3479     m_process->send(Messages::WebPage::SetEnableVerticalRubberBanding(enableVerticalRubberBanding), m_pageID);
3480 }
3481     
3482 bool WebPageProxy::verticalRubberBandingIsEnabled() const
3483 {
3484     return m_enableVerticalRubberBanding;
3485 }
3486     
3487 void WebPageProxy::setEnableHorizontalRubberBanding(bool enableHorizontalRubberBanding)
3488 {
3489     if (enableHorizontalRubberBanding == m_enableHorizontalRubberBanding)
3490         return;
3491
3492     m_enableHorizontalRubberBanding = enableHorizontalRubberBanding;
3493
3494     if (!hasRunningProcess())
3495         return;
3496     m_process->send(Messages::WebPage::SetEnableHorizontalRubberBanding(enableHorizontalRubberBanding), m_pageID);
3497 }
3498     
3499 bool WebPageProxy::horizontalRubberBandingIsEnabled() const
3500 {
3501     return m_enableHorizontalRubberBanding;
3502 }
3503
3504 void WebPageProxy::setBackgroundExtendsBeyondPage(bool backgroundExtendsBeyondPage)
3505 {
3506     if (backgroundExtendsBeyondPage == m_backgroundExtendsBeyondPage)
3507         return;
3508
3509     m_backgroundExtendsBeyondPage = backgroundExtendsBeyondPage;
3510
3511     if (!hasRunningProcess())
3512         return;
3513     m_process->send(Messages::WebPage::SetBackgroundExtendsBeyondPage(backgroundExtendsBeyondPage), m_pageID);
3514 }
3515
3516 bool WebPageProxy::backgroundExtendsBeyondPage() const
3517 {
3518     return m_backgroundExtendsBeyondPage;
3519 }
3520
3521 void WebPageProxy::setPaginationMode(WebCore::Pagination::Mode mode)
3522 {
3523     if (mode == m_paginationMode)
3524         return;
3525
3526     m_paginationMode = mode;
3527
3528     if (!hasRunningProcess())
3529         return;
3530     m_process->send(Messages::WebPage::SetPaginationMode(mode), m_pageID);
3531 }
3532
3533 void WebPageProxy::setPaginationBehavesLikeColumns(bool behavesLikeColumns)
3534 {
3535     if (behavesLikeColumns == m_paginationBehavesLikeColumns)
3536         return;
3537
3538     m_paginationBehavesLikeColumns = behavesLikeColumns;
3539
3540     if (!hasRunningProcess())
3541         return;
3542     m_process->send(Messages::WebPage::SetPaginationBehavesLikeColumns(behavesLikeColumns), m_pageID);
3543 }
3544
3545 void WebPageProxy::setPageLength(double pageLength)
3546 {
3547     if (pageLength == m_pageLength)
3548         return;
3549
3550     m_pageLength = pageLength;
3551
3552     if (!hasRunningProcess())
3553         return;
3554     m_process->send(Messages::WebPage::SetPageLength(pageLength), m_pageID);
3555 }
3556
3557 void WebPageProxy::setGapBetweenPages(double gap)
3558 {
3559     if (gap == m_gapBetweenPages)
3560         return;
3561
3562     m_gapBetweenPages = gap;
3563
3564     if (!hasRunningProcess())
3565         return;
3566     m_process->send(Messages::WebPage::SetGapBetweenPages(gap), m_pageID);
3567 }
3568
3569 void WebPageProxy::setPaginationLineGridEnabled(bool lineGridEnabled)
3570 {
3571     if (lineGridEnabled == m_paginationLineGridEnabled)
3572         return;
3573     
3574     m_paginationLineGridEnabled = lineGridEnabled;
3575     
3576     if (!hasRunningProcess())
3577         return;
3578     m_process->send(Messages::WebPage::SetPaginationLineGridEnabled(lineGridEnabled), m_pageID);
3579 }
3580
3581 void WebPageProxy::pageScaleFactorDidChange(double scaleFactor)
3582 {
3583     m_pageScaleFactor = scaleFactor;
3584 }
3585
3586 void WebPageProxy::pluginScaleFactorDidChange(double pluginScaleFactor)
3587 {
3588     m_pluginScaleFactor = pluginScaleFactor;
3589 }
3590
3591 void WebPageProxy::pluginZoomFactorDidChange(double pluginZoomFactor)
3592 {
3593     m_pluginZoomFactor = pluginZoomFactor;
3594 }
3595
3596 void WebPageProxy::findStringMatches(const String& string, FindOptions options, unsigned maxMatchCount)
3597 {
3598     if (string.isEmpty()) {
3599         didFindStringMatches(string, Vector<Vector<WebCore::IntRect>> (), 0);
3600         return;
3601     }
3602
3603     m_process->send(Messages::WebPage::FindStringMatches(string, options, maxMatchCount), m_pageID);
3604 }
3605
3606 void WebPageProxy::findString(const String& string, FindOptions options, unsigned maxMatchCount)
3607 {
3608     m_process->send(Messages::WebPage::FindString(string, options, maxMatchCount), m_pageID);
3609 }
3610
3611 void WebPageProxy::getImageForFindMatch(int32_t matchIndex)
3612 {
3613     m_process->send(Messages::WebPage::GetImageForFindMatch(matchIndex), m_pageID);
3614 }
3615
3616 void WebPageProxy::selectFindMatch(int32_t matchIndex)
3617 {
3618     m_process->send(Messages::WebPage::SelectFindMatch(matchIndex), m_pageID);
3619 }
3620
3621 void WebPageProxy::indicateFindMatch(int32_t matchIndex)
3622 {
3623     m_process->send(Messages::WebPage::IndicateFindMatch(matchIndex), m_pageID);
3624 }
3625
3626 void WebPageProxy::hideFindUI()
3627 {
3628     m_process->send(Messages::WebPage::HideFindUI(), m_pageID);
3629 }