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