1/*
2 * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Intel Corporation. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "WebPageProxy.h"
29
30#include "APIArray.h"
31#include "APIAttachment.h"
32#include "APIContextMenuClient.h"
33#include "APIFindClient.h"
34#include "APIFindMatchesClient.h"
35#include "APIFormClient.h"
36#include "APIFrameInfo.h"
37#include "APIFullscreenClient.h"
38#include "APIGeometry.h"
39#include "APIHistoryClient.h"
40#include "APIHitTestResult.h"
41#include "APIIconLoadingClient.h"
42#include "APILegacyContextHistoryClient.h"
43#include "APILoaderClient.h"
44#include "APINavigation.h"
45#include "APINavigationAction.h"
46#include "APINavigationClient.h"
47#include "APINavigationResponse.h"
48#include "APIOpenPanelParameters.h"
49#include "APIPageConfiguration.h"
50#include "APIPolicyClient.h"
51#include "APISecurityOrigin.h"
52#include "APIUIClient.h"
53#include "APIURLRequest.h"
54#include "APIWebsitePolicies.h"
55#include "AuthenticationChallengeProxy.h"
56#include "AuthenticationDecisionListener.h"
57#include "DataReference.h"
58#include "DownloadProxy.h"
59#include "DrawingAreaMessages.h"
60#include "DrawingAreaProxy.h"
61#include "EventDispatcherMessages.h"
62#include "FormDataReference.h"
63#include "FrameInfoData.h"
64#include "LoadParameters.h"
65#include "Logging.h"
66#include "NativeWebGestureEvent.h"
67#include "NativeWebKeyboardEvent.h"
68#include "NativeWebMouseEvent.h"
69#include "NativeWebWheelEvent.h"
70#include "NavigationActionData.h"
71#include "NetworkProcessMessages.h"
72#include "NetworkProcessProxy.h"
73#include "NotificationPermissionRequest.h"
74#include "NotificationPermissionRequestManager.h"
75#include "OptionalCallbackID.h"
76#include "PageClient.h"
77#include "PluginInformation.h"
78#include "PluginProcessManager.h"
79#include "PrintInfo.h"
80#include "ProvisionalPageProxy.h"
81#include "SafeBrowsingWarning.h"
82#include "ShareSheetCallbackID.h"
83#include "SharedBufferDataReference.h"
84#include "SyntheticEditingCommandType.h"
85#include "TextChecker.h"
86#include "TextCheckerState.h"
87#include "TextInputContext.h"
88#include "UIMessagePortChannelProvider.h"
89#include "URLSchemeTaskParameters.h"
90#include "UndoOrRedo.h"
91#include "UserMediaPermissionRequestProxy.h"
92#include "UserMediaProcessManager.h"
93#include "WKContextPrivate.h"
94#include "WebAutomationSession.h"
95#include "WebBackForwardList.h"
96#include "WebBackForwardListItem.h"
97#include "WebCertificateInfo.h"
98#include "WebContextMenuItem.h"
99#include "WebContextMenuProxy.h"
100#include "WebCoreArgumentCoders.h"
101#include "WebEditCommandProxy.h"
102#include "WebEvent.h"
103#include "WebEventConversion.h"
104#include "WebFramePolicyListenerProxy.h"
105#include "WebFullScreenManagerProxy.h"
106#include "WebFullScreenManagerProxyMessages.h"
107#include "WebImage.h"
108#include "WebInspectorProxy.h"
109#include "WebInspectorUtilities.h"
110#include "WebNavigationDataStore.h"
111#include "WebNavigationState.h"
112#include "WebNotificationManagerProxy.h"
113#include "WebOpenPanelResultListenerProxy.h"
114#include "WebPageCreationParameters.h"
115#include "WebPageDebuggable.h"
116#include "WebPageGroup.h"
117#include "WebPageGroupData.h"
118#include "WebPageInspectorController.h"
119#include "WebPageMessages.h"
120#include "WebPageProxyMessages.h"
121#include "WebPaymentCoordinatorProxy.h"
122#include "WebPopupItem.h"
123#include "WebPopupMenuProxy.h"
124#include "WebPreferences.h"
125#include "WebPreferencesKeys.h"
126#include "WebProcessMessages.h"
127#include "WebProcessPool.h"
128#include "WebProcessProxy.h"
129#include "WebProtectionSpace.h"
130#include "WebResourceLoadStatisticsStore.h"
131#include "WebURLSchemeHandler.h"
132#include "WebUserContentControllerProxy.h"
133#include "WebViewDidMoveToWindowObserver.h"
134#include "WebsiteDataStore.h"
135#include <WebCore/AdClickAttribution.h>
136#include <WebCore/BitmapImage.h>
137#include <WebCore/DOMPasteAccess.h>
138#include <WebCore/DeprecatedGlobalSettings.h>
139#include <WebCore/DiagnosticLoggingClient.h>
140#include <WebCore/DiagnosticLoggingKeys.h>
141#include <WebCore/DragController.h>
142#include <WebCore/DragData.h>
143#include <WebCore/EventNames.h>
144#include <WebCore/FloatRect.h>
145#include <WebCore/FocusDirection.h>
146#include <WebCore/FontAttributeChanges.h>
147#include <WebCore/FrameLoader.h>
148#include <WebCore/GlobalFrameIdentifier.h>
149#include <WebCore/GlobalWindowIdentifier.h>
150#include <WebCore/JSDOMBinding.h>
151#include <WebCore/JSDOMExceptionHandling.h>
152#include <WebCore/LengthBox.h>
153#include <WebCore/MIMETypeRegistry.h>
154#include <WebCore/MediaStreamRequest.h>
155#include <WebCore/PerformanceLoggingClient.h>
156#include <WebCore/PlatformEvent.h>
157#include <WebCore/PublicSuffix.h>
158#include <WebCore/RenderEmbeddedObject.h>
159#include <WebCore/ResourceLoadStatistics.h>
160#include <WebCore/SSLKeyGenerator.h>
161#include <WebCore/SerializedCryptoKeyWrap.h>
162#include <WebCore/ShareData.h>
163#include <WebCore/SharedBuffer.h>
164#include <WebCore/ShouldTreatAsContinuingLoad.h>
165#include <WebCore/TextCheckerClient.h>
166#include <WebCore/TextIndicator.h>
167#include <WebCore/ValidationBubble.h>
168#include <WebCore/WindowFeatures.h>
169#include <WebCore/WritingDirection.h>
170#include <stdio.h>
171#include <wtf/NeverDestroyed.h>
172#include <wtf/SystemTracing.h>
173#include <wtf/URL.h>
174#include <wtf/URLParser.h>
175#include <wtf/text/StringView.h>
176#include <wtf/text/TextStream.h>
177
178#if ENABLE(APPLICATION_MANIFEST)
179#include "APIApplicationManifest.h"
180#endif
181
182#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
183#include "RemoteScrollingCoordinatorProxy.h"
184#endif
185
186#ifndef NDEBUG
187#include <wtf/RefCountedLeakCounter.h>
188#endif
189
190#if PLATFORM(COCOA)
191#include "AttributedString.h"
192#include "InsertTextOptions.h"
193#include "RemoteLayerTreeDrawingAreaProxy.h"
194#include "RemoteLayerTreeScrollingPerformanceData.h"
195#include "TouchBarMenuData.h"
196#include "TouchBarMenuItemData.h"
197#include "VideoFullscreenManagerProxy.h"
198#include "VideoFullscreenManagerProxyMessages.h"
199#include <WebCore/RunLoopObserver.h>
200#include <WebCore/TextIndicatorWindow.h>
201#include <wtf/MachSendRight.h>
202#endif
203
204#if PLATFORM(COCOA) || PLATFORM(GTK)
205#include "ViewSnapshotStore.h"
206#endif
207
208#if PLATFORM(GTK)
209#include "WebSelectionData.h"
210#endif
211
212#if USE(CAIRO)
213#include <WebCore/CairoUtilities.h>
214#endif
215
216#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
217#include <WebCore/MediaPlaybackTarget.h>
218#include <WebCore/WebMediaSessionManager.h>
219#endif
220
221#if ENABLE(MEDIA_SESSION)
222#include "WebMediaSessionFocusManager.h"
223#include "WebMediaSessionMetadata.h"
224#include <WebCore/MediaSessionMetadata.h>
225#endif
226
227#if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
228#include "PlaybackSessionManagerProxy.h"
229#endif
230
231#if ENABLE(WEB_AUTHN)
232#include "WebAuthenticatorCoordinatorProxy.h"
233#endif
234
235#if ENABLE(REMOTE_INSPECTOR)
236#include <JavaScriptCore/RemoteInspector.h>
237#endif
238
239#if HAVE(SEC_KEY_PROXY)
240#include "SecKeyProxyStore.h"
241#endif
242
243#if HAVE(PENCILKIT)
244#include "EditableImageController.h"
245#endif
246
247// This controls what strategy we use for mouse wheel coalescing.
248#define MERGE_WHEEL_EVENTS 1
249
250#define MESSAGE_CHECK(process, assertion) MESSAGE_CHECK_BASE(assertion, process->connection())
251#define MESSAGE_CHECK_URL(process, url) MESSAGE_CHECK_BASE(checkURLReceivedFromCurrentOrPreviousWebProcess(process, url), process->connection())
252
253#define RELEASE_LOG_IF_ALLOWED(channel, fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), channel, "%p - WebPageProxy::" fmt, this, ##__VA_ARGS__)
254#define RELEASE_LOG_ERROR_IF_ALLOWED(channel, fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), channel, "%p - WebPageProxy::" fmt, this, ##__VA_ARGS__)
255
256// Represents the number of wheel events we can hold in the queue before we start pushing them preemptively.
257static const unsigned wheelEventQueueSizeThreshold = 10;
258
259static const Seconds resetRecentCrashCountDelay = 30_s;
260static unsigned maximumWebProcessRelaunchAttempts = 1;
261
262namespace WebKit {
263using namespace WebCore;
264
265DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageProxyCounter, ("WebPageProxy"));
266
267class StorageRequests {
268 WTF_MAKE_NONCOPYABLE(StorageRequests); WTF_MAKE_FAST_ALLOCATED;
269 friend NeverDestroyed<StorageRequests>;
270public:
271 static StorageRequests& singleton();
272
273 void processOrAppend(CompletionHandler<void()>&& completionHandler)
274 {
275 if (m_requestsAreBeingProcessed) {
276 m_requests.append(WTFMove(completionHandler));
277 return;
278 }
279 m_requestsAreBeingProcessed = true;
280 completionHandler();
281 }
282
283 void processNextIfAny()
284 {
285 if (m_requests.isEmpty()) {
286 m_requestsAreBeingProcessed = false;
287 return;
288 }
289 m_requests.takeFirst()();
290 }
291
292private:
293 StorageRequests() { }
294 ~StorageRequests() { }
295
296 Deque<CompletionHandler<void()>> m_requests;
297 bool m_requestsAreBeingProcessed { false };
298};
299
300StorageRequests& StorageRequests::singleton()
301{
302 static NeverDestroyed<StorageRequests> requests;
303 return requests;
304}
305
306#if !LOG_DISABLED
307static const char* webMouseEventTypeString(WebEvent::Type type)
308{
309 switch (type) {
310 case WebEvent::MouseDown:
311 return "MouseDown";
312 case WebEvent::MouseUp:
313 return "MouseUp";
314 case WebEvent::MouseMove:
315 return "MouseMove";
316 case WebEvent::MouseForceChanged:
317 return "MouseForceChanged";
318 case WebEvent::MouseForceDown:
319 return "MouseForceDown";
320 case WebEvent::MouseForceUp:
321 return "MouseForceUp";
322 default:
323 ASSERT_NOT_REACHED();
324 return "<unknown>";
325 }
326}
327
328static const char* webKeyboardEventTypeString(WebEvent::Type type)
329{
330 switch (type) {
331 case WebEvent::KeyDown:
332 return "KeyDown";
333 case WebEvent::KeyUp:
334 return "KeyUp";
335 case WebEvent::RawKeyDown:
336 return "RawKeyDown";
337 case WebEvent::Char:
338 return "Char";
339 default:
340 ASSERT_NOT_REACHED();
341 return "<unknown>";
342 }
343}
344#endif // !LOG_DISABLED
345
346class PageClientProtector {
347 WTF_MAKE_NONCOPYABLE(PageClientProtector);
348public:
349 PageClientProtector(PageClient& pageClient)
350 : m_pageClient(makeWeakPtr(pageClient))
351 {
352 m_pageClient->refView();
353 }
354
355 ~PageClientProtector()
356 {
357 ASSERT(m_pageClient);
358 m_pageClient->derefView();
359 }
360
361private:
362 WeakPtr<PageClient> m_pageClient;
363};
364
365void WebPageProxy::forMostVisibleWebPageIfAny(PAL::SessionID sessionID, const SecurityOriginData& origin, CompletionHandler<void(WebPageProxy*)>&& completionHandler)
366{
367 // 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.
368 WebPageProxy* selectedPage = nullptr;
369 WebProcessProxy::forWebPagesWithOrigin(sessionID, origin, [&](auto& page) {
370 if (!page.mainFrame())
371 return;
372 if (page.isViewVisible() && (!selectedPage || !selectedPage->isViewVisible())) {
373 selectedPage = &page;
374 return;
375 }
376 if (page.isViewFocused() && (!selectedPage || !selectedPage->isViewFocused())) {
377 selectedPage = &page;
378 return;
379 }
380 });
381 completionHandler(selectedPage);
382}
383
384Ref<WebPageProxy> WebPageProxy::create(PageClient& pageClient, WebProcessProxy& process, uint64_t pageID, Ref<API::PageConfiguration>&& configuration)
385{
386 return adoptRef(*new WebPageProxy(pageClient, process, pageID, WTFMove(configuration)));
387}
388
389WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uint64_t pageID, Ref<API::PageConfiguration>&& configuration)
390 : m_pageClient(makeWeakPtr(pageClient))
391 , m_configuration(WTFMove(configuration))
392 , m_navigationClient(makeUniqueRef<API::NavigationClient>())
393 , m_historyClient(makeUniqueRef<API::HistoryClient>())
394 , m_iconLoadingClient(std::make_unique<API::IconLoadingClient>())
395 , m_formClient(std::make_unique<API::FormClient>())
396 , m_uiClient(std::make_unique<API::UIClient>())
397 , m_findClient(std::make_unique<API::FindClient>())
398 , m_findMatchesClient(std::make_unique<API::FindMatchesClient>())
399#if ENABLE(CONTEXT_MENUS)
400 , m_contextMenuClient(std::make_unique<API::ContextMenuClient>())
401#endif
402 , m_navigationState(std::make_unique<WebNavigationState>())
403 , m_process(process)
404 , m_pageGroup(*m_configuration->pageGroup())
405 , m_preferences(*m_configuration->preferences())
406 , m_userContentController(*m_configuration->userContentController())
407 , m_visitedLinkStore(*m_configuration->visitedLinkStore())
408 , m_websiteDataStore(m_configuration->websiteDataStore()->websiteDataStore())
409 , m_userAgent(standardUserAgent())
410 , m_overrideContentSecurityPolicy { m_configuration->overrideContentSecurityPolicy() }
411 , m_treatsSHA1CertificatesAsInsecure(m_configuration->treatsSHA1SignedCertificatesAsInsecure())
412#if ENABLE(FULLSCREEN_API)
413 , m_fullscreenClient(std::make_unique<API::FullscreenClient>())
414#endif
415 , m_geolocationPermissionRequestManager(*this)
416 , m_notificationPermissionRequestManager(*this)
417#if PLATFORM(IOS_FAMILY)
418 , m_alwaysRunsAtForegroundPriority(m_configuration->alwaysRunsAtForegroundPriority())
419#endif
420 , m_initialCapitalizationEnabled(m_configuration->initialCapitalizationEnabled())
421 , m_cpuLimit(m_configuration->cpuLimit())
422 , m_backForwardList(WebBackForwardList::create(*this))
423 , m_waitsForPaintAfterViewDidMoveToWindow(m_configuration->waitsForPaintAfterViewDidMoveToWindow())
424 , m_hasRunningProcess(process.state() != WebProcessProxy::State::Terminated)
425 , m_pageID(pageID)
426 , m_controlledByAutomation(m_configuration->isControlledByAutomation())
427#if PLATFORM(COCOA)
428 , m_isSmartInsertDeleteEnabled(TextChecker::isSmartInsertDeleteEnabled())
429#endif
430 , m_pageLoadState(*this)
431 , m_configurationPreferenceValues(m_configuration->preferenceValues())
432 , m_inspectorController(std::make_unique<WebPageInspectorController>(*this))
433#if ENABLE(REMOTE_INSPECTOR)
434 , m_inspectorDebuggable(std::make_unique<WebPageDebuggable>(*this))
435#endif
436 , m_resetRecentCrashCountTimer(RunLoop::main(), this, &WebPageProxy::resetRecentCrashCount)
437{
438 RELEASE_LOG_IF_ALLOWED(Loading, "constructor: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
439
440 if (!m_configuration->drawsBackground())
441 m_backgroundColor = Color(Color::transparent);
442
443 m_webProcessLifetimeTracker.addObserver(m_visitedLinkStore);
444 m_webProcessLifetimeTracker.addObserver(m_websiteDataStore);
445
446 updateActivityState();
447 updateThrottleState();
448 updateHiddenPageThrottlingAutoIncreases();
449
450#if HAVE(OUT_OF_PROCESS_LAYER_HOSTING)
451 m_layerHostingMode = m_activityState & ActivityState::IsInWindow ? WebPageProxy::pageClient().viewLayerHostingMode() : LayerHostingMode::OutOfProcess;
452#endif
453
454 platformInitialize();
455
456#ifndef NDEBUG
457 webPageProxyCounter.increment();
458#endif
459
460 WebProcessPool::statistics().wkPageCount++;
461
462 m_preferences->addPage(*this);
463 m_pageGroup->addPage(this);
464
465 m_inspector = WebInspectorProxy::create(this);
466
467 if (hasRunningProcess())
468 didAttachToRunningProcess();
469
470 m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID, *this);
471
472#if PLATFORM(IOS_FAMILY)
473 DeprecatedGlobalSettings::setDisableScreenSizeOverride(preferencesStore().getBoolValueForKey(WebPreferencesKey::disableScreenSizeOverrideKey()));
474#endif
475
476#if PLATFORM(COCOA)
477 m_activityStateChangeDispatcher = std::make_unique<RunLoopObserver>(static_cast<CFIndex>(RunLoopObserver::WellKnownRunLoopOrders::ActivityStateChange), [this] {
478 this->dispatchActivityStateChange();
479 });
480#endif
481
482#if ENABLE(REMOTE_INSPECTOR)
483 m_inspectorDebuggable->setRemoteDebuggingAllowed(true);
484 m_inspectorDebuggable->init();
485#endif
486
487 createInspectorTargets();
488}
489
490WebPageProxy::~WebPageProxy()
491{
492 RELEASE_LOG_IF_ALLOWED(Loading, "destructor: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
493
494 ASSERT(m_process->webPage(m_pageID) != this);
495#if !ASSERT_DISABLED
496 for (WebPageProxy* page : m_process->pages())
497 ASSERT(page != this);
498#endif
499
500 if (!m_isClosed)
501 close();
502
503 WebProcessPool::statistics().wkPageCount--;
504
505 if (m_spellDocumentTag)
506 TextChecker::closeSpellDocumentWithTag(m_spellDocumentTag.value());
507
508 m_preferences->removePage(*this);
509 m_pageGroup->removePage(this);
510
511#ifndef NDEBUG
512 webPageProxyCounter.decrement();
513#endif
514}
515
516// FIXME: Should return a const PageClient& and add a separate non-const
517// version of this function, but several PageClient methods will need to become
518// const for this to be possible.
519PageClient& WebPageProxy::pageClient() const
520{
521 ASSERT(m_pageClient);
522 return *m_pageClient;
523}
524
525PAL::SessionID WebPageProxy::sessionID() const
526{
527 return m_websiteDataStore->sessionID();
528}
529
530DrawingAreaProxy* WebPageProxy::provisionalDrawingArea() const
531{
532 if (m_provisionalPage && m_provisionalPage->drawingArea())
533 return m_provisionalPage->drawingArea();
534 return drawingArea();
535}
536
537const API::PageConfiguration& WebPageProxy::configuration() const
538{
539 return m_configuration.get();
540}
541
542ProcessID WebPageProxy::processIdentifier() const
543{
544 if (m_isClosed)
545 return 0;
546
547 return m_process->processIdentifier();
548}
549
550bool WebPageProxy::hasRunningProcess() const
551{
552 // A page that has been explicitly closed is never valid.
553 if (m_isClosed)
554 return false;
555
556 return m_hasRunningProcess;
557}
558
559void WebPageProxy::notifyProcessPoolToPrewarm()
560{
561 m_process->processPool().didReachGoodTimeToPrewarm();
562}
563
564void WebPageProxy::setPreferences(WebPreferences& preferences)
565{
566 if (&preferences == m_preferences.ptr())
567 return;
568
569 m_preferences->removePage(*this);
570 m_preferences = preferences;
571 m_preferences->addPage(*this);
572
573 preferencesDidChange();
574}
575
576void WebPageProxy::setHistoryClient(UniqueRef<API::HistoryClient>&& historyClient)
577{
578 m_historyClient = WTFMove(historyClient);
579}
580
581void WebPageProxy::setNavigationClient(UniqueRef<API::NavigationClient>&& navigationClient)
582{
583 m_navigationClient = WTFMove(navigationClient);
584}
585
586void WebPageProxy::setLoaderClient(std::unique_ptr<API::LoaderClient>&& loaderClient)
587{
588 m_loaderClient = WTFMove(loaderClient);
589}
590
591void WebPageProxy::setPolicyClient(std::unique_ptr<API::PolicyClient>&& policyClient)
592{
593 m_policyClient = WTFMove(policyClient);
594}
595
596void WebPageProxy::setFormClient(std::unique_ptr<API::FormClient>&& formClient)
597{
598 if (!formClient) {
599 m_formClient = std::make_unique<API::FormClient>();
600 return;
601 }
602
603 m_formClient = WTFMove(formClient);
604}
605
606void WebPageProxy::setUIClient(std::unique_ptr<API::UIClient>&& uiClient)
607{
608 if (!uiClient) {
609 m_uiClient = std::make_unique<API::UIClient>();
610 return;
611 }
612
613 m_uiClient = WTFMove(uiClient);
614
615 if (hasRunningProcess())
616 m_process->send(Messages::WebPage::SetCanRunBeforeUnloadConfirmPanel(m_uiClient->canRunBeforeUnloadConfirmPanel()), m_pageID);
617
618 setCanRunModal(m_uiClient->canRunModal());
619 setNeedsFontAttributes(m_uiClient->needsFontAttributes());
620}
621
622void WebPageProxy::setIconLoadingClient(std::unique_ptr<API::IconLoadingClient>&& iconLoadingClient)
623{
624 bool hasClient = iconLoadingClient.get();
625 if (!iconLoadingClient)
626 m_iconLoadingClient = std::make_unique<API::IconLoadingClient>();
627 else
628 m_iconLoadingClient = WTFMove(iconLoadingClient);
629
630 if (!hasRunningProcess())
631 return;
632
633 m_process->send(Messages::WebPage::SetUseIconLoadingClient(hasClient), m_pageID);
634}
635
636void WebPageProxy::setFindClient(std::unique_ptr<API::FindClient>&& findClient)
637{
638 if (!findClient) {
639 m_findClient = std::make_unique<API::FindClient>();
640 return;
641 }
642
643 m_findClient = WTFMove(findClient);
644}
645
646void WebPageProxy::setFindMatchesClient(std::unique_ptr<API::FindMatchesClient>&& findMatchesClient)
647{
648 if (!findMatchesClient) {
649 m_findMatchesClient = std::make_unique<API::FindMatchesClient>();
650 return;
651 }
652
653 m_findMatchesClient = WTFMove(findMatchesClient);
654}
655
656void WebPageProxy::setDiagnosticLoggingClient(std::unique_ptr<API::DiagnosticLoggingClient>&& diagnosticLoggingClient)
657{
658 m_diagnosticLoggingClient = WTFMove(diagnosticLoggingClient);
659}
660
661#if ENABLE(CONTEXT_MENUS)
662void WebPageProxy::setContextMenuClient(std::unique_ptr<API::ContextMenuClient>&& contextMenuClient)
663{
664 if (!contextMenuClient) {
665 m_contextMenuClient = std::make_unique<API::ContextMenuClient>();
666 return;
667 }
668
669 m_contextMenuClient = WTFMove(contextMenuClient);
670}
671#endif
672
673void WebPageProxy::setInjectedBundleClient(const WKPageInjectedBundleClientBase* client)
674{
675 if (!client) {
676 m_injectedBundleClient = nullptr;
677 return;
678 }
679
680 m_injectedBundleClient = std::make_unique<WebPageInjectedBundleClient>();
681 m_injectedBundleClient->initialize(client);
682}
683
684void WebPageProxy::handleMessage(IPC::Connection& connection, const String& messageName, const WebKit::UserData& messageBody)
685{
686 ASSERT(m_process->connection() == &connection);
687
688 if (!m_injectedBundleClient)
689 return;
690
691 m_injectedBundleClient->didReceiveMessageFromInjectedBundle(this, messageName, m_process->transformHandlesToObjects(messageBody.object()).get());
692}
693
694void WebPageProxy::handleSynchronousMessage(IPC::Connection& connection, const String& messageName, const UserData& messageBody, CompletionHandler<void(UserData&&)>&& completionHandler)
695{
696 ASSERT(m_process->connection() == &connection);
697
698 if (!m_injectedBundleClient)
699 return completionHandler({ });
700
701 RefPtr<API::Object> returnData;
702 m_injectedBundleClient->didReceiveSynchronousMessageFromInjectedBundle(this, messageName, m_process->transformHandlesToObjects(messageBody.object()).get(), returnData);
703 completionHandler(UserData(m_process->transformObjectsToHandles(returnData.get())));
704}
705
706void WebPageProxy::launchProcess(const RegistrableDomain& registrableDomain)
707{
708 ASSERT(!m_isClosed);
709 ASSERT(!hasRunningProcess());
710
711 RELEASE_LOG_IF_ALLOWED(Loading, "launchProcess: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
712
713 m_process->removeWebPage(*this, WebProcessProxy::EndsUsingDataStore::Yes);
714 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
715
716 auto& processPool = m_process->processPool();
717
718 auto* relatedPage = m_configuration->relatedPage();
719 if (relatedPage && !relatedPage->isClosed())
720 m_process = relatedPage->ensureRunningProcess();
721 else
722 m_process = processPool.processForRegistrableDomain(m_websiteDataStore.get(), this, registrableDomain);
723 m_hasRunningProcess = true;
724
725 m_process->addExistingWebPage(*this, WebProcessProxy::BeginsUsingDataStore::Yes);
726 m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID, *this);
727
728 finishAttachingToWebProcess(IsProcessSwap::No);
729}
730
731bool WebPageProxy::suspendCurrentPageIfPossible(API::Navigation& navigation, Optional<uint64_t> mainFrameID, ProcessSwapRequestedByClient processSwapRequestedByClient, ShouldDelayClosingUntilEnteringAcceleratedCompositingMode shouldDelayClosingUntilEnteringAcceleratedCompositingMode)
732{
733 m_lastSuspendedPage = nullptr;
734
735 if (!mainFrameID)
736 return false;
737
738 if (!hasCommittedAnyProvisionalLoads()) {
739 RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because has not committed any load yet", m_process->processIdentifier());
740 return false;
741 }
742
743 if (isPageOpenedByDOMShowingInitialEmptyDocument()) {
744 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());
745 return false;
746 }
747
748 auto* fromItem = navigation.fromItem();
749
750 // If the source and the destination back / forward list items are the same, then this is a client-side redirect. In this case,
751 // there is no need to suspend the previous page as there will be no way to get back to it.
752 if (fromItem && fromItem == m_backForwardList->currentItem()) {
753 RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because this is a client-side redirect", m_process->processIdentifier());
754 return false;
755 }
756
757 if (fromItem && fromItem->url() != pageLoadState().url()) {
758 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());
759 ASSERT_NOT_REACHED();
760 return false;
761 }
762
763 RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "suspendCurrentPageIfPossible: Suspending current page for process pid %i", m_process->processIdentifier());
764 auto suspendedPage = std::make_unique<SuspendedPageProxy>(*this, m_process.copyRef(), *mainFrameID, shouldDelayClosingUntilEnteringAcceleratedCompositingMode);
765
766 LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " created suspended page %s for process pid %i, back/forward item %s" PRIu64, pageID(), suspendedPage->loggingString(), m_process->processIdentifier(), fromItem ? fromItem->itemID().logString() : 0);
767
768 // If the client forced a swap then it may not be web-compatible to keep the previous page because other windows may have an opener link to it. We thus close it as soon as we
769 // can do so without flashing.
770 if (processSwapRequestedByClient == ProcessSwapRequestedByClient::Yes)
771 suspendedPage->closeWithoutFlashing();
772
773 if (fromItem && m_preferences->usesPageCache())
774 fromItem->setSuspendedPage(suspendedPage.get());
775
776 m_lastSuspendedPage = makeWeakPtr(*suspendedPage);
777 m_process->processPool().addSuspendedPage(WTFMove(suspendedPage));
778 return true;
779}
780
781void WebPageProxy::swapToWebProcess(Ref<WebProcessProxy>&& process, std::unique_ptr<DrawingAreaProxy>&& drawingArea, RefPtr<WebFrameProxy>&& mainFrame)
782{
783 ASSERT(!m_isClosed);
784 RELEASE_LOG_IF_ALLOWED(Loading, "swapToWebProcess: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
785
786 m_process = WTFMove(process);
787 m_websiteDataStore = m_process->websiteDataStore();
788
789 if (m_logger)
790 m_logger->setEnabled(this, isAlwaysOnLoggingAllowed());
791
792 ASSERT(!m_drawingArea);
793 setDrawingArea(WTFMove(drawingArea));
794 ASSERT(!m_mainFrame);
795 m_mainFrame = WTFMove(mainFrame);
796 m_hasRunningProcess = true;
797
798 m_process->addExistingWebPage(*this, WebProcessProxy::BeginsUsingDataStore::No);
799 m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID, *this);
800
801 finishAttachingToWebProcess(IsProcessSwap::Yes);
802}
803
804void WebPageProxy::finishAttachingToWebProcess(IsProcessSwap isProcessSwap)
805{
806 ASSERT(m_process->state() != AuxiliaryProcessProxy::State::Terminated);
807
808 if (m_process->state() == AuxiliaryProcessProxy::State::Running) {
809 // In the process-swap case, the ProvisionalPageProxy constructor already took care of calling webPageEnteringWebProcess()
810 // when the process was provisional.
811 if (isProcessSwap != IsProcessSwap::Yes)
812 m_webProcessLifetimeTracker.webPageEnteringWebProcess(m_process);
813 }
814
815 updateActivityState();
816 updateThrottleState();
817
818 didAttachToRunningProcess();
819
820 // In the process-swap case, the ProvisionalPageProxy already took care of initializing the WebPage in the WebProcess.
821 if (isProcessSwap != IsProcessSwap::Yes)
822 initializeWebPage();
823
824 m_inspector->updateForNewPageProcess(this);
825
826#if ENABLE(REMOTE_INSPECTOR)
827 remoteInspectorInformationDidChange();
828#endif
829
830 clearInspectorTargets();
831 createInspectorTargets();
832
833 pageClient().didRelaunchProcess();
834 m_pageLoadState.didSwapWebProcesses();
835 m_drawingArea->waitForBackingStoreUpdateOnNextPaint();
836}
837
838void WebPageProxy::didAttachToRunningProcess()
839{
840 ASSERT(hasRunningProcess());
841
842#if ENABLE(FULLSCREEN_API)
843 ASSERT(!m_fullScreenManager);
844 m_fullScreenManager = std::make_unique<WebFullScreenManagerProxy>(*this, pageClient().fullScreenManagerProxyClient());
845#endif
846#if PLATFORM(IOS_FAMILY) && HAVE(AVKIT) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
847 ASSERT(!m_playbackSessionManager);
848 m_playbackSessionManager = PlaybackSessionManagerProxy::create(*this);
849 ASSERT(!m_videoFullscreenManager);
850 m_videoFullscreenManager = VideoFullscreenManagerProxy::create(*this, *m_playbackSessionManager);
851#endif
852
853#if ENABLE(APPLE_PAY)
854 ASSERT(!m_paymentCoordinator);
855 m_paymentCoordinator = std::make_unique<WebPaymentCoordinatorProxy>(*this);
856#endif
857
858#if USE(SYSTEM_PREVIEW)
859 ASSERT(!m_systemPreviewController);
860 m_systemPreviewController = std::make_unique<SystemPreviewController>(*this);
861#endif
862
863#if ENABLE(WEB_AUTHN)
864 ASSERT(!m_credentialsMessenger);
865 m_credentialsMessenger = std::make_unique<WebAuthenticatorCoordinatorProxy>(*this);
866#endif
867
868#if HAVE(PENCILKIT)
869 ASSERT(!m_editableImageController);
870 m_editableImageController = std::make_unique<EditableImageController>(*this);
871#endif
872}
873
874RefPtr<API::Navigation> WebPageProxy::launchProcessForReload()
875{
876 RELEASE_LOG_IF_ALLOWED(Loading, "launchProcessForReload: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
877
878 if (m_isClosed) {
879 RELEASE_LOG_IF_ALLOWED(Loading, "launchProcessForReload: page is closed: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
880 return nullptr;
881 }
882
883 ASSERT(!hasRunningProcess());
884 auto registrableDomain = m_backForwardList->currentItem() ? RegistrableDomain { URL(URL(), m_backForwardList->currentItem()->url()) } : RegistrableDomain { };
885 launchProcess(registrableDomain);
886
887 if (!m_backForwardList->currentItem()) {
888 RELEASE_LOG_IF_ALLOWED(Loading, "launchProcessForReload: no current item to reload: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
889 return nullptr;
890 }
891
892 auto navigation = m_navigationState->createReloadNavigation();
893
894 // We allow stale content when reloading a WebProcess that's been killed or crashed.
895 m_process->send(Messages::WebPage::GoToBackForwardItem(navigation->navigationID(), m_backForwardList->currentItem()->itemID(), FrameLoadType::IndexedBackForward, ShouldTreatAsContinuingLoad::No, WTF::nullopt), m_pageID);
896 m_process->responsivenessTimer().start();
897
898 return navigation;
899}
900
901RefPtr<API::Navigation> WebPageProxy::launchProcessWithItem(WebBackForwardListItem& item)
902{
903 RELEASE_LOG_IF_ALLOWED(Loading, "launchProcessWithItem: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
904
905 if (m_isClosed) {
906 RELEASE_LOG_IF_ALLOWED(Loading, "launchProcessWithItem: page is closed: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
907 return nullptr;
908 }
909
910 ASSERT(!hasRunningProcess());
911 launchProcess(RegistrableDomain { URL(URL(), item.url()) });
912
913 if (&item != m_backForwardList->currentItem())
914 m_backForwardList->goToItem(item);
915
916 auto navigation = m_navigationState->createBackForwardNavigation(item, m_backForwardList->currentItem(), FrameLoadType::IndexedBackForward);
917
918 m_process->send(Messages::WebPage::GoToBackForwardItem(navigation->navigationID(), item.itemID(), FrameLoadType::IndexedBackForward, ShouldTreatAsContinuingLoad::No, WTF::nullopt), m_pageID);
919 m_process->responsivenessTimer().start();
920
921 return navigation;
922}
923
924void WebPageProxy::setDrawingArea(std::unique_ptr<DrawingAreaProxy>&& drawingArea)
925{
926 m_drawingArea = WTFMove(drawingArea);
927 if (!m_drawingArea)
928 return;
929
930#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
931 if (m_drawingArea->type() == DrawingAreaTypeRemoteLayerTree) {
932 m_scrollingCoordinatorProxy = std::make_unique<RemoteScrollingCoordinatorProxy>(*this);
933#if PLATFORM(IOS_FAMILY)
934 // On iOS, main frame scrolls are sent in terms of visible rect updates.
935 m_scrollingCoordinatorProxy->setPropagatesMainFrameScrolls(false);
936#endif
937 }
938#endif
939}
940
941void WebPageProxy::initializeWebPage()
942{
943 if (!hasRunningProcess())
944 return;
945
946 setDrawingArea(pageClient().createDrawingAreaProxy(m_process));
947 ASSERT(m_drawingArea);
948
949 process().send(Messages::WebProcess::CreateWebPage(m_pageID, creationParameters(m_process, *m_drawingArea)), 0);
950
951 m_process->addVisitedLinkStoreUser(visitedLinkStore(), m_pageID);
952}
953
954void WebPageProxy::close()
955{
956 if (m_isClosed)
957 return;
958
959 RELEASE_LOG_IF_ALLOWED(Loading, "close: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
960
961 m_isClosed = true;
962
963 reportPageLoadResult(ResourceError { ResourceError::Type::Cancellation });
964
965 if (m_activePopupMenu)
966 m_activePopupMenu->cancelTracking();
967
968 if (m_controlledByAutomation) {
969 if (auto* automationSession = process().processPool().automationSession())
970 automationSession->willClosePage(*this);
971 }
972
973#if ENABLE(CONTEXT_MENUS)
974 m_activeContextMenu = nullptr;
975#endif
976
977 m_provisionalPage = nullptr;
978
979 m_inspector->invalidate();
980
981 m_backForwardList->pageClosed();
982 m_inspectorController->pageClosed();
983#if ENABLE(REMOTE_INSPECTOR)
984 m_inspectorDebuggable = nullptr;
985#endif
986 pageClient().pageClosed();
987
988 m_process->disconnectFramesFromPage(this);
989
990 resetState(ResetStateReason::PageInvalidated);
991
992 m_loaderClient = nullptr;
993 m_navigationClient = makeUniqueRef<API::NavigationClient>();
994 m_policyClient = nullptr;
995 m_iconLoadingClient = std::make_unique<API::IconLoadingClient>();
996 m_formClient = std::make_unique<API::FormClient>();
997 m_uiClient = std::make_unique<API::UIClient>();
998 m_findClient = std::make_unique<API::FindClient>();
999 m_findMatchesClient = std::make_unique<API::FindMatchesClient>();
1000 m_diagnosticLoggingClient = nullptr;
1001#if ENABLE(CONTEXT_MENUS)
1002 m_contextMenuClient = std::make_unique<API::ContextMenuClient>();
1003#endif
1004#if ENABLE(FULLSCREEN_API)
1005 m_fullscreenClient = std::make_unique<API::FullscreenClient>();
1006#endif
1007
1008 m_webProcessLifetimeTracker.pageWasInvalidated();
1009
1010 m_process->processPool().removeAllSuspendedPagesForPage(*this);
1011
1012 m_process->send(Messages::WebPage::Close(), m_pageID);
1013 m_process->removeWebPage(*this, WebProcessProxy::EndsUsingDataStore::Yes);
1014 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
1015 m_process->processPool().supplement<WebNotificationManagerProxy>()->clearNotifications(this);
1016
1017 // Null out related WebPageProxy to avoid leaks.
1018 m_configuration->setRelatedPage(nullptr);
1019
1020#if PLATFORM(IOS_FAMILY)
1021 // Make sure we don't hold a process assertion after getting closed.
1022 m_activityToken = nullptr;
1023#endif
1024
1025 stopAllURLSchemeTasks();
1026 updatePlayingMediaDidChange(MediaProducer::IsNotPlaying);
1027}
1028
1029bool WebPageProxy::tryClose()
1030{
1031 if (!hasRunningProcess())
1032 return true;
1033
1034 RELEASE_LOG_IF_ALLOWED(Loading, "tryClose: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1035
1036 // Close without delay if the process allows it. Our goal is to terminate
1037 // the process, so we check a per-process status bit.
1038 if (m_process->isSuddenTerminationEnabled())
1039 return true;
1040
1041 m_process->send(Messages::WebPage::TryClose(), m_pageID);
1042 m_process->responsivenessTimer().start();
1043 return false;
1044}
1045
1046bool WebPageProxy::maybeInitializeSandboxExtensionHandle(WebProcessProxy& process, const URL& url, SandboxExtension::Handle& sandboxExtensionHandle)
1047{
1048 if (!url.isLocalFile())
1049 return false;
1050
1051 if (process.hasAssumedReadAccessToURL(url))
1052 return false;
1053
1054 // Inspector resources are in a directory with assumed access.
1055 ASSERT_WITH_SECURITY_IMPLICATION(!WebKit::isInspectorPage(*this));
1056
1057 SandboxExtension::createHandle("/", SandboxExtension::Type::ReadOnly, sandboxExtensionHandle);
1058 return true;
1059}
1060
1061#if !PLATFORM(COCOA)
1062void WebPageProxy::addPlatformLoadParameters(LoadParameters&)
1063{
1064}
1065#endif
1066
1067WebProcessProxy& WebPageProxy::ensureRunningProcess()
1068{
1069 if (!hasRunningProcess())
1070 launchProcess({ });
1071
1072 return m_process;
1073}
1074
1075RefPtr<API::Navigation> WebPageProxy::loadRequest(ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData)
1076{
1077 if (m_isClosed)
1078 return nullptr;
1079
1080 RELEASE_LOG_IF_ALLOWED(Loading, "loadRequest: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1081
1082 if (!hasRunningProcess())
1083 launchProcess(RegistrableDomain { request.url() });
1084
1085 auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem());
1086 loadRequestWithNavigationShared(m_process.copyRef(), navigation.get(), WTFMove(request), shouldOpenExternalURLsPolicy, userData, ShouldTreatAsContinuingLoad::No);
1087 return navigation;
1088}
1089
1090void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& process, API::Navigation& navigation, ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& websitePolicies)
1091{
1092 ASSERT(!m_isClosed);
1093
1094 RELEASE_LOG_IF_ALLOWED(Loading, "loadRequestWithNavigation: webPID = %i, pageID = %" PRIu64, process->processIdentifier(), m_pageID);
1095
1096 auto transaction = m_pageLoadState.transaction();
1097
1098 auto url = request.url();
1099 if (shouldTreatAsContinuingLoad != ShouldTreatAsContinuingLoad::Yes)
1100 m_pageLoadState.setPendingAPIRequestURL(transaction, url);
1101
1102 LoadParameters loadParameters;
1103 loadParameters.navigationID = navigation.navigationID();
1104 loadParameters.request = WTFMove(request);
1105 loadParameters.shouldOpenExternalURLsPolicy = (uint64_t)shouldOpenExternalURLsPolicy;
1106 loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1107 loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::Yes;
1108 loadParameters.websitePolicies = WTFMove(websitePolicies);
1109 loadParameters.lockHistory = navigation.lockHistory();
1110 loadParameters.lockBackForwardList = navigation.lockBackForwardList();
1111 loadParameters.clientRedirectSourceForHistory = navigation.clientRedirectSourceForHistory();
1112 bool createdExtension = maybeInitializeSandboxExtensionHandle(process, url, loadParameters.sandboxExtensionHandle);
1113 if (createdExtension)
1114 willAcquireUniversalFileReadSandboxExtension(process);
1115 addPlatformLoadParameters(loadParameters);
1116
1117 process->send(Messages::WebPage::LoadRequest(loadParameters), m_pageID);
1118 process->responsivenessTimer().start();
1119}
1120
1121RefPtr<API::Navigation> WebPageProxy::loadFile(const String& fileURLString, const String& resourceDirectoryURLString, API::Object* userData)
1122{
1123 RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1124
1125 if (m_isClosed) {
1126 RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: page is closed: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1127 return nullptr;
1128 }
1129
1130 if (!hasRunningProcess())
1131 launchProcess({ });
1132
1133 URL fileURL = URL(URL(), fileURLString);
1134 if (!fileURL.isLocalFile()) {
1135 RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: file is not local: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1136 return nullptr;
1137 }
1138
1139 URL resourceDirectoryURL;
1140 if (resourceDirectoryURLString.isNull())
1141 resourceDirectoryURL = URL({ }, "file:///"_s);
1142 else {
1143 resourceDirectoryURL = URL(URL(), resourceDirectoryURLString);
1144 if (!resourceDirectoryURL.isLocalFile()) {
1145 RELEASE_LOG_IF_ALLOWED(Loading, "loadFile: resource URL is not local: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1146 return nullptr;
1147 }
1148 }
1149
1150 auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(fileURL), m_backForwardList->currentItem());
1151
1152 auto transaction = m_pageLoadState.transaction();
1153
1154 m_pageLoadState.setPendingAPIRequestURL(transaction, fileURLString);
1155
1156 String resourceDirectoryPath = resourceDirectoryURL.fileSystemPath();
1157
1158 LoadParameters loadParameters;
1159 loadParameters.navigationID = navigation->navigationID();
1160 loadParameters.request = fileURL;
1161 loadParameters.shouldOpenExternalURLsPolicy = (uint64_t)ShouldOpenExternalURLsPolicy::ShouldNotAllow;
1162 loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1163 SandboxExtension::createHandle(resourceDirectoryPath, SandboxExtension::Type::ReadOnly, loadParameters.sandboxExtensionHandle);
1164 addPlatformLoadParameters(loadParameters);
1165
1166 m_process->assumeReadAccessToBaseURL(*this, resourceDirectoryURL);
1167 m_process->send(Messages::WebPage::LoadRequest(loadParameters), m_pageID);
1168 m_process->responsivenessTimer().start();
1169
1170 return navigation;
1171}
1172
1173RefPtr<API::Navigation> WebPageProxy::loadData(const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData)
1174{
1175 RELEASE_LOG_IF_ALLOWED(Loading, "loadData: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1176
1177 if (m_isClosed) {
1178 RELEASE_LOG_IF_ALLOWED(Loading, "loadData: page is closed: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1179 return nullptr;
1180 }
1181
1182 if (!hasRunningProcess())
1183 launchProcess({ });
1184
1185 auto navigation = m_navigationState->createLoadDataNavigation(std::make_unique<API::SubstituteData>(data.vector(), MIMEType, encoding, baseURL, userData));
1186 loadDataWithNavigationShared(m_process.copyRef(), navigation, data, MIMEType, encoding, baseURL, userData, ShouldTreatAsContinuingLoad::No);
1187 return navigation;
1188}
1189
1190void WebPageProxy::loadDataWithNavigationShared(Ref<WebProcessProxy>&& process, API::Navigation& navigation, const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& websitePolicies)
1191{
1192 RELEASE_LOG_IF_ALLOWED(Loading, "loadDataWithNavigation: webPID = %i, pageID = %" PRIu64, process->processIdentifier(), m_pageID);
1193
1194 ASSERT(!m_isClosed);
1195
1196 auto transaction = m_pageLoadState.transaction();
1197
1198 m_pageLoadState.setPendingAPIRequestURL(transaction, !baseURL.isEmpty() ? baseURL : WTF::blankURL().string());
1199
1200 LoadParameters loadParameters;
1201 loadParameters.navigationID = navigation.navigationID();
1202 loadParameters.data = data;
1203 loadParameters.MIMEType = MIMEType;
1204 loadParameters.encodingName = encoding;
1205 loadParameters.baseURLString = baseURL;
1206 loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::Yes;
1207 loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1208 loadParameters.websitePolicies = WTFMove(websitePolicies);
1209 addPlatformLoadParameters(loadParameters);
1210
1211 process->assumeReadAccessToBaseURL(*this, baseURL);
1212 process->send(Messages::WebPage::LoadData(loadParameters), m_pageID);
1213 process->responsivenessTimer().start();
1214}
1215
1216void WebPageProxy::loadAlternateHTML(const IPC::DataReference& htmlData, const String& encoding, const URL& baseURL, const URL& unreachableURL, API::Object* userData)
1217{
1218 RELEASE_LOG_IF_ALLOWED(Loading, "loadAlternateHTML: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1219
1220 // When the UIProcess is in the process of handling a failing provisional load, do not attempt to
1221 // start a second alternative HTML load as this will prevent the page load state from being
1222 // handled properly.
1223 if (m_isClosed || m_isLoadingAlternateHTMLStringForFailingProvisionalLoad) {
1224 RELEASE_LOG_IF_ALLOWED(Loading, "loadAlternateHTML: page is closed (or other): webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1225 return;
1226 }
1227
1228 if (!m_failingProvisionalLoadURL.isEmpty())
1229 m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = true;
1230
1231 if (!hasRunningProcess())
1232 launchProcess(RegistrableDomain { baseURL });
1233
1234 auto transaction = m_pageLoadState.transaction();
1235
1236 m_pageLoadState.setPendingAPIRequestURL(transaction, unreachableURL);
1237 m_pageLoadState.setUnreachableURL(transaction, unreachableURL);
1238
1239 if (m_mainFrame)
1240 m_mainFrame->setUnreachableURL(unreachableURL);
1241
1242 LoadParameters loadParameters;
1243 loadParameters.navigationID = 0;
1244 loadParameters.data = htmlData;
1245 loadParameters.MIMEType = "text/html"_s;
1246 loadParameters.encodingName = encoding;
1247 loadParameters.baseURLString = baseURL;
1248 loadParameters.unreachableURLString = unreachableURL;
1249 loadParameters.provisionalLoadErrorURLString = m_failingProvisionalLoadURL;
1250 loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1251 addPlatformLoadParameters(loadParameters);
1252
1253 m_process->assumeReadAccessToBaseURL(*this, baseURL);
1254 m_process->assumeReadAccessToBaseURL(*this, unreachableURL);
1255 m_process->send(Messages::WebPage::LoadAlternateHTML(loadParameters), m_pageID);
1256 m_process->responsivenessTimer().start();
1257}
1258
1259void WebPageProxy::loadWebArchiveData(API::Data* webArchiveData, API::Object* userData)
1260{
1261 RELEASE_LOG_IF_ALLOWED(Loading, "loadWebArchiveData: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1262
1263 if (m_isClosed) {
1264 RELEASE_LOG_IF_ALLOWED(Loading, "loadWebArchiveData: page is closed: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1265 return;
1266 }
1267
1268 if (!hasRunningProcess())
1269 launchProcess({ });
1270
1271 auto transaction = m_pageLoadState.transaction();
1272 m_pageLoadState.setPendingAPIRequestURL(transaction, WTF::blankURL().string());
1273
1274 LoadParameters loadParameters;
1275 loadParameters.navigationID = 0;
1276 loadParameters.data = webArchiveData->dataReference();
1277 loadParameters.MIMEType = "application/x-webarchive"_s;
1278 loadParameters.encodingName = "utf-16"_s;
1279 loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1280 addPlatformLoadParameters(loadParameters);
1281
1282 m_process->send(Messages::WebPage::LoadData(loadParameters), m_pageID);
1283 m_process->responsivenessTimer().start();
1284}
1285
1286void WebPageProxy::navigateToPDFLinkWithSimulatedClick(const String& urlString, IntPoint documentPoint, IntPoint screenPoint)
1287{
1288 RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1289
1290 if (m_isClosed) {
1291 RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick: page is closed: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1292 return;
1293 }
1294
1295 if (WTF::protocolIsJavaScript(urlString))
1296 return;
1297
1298 if (!hasRunningProcess())
1299 launchProcess(RegistrableDomain { URL(URL(), urlString) });
1300
1301 m_process->send(Messages::WebPage::NavigateToPDFLinkWithSimulatedClick(urlString, documentPoint, screenPoint), m_pageID);
1302 m_process->responsivenessTimer().start();
1303}
1304
1305void WebPageProxy::stopLoading()
1306{
1307 RELEASE_LOG_IF_ALLOWED(Loading, "stopLoading: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1308
1309 if (!hasRunningProcess()) {
1310 RELEASE_LOG_IF_ALLOWED(Loading, "navigateToPDFLinkWithSimulatedClick: page is not valid: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1311 return;
1312 }
1313
1314 m_process->send(Messages::WebPage::StopLoading(), m_pageID);
1315 if (m_provisionalPage) {
1316 m_provisionalPage->cancel();
1317 m_provisionalPage = nullptr;
1318 }
1319 m_process->responsivenessTimer().start();
1320}
1321
1322RefPtr<API::Navigation> WebPageProxy::reload(OptionSet<WebCore::ReloadOption> options)
1323{
1324 RELEASE_LOG_IF_ALLOWED(Loading, "reload: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1325
1326 SandboxExtension::Handle sandboxExtensionHandle;
1327
1328 String url = currentURL();
1329 if (!url.isEmpty()) {
1330 auto transaction = m_pageLoadState.transaction();
1331 m_pageLoadState.setPendingAPIRequestURL(transaction, url);
1332
1333 // We may not have an extension yet if back/forward list was reinstated after a WebProcess crash or a browser relaunch
1334 bool createdExtension = maybeInitializeSandboxExtensionHandle(m_process, URL(URL(), url), sandboxExtensionHandle);
1335 if (createdExtension)
1336 willAcquireUniversalFileReadSandboxExtension(m_process);
1337 }
1338
1339 if (!hasRunningProcess())
1340 return launchProcessForReload();
1341
1342 auto navigation = m_navigationState->createReloadNavigation();
1343
1344 // Store decision to reload without content blockers on the navigation so that we can later set the corresponding
1345 // WebsitePolicies flag in WebPageProxy::receivedNavigationPolicyDecision().
1346 if (options.contains(WebCore::ReloadOption::DisableContentBlockers))
1347 navigation->setUserContentExtensionsEnabled(false);
1348
1349 m_process->send(Messages::WebPage::Reload(navigation->navigationID(), options.toRaw(), sandboxExtensionHandle), m_pageID);
1350 m_process->responsivenessTimer().start();
1351
1352 return navigation;
1353}
1354
1355void WebPageProxy::recordAutomaticNavigationSnapshot()
1356{
1357 if (m_shouldSuppressNextAutomaticNavigationSnapshot)
1358 return;
1359
1360 if (WebBackForwardListItem* item = m_backForwardList->currentItem())
1361 recordNavigationSnapshot(*item);
1362}
1363
1364void WebPageProxy::recordNavigationSnapshot(WebBackForwardListItem& item)
1365{
1366 if (!m_shouldRecordNavigationSnapshots)
1367 return;
1368
1369#if PLATFORM(COCOA) || PLATFORM(GTK)
1370 ViewSnapshotStore::singleton().recordSnapshot(*this, item);
1371#else
1372 UNUSED_PARAM(item);
1373#endif
1374}
1375
1376RefPtr<API::Navigation> WebPageProxy::goForward()
1377{
1378 WebBackForwardListItem* forwardItem = m_backForwardList->forwardItem();
1379 if (!forwardItem)
1380 return nullptr;
1381
1382 return goToBackForwardItem(*forwardItem, FrameLoadType::Forward);
1383}
1384
1385RefPtr<API::Navigation> WebPageProxy::goBack()
1386{
1387 WebBackForwardListItem* backItem = m_backForwardList->backItem();
1388 if (!backItem)
1389 return nullptr;
1390
1391 return goToBackForwardItem(*backItem, FrameLoadType::Back);
1392}
1393
1394RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item)
1395{
1396 return goToBackForwardItem(item, FrameLoadType::IndexedBackForward);
1397}
1398
1399RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item, FrameLoadType frameLoadType)
1400{
1401 RELEASE_LOG_IF_ALLOWED(Loading, "goToBackForwardItem: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1402 LOG(Loading, "WebPageProxy %p goToBackForwardItem to item URL %s", this, item.url().utf8().data());
1403
1404 if (!hasRunningProcess())
1405 return launchProcessWithItem(item);
1406
1407 auto transaction = m_pageLoadState.transaction();
1408
1409 m_pageLoadState.setPendingAPIRequestURL(transaction, item.url());
1410
1411 RefPtr<API::Navigation> navigation;
1412 if (!m_backForwardList->currentItem()->itemIsInSameDocument(item))
1413 navigation = m_navigationState->createBackForwardNavigation(item, m_backForwardList->currentItem(), frameLoadType);
1414
1415 m_process->send(Messages::WebPage::GoToBackForwardItem(navigation ? navigation->navigationID() : 0, item.itemID(), frameLoadType, ShouldTreatAsContinuingLoad::No, WTF::nullopt), m_pageID);
1416 m_process->responsivenessTimer().start();
1417
1418 return navigation;
1419}
1420
1421void WebPageProxy::tryRestoreScrollPosition()
1422{
1423 RELEASE_LOG_IF_ALLOWED(Loading, "tryRestoreScrollPosition: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1424
1425 if (!hasRunningProcess()) {
1426 RELEASE_LOG_IF_ALLOWED(Loading, "tryRestoreScrollPosition: page is not valid: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
1427 return;
1428 }
1429
1430 m_process->send(Messages::WebPage::TryRestoreScrollPosition(), m_pageID);
1431}
1432
1433void WebPageProxy::didChangeBackForwardList(WebBackForwardListItem* added, Vector<Ref<WebBackForwardListItem>>&& removed)
1434{
1435 PageClientProtector protector(pageClient());
1436
1437 if (!m_navigationClient->didChangeBackForwardList(*this, added, removed) && m_loaderClient)
1438 m_loaderClient->didChangeBackForwardList(*this, added, WTFMove(removed));
1439
1440 auto transaction = m_pageLoadState.transaction();
1441
1442 m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
1443 m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
1444}
1445
1446void WebPageProxy::willGoToBackForwardListItem(const BackForwardItemIdentifier& itemID, bool inPageCache)
1447{
1448 PageClientProtector protector(pageClient());
1449
1450 if (auto* item = m_backForwardList->itemForID(itemID))
1451 m_navigationClient->willGoToBackForwardListItem(*this, *item, inPageCache);
1452}
1453
1454bool WebPageProxy::shouldKeepCurrentBackForwardListItemInList(WebBackForwardListItem& item)
1455{
1456 PageClientProtector protector(pageClient());
1457
1458 return !m_loaderClient || m_loaderClient->shouldKeepCurrentBackForwardListItemInList(*this, item);
1459}
1460
1461bool WebPageProxy::canShowMIMEType(const String& mimeType)
1462{
1463 if (MIMETypeRegistry::canShowMIMEType(mimeType))
1464 return true;
1465
1466#if ENABLE(NETSCAPE_PLUGIN_API)
1467 String newMimeType = mimeType;
1468 PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL());
1469 if (!plugin.path.isNull() && m_preferences->pluginsEnabled())
1470 return true;
1471#endif // ENABLE(NETSCAPE_PLUGIN_API)
1472
1473#if PLATFORM(COCOA)
1474 // On Mac, we can show PDFs.
1475 if (MIMETypeRegistry::isPDFOrPostScriptMIMEType(mimeType) && !WebProcessPool::omitPDFSupport())
1476 return true;
1477#endif // PLATFORM(COCOA)
1478
1479 return false;
1480}
1481
1482void WebPageProxy::setControlledByAutomation(bool controlled)
1483{
1484 if (m_controlledByAutomation == controlled)
1485 return;
1486
1487 m_controlledByAutomation = controlled;
1488
1489 if (!hasRunningProcess())
1490 return;
1491
1492 m_process->send(Messages::WebPage::SetControlledByAutomation(controlled), m_pageID);
1493 m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation));
1494}
1495
1496void WebPageProxy::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type)
1497{
1498 m_inspectorController->createInspectorTarget(targetId, type);
1499}
1500
1501void WebPageProxy::destroyInspectorTarget(const String& targetId)
1502{
1503 m_inspectorController->destroyInspectorTarget(targetId);
1504}
1505
1506void WebPageProxy::sendMessageToInspectorFrontend(const String& targetId, const String& message)
1507{
1508 m_inspectorController->sendMessageToInspectorFrontend(targetId, message);
1509}
1510
1511#if ENABLE(REMOTE_INSPECTOR)
1512void WebPageProxy::setIndicating(bool indicating)
1513{
1514 if (!hasRunningProcess())
1515 return;
1516
1517 m_process->send(Messages::WebPage::SetIndicating(indicating), m_pageID);
1518}
1519
1520bool WebPageProxy::allowsRemoteInspection() const
1521{
1522 return m_inspectorDebuggable->remoteDebuggingAllowed();
1523}
1524
1525void WebPageProxy::setAllowsRemoteInspection(bool allow)
1526{
1527 m_inspectorDebuggable->setRemoteDebuggingAllowed(allow);
1528}
1529
1530String WebPageProxy::remoteInspectionNameOverride() const
1531{
1532 return m_inspectorDebuggable->nameOverride();
1533}
1534
1535void WebPageProxy::setRemoteInspectionNameOverride(const String& name)
1536{
1537 m_inspectorDebuggable->setNameOverride(name);
1538}
1539
1540void WebPageProxy::remoteInspectorInformationDidChange()
1541{
1542 m_inspectorDebuggable->update();
1543}
1544#endif
1545
1546void WebPageProxy::clearInspectorTargets()
1547{
1548 m_inspectorController->clearTargets();
1549}
1550
1551void WebPageProxy::createInspectorTargets()
1552{
1553 String pageTargetId = makeString("page-", m_pageID);
1554 m_inspectorController->createInspectorTarget(pageTargetId, Inspector::InspectorTargetType::Page);
1555}
1556
1557void WebPageProxy::setBackgroundColor(const Optional<Color>& color)
1558{
1559 if (m_backgroundColor == color)
1560 return;
1561
1562 m_backgroundColor = color;
1563 if (hasRunningProcess())
1564 m_process->send(Messages::WebPage::SetBackgroundColor(color), m_pageID);
1565}
1566
1567void WebPageProxy::setTopContentInset(float contentInset)
1568{
1569 if (m_topContentInset == contentInset)
1570 return;
1571
1572 m_topContentInset = contentInset;
1573
1574 if (!hasRunningProcess())
1575 return;
1576#if PLATFORM(COCOA)
1577 MachSendRight fence = m_drawingArea->createFence();
1578
1579 auto fenceAttachment = IPC::Attachment(fence.leakSendRight(), MACH_MSG_TYPE_MOVE_SEND);
1580 m_process->send(Messages::WebPage::SetTopContentInsetFenced(contentInset, fenceAttachment), m_pageID);
1581#else
1582 m_process->send(Messages::WebPage::SetTopContentInset(contentInset), m_pageID);
1583#endif
1584}
1585
1586void WebPageProxy::setUnderlayColor(const Color& color)
1587{
1588 if (m_underlayColor == color)
1589 return;
1590
1591 m_underlayColor = color;
1592
1593 if (hasRunningProcess())
1594 m_process->send(Messages::WebPage::SetUnderlayColor(color), m_pageID);
1595}
1596
1597void WebPageProxy::viewWillStartLiveResize()
1598{
1599 if (!hasRunningProcess())
1600 return;
1601
1602 closeOverlayedViews();
1603 m_process->send(Messages::WebPage::ViewWillStartLiveResize(), m_pageID);
1604}
1605
1606void WebPageProxy::viewWillEndLiveResize()
1607{
1608 if (!hasRunningProcess())
1609 return;
1610 m_process->send(Messages::WebPage::ViewWillEndLiveResize(), m_pageID);
1611}
1612
1613void WebPageProxy::setViewNeedsDisplay(const Region& region)
1614{
1615 pageClient().setViewNeedsDisplay(region);
1616}
1617
1618void WebPageProxy::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin)
1619{
1620 pageClient().requestScroll(scrollPosition, scrollOrigin);
1621}
1622
1623WebCore::FloatPoint WebPageProxy::viewScrollPosition() const
1624{
1625 return pageClient().viewScrollPosition();
1626}
1627
1628void WebPageProxy::setSuppressVisibilityUpdates(bool flag)
1629{
1630 if (m_suppressVisibilityUpdates == flag)
1631 return;
1632 m_suppressVisibilityUpdates = flag;
1633
1634 if (!m_suppressVisibilityUpdates) {
1635#if PLATFORM(COCOA)
1636 m_activityStateChangeDispatcher->schedule();
1637#else
1638 dispatchActivityStateChange();
1639#endif
1640 }
1641}
1642
1643void WebPageProxy::updateActivityState(OptionSet<ActivityState::Flag> flagsToUpdate)
1644{
1645 m_activityState.remove(flagsToUpdate);
1646 if (flagsToUpdate & ActivityState::IsFocused && pageClient().isViewFocused())
1647 m_activityState.add(ActivityState::IsFocused);
1648 if (flagsToUpdate & ActivityState::WindowIsActive && pageClient().isViewWindowActive())
1649 m_activityState.add(ActivityState::WindowIsActive);
1650 if (flagsToUpdate & ActivityState::IsVisible && pageClient().isViewVisible())
1651 m_activityState.add(ActivityState::IsVisible);
1652 if (flagsToUpdate & ActivityState::IsVisibleOrOccluded && pageClient().isViewVisibleOrOccluded())
1653 m_activityState.add(ActivityState::IsVisibleOrOccluded);
1654 if (flagsToUpdate & ActivityState::IsInWindow && pageClient().isViewInWindow())
1655 m_activityState.add(ActivityState::IsInWindow);
1656 if (flagsToUpdate & ActivityState::IsVisuallyIdle && pageClient().isVisuallyIdle())
1657 m_activityState.add(ActivityState::IsVisuallyIdle);
1658 if (flagsToUpdate & ActivityState::IsAudible && m_mediaState & MediaProducer::IsPlayingAudio && !(m_mutedState & MediaProducer::AudioIsMuted))
1659 m_activityState.add(ActivityState::IsAudible);
1660 if (flagsToUpdate & ActivityState::IsLoading && m_pageLoadState.isLoading())
1661 m_activityState.add(ActivityState::IsLoading);
1662 if (flagsToUpdate & ActivityState::IsCapturingMedia && m_mediaState & (MediaProducer::HasActiveAudioCaptureDevice | MediaProducer::HasActiveVideoCaptureDevice))
1663 m_activityState.add(ActivityState::IsCapturingMedia);
1664}
1665
1666void WebPageProxy::activityStateDidChange(OptionSet<ActivityState::Flag> mayHaveChanged, bool wantsSynchronousReply, ActivityStateChangeDispatchMode dispatchMode)
1667{
1668 LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << pageID() << " activityStateDidChange - mayHaveChanged " << mayHaveChanged);
1669
1670 m_potentiallyChangedActivityStateFlags.add(mayHaveChanged);
1671 m_activityStateChangeWantsSynchronousReply = m_activityStateChangeWantsSynchronousReply || wantsSynchronousReply;
1672
1673 if (m_suppressVisibilityUpdates && dispatchMode != ActivityStateChangeDispatchMode::Immediate)
1674 return;
1675
1676#if PLATFORM(COCOA)
1677 bool isNewlyInWindow = !isInWindow() && (mayHaveChanged & ActivityState::IsInWindow) && pageClient().isViewInWindow();
1678 if (dispatchMode == ActivityStateChangeDispatchMode::Immediate || isNewlyInWindow) {
1679 dispatchActivityStateChange();
1680 return;
1681 }
1682 m_activityStateChangeDispatcher->schedule();
1683#else
1684 UNUSED_PARAM(dispatchMode);
1685 dispatchActivityStateChange();
1686#endif
1687}
1688
1689void WebPageProxy::viewDidLeaveWindow()
1690{
1691 closeOverlayedViews();
1692#if PLATFORM(IOS_FAMILY) && HAVE(AVKIT) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
1693 // When leaving the current page, close the video fullscreen.
1694 if (m_videoFullscreenManager)
1695 m_videoFullscreenManager->requestHideAndExitFullscreen();
1696#endif
1697}
1698
1699void WebPageProxy::viewDidEnterWindow()
1700{
1701 LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
1702 if (m_layerHostingMode != layerHostingMode) {
1703 m_layerHostingMode = layerHostingMode;
1704 m_process->send(Messages::WebPage::SetLayerHostingMode(layerHostingMode), m_pageID);
1705 }
1706}
1707
1708void WebPageProxy::dispatchActivityStateChange()
1709{
1710#if PLATFORM(COCOA)
1711 m_activityStateChangeDispatcher->invalidate();
1712#endif
1713
1714 if (!hasRunningProcess())
1715 return;
1716
1717 LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << pageID() << " dispatchActivityStateChange - potentiallyChangedActivityStateFlags " << m_potentiallyChangedActivityStateFlags);
1718
1719 // If the visibility state may have changed, then so may the visually idle & occluded agnostic state.
1720 if (m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible)
1721 m_potentiallyChangedActivityStateFlags.add({ ActivityState::IsVisibleOrOccluded, ActivityState::IsVisuallyIdle });
1722
1723 // Record the prior view state, update the flags that may have changed,
1724 // and check which flags have actually changed.
1725 auto previousActivityState = m_activityState;
1726 updateActivityState(m_potentiallyChangedActivityStateFlags);
1727 auto changed = m_activityState ^ previousActivityState;
1728
1729 if (changed)
1730 LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << pageID() << " dispatchActivityStateChange: state changed from " << previousActivityState << " to " << m_activityState);
1731
1732 if ((changed & ActivityState::WindowIsActive) && isViewWindowActive())
1733 updateCurrentModifierState();
1734
1735 if ((m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible) && isViewVisible())
1736 viewIsBecomingVisible();
1737
1738 bool isNowInWindow = (changed & ActivityState::IsInWindow) && isInWindow();
1739 // We always want to wait for the Web process to reply if we've been in-window before and are coming back in-window.
1740 if (m_viewWasEverInWindow && isNowInWindow) {
1741 if (m_drawingArea->hasVisibleContent() && m_waitsForPaintAfterViewDidMoveToWindow && !m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow)
1742 m_activityStateChangeWantsSynchronousReply = true;
1743 m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow = false;
1744 }
1745
1746 // Don't wait synchronously if the view state is not visible. (This matters in particular on iOS, where a hidden page may be suspended.)
1747 if (!(m_activityState & ActivityState::IsVisible))
1748 m_activityStateChangeWantsSynchronousReply = false;
1749
1750 auto activityStateChangeID = m_activityStateChangeWantsSynchronousReply ? takeNextActivityStateChangeID() : static_cast<ActivityStateChangeID>(ActivityStateChangeAsynchronous);
1751
1752 if (changed || activityStateChangeID != ActivityStateChangeAsynchronous || !m_nextActivityStateChangeCallbacks.isEmpty())
1753 m_process->send(Messages::WebPage::SetActivityState(m_activityState, activityStateChangeID, m_nextActivityStateChangeCallbacks), m_pageID);
1754
1755 m_nextActivityStateChangeCallbacks.clear();
1756
1757 // This must happen after the SetActivityState message is sent, to ensure the page visibility event can fire.
1758 updateThrottleState();
1759
1760#if ENABLE(POINTER_LOCK)
1761 if (((changed & ActivityState::IsVisible) && !isViewVisible()) || ((changed & ActivityState::WindowIsActive) && !pageClient().isViewWindowActive())
1762 || ((changed & ActivityState::IsFocused) && !(m_activityState & ActivityState::IsFocused)))
1763 requestPointerUnlock();
1764#endif
1765
1766 if (changed & ActivityState::IsVisible) {
1767 if (isViewVisible())
1768 m_visiblePageToken = m_process->visiblePageToken();
1769 else {
1770 m_visiblePageToken = nullptr;
1771
1772 // If we've started the responsiveness timer as part of telling the web process to update the backing store
1773 // state, it might not send back a reply (since it won't paint anything if the web page is hidden) so we
1774 // stop the unresponsiveness timer here.
1775 m_process->responsivenessTimer().stop();
1776 }
1777 }
1778
1779 if (changed & ActivityState::IsInWindow) {
1780 if (isInWindow())
1781 viewDidEnterWindow();
1782 else
1783 viewDidLeaveWindow();
1784 }
1785
1786 updateBackingStoreDiscardableState();
1787
1788 if (activityStateChangeID != ActivityStateChangeAsynchronous)
1789 waitForDidUpdateActivityState(activityStateChangeID);
1790
1791 m_potentiallyChangedActivityStateFlags = { };
1792 m_activityStateChangeWantsSynchronousReply = false;
1793 m_viewWasEverInWindow |= isNowInWindow;
1794}
1795
1796bool WebPageProxy::isAlwaysOnLoggingAllowed() const
1797{
1798 return sessionID().isAlwaysOnLoggingAllowed();
1799}
1800
1801void WebPageProxy::updateThrottleState()
1802{
1803 bool processSuppressionEnabled = m_preferences->pageVisibilityBasedProcessSuppressionEnabled();
1804
1805 // If process suppression is not enabled take a token on the process pool to disable suppression of support processes.
1806 if (!processSuppressionEnabled)
1807 m_preventProcessSuppressionCount = m_process->processPool().processSuppressionDisabledForPageCount();
1808 else if (!m_preventProcessSuppressionCount)
1809 m_preventProcessSuppressionCount = nullptr;
1810
1811 if (m_activityState & ActivityState::IsVisuallyIdle)
1812 m_pageIsUserObservableCount = nullptr;
1813 else if (!m_pageIsUserObservableCount)
1814 m_pageIsUserObservableCount = m_process->processPool().userObservablePageCount();
1815
1816#if PLATFORM(IOS_FAMILY)
1817 bool isCapturingMedia = m_activityState.contains(ActivityState::IsCapturingMedia);
1818 bool isAudible = m_activityState.contains(ActivityState::IsAudible);
1819 if (!isViewVisible() && !m_alwaysRunsAtForegroundPriority && !isCapturingMedia && !isAudible) {
1820 if (m_activityToken) {
1821 RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because the view is no longer visible");
1822 m_activityToken = nullptr;
1823 }
1824 } else if (!m_activityToken) {
1825 if (isViewVisible())
1826 RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because the view is visible");
1827 else if (isAudible)
1828 RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because we are playing audio");
1829 else if (isCapturingMedia)
1830 RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because media capture is active");
1831 else
1832 RELEASE_LOG_IF_ALLOWED(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion even though the view is not visible because m_alwaysRunsAtForegroundPriority is true");
1833 m_activityToken = m_process->throttler().foregroundActivityToken();
1834 }
1835#endif
1836}
1837
1838void WebPageProxy::updateHiddenPageThrottlingAutoIncreases()
1839{
1840 if (!m_preferences->hiddenPageDOMTimerThrottlingAutoIncreases())
1841 m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = nullptr;
1842 else if (!m_hiddenPageDOMTimerThrottlingAutoIncreasesCount)
1843 m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = m_process->processPool().hiddenPageThrottlingAutoIncreasesCount();
1844}
1845
1846void WebPageProxy::layerHostingModeDidChange()
1847{
1848 if (!hasRunningProcess())
1849 return;
1850
1851 LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
1852 if (m_layerHostingMode == layerHostingMode)
1853 return;
1854
1855 m_layerHostingMode = layerHostingMode;
1856 m_process->send(Messages::WebPage::SetLayerHostingMode(layerHostingMode), m_pageID);
1857}
1858
1859void WebPageProxy::waitForDidUpdateActivityState(ActivityStateChangeID activityStateChangeID)
1860{
1861 if (!hasRunningProcess())
1862 return;
1863
1864 if (m_process->state() != WebProcessProxy::State::Running)
1865 return;
1866
1867 // If we have previously timed out with no response from the WebProcess, don't block the UIProcess again until it starts responding.
1868 if (m_waitingForDidUpdateActivityState)
1869 return;
1870
1871#if PLATFORM(IOS_FAMILY)
1872 // Hail Mary check. Should not be possible (dispatchActivityStateChange should force async if not visible,
1873 // and if visible we should be holding an assertion) - but we should never block on a suspended process.
1874 if (!m_activityToken) {
1875 ASSERT_NOT_REACHED();
1876 return;
1877 }
1878#endif
1879
1880 m_waitingForDidUpdateActivityState = true;
1881
1882 m_drawingArea->waitForDidUpdateActivityState(activityStateChangeID);
1883}
1884
1885IntSize WebPageProxy::viewSize() const
1886{
1887 return pageClient().viewSize();
1888}
1889
1890void WebPageProxy::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& keyboardEvent, WTF::Function<void (CallbackBase::Error)>&& callbackFunction)
1891{
1892 if (!hasRunningProcess()) {
1893 callbackFunction(CallbackBase::Error::OwnerWasInvalidated);
1894 return;
1895 }
1896
1897 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
1898 m_process->send(Messages::WebPage::SetInitialFocus(forward, isKeyboardEventValid, keyboardEvent, callbackID), m_pageID);
1899}
1900
1901void WebPageProxy::clearSelection()
1902{
1903 if (!hasRunningProcess())
1904 return;
1905 m_process->send(Messages::WebPage::ClearSelection(), m_pageID);
1906}
1907
1908void WebPageProxy::restoreSelectionInFocusedEditableElement()
1909{
1910 if (!hasRunningProcess())
1911 return;
1912 m_process->send(Messages::WebPage::RestoreSelectionInFocusedEditableElement(), m_pageID);
1913}
1914
1915void WebPageProxy::validateCommand(const String& commandName, WTF::Function<void (const String&, bool, int32_t, CallbackBase::Error)>&& callbackFunction)
1916{
1917 if (!hasRunningProcess()) {
1918 callbackFunction(String(), false, 0, CallbackBase::Error::Unknown);
1919 return;
1920 }
1921
1922 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
1923 m_process->send(Messages::WebPage::ValidateCommand(commandName, callbackID), m_pageID);
1924}
1925
1926void WebPageProxy::increaseListLevel()
1927{
1928 if (!hasRunningProcess())
1929 return;
1930
1931 m_process->send(Messages::WebPage::IncreaseListLevel(), m_pageID);
1932}
1933
1934void WebPageProxy::decreaseListLevel()
1935{
1936 if (!hasRunningProcess())
1937 return;
1938
1939 m_process->send(Messages::WebPage::DecreaseListLevel(), m_pageID);
1940}
1941
1942void WebPageProxy::changeListType()
1943{
1944 if (!hasRunningProcess())
1945 return;
1946
1947 m_process->send(Messages::WebPage::ChangeListType(), m_pageID);
1948}
1949
1950void WebPageProxy::setBaseWritingDirection(WritingDirection direction)
1951{
1952 if (!hasRunningProcess())
1953 return;
1954
1955 m_process->send(Messages::WebPage::SetBaseWritingDirection(direction), m_pageID);
1956}
1957
1958void WebPageProxy::updateFontAttributesAfterEditorStateChange()
1959{
1960 m_cachedFontAttributesAtSelectionStart.reset();
1961
1962 if (m_editorState.isMissingPostLayoutData)
1963 return;
1964
1965 if (auto fontAttributes = m_editorState.postLayoutData().fontAttributes) {
1966 m_uiClient->didChangeFontAttributes(*fontAttributes);
1967 m_cachedFontAttributesAtSelectionStart = WTFMove(fontAttributes);
1968 }
1969}
1970
1971void WebPageProxy::setNeedsFontAttributes(bool needsFontAttributes)
1972{
1973 if (m_needsFontAttributes == needsFontAttributes)
1974 return;
1975
1976 m_needsFontAttributes = needsFontAttributes;
1977
1978 if (hasRunningProcess())
1979 m_process->send(Messages::WebPage::SetNeedsFontAttributes(needsFontAttributes), m_pageID);
1980}
1981
1982bool WebPageProxy::maintainsInactiveSelection() const
1983{
1984 // Regardless of what the client wants to do, keep selections if a local Inspector is open.
1985 // Otherwise, there is no way to use the console to inspect the state of a selection.
1986 if (inspector() && inspector()->isVisible())
1987 return true;
1988
1989 return m_maintainsInactiveSelection;
1990}
1991
1992void WebPageProxy::setMaintainsInactiveSelection(bool newValue)
1993{
1994 m_maintainsInactiveSelection = newValue;
1995}
1996
1997void WebPageProxy::scheduleFullEditorStateUpdate()
1998{
1999 if (!hasRunningProcess())
2000 return;
2001
2002 m_process->send(Messages::WebPage::ScheduleFullEditorStateUpdate(), m_pageID);
2003}
2004
2005void WebPageProxy::selectAll()
2006{
2007 if (!hasRunningProcess())
2008 return;
2009
2010 m_process->send(Messages::WebPage::SelectAll(), m_pageID);
2011}
2012
2013void WebPageProxy::executeEditCommand(const String& commandName, const String& argument, WTF::Function<void(CallbackBase::Error)>&& callbackFunction)
2014{
2015 if (!hasRunningProcess()) {
2016 callbackFunction(CallbackBase::Error::Unknown);
2017 return;
2018 }
2019
2020 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
2021 m_process->send(Messages::WebPage::ExecuteEditCommandWithCallback(commandName, argument, callbackID), m_pageID);
2022}
2023
2024void WebPageProxy::executeEditCommand(const String& commandName, const String& argument)
2025{
2026 static NeverDestroyed<String> ignoreSpellingCommandName(MAKE_STATIC_STRING_IMPL("ignoreSpelling"));
2027
2028 if (!hasRunningProcess())
2029 return;
2030
2031 if (commandName == ignoreSpellingCommandName)
2032 ++m_pendingLearnOrIgnoreWordMessageCount;
2033
2034 m_process->send(Messages::WebPage::ExecuteEditCommand(commandName, argument), m_pageID);
2035}
2036
2037void WebPageProxy::requestFontAttributesAtSelectionStart(Function<void(const WebCore::FontAttributes&, CallbackBase::Error)>&& callback)
2038{
2039 if (!hasRunningProcess()) {
2040 callback({ }, CallbackBase::Error::Unknown);
2041 return;
2042 }
2043
2044 auto callbackID = m_callbacks.put(WTFMove(callback), m_process->throttler().backgroundActivityToken());
2045 m_process->send(Messages::WebPage::RequestFontAttributesAtSelectionStart(callbackID), m_pageID);
2046}
2047
2048void WebPageProxy::fontAttributesCallback(const WebCore::FontAttributes& attributes, CallbackID callbackID)
2049{
2050 m_cachedFontAttributesAtSelectionStart = attributes;
2051
2052 if (auto callback = m_callbacks.take<FontAttributesCallback>(callbackID))
2053 callback->performCallbackWithReturnValue(attributes);
2054}
2055
2056void WebPageProxy::setEditable(bool editable)
2057{
2058 if (editable == m_isEditable)
2059 return;
2060
2061 m_isEditable = editable;
2062
2063 if (!hasRunningProcess())
2064 return;
2065
2066 m_process->send(Messages::WebPage::SetEditable(editable), m_pageID);
2067}
2068
2069void WebPageProxy::setMediaStreamCaptureMuted(bool muted)
2070{
2071 if (muted)
2072 setMuted(m_mutedState | WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2073 else
2074 setMuted(m_mutedState & ~WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2075}
2076
2077void WebPageProxy::activateMediaStreamCaptureInPage()
2078{
2079#if ENABLE(MEDIA_STREAM)
2080 UserMediaProcessManager::singleton().muteCaptureMediaStreamsExceptIn(*this);
2081#endif
2082 setMuted(m_mutedState & ~WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2083}
2084
2085#if !PLATFORM(IOS_FAMILY)
2086void WebPageProxy::didCommitLayerTree(const RemoteLayerTreeTransaction&)
2087{
2088}
2089
2090void WebPageProxy::layerTreeCommitComplete()
2091{
2092}
2093#endif
2094
2095#if ENABLE(DRAG_SUPPORT)
2096void WebPageProxy::dragEntered(DragData& dragData, const String& dragStorageName)
2097{
2098 performDragControllerAction(DragControllerAction::Entered, dragData, dragStorageName, { }, { });
2099}
2100
2101void WebPageProxy::dragUpdated(DragData& dragData, const String& dragStorageName)
2102{
2103 performDragControllerAction(DragControllerAction::Updated, dragData, dragStorageName, { }, { });
2104}
2105
2106void WebPageProxy::dragExited(DragData& dragData, const String& dragStorageName)
2107{
2108 performDragControllerAction(DragControllerAction::Exited, dragData, dragStorageName, { }, { });
2109}
2110
2111void WebPageProxy::performDragOperation(DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsForUpload)
2112{
2113 performDragControllerAction(DragControllerAction::PerformDragOperation, dragData, dragStorageName, WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionsForUpload));
2114}
2115
2116void WebPageProxy::performDragControllerAction(DragControllerAction action, DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsForUpload)
2117{
2118 if (!hasRunningProcess())
2119 return;
2120#if PLATFORM(GTK)
2121 UNUSED_PARAM(dragStorageName);
2122 UNUSED_PARAM(sandboxExtensionHandle);
2123 UNUSED_PARAM(sandboxExtensionsForUpload);
2124
2125 String url = dragData.asURL();
2126 if (!url.isEmpty())
2127 m_process->assumeReadAccessToBaseURL(*this, url);
2128
2129 ASSERT(dragData.platformData());
2130 WebSelectionData selection(*dragData.platformData());
2131 m_process->send(Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), selection, dragData.flags()), m_pageID);
2132#else
2133 m_process->send(Messages::WebPage::PerformDragControllerAction(action, dragData, sandboxExtensionHandle, sandboxExtensionsForUpload), m_pageID);
2134#endif
2135}
2136
2137void WebPageProxy::didPerformDragControllerAction(uint64_t dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect, const IntRect& editableElementRect)
2138{
2139 MESSAGE_CHECK(m_process, dragOperation <= DragOperationDelete);
2140
2141 m_currentDragOperation = static_cast<DragOperation>(dragOperation);
2142 m_currentDragHandlingMethod = dragHandlingMethod;
2143 m_currentDragIsOverFileInput = mouseIsOverFileInput;
2144 m_currentDragNumberOfFilesToBeAccepted = numberOfItemsToBeAccepted;
2145 m_currentDragCaretEditableElementRect = editableElementRect;
2146 setDragCaretRect(insertionRect);
2147}
2148
2149#if PLATFORM(GTK)
2150void WebPageProxy::startDrag(WebSelectionData&& selection, uint64_t dragOperation, const ShareableBitmap::Handle& dragImageHandle)
2151{
2152 RefPtr<ShareableBitmap> dragImage = !dragImageHandle.isNull() ? ShareableBitmap::create(dragImageHandle) : nullptr;
2153 pageClient().startDrag(WTFMove(selection.selectionData), static_cast<WebCore::DragOperation>(dragOperation), WTFMove(dragImage));
2154
2155 didStartDrag();
2156}
2157#endif
2158
2159void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t operation)
2160{
2161 if (!hasRunningProcess())
2162 return;
2163 m_process->send(Messages::WebPage::DragEnded(clientPosition, globalPosition, operation), m_pageID);
2164 setDragCaretRect({ });
2165}
2166
2167void WebPageProxy::didPerformDragOperation(bool handled)
2168{
2169 pageClient().didPerformDragOperation(handled);
2170}
2171
2172void WebPageProxy::didStartDrag()
2173{
2174 if (hasRunningProcess())
2175 m_process->send(Messages::WebPage::DidStartDrag(), m_pageID);
2176}
2177
2178void WebPageProxy::dragCancelled()
2179{
2180 if (hasRunningProcess())
2181 m_process->send(Messages::WebPage::DragCancelled(), m_pageID);
2182}
2183
2184void WebPageProxy::didEndDragging()
2185{
2186 resetCurrentDragInformation();
2187}
2188
2189void WebPageProxy::resetCurrentDragInformation()
2190{
2191 m_currentDragOperation = WebCore::DragOperationNone;
2192 m_currentDragHandlingMethod = DragHandlingMethod::None;
2193 m_currentDragIsOverFileInput = false;
2194 m_currentDragNumberOfFilesToBeAccepted = 0;
2195 setDragCaretRect({ });
2196}
2197
2198#if !ENABLE(DATA_INTERACTION)
2199
2200void WebPageProxy::setDragCaretRect(const IntRect& dragCaretRect)
2201{
2202 m_currentDragCaretRect = dragCaretRect;
2203}
2204
2205#endif
2206
2207#endif // ENABLE(DRAG_SUPPORT)
2208
2209static bool removeOldRedundantEvent(Deque<NativeWebMouseEvent>& queue, WebEvent::Type incomingEventType)
2210{
2211 if (incomingEventType != WebEvent::MouseMove && incomingEventType != WebEvent::MouseForceChanged)
2212 return false;
2213
2214 auto it = queue.rbegin();
2215 auto end = queue.rend();
2216
2217 // Must not remove the first event in the deque, since it is already being dispatched.
2218 if (it != end)
2219 --end;
2220
2221 for (; it != end; ++it) {
2222 auto type = it->type();
2223 if (type == incomingEventType) {
2224 queue.remove(--it.base());
2225 return true;
2226 }
2227 if (type != WebEvent::MouseMove && type != WebEvent::MouseForceChanged)
2228 break;
2229 }
2230 return false;
2231}
2232
2233void WebPageProxy::handleMouseEvent(const NativeWebMouseEvent& event)
2234{
2235 if (!hasRunningProcess())
2236 return;
2237
2238#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2239 if (m_scrollingCoordinatorProxy)
2240 m_scrollingCoordinatorProxy->handleMouseEvent(platform(event));
2241#endif
2242
2243 // If we receive multiple mousemove or mouseforcechanged events and the most recent mousemove or mouseforcechanged event
2244 // (respectively) has not yet been sent to WebProcess for processing, remove the pending mouse event and insert the new
2245 // event in the queue.
2246 bool didRemoveEvent = removeOldRedundantEvent(m_mouseEventQueue, event.type());
2247 m_mouseEventQueue.append(event);
2248
2249#if LOG_DISABLED
2250 UNUSED_PARAM(didRemoveEvent);
2251#else
2252 LOG(MouseHandling, "UIProcess: %s mouse event %s (queue size %zu)", didRemoveEvent ? "replaced" : "enqueued", webMouseEventTypeString(event.type()), m_mouseEventQueue.size());
2253#endif
2254
2255 if (m_mouseEventQueue.size() == 1) // Otherwise, called from DidReceiveEvent message handler.
2256 processNextQueuedMouseEvent();
2257}
2258
2259void WebPageProxy::processNextQueuedMouseEvent()
2260{
2261 if (!hasRunningProcess())
2262 return;
2263
2264 ASSERT(!m_mouseEventQueue.isEmpty());
2265
2266 const NativeWebMouseEvent& event = m_mouseEventQueue.first();
2267
2268 if (pageClient().windowIsFrontWindowUnderMouse(event))
2269 setToolTip(String());
2270
2271 WebEvent::Type eventType = event.type();
2272 if (eventType == WebEvent::MouseDown || eventType == WebEvent::MouseForceChanged || eventType == WebEvent::MouseForceDown)
2273 m_process->responsivenessTimer().startWithLazyStop();
2274 else if (eventType != WebEvent::MouseMove) {
2275 // NOTE: This does not start the responsiveness timer because mouse move should not indicate interaction.
2276 m_process->responsivenessTimer().start();
2277 }
2278
2279 LOG(MouseHandling, "UIProcess: sent mouse event %s (queue size %zu)", webMouseEventTypeString(eventType), m_mouseEventQueue.size());
2280 m_process->send(Messages::WebPage::MouseEvent(event), m_pageID);
2281}
2282
2283#if MERGE_WHEEL_EVENTS
2284static bool canCoalesce(const WebWheelEvent& a, const WebWheelEvent& b)
2285{
2286 if (a.position() != b.position())
2287 return false;
2288 if (a.globalPosition() != b.globalPosition())
2289 return false;
2290 if (a.modifiers() != b.modifiers())
2291 return false;
2292 if (a.granularity() != b.granularity())
2293 return false;
2294#if PLATFORM(COCOA)
2295 if (a.phase() != b.phase())
2296 return false;
2297 if (a.momentumPhase() != b.momentumPhase())
2298 return false;
2299 if (a.hasPreciseScrollingDeltas() != b.hasPreciseScrollingDeltas())
2300 return false;
2301#endif
2302
2303 return true;
2304}
2305
2306static WebWheelEvent coalesce(const WebWheelEvent& a, const WebWheelEvent& b)
2307{
2308 ASSERT(canCoalesce(a, b));
2309
2310 FloatSize mergedDelta = a.delta() + b.delta();
2311 FloatSize mergedWheelTicks = a.wheelTicks() + b.wheelTicks();
2312
2313#if PLATFORM(COCOA)
2314 FloatSize mergedUnacceleratedScrollingDelta = a.unacceleratedScrollingDelta() + b.unacceleratedScrollingDelta();
2315
2316 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());
2317#else
2318 return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.modifiers(), b.timestamp());
2319#endif
2320}
2321#endif // MERGE_WHEEL_EVENTS
2322
2323static WebWheelEvent coalescedWheelEvent(Deque<NativeWebWheelEvent>& queue, Vector<NativeWebWheelEvent>& coalescedEvents)
2324{
2325 ASSERT(!queue.isEmpty());
2326 ASSERT(coalescedEvents.isEmpty());
2327
2328#if MERGE_WHEEL_EVENTS
2329 NativeWebWheelEvent firstEvent = queue.takeFirst();
2330 coalescedEvents.append(firstEvent);
2331
2332 WebWheelEvent event = firstEvent;
2333 while (!queue.isEmpty() && canCoalesce(event, queue.first())) {
2334 NativeWebWheelEvent firstEvent = queue.takeFirst();
2335 coalescedEvents.append(firstEvent);
2336 event = coalesce(event, firstEvent);
2337 }
2338
2339 return event;
2340#else
2341 while (!queue.isEmpty())
2342 coalescedEvents.append(queue.takeFirst());
2343 return coalescedEvents.last();
2344#endif
2345}
2346
2347void WebPageProxy::handleWheelEvent(const NativeWebWheelEvent& event)
2348{
2349#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2350 if (m_scrollingCoordinatorProxy && m_scrollingCoordinatorProxy->handleWheelEvent(platform(event)))
2351 return;
2352#endif
2353
2354 if (!hasRunningProcess())
2355 return;
2356
2357 closeOverlayedViews();
2358
2359 if (!m_currentlyProcessedWheelEvents.isEmpty()) {
2360 m_wheelEventQueue.append(event);
2361 if (!shouldProcessWheelEventNow(event))
2362 return;
2363 // The queue has too many wheel events, so push a new event.
2364 }
2365
2366 if (!m_wheelEventQueue.isEmpty()) {
2367 processNextQueuedWheelEvent();
2368 return;
2369 }
2370
2371 auto coalescedWheelEvent = std::make_unique<Vector<NativeWebWheelEvent>>();
2372 coalescedWheelEvent->append(event);
2373 m_currentlyProcessedWheelEvents.append(WTFMove(coalescedWheelEvent));
2374 sendWheelEvent(event);
2375}
2376
2377void WebPageProxy::processNextQueuedWheelEvent()
2378{
2379 auto nextCoalescedEvent = std::make_unique<Vector<NativeWebWheelEvent>>();
2380 WebWheelEvent nextWheelEvent = coalescedWheelEvent(m_wheelEventQueue, *nextCoalescedEvent.get());
2381 m_currentlyProcessedWheelEvents.append(WTFMove(nextCoalescedEvent));
2382 sendWheelEvent(nextWheelEvent);
2383}
2384
2385void WebPageProxy::sendWheelEvent(const WebWheelEvent& event)
2386{
2387 m_process->send(
2388 Messages::EventDispatcher::WheelEvent(
2389 m_pageID,
2390 event,
2391 shouldUseImplicitRubberBandControl() ? !m_backForwardList->backItem() : rubberBandsAtLeft(),
2392 shouldUseImplicitRubberBandControl() ? !m_backForwardList->forwardItem() : rubberBandsAtRight(),
2393 rubberBandsAtTop(),
2394 rubberBandsAtBottom()
2395 ), 0);
2396
2397 // Manually ping the web process to check for responsiveness since our wheel
2398 // event will dispatch to a non-main thread, which always responds.
2399 m_process->isResponsiveWithLazyStop();
2400}
2401
2402bool WebPageProxy::shouldProcessWheelEventNow(const WebWheelEvent& event) const
2403{
2404#if PLATFORM(GTK)
2405 // Don't queue events representing a non-trivial scrolling phase to
2406 // avoid having them trapped in the queue, potentially preventing a
2407 // scrolling session to beginning or end correctly.
2408 // This is only needed by platforms whose WebWheelEvent has this phase
2409 // information (Cocoa and GTK+) but Cocoa was fine without it.
2410 if (event.phase() == WebWheelEvent::Phase::PhaseNone
2411 || event.phase() == WebWheelEvent::Phase::PhaseChanged
2412 || event.momentumPhase() == WebWheelEvent::Phase::PhaseNone
2413 || event.momentumPhase() == WebWheelEvent::Phase::PhaseChanged)
2414 return true;
2415#else
2416 UNUSED_PARAM(event);
2417#endif
2418 if (m_wheelEventQueue.size() >= wheelEventQueueSizeThreshold)
2419 return true;
2420 return false;
2421}
2422
2423void WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event)
2424{
2425 if (!hasRunningProcess())
2426 return;
2427
2428 LOG(KeyHandling, "WebPageProxy::handleKeyboardEvent: %s", webKeyboardEventTypeString(event.type()));
2429
2430 m_keyEventQueue.append(event);
2431
2432 ResponsivenessTimer& responsivenessTimer = m_process->responsivenessTimer();
2433 if (event.type() == WebEvent::KeyDown)
2434 responsivenessTimer.startWithLazyStop();
2435 else
2436 responsivenessTimer.start();
2437
2438 if (m_keyEventQueue.size() == 1) { // Otherwise, sent from DidReceiveEvent message handler.
2439 LOG(KeyHandling, " UI process: sent keyEvent from handleKeyboardEvent");
2440 m_process->send(Messages::WebPage::KeyEvent(event), m_pageID);
2441 }
2442}
2443
2444WebPreferencesStore WebPageProxy::preferencesStore() const
2445{
2446 if (m_configurationPreferenceValues.isEmpty())
2447 return m_preferences->store();
2448
2449 WebPreferencesStore store = m_preferences->store();
2450 for (const auto& preference : m_configurationPreferenceValues)
2451 store.m_values.set(preference.key, preference.value);
2452
2453 return store;
2454}
2455
2456#if ENABLE(NETSCAPE_PLUGIN_API)
2457void WebPageProxy::findPlugin(const String& mimeType, uint32_t processType, const String& urlString, const String& frameURLString, const String& pageURLString, bool allowOnlyApplicationPlugins, Messages::WebPageProxy::FindPlugin::DelayedReply&& reply)
2458{
2459 PageClientProtector protector(pageClient());
2460
2461 MESSAGE_CHECK_URL(m_process, urlString);
2462
2463 URL pluginURL = URL { URL(), urlString };
2464 String newMimeType = mimeType.convertToASCIILowercase();
2465
2466 PluginData::AllowedPluginTypes allowedPluginTypes = allowOnlyApplicationPlugins ? PluginData::OnlyApplicationPlugins : PluginData::AllPlugins;
2467
2468 URL pageURL = URL { URL(), pageURLString };
2469 if (!m_process->processPool().pluginInfoStore().isSupportedPlugin(mimeType, pluginURL, frameURLString, pageURL)) {
2470 reply(0, newMimeType, PluginModuleLoadNormally, { }, true);
2471 return;
2472 }
2473
2474 PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, pluginURL, allowedPluginTypes);
2475 if (!plugin.path) {
2476 reply(0, newMimeType, PluginModuleLoadNormally, { }, false);
2477 return;
2478 }
2479
2480 uint32_t pluginLoadPolicy = PluginInfoStore::defaultLoadPolicyForPlugin(plugin);
2481
2482#if PLATFORM(COCOA)
2483 auto pluginInformation = createPluginInformationDictionary(plugin, frameURLString, String(), pageURLString, String(), String());
2484#endif
2485
2486 auto findPluginCompletion = [processType, reply = WTFMove(reply), newMimeType = WTFMove(newMimeType), plugin = WTFMove(plugin)] (uint32_t pluginLoadPolicy, const String& unavailabilityDescription) mutable {
2487 PluginProcessSandboxPolicy pluginProcessSandboxPolicy = PluginProcessSandboxPolicyNormal;
2488 switch (pluginLoadPolicy) {
2489 case PluginModuleLoadNormally:
2490 pluginProcessSandboxPolicy = PluginProcessSandboxPolicyNormal;
2491 break;
2492 case PluginModuleLoadUnsandboxed:
2493 pluginProcessSandboxPolicy = PluginProcessSandboxPolicyUnsandboxed;
2494 break;
2495
2496 case PluginModuleBlockedForSecurity:
2497 case PluginModuleBlockedForCompatibility:
2498 reply(0, newMimeType, pluginLoadPolicy, unavailabilityDescription, false);
2499 return;
2500 }
2501
2502 reply(PluginProcessManager::singleton().pluginProcessToken(plugin, static_cast<PluginProcessType>(processType), pluginProcessSandboxPolicy), newMimeType, pluginLoadPolicy, unavailabilityDescription, false);
2503 };
2504
2505#if PLATFORM(COCOA)
2506 m_navigationClient->decidePolicyForPluginLoad(*this, static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy), pluginInformation.get(), WTFMove(findPluginCompletion));
2507#else
2508 findPluginCompletion(pluginLoadPolicy, { });
2509#endif
2510}
2511
2512#endif // ENABLE(NETSCAPE_PLUGIN_API)
2513
2514#if ENABLE(TOUCH_EVENTS)
2515
2516static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b)
2517{
2518 if (static_cast<uintptr_t>(b) > static_cast<uintptr_t>(a))
2519 return b;
2520 return a;
2521}
2522
2523void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent)
2524{
2525#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2526 const EventNames& names = eventNames();
2527 for (auto& touchPoint : touchStartEvent.touchPoints()) {
2528 IntPoint location = touchPoint.location();
2529 auto updateTrackingType = [this, location](TrackingType& trackingType, const AtomicString& eventName) {
2530 if (trackingType == TrackingType::Synchronous)
2531 return;
2532
2533 TrackingType trackingTypeForLocation = m_scrollingCoordinatorProxy->eventTrackingTypeForPoint(eventName, location);
2534
2535 trackingType = mergeTrackingTypes(trackingType, trackingTypeForLocation);
2536 };
2537 updateTrackingType(m_touchAndPointerEventTracking.touchForceChangedTracking, names.touchforcechangeEvent);
2538 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.touchstartEvent);
2539 updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.touchmoveEvent);
2540 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.touchendEvent);
2541 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.pointerdownEvent);
2542 updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.pointermoveEvent);
2543 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.pointerupEvent);
2544 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, names.mousedownEvent);
2545 updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, names.mousemoveEvent);
2546 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, names.mouseupEvent);
2547 }
2548#else
2549 UNUSED_PARAM(touchStartEvent);
2550 m_touchAndPointerEventTracking.touchForceChangedTracking = TrackingType::Synchronous;
2551 m_touchAndPointerEventTracking.touchStartTracking = TrackingType::Synchronous;
2552 m_touchAndPointerEventTracking.touchMoveTracking = TrackingType::Synchronous;
2553 m_touchAndPointerEventTracking.touchEndTracking = TrackingType::Synchronous;
2554#endif // ENABLE(ASYNC_SCROLLING)
2555}
2556
2557TrackingType WebPageProxy::touchEventTrackingType(const WebTouchEvent& touchStartEvent) const
2558{
2559 // We send all events if any type is needed, we just do it asynchronously for the types that are not tracked.
2560 //
2561 // Touch events define a sequence with strong dependencies. For example, we can expect
2562 // a TouchMove to only appear after a TouchStart, and the ids of the touch points is consistent between
2563 // the two.
2564 //
2565 // WebCore should not have to set up its state correctly after some events were dismissed.
2566 // For example, we don't want to send a TouchMoved without a TouchPressed.
2567 // We send everything, WebCore updates its internal state and dispatch what is needed to the page.
2568 TrackingType globalTrackingType = m_touchAndPointerEventTracking.isTrackingAnything() ? TrackingType::Asynchronous : TrackingType::NotTracking;
2569
2570 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchForceChangedTracking);
2571 for (auto& touchPoint : touchStartEvent.touchPoints()) {
2572 switch (touchPoint.state()) {
2573 case WebPlatformTouchPoint::TouchReleased:
2574 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchEndTracking);
2575 break;
2576 case WebPlatformTouchPoint::TouchPressed:
2577 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchStartTracking);
2578 break;
2579 case WebPlatformTouchPoint::TouchMoved:
2580 case WebPlatformTouchPoint::TouchStationary:
2581 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchMoveTracking);
2582 break;
2583 case WebPlatformTouchPoint::TouchCancelled:
2584 globalTrackingType = mergeTrackingTypes(globalTrackingType, TrackingType::Asynchronous);
2585 break;
2586 }
2587 }
2588
2589 return globalTrackingType;
2590}
2591
2592#endif
2593
2594#if ENABLE(MAC_GESTURE_EVENTS)
2595void WebPageProxy::handleGestureEvent(const NativeWebGestureEvent& event)
2596{
2597 if (!hasRunningProcess())
2598 return;
2599
2600 m_gestureEventQueue.append(event);
2601 // FIXME: Consider doing some coalescing here.
2602
2603 ResponsivenessTimer& responsivenessTimer = m_process->responsivenessTimer();
2604 if (event.type() == WebEvent::GestureStart || event.type() == WebEvent::GestureChange)
2605 responsivenessTimer.startWithLazyStop();
2606 else
2607 responsivenessTimer.start();
2608
2609 m_process->send(Messages::EventDispatcher::GestureEvent(m_pageID, event), 0);
2610}
2611#endif
2612
2613#if ENABLE(IOS_TOUCH_EVENTS)
2614void WebPageProxy::handleTouchEventSynchronously(NativeWebTouchEvent& event)
2615{
2616 if (!hasRunningProcess())
2617 return;
2618
2619 TraceScope scope(SyncTouchEventStart, SyncTouchEventEnd);
2620
2621 updateTouchEventTracking(event);
2622
2623 TrackingType touchEventsTrackingType = touchEventTrackingType(event);
2624 if (touchEventsTrackingType == TrackingType::NotTracking)
2625 return;
2626
2627 if (touchEventsTrackingType == TrackingType::Asynchronous) {
2628 // We can end up here if a native gesture has not started but the event handlers are passive.
2629 //
2630 // The client of WebPageProxy asks the event to be sent synchronously since the touch event
2631 // can prevent a native gesture.
2632 // But, here we know that all events handlers that can handle this events are passive.
2633 // We can use asynchronous dispatch and pretend to the client that the page does nothing with the events.
2634 event.setCanPreventNativeGestures(false);
2635 handleTouchEventAsynchronously(event);
2636 didReceiveEvent(event.type(), false);
2637 return;
2638 }
2639
2640 m_process->responsivenessTimer().start();
2641 bool handled = false;
2642 bool replyReceived = m_process->sendSync(Messages::WebPage::TouchEventSync(event), Messages::WebPage::TouchEventSync::Reply(handled), m_pageID, 1_s);
2643 // 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.
2644 if (!replyReceived)
2645 handled = true;
2646 didReceiveEvent(event.type(), handled);
2647 pageClient().doneWithTouchEvent(event, handled);
2648 m_process->responsivenessTimer().stop();
2649
2650 if (event.allTouchPointsAreReleased())
2651 m_touchAndPointerEventTracking.reset();
2652}
2653
2654void WebPageProxy::handleTouchEventAsynchronously(const NativeWebTouchEvent& event)
2655{
2656 if (!hasRunningProcess())
2657 return;
2658
2659 TrackingType touchEventsTrackingType = touchEventTrackingType(event);
2660 if (touchEventsTrackingType == TrackingType::NotTracking)
2661 return;
2662
2663 m_process->send(Messages::EventDispatcher::TouchEvent(m_pageID, event), 0);
2664
2665 if (event.allTouchPointsAreReleased())
2666 m_touchAndPointerEventTracking.reset();
2667}
2668
2669#elif ENABLE(TOUCH_EVENTS)
2670void WebPageProxy::handleTouchEvent(const NativeWebTouchEvent& event)
2671{
2672 if (!hasRunningProcess())
2673 return;
2674
2675 updateTouchEventTracking(event);
2676
2677 if (touchEventTrackingType(event) == TrackingType::NotTracking)
2678 return;
2679
2680 // If the page is suspended, which should be the case during panning, pinching
2681 // and animation on the page itself (kinetic scrolling, tap to zoom) etc, then
2682 // we do not send any of the events to the page even if is has listeners.
2683 if (!m_isPageSuspended) {
2684 m_touchEventQueue.append(event);
2685 m_process->responsivenessTimer().start();
2686 m_process->send(Messages::WebPage::TouchEvent(event), m_pageID);
2687 } else {
2688 if (m_touchEventQueue.isEmpty()) {
2689 bool isEventHandled = false;
2690 pageClient().doneWithTouchEvent(event, isEventHandled);
2691 } else {
2692 // We attach the incoming events to the newest queued event so that all
2693 // the events are delivered in the correct order when the event is dequed.
2694 QueuedTouchEvents& lastEvent = m_touchEventQueue.last();
2695 lastEvent.deferredTouchEvents.append(event);
2696 }
2697 }
2698
2699 if (event.allTouchPointsAreReleased())
2700 m_touchAndPointerEventTracking.reset();
2701}
2702#endif // ENABLE(TOUCH_EVENTS)
2703
2704#if ENABLE(POINTER_EVENTS)
2705void WebPageProxy::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint)
2706{
2707 m_process->send(Messages::WebPage::CancelPointer(pointerId, documentPoint), m_pageID);
2708}
2709#endif
2710
2711void WebPageProxy::scrollBy(ScrollDirection direction, ScrollGranularity granularity)
2712{
2713 if (!hasRunningProcess())
2714 return;
2715
2716 m_process->send(Messages::WebPage::ScrollBy(direction, granularity), m_pageID);
2717}
2718
2719void WebPageProxy::centerSelectionInVisibleArea()
2720{
2721 if (!hasRunningProcess())
2722 return;
2723
2724 m_process->send(Messages::WebPage::CenterSelectionInVisibleArea(), m_pageID);
2725}
2726
2727class WebPageProxy::PolicyDecisionSender : public RefCounted<PolicyDecisionSender> {
2728public:
2729 using SendFunction = CompletionHandler<void(PolicyCheckIdentifier, PolicyAction, uint64_t newNavigationID, DownloadID, Optional<WebsitePoliciesData>)>;
2730
2731 static Ref<PolicyDecisionSender> create(PolicyCheckIdentifier identifier, SendFunction&& sendFunction)
2732 {
2733 return adoptRef(*new PolicyDecisionSender(identifier, WTFMove(sendFunction)));
2734 }
2735
2736 template<typename... Args> void send(Args... args)
2737 {
2738 if (m_sendFunction)
2739 m_sendFunction(m_identifier, std::forward<Args>(args)...);
2740 }
2741private:
2742 PolicyDecisionSender(PolicyCheckIdentifier identifier, SendFunction sendFunction)
2743 : m_sendFunction(WTFMove(sendFunction))
2744 , m_identifier(identifier)
2745 { }
2746
2747 SendFunction m_sendFunction;
2748 PolicyCheckIdentifier m_identifier;
2749};
2750
2751void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, API::Navigation* navigation, ProcessSwapRequestedByClient processSwapRequestedByClient, WebFrameProxy& frame, API::WebsitePolicies* policies, Ref<PolicyDecisionSender>&& sender)
2752{
2753 Ref<WebsiteDataStore> websiteDataStore = m_websiteDataStore.copyRef();
2754 Optional<WebsitePoliciesData> data;
2755 if (policies) {
2756 data = policies->data();
2757 if (policies->websiteDataStore() && &policies->websiteDataStore()->websiteDataStore() != websiteDataStore.ptr()) {
2758 websiteDataStore = policies->websiteDataStore()->websiteDataStore();
2759 processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
2760 }
2761 }
2762
2763 if (navigation && !navigation->userContentExtensionsEnabled()) {
2764 if (!data)
2765 data = WebsitePoliciesData { };
2766 data->contentBlockersEnabled = false;
2767 }
2768
2769#if ENABLE(DEVICE_ORIENTATION)
2770 if (navigation && (!data || data->deviceOrientationAndMotionAccessState == WebCore::DeviceOrientationOrMotionPermissionState::Prompt)) {
2771 auto deviceOrientationPermission = websiteDataStore->deviceOrientationAndMotionAccessController().cachedDeviceOrientationPermission(SecurityOriginData::fromURL(navigation->currentRequest().url()));
2772 if (deviceOrientationPermission != WebCore::DeviceOrientationOrMotionPermissionState::Prompt) {
2773 if (!data)
2774 data = WebsitePoliciesData { };
2775 data->deviceOrientationAndMotionAccessState = deviceOrientationPermission;
2776 }
2777 }
2778#endif
2779
2780#if PLATFORM(COCOA)
2781 static const bool forceDownloadFromDownloadAttribute = false;
2782#else
2783 static const bool forceDownloadFromDownloadAttribute = true;
2784#endif
2785 if (policyAction == PolicyAction::Use && navigation && (navigation->isSystemPreview() || (forceDownloadFromDownloadAttribute && navigation->shouldPerformDownload())))
2786 policyAction = PolicyAction::Download;
2787
2788 if (policyAction != PolicyAction::Use || !frame.isMainFrame() || !navigation) {
2789 receivedPolicyDecision(policyAction, navigation, WTFMove(data), WTFMove(sender));
2790 return;
2791 }
2792
2793 Ref<WebProcessProxy> sourceProcess = process();
2794 URL sourceURL = URL { URL(), pageLoadState().url() };
2795 if (auto* provisionalPage = provisionalPageProxy()) {
2796 if (provisionalPage->navigationID() == navigation->navigationID()) {
2797 sourceProcess = provisionalPage->process();
2798 sourceURL = provisionalPage->provisionalURL();
2799 }
2800 }
2801
2802 process().processPool().processForNavigation(*this, *navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, WTFMove(websiteDataStore), [this, protectedThis = makeRef(*this), policyAction, navigation = makeRef(*navigation), sourceProcess = sourceProcess.copyRef(),
2803 data = WTFMove(data), sender = WTFMove(sender), processSwapRequestedByClient] (Ref<WebProcessProxy>&& processForNavigation, SuspendedPageProxy* destinationSuspendedPage, const String& reason) mutable {
2804 // If the navigation has been destroyed, then no need to proceed.
2805 if (isClosed() || !navigationState().hasNavigation(navigation->navigationID())) {
2806 receivedPolicyDecision(policyAction, navigation.ptr(), WTFMove(data), WTFMove(sender));
2807 return;
2808 }
2809
2810 bool shouldProcessSwap = processForNavigation.ptr() != sourceProcess.ptr();
2811 if (shouldProcessSwap) {
2812 policyAction = PolicyAction::StopAllLoads;
2813 RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "decidePolicyForNavigationAction, swapping process %i with process %i for navigation, reason: %{public}s", processIdentifier(), processForNavigation->processIdentifier(), reason.utf8().data());
2814 LOG(ProcessSwapping, "(ProcessSwapping) Switching from process %i to new process (%i) for navigation %" PRIu64 " '%s'", processIdentifier(), processForNavigation->processIdentifier(), navigation->navigationID(), navigation->loggingString());
2815 } else
2816 RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "decidePolicyForNavigationAction: keep using process %i for navigation, reason: %{public}s", processIdentifier(), reason.utf8().data());
2817
2818 if (shouldProcessSwap) {
2819 // FIXME: Architecturally we do not currently support multiple WebPage's with the same ID in a given WebProcess.
2820 // In the case where the destination WebProcess has a SuspendedPageProxy for this WebPage, we should have thrown
2821 // it away to support WebProcess re-use.
2822 ASSERT(destinationSuspendedPage || !process().processPool().hasSuspendedPageFor(processForNavigation, *this));
2823
2824 auto suspendedPage = destinationSuspendedPage ? process().processPool().takeSuspendedPage(*destinationSuspendedPage) : nullptr;
2825 if (suspendedPage && suspendedPage->failedToSuspend())
2826 suspendedPage = nullptr;
2827
2828 continueNavigationInNewProcess(navigation, WTFMove(suspendedPage), WTFMove(processForNavigation), processSwapRequestedByClient, WTFMove(data));
2829 }
2830
2831 receivedPolicyDecision(policyAction, navigation.ptr(), shouldProcessSwap ? WTF::nullopt : WTFMove(data), WTFMove(sender), shouldProcessSwap ? WillContinueLoadInNewProcess::Yes : WillContinueLoadInNewProcess::No);
2832 });
2833}
2834
2835void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, Optional<WebsitePoliciesData>&& websitePolicies, Ref<PolicyDecisionSender>&& sender, WillContinueLoadInNewProcess willContinueLoadInNewProcess)
2836{
2837 if (!hasRunningProcess()) {
2838 sender->send(PolicyAction::Ignore, 0, DownloadID(), WTF::nullopt);
2839 return;
2840 }
2841
2842 auto transaction = m_pageLoadState.transaction();
2843
2844 if (action == PolicyAction::Ignore && willContinueLoadInNewProcess == WillContinueLoadInNewProcess::No)
2845 m_pageLoadState.clearPendingAPIRequestURL(transaction);
2846
2847 DownloadID downloadID = { };
2848 if (action == PolicyAction::Download) {
2849 // Create a download proxy.
2850 auto& download = m_process->processPool().createDownloadProxy(m_decidePolicyForResponseRequest, this);
2851 if (navigation) {
2852 download.setWasUserInitiated(navigation->wasUserInitiated());
2853 download.setRedirectChain(navigation->takeRedirectChain());
2854 }
2855
2856 downloadID = download.downloadID();
2857 handleDownloadRequest(download);
2858 m_decidePolicyForResponseRequest = { };
2859 }
2860
2861 sender->send(action, navigation ? navigation->navigationID() : 0, downloadID, WTFMove(websitePolicies));
2862}
2863
2864void WebPageProxy::commitProvisionalPage(uint64_t frameID, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, uint32_t frameLoadType, const WebCore::CertificateInfo& certificateInfo, bool containsPluginDocument, Optional<WebCore::HasInsecureContent> forcedHasInsecureContent, const UserData& userData)
2865{
2866 ASSERT(m_provisionalPage);
2867 RELEASE_LOG_IF_ALLOWED(Loading, "commitProvisionalPage: previousPID = %i, newPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_provisionalPage->process().processIdentifier(), m_pageID);
2868
2869 Optional<uint64_t> mainFrameIDInPreviousProcess = m_mainFrame ? makeOptional(m_mainFrame->frameID()) : WTF::nullopt;
2870
2871 ASSERT(m_process.ptr() != &m_provisionalPage->process());
2872
2873 auto shouldDelayClosingUntilEnteringAcceleratedCompositingMode = ShouldDelayClosingUntilEnteringAcceleratedCompositingMode::No;
2874#if PLATFORM(MAC)
2875 // 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
2876 // entered accelerated compositing for the new page or we will flash on navigation.
2877 if (drawingArea()->type() == DrawingAreaTypeTiledCoreAnimation)
2878 shouldDelayClosingUntilEnteringAcceleratedCompositingMode = ShouldDelayClosingUntilEnteringAcceleratedCompositingMode::Yes;
2879#endif
2880
2881 processDidTerminate(ProcessTerminationReason::NavigationSwap);
2882
2883 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
2884 auto* navigation = navigationState().navigation(m_provisionalPage->navigationID());
2885 bool didSuspendPreviousPage = navigation ? suspendCurrentPageIfPossible(*navigation, mainFrameIDInPreviousProcess, m_provisionalPage->processSwapRequestedByClient(), shouldDelayClosingUntilEnteringAcceleratedCompositingMode) : false;
2886 m_process->removeWebPage(*this, m_websiteDataStore.ptr() == &m_provisionalPage->process().websiteDataStore() ? WebProcessProxy::EndsUsingDataStore::No : WebProcessProxy::EndsUsingDataStore::Yes);
2887
2888 // There is no way we'll be able to return to the page in the previous page so close it.
2889 if (!didSuspendPreviousPage)
2890 m_process->send(Messages::WebPage::Close(), pageID());
2891
2892 swapToWebProcess(m_provisionalPage->process(), m_provisionalPage->takeDrawingArea(), m_provisionalPage->mainFrame());
2893
2894#if PLATFORM(COCOA)
2895 auto accessibilityToken = m_provisionalPage->takeAccessibilityToken();
2896 if (!accessibilityToken.isEmpty())
2897 registerWebProcessAccessibilityToken({ accessibilityToken.data(), accessibilityToken.size() });
2898#endif
2899
2900 didCommitLoadForFrame(frameID, navigationID, mimeType, frameHasCustomContentProvider, frameLoadType, certificateInfo, containsPluginDocument, forcedHasInsecureContent, userData);
2901
2902 m_provisionalPage = nullptr;
2903}
2904
2905void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, std::unique_ptr<SuspendedPageProxy>&& suspendedPageProxy, Ref<WebProcessProxy>&& newProcess, ProcessSwapRequestedByClient processSwapRequestedByClient, Optional<WebsitePoliciesData>&& websitePolicies)
2906{
2907 RELEASE_LOG_IF_ALLOWED(Loading, "continueNavigationInNewProcess: webPID = %i, pageID = %" PRIu64 ", newProcessPID = %i, hasSuspendedPage = %i", m_process->processIdentifier(), m_pageID, newProcess->processIdentifier(), !!suspendedPageProxy);
2908 LOG(Loading, "Continuing navigation %" PRIu64 " '%s' in a new web process", navigation.navigationID(), navigation.loggingString());
2909
2910 if (m_provisionalPage) {
2911 RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "continueNavigationInNewProcess: There is already a pending provisional load, cancelling it (provisonalNavigationID: %llu, navigationID: %llu)", m_provisionalPage->navigationID(), navigation.navigationID());
2912 if (m_provisionalPage->navigationID() != navigation.navigationID())
2913 m_provisionalPage->cancel();
2914 m_provisionalPage = nullptr;
2915 }
2916
2917 m_provisionalPage = std::make_unique<ProvisionalPageProxy>(*this, newProcess.copyRef(), WTFMove(suspendedPageProxy), navigation.navigationID(), navigation.currentRequestIsRedirect(), navigation.currentRequest(), processSwapRequestedByClient);
2918
2919 if (auto* item = navigation.targetItem()) {
2920 LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data());
2921
2922 auto transaction = m_pageLoadState.transaction();
2923 m_pageLoadState.setPendingAPIRequestURL(transaction, item->url());
2924
2925 m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies));
2926 return;
2927 }
2928
2929 if (m_backForwardList->currentItem() && (navigation.lockBackForwardList() == LockBackForwardList::Yes || navigation.lockHistory() == LockHistory::Yes)) {
2930 // 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
2931 // it instead of creating a new one.
2932 newProcess->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()), m_pageID);
2933 }
2934
2935 // FIXME: Work out timing of responding with the last policy delegate, etc
2936 ASSERT(!navigation.currentRequest().isEmpty());
2937 if (auto& substituteData = navigation.substituteData())
2938 m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), WTFMove(websitePolicies));
2939 else
2940 m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation.currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, WTFMove(websitePolicies));
2941}
2942
2943bool WebPageProxy::isPageOpenedByDOMShowingInitialEmptyDocument() const
2944{
2945 return openedByDOM() && !hasCommittedAnyProvisionalLoads();
2946}
2947
2948// MSVC gives a redeclaration error if noreturn is used on the definition and not the declaration, while
2949// Cocoa tests segfault if it is moved to the declaration site (even if we move the definition with it!).
2950#if !COMPILER(MSVC)
2951NO_RETURN_DUE_TO_ASSERT
2952#endif
2953void WebPageProxy::didFailToSuspendAfterProcessSwap()
2954{
2955 // Only the SuspendedPageProxy should be getting this call.
2956 ASSERT_NOT_REACHED();
2957}
2958
2959#if !COMPILER(MSVC)
2960NO_RETURN_DUE_TO_ASSERT
2961#endif
2962void WebPageProxy::didSuspendAfterProcessSwap()
2963{
2964 // Only the SuspendedPageProxy should be getting this call.
2965 ASSERT_NOT_REACHED();
2966}
2967
2968void WebPageProxy::setUserAgent(String&& userAgent)
2969{
2970 if (m_userAgent == userAgent)
2971 return;
2972 m_userAgent = WTFMove(userAgent);
2973
2974#if ENABLE(SERVICE_WORKER)
2975 // We update the service worker there at the moment to be sure we use values used by actual web pages.
2976 // FIXME: Refactor this when we have a better User-Agent story.
2977 process().processPool().updateServiceWorkerUserAgent(m_userAgent);
2978#endif
2979
2980 if (!hasRunningProcess())
2981 return;
2982 m_process->send(Messages::WebPage::SetUserAgent(m_userAgent), m_pageID);
2983}
2984
2985void WebPageProxy::setApplicationNameForUserAgent(const String& applicationName)
2986{
2987 if (m_applicationNameForUserAgent == applicationName)
2988 return;
2989
2990 m_applicationNameForUserAgent = applicationName;
2991 if (!m_customUserAgent.isEmpty())
2992 return;
2993
2994 setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
2995}
2996
2997void WebPageProxy::setCustomUserAgent(const String& customUserAgent)
2998{
2999 if (m_customUserAgent == customUserAgent)
3000 return;
3001
3002 m_customUserAgent = customUserAgent;
3003
3004 if (m_customUserAgent.isEmpty()) {
3005 setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3006 return;
3007 }
3008
3009 setUserAgent(String { m_customUserAgent });
3010}
3011
3012void WebPageProxy::resumeActiveDOMObjectsAndAnimations()
3013{
3014 if (!hasRunningProcess() || !m_isPageSuspended)
3015 return;
3016
3017 m_isPageSuspended = false;
3018
3019 m_process->send(Messages::WebPage::ResumeActiveDOMObjectsAndAnimations(), m_pageID);
3020}
3021
3022void WebPageProxy::suspendActiveDOMObjectsAndAnimations()
3023{
3024 if (!hasRunningProcess() || m_isPageSuspended)
3025 return;
3026
3027 m_isPageSuspended = true;
3028
3029 m_process->send(Messages::WebPage::SuspendActiveDOMObjectsAndAnimations(), m_pageID);
3030}
3031
3032bool WebPageProxy::supportsTextEncoding() const
3033{
3034 // FIXME (118840): We should probably only support this for text documents, not all non-image documents.
3035 return m_mainFrame && !m_mainFrame->isDisplayingStandaloneImageDocument();
3036}
3037
3038void WebPageProxy::setCustomTextEncodingName(const String& encodingName)
3039{
3040 if (m_customTextEncodingName == encodingName)
3041 return;
3042 m_customTextEncodingName = encodingName;
3043
3044 if (!hasRunningProcess())
3045 return;
3046 m_process->send(Messages::WebPage::SetCustomTextEncodingName(encodingName), m_pageID);
3047}
3048
3049SessionState WebPageProxy::sessionState(WTF::Function<bool (WebBackForwardListItem&)>&& filter) const
3050{
3051 SessionState sessionState;
3052
3053 sessionState.backForwardListState = m_backForwardList->backForwardListState(WTFMove(filter));
3054
3055 String provisionalURLString = m_pageLoadState.pendingAPIRequestURL();
3056 if (provisionalURLString.isEmpty())
3057 provisionalURLString = m_pageLoadState.provisionalURL();
3058
3059 if (!provisionalURLString.isEmpty())
3060 sessionState.provisionalURL = URL(URL(), provisionalURLString);
3061
3062 sessionState.renderTreeSize = renderTreeSize();
3063 return sessionState;
3064}
3065
3066RefPtr<API::Navigation> WebPageProxy::restoreFromSessionState(SessionState sessionState, bool navigate)
3067{
3068 RELEASE_LOG_IF_ALLOWED(Loading, "restoreFromSessionState: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
3069
3070 m_sessionRestorationRenderTreeSize = 0;
3071 m_hitRenderTreeSizeThreshold = false;
3072
3073 bool hasBackForwardList = !!sessionState.backForwardListState.currentIndex;
3074
3075 if (hasBackForwardList) {
3076 m_backForwardList->restoreFromState(WTFMove(sessionState.backForwardListState));
3077 process().send(Messages::WebPage::RestoreSession(m_backForwardList->itemStates()), m_pageID);
3078
3079 auto transaction = m_pageLoadState.transaction();
3080 m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
3081 m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
3082
3083 // The back / forward list was restored from a sessionState so we don't want to snapshot the current
3084 // page when navigating away. Suppress navigation snapshotting until the next load has committed
3085 suppressNextAutomaticNavigationSnapshot();
3086 }
3087
3088 // FIXME: Navigating should be separate from state restoration.
3089 if (navigate) {
3090 m_sessionRestorationRenderTreeSize = sessionState.renderTreeSize;
3091 if (!m_sessionRestorationRenderTreeSize)
3092 m_hitRenderTreeSizeThreshold = true; // If we didn't get data on renderTreeSize, just don't fire the milestone.
3093
3094 if (!sessionState.provisionalURL.isNull())
3095 return loadRequest(sessionState.provisionalURL);
3096
3097 if (hasBackForwardList) {
3098 if (WebBackForwardListItem* item = m_backForwardList->currentItem())
3099 return goToBackForwardItem(*item);
3100 }
3101 }
3102
3103 return nullptr;
3104}
3105
3106bool WebPageProxy::supportsTextZoom() const
3107{
3108 // FIXME (118840): This should also return false for standalone media and plug-in documents.
3109 if (!m_mainFrame || m_mainFrame->isDisplayingStandaloneImageDocument())
3110 return false;
3111
3112 return true;
3113}
3114
3115void WebPageProxy::setTextZoomFactor(double zoomFactor)
3116{
3117 if (m_textZoomFactor == zoomFactor)
3118 return;
3119
3120 m_textZoomFactor = zoomFactor;
3121
3122 if (!hasRunningProcess())
3123 return;
3124
3125 m_process->send(Messages::WebPage::SetTextZoomFactor(m_textZoomFactor), m_pageID);
3126}
3127
3128void WebPageProxy::setPageZoomFactor(double zoomFactor)
3129{
3130 if (m_pageZoomFactor == zoomFactor)
3131 return;
3132
3133 closeOverlayedViews();
3134
3135 m_pageZoomFactor = zoomFactor;
3136
3137 if (!hasRunningProcess())
3138 return;
3139
3140 m_process->send(Messages::WebPage::SetPageZoomFactor(m_pageZoomFactor), m_pageID);
3141}
3142
3143void WebPageProxy::setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor)
3144{
3145 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
3146 return;
3147
3148 closeOverlayedViews();
3149
3150 m_pageZoomFactor = pageZoomFactor;
3151 m_textZoomFactor = textZoomFactor;
3152
3153 if (!hasRunningProcess())
3154 return;
3155
3156 m_process->send(Messages::WebPage::SetPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor), m_pageID);
3157}
3158
3159double WebPageProxy::pageZoomFactor() const
3160{
3161 // Zoom factor for non-PDF pages persists across page loads. We maintain a separate member variable for PDF
3162 // zoom which ensures that we don't use the PDF zoom for a normal page.
3163 if (m_mainFramePluginHandlesPageScaleGesture)
3164 return m_pluginZoomFactor;
3165 return m_pageZoomFactor;
3166}
3167
3168double WebPageProxy::pageScaleFactor() const
3169{
3170 // PDF documents use zoom and scale factors to size themselves appropriately in the window. We store them
3171 // separately but decide which to return based on the main frame.
3172 if (m_mainFramePluginHandlesPageScaleGesture)
3173 return m_pluginScaleFactor;
3174 return m_pageScaleFactor;
3175}
3176
3177void WebPageProxy::scalePage(double scale, const IntPoint& origin)
3178{
3179 ASSERT(scale > 0);
3180
3181 m_pageScaleFactor = scale;
3182
3183 if (!hasRunningProcess())
3184 return;
3185
3186 m_process->send(Messages::WebPage::ScalePage(scale, origin), m_pageID);
3187}
3188
3189void WebPageProxy::scalePageInViewCoordinates(double scale, const IntPoint& centerInViewCoordinates)
3190{
3191 ASSERT(scale > 0);
3192
3193 m_pageScaleFactor = scale;
3194
3195 if (!hasRunningProcess())
3196 return;
3197
3198 m_process->send(Messages::WebPage::ScalePageInViewCoordinates(scale, centerInViewCoordinates), m_pageID);
3199}
3200
3201void WebPageProxy::scaleView(double scale)
3202{
3203 ASSERT(scale > 0);
3204
3205 m_viewScaleFactor = scale;
3206
3207 if (!hasRunningProcess())
3208 return;
3209
3210 m_process->send(Messages::WebPage::ScaleView(scale), m_pageID);
3211}
3212
3213void WebPageProxy::setIntrinsicDeviceScaleFactor(float scaleFactor)
3214{
3215 if (m_intrinsicDeviceScaleFactor == scaleFactor)
3216 return;
3217
3218 m_intrinsicDeviceScaleFactor = scaleFactor;
3219
3220 if (m_drawingArea)
3221 m_drawingArea->deviceScaleFactorDidChange();
3222}
3223
3224void WebPageProxy::windowScreenDidChange(PlatformDisplayID displayID)
3225{
3226 if (!hasRunningProcess())
3227 return;
3228
3229 m_process->send(Messages::WebPage::WindowScreenDidChange(displayID), m_pageID);
3230}
3231
3232float WebPageProxy::deviceScaleFactor() const
3233{
3234 return m_customDeviceScaleFactor.valueOr(m_intrinsicDeviceScaleFactor);
3235}
3236
3237void WebPageProxy::setCustomDeviceScaleFactor(float customScaleFactor)
3238{
3239 // FIXME: Remove this once we bump cairo requirements to support HiDPI.
3240 // https://bugs.webkit.org/show_bug.cgi?id=133378
3241#if USE(CAIRO) && !HAVE(CAIRO_SURFACE_SET_DEVICE_SCALE)
3242 return;
3243#endif
3244
3245 if (m_customDeviceScaleFactor && m_customDeviceScaleFactor.value() == customScaleFactor)
3246 return;
3247
3248 float oldScaleFactor = deviceScaleFactor();
3249
3250 // A value of 0 clears the customScaleFactor.
3251 if (customScaleFactor)
3252 m_customDeviceScaleFactor = customScaleFactor;
3253 else
3254 m_customDeviceScaleFactor = WTF::nullopt;
3255
3256 if (!hasRunningProcess())
3257 return;
3258
3259 if (deviceScaleFactor() != oldScaleFactor)
3260 m_drawingArea->deviceScaleFactorDidChange();
3261}
3262
3263void WebPageProxy::accessibilitySettingsDidChange()
3264{
3265 if (!hasRunningProcess())
3266 return;
3267
3268 m_process->send(Messages::WebPage::AccessibilitySettingsDidChange(), m_pageID);
3269}
3270
3271void WebPageProxy::setUseFixedLayout(bool fixed)
3272{
3273 // This check is fine as the value is initialized in the web
3274 // process as part of the creation parameters.
3275 if (fixed == m_useFixedLayout)
3276 return;
3277
3278 m_useFixedLayout = fixed;
3279 if (!fixed)
3280 m_fixedLayoutSize = IntSize();
3281
3282 if (!hasRunningProcess())
3283 return;
3284
3285 m_process->send(Messages::WebPage::SetUseFixedLayout(fixed), m_pageID);
3286}
3287
3288void WebPageProxy::setFixedLayoutSize(const IntSize& size)
3289{
3290 if (size == m_fixedLayoutSize)
3291 return;
3292
3293 m_fixedLayoutSize = size;
3294
3295 if (!hasRunningProcess())
3296 return;
3297
3298 m_process->send(Messages::WebPage::SetFixedLayoutSize(size), m_pageID);
3299}
3300
3301void WebPageProxy::setAlwaysShowsHorizontalScroller(bool alwaysShowsHorizontalScroller)
3302{
3303 if (alwaysShowsHorizontalScroller == m_alwaysShowsHorizontalScroller)
3304 return;
3305
3306 m_alwaysShowsHorizontalScroller = alwaysShowsHorizontalScroller;
3307
3308 if (!hasRunningProcess())
3309 return;
3310
3311 m_process->send(Messages::WebPage::SetAlwaysShowsHorizontalScroller(alwaysShowsHorizontalScroller), m_pageID);
3312}
3313
3314void WebPageProxy::setAlwaysShowsVerticalScroller(bool alwaysShowsVerticalScroller)
3315{
3316 if (alwaysShowsVerticalScroller == m_alwaysShowsVerticalScroller)
3317 return;
3318
3319 m_alwaysShowsVerticalScroller = alwaysShowsVerticalScroller;
3320
3321 if (!hasRunningProcess())
3322 return;
3323
3324 m_process->send(Messages::WebPage::SetAlwaysShowsVerticalScroller(alwaysShowsVerticalScroller), m_pageID);
3325}
3326
3327void WebPageProxy::listenForLayoutMilestones(OptionSet<WebCore::LayoutMilestone> milestones)
3328{
3329 if (milestones == m_observedLayoutMilestones)
3330 return;
3331
3332 m_observedLayoutMilestones = milestones;
3333
3334 if (!hasRunningProcess())
3335 return;
3336
3337 m_process->send(Messages::WebPage::ListenForLayoutMilestones(milestones), m_pageID);
3338}
3339
3340void WebPageProxy::setSuppressScrollbarAnimations(bool suppressAnimations)
3341{
3342 if (suppressAnimations == m_suppressScrollbarAnimations)
3343 return;
3344
3345 m_suppressScrollbarAnimations = suppressAnimations;
3346
3347 if (!hasRunningProcess())
3348 return;
3349
3350 m_process->send(Messages::WebPage::SetSuppressScrollbarAnimations(suppressAnimations), m_pageID);
3351}
3352
3353bool WebPageProxy::rubberBandsAtLeft() const
3354{
3355 return m_rubberBandsAtLeft;
3356}
3357
3358void WebPageProxy::setRubberBandsAtLeft(bool rubberBandsAtLeft)
3359{
3360 m_rubberBandsAtLeft = rubberBandsAtLeft;
3361}
3362
3363bool WebPageProxy::rubberBandsAtRight() const
3364{
3365 return m_rubberBandsAtRight;
3366}
3367
3368void WebPageProxy::setRubberBandsAtRight(bool rubberBandsAtRight)
3369{
3370 m_rubberBandsAtRight = rubberBandsAtRight;
3371}
3372
3373bool WebPageProxy::rubberBandsAtTop() const
3374{
3375 return m_rubberBandsAtTop;
3376}
3377
3378void WebPageProxy::setRubberBandsAtTop(bool rubberBandsAtTop)
3379{
3380 m_rubberBandsAtTop = rubberBandsAtTop;
3381}
3382
3383bool WebPageProxy::rubberBandsAtBottom() const
3384{
3385 return m_rubberBandsAtBottom;
3386}
3387
3388void WebPageProxy::setRubberBandsAtBottom(bool rubberBandsAtBottom)
3389{
3390 m_rubberBandsAtBottom = rubberBandsAtBottom;
3391}
3392
3393void WebPageProxy::setEnableVerticalRubberBanding(bool enableVerticalRubberBanding)
3394{
3395 if (enableVerticalRubberBanding == m_enableVerticalRubberBanding)
3396 return;
3397
3398 m_enableVerticalRubberBanding = enableVerticalRubberBanding;
3399
3400 if (!hasRunningProcess())
3401 return;
3402 m_process->send(Messages::WebPage::SetEnableVerticalRubberBanding(enableVerticalRubberBanding), m_pageID);
3403}
3404
3405bool WebPageProxy::verticalRubberBandingIsEnabled() const
3406{
3407 return m_enableVerticalRubberBanding;
3408}
3409
3410void WebPageProxy::setEnableHorizontalRubberBanding(bool enableHorizontalRubberBanding)
3411{
3412 if (enableHorizontalRubberBanding == m_enableHorizontalRubberBanding)
3413 return;
3414
3415 m_enableHorizontalRubberBanding = enableHorizontalRubberBanding;
3416
3417 if (!hasRunningProcess())
3418 return;
3419 m_process->send(Messages::WebPage::SetEnableHorizontalRubberBanding(enableHorizontalRubberBanding), m_pageID);
3420}
3421
3422bool WebPageProxy::horizontalRubberBandingIsEnabled() const
3423{
3424 return m_enableHorizontalRubberBanding;
3425}
3426
3427void WebPageProxy::setBackgroundExtendsBeyondPage(bool backgroundExtendsBeyondPage)
3428{
3429 if (backgroundExtendsBeyondPage == m_backgroundExtendsBeyondPage)
3430 return;
3431
3432 m_backgroundExtendsBeyondPage = backgroundExtendsBeyondPage;
3433
3434 if (!hasRunningProcess())
3435 return;
3436 m_process->send(Messages::WebPage::SetBackgroundExtendsBeyondPage(backgroundExtendsBeyondPage), m_pageID);
3437}
3438
3439bool WebPageProxy::backgroundExtendsBeyondPage() const
3440{
3441 return m_backgroundExtendsBeyondPage;
3442}
3443
3444void WebPageProxy::setPaginationMode(WebCore::Pagination::Mode mode)
3445{
3446 if (mode == m_paginationMode)
3447 return;
3448
3449 m_paginationMode = mode;
3450
3451 if (!hasRunningProcess())
3452 return;
3453 m_process->send(Messages::WebPage::SetPaginationMode(mode), m_pageID);
3454}
3455
3456void WebPageProxy::setPaginationBehavesLikeColumns(bool behavesLikeColumns)
3457{
3458 if (behavesLikeColumns == m_paginationBehavesLikeColumns)
3459 return;
3460
3461 m_paginationBehavesLikeColumns = behavesLikeColumns;
3462
3463 if (!hasRunningProcess())
3464 return;
3465 m_process->send(Messages::WebPage::SetPaginationBehavesLikeColumns(behavesLikeColumns), m_pageID);
3466}
3467
3468void WebPageProxy::setPageLength(double pageLength)
3469{
3470 if (pageLength == m_pageLength)
3471 return;
3472
3473 m_pageLength = pageLength;
3474
3475 if (!hasRunningProcess())
3476 return;
3477 m_process->send(Messages::WebPage::SetPageLength(pageLength), m_pageID);
3478}
3479
3480void WebPageProxy::setGapBetweenPages(double gap)
3481{
3482 if (gap == m_gapBetweenPages)
3483 return;
3484
3485 m_gapBetweenPages = gap;
3486
3487 if (!hasRunningProcess())
3488 return;
3489 m_process->send(Messages::WebPage::SetGapBetweenPages(gap), m_pageID);
3490}
3491
3492void WebPageProxy::setPaginationLineGridEnabled(bool lineGridEnabled)
3493{
3494 if (lineGridEnabled == m_paginationLineGridEnabled)
3495 return;
3496
3497 m_paginationLineGridEnabled = lineGridEnabled;
3498
3499 if (!hasRunningProcess())
3500 return;
3501 m_process->send(Messages::WebPage::SetPaginationLineGridEnabled(lineGridEnabled), m_pageID);
3502}
3503
3504void WebPageProxy::pageScaleFactorDidChange(double scaleFactor)
3505{
3506 m_pageScaleFactor = scaleFactor;
3507}
3508
3509void WebPageProxy::pluginScaleFactorDidChange(double pluginScaleFactor)
3510{
3511 m_pluginScaleFactor = pluginScaleFactor;
3512}
3513
3514void WebPageProxy::pluginZoomFactorDidChange(double pluginZoomFactor)
3515{
3516 m_pluginZoomFactor = pluginZoomFactor;
3517}
3518
3519void WebPageProxy::findStringMatches(const String& string, FindOptions options, unsigned maxMatchCount)
3520{
3521 if (string.isEmpty()) {
3522 didFindStringMatches(string, Vector<Vector<WebCore::IntRect>> (), 0);
3523 return;
3524 }
3525
3526 m_process->send(Messages::WebPage::FindStringMatches(string, options, maxMatchCount), m_pageID);
3527}
3528
3529void WebPageProxy::findString(const String& string, FindOptions options, unsigned maxMatchCount)
3530{
3531 m_process->send(Messages::WebPage::FindString(string, options, maxMatchCount), m_pageID);
3532}
3533
3534void WebPageProxy::getImageForFindMatch(int32_t matchIndex)
3535{
3536 m_process->send(Messages::WebPage::GetImageForFindMatch(matchIndex), m_pageID);
3537}
3538
3539void WebPageProxy::selectFindMatch(int32_t matchIndex)
3540{
3541 m_process->send(Messages::WebPage::SelectFindMatch(matchIndex), m_pageID);
3542}
3543
3544void WebPageProxy::hideFindUI()
3545{
3546 m_process->send(Messages::WebPage::HideFindUI(), m_pageID);
3547}
3548
3549void WebPageProxy::countStringMatches(const String& string, FindOptions options, unsigned maxMatchCount)
3550{
3551 if (!hasRunningProcess())
3552 return;
3553
3554 m_process->send(Messages::WebPage::CountStringMatches(string, options, maxMatchCount), m_pageID);
3555}
3556
3557void WebPageProxy::replaceMatches(Vector<uint32_t>&& matchIndices, const String& replacementText, bool selectionOnly, Function<void(uint64_t, CallbackBase::Error)>&& callback)
3558{
3559 if (!hasRunningProcess()) {
3560 callback(0, CallbackBase::Error::Unknown);
3561 return;
3562 }
3563
3564 auto callbackID = m_callbacks.put(WTFMove(callback), m_process->throttler().backgroundActivityToken());
3565 m_process->send(Messages::WebPage::ReplaceMatches(WTFMove(matchIndices), replacementText, selectionOnly, callbackID), m_pageID);
3566}
3567
3568void WebPageProxy::launchInitialProcessIfNecessary()
3569{
3570 if (&process() == process().processPool().dummyProcessProxy())
3571 launchProcess({ });
3572}
3573
3574void WebPageProxy::runJavaScriptInMainFrame(const String& script, bool forceUserGesture, WTF::Function<void (API::SerializedScriptValue*, bool hadException, const ExceptionDetails&, CallbackBase::Error)>&& callbackFunction)
3575{
3576 runJavaScriptInMainFrameScriptWorld(script, forceUserGesture, WTF::nullopt, WTFMove(callbackFunction));
3577}
3578
3579void WebPageProxy::runJavaScriptInMainFrameScriptWorld(const String& script, bool forceUserGesture, const Optional<String>& worldName, WTF::Function<void(API::SerializedScriptValue*, bool hadException, const ExceptionDetails&, CallbackBase::Error)>&& callbackFunction)
3580{
3581 // For backward-compatibility support running script in a WebView which has not done any loads yets.
3582 launchInitialProcessIfNecessary();
3583
3584 if (!hasRunningProcess()) {
3585 callbackFunction(nullptr, false, { }, CallbackBase::Error::Unknown);
3586 return;
3587 }
3588
3589 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3590 m_process->send(Messages::WebPage::RunJavaScriptInMainFrameScriptWorld(script, forceUserGesture, worldName, callbackID), m_pageID);
3591}
3592
3593void WebPageProxy::runJavaScriptInFrame(uint64_t frameID, const String& script, bool forceUserGesture, WTF::Function<void(API::SerializedScriptValue*, bool hadException, const ExceptionDetails&, CallbackBase::Error)>&& callbackFunction)
3594{
3595 ASSERT(mainFrame()->frameID() != frameID);
3596 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3597 m_process->send(Messages::WebPage::RunJavaScriptInFrame(frameID, script, forceUserGesture, callbackID), m_pageID);
3598}
3599
3600void WebPageProxy::getRenderTreeExternalRepresentation(WTF::Function<void (const String&, CallbackBase::Error)>&& callbackFunction)
3601{
3602 if (!hasRunningProcess()) {
3603 callbackFunction(String(), CallbackBase::Error::Unknown);
3604 return;
3605 }
3606
3607 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3608 m_process->send(Messages::WebPage::GetRenderTreeExternalRepresentation(callbackID), m_pageID);
3609}
3610
3611void WebPageProxy::getSourceForFrame(WebFrameProxy* frame, WTF::Function<void (const String&, CallbackBase::Error)>&& callbackFunction)
3612{
3613 if (!hasRunningProcess()) {
3614 callbackFunction(String(), CallbackBase::Error::Unknown);
3615 return;
3616 }
3617
3618 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3619 m_loadDependentStringCallbackIDs.add(callbackID);
3620 m_process->send(Messages::WebPage::GetSourceForFrame(frame->frameID(), callbackID), m_pageID);
3621}
3622
3623void WebPageProxy::getContentsAsString(WTF::Function<void (const String&, CallbackBase::Error)>&& callbackFunction)
3624{
3625 if (!hasRunningProcess()) {
3626 callbackFunction(String(), CallbackBase::Error::Unknown);
3627 return;
3628 }
3629
3630 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3631 m_loadDependentStringCallbackIDs.add(callbackID);
3632 m_process->send(Messages::WebPage::GetContentsAsString(callbackID), m_pageID);
3633}
3634
3635#if PLATFORM(COCOA)
3636void WebPageProxy::getContentsAsAttributedString(CompletionHandler<void(const AttributedString&)>&& completionHandler)
3637{
3638 if (!hasRunningProcess()) {
3639 completionHandler(AttributedString());
3640 return;
3641 }
3642
3643 m_process->connection()->sendWithAsyncReply(Messages::WebPage::GetContentsAsAttributedString(), WTFMove(completionHandler), m_pageID);
3644}
3645#endif
3646
3647void WebPageProxy::getBytecodeProfile(WTF::Function<void (const String&, CallbackBase::Error)>&& callbackFunction)
3648{
3649 if (!hasRunningProcess()) {
3650 callbackFunction(String(), CallbackBase::Error::Unknown);
3651 return;
3652 }
3653
3654 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3655 m_loadDependentStringCallbackIDs.add(callbackID);
3656 m_process->send(Messages::WebPage::GetBytecodeProfile(callbackID), m_pageID);
3657}
3658
3659void WebPageProxy::getSamplingProfilerOutput(WTF::Function<void (const String&, CallbackBase::Error)>&& callbackFunction)
3660{
3661 if (!hasRunningProcess()) {
3662 callbackFunction(String(), CallbackBase::Error::Unknown);
3663 return;
3664 }
3665
3666 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3667 m_loadDependentStringCallbackIDs.add(callbackID);
3668 m_process->send(Messages::WebPage::GetSamplingProfilerOutput(callbackID), m_pageID);
3669}
3670
3671#if ENABLE(MHTML)
3672void WebPageProxy::getContentsAsMHTMLData(Function<void (API::Data*, CallbackBase::Error)>&& callbackFunction)
3673{
3674 if (!hasRunningProcess()) {
3675 callbackFunction(nullptr, CallbackBase::Error::Unknown);
3676 return;
3677 }
3678
3679 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3680 m_process->send(Messages::WebPage::GetContentsAsMHTMLData(callbackID), m_pageID);
3681}
3682#endif
3683
3684void WebPageProxy::getSelectionOrContentsAsString(WTF::Function<void (const String&, CallbackBase::Error)>&& callbackFunction)
3685{
3686 if (!hasRunningProcess()) {
3687 callbackFunction(String(), CallbackBase::Error::Unknown);
3688 return;
3689 }
3690
3691 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3692 m_process->send(Messages::WebPage::GetSelectionOrContentsAsString(callbackID), m_pageID);
3693}
3694
3695void WebPageProxy::getSelectionAsWebArchiveData(Function<void (API::Data*, CallbackBase::Error)>&& callbackFunction)
3696{
3697 if (!hasRunningProcess()) {
3698 callbackFunction(nullptr, CallbackBase::Error::Unknown);
3699 return;
3700 }
3701
3702 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3703 m_process->send(Messages::WebPage::GetSelectionAsWebArchiveData(callbackID), m_pageID);
3704}
3705
3706void WebPageProxy::getMainResourceDataOfFrame(WebFrameProxy* frame, Function<void (API::Data*, CallbackBase::Error)>&& callbackFunction)
3707{
3708 if (!hasRunningProcess() || !frame) {
3709 callbackFunction(nullptr, CallbackBase::Error::Unknown);
3710 return;
3711 }
3712
3713 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3714 m_process->send(Messages::WebPage::GetMainResourceDataOfFrame(frame->frameID(), callbackID), m_pageID);
3715}
3716
3717void WebPageProxy::getResourceDataFromFrame(WebFrameProxy* frame, API::URL* resourceURL, Function<void (API::Data*, CallbackBase::Error)>&& callbackFunction)
3718{
3719 if (!hasRunningProcess()) {
3720 callbackFunction(nullptr, CallbackBase::Error::Unknown);
3721 return;
3722 }
3723
3724 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3725 m_process->send(Messages::WebPage::GetResourceDataFromFrame(frame->frameID(), resourceURL->string(), callbackID), m_pageID);
3726}
3727
3728void WebPageProxy::getWebArchiveOfFrame(WebFrameProxy* frame, Function<void (API::Data*, CallbackBase::Error)>&& callbackFunction)
3729{
3730 if (!hasRunningProcess()) {
3731 callbackFunction(nullptr, CallbackBase::Error::Unknown);
3732 return;
3733 }
3734
3735 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
3736 m_process->send(Messages::WebPage::GetWebArchiveOfFrame(frame->frameID(), callbackID), m_pageID);
3737}
3738
3739void WebPageProxy::forceRepaint(RefPtr<VoidCallback>&& callback)
3740{
3741 if (!hasRunningProcess()) {
3742 // FIXME: If the page is invalid we should not call the callback. It'd be better to just return false from forceRepaint.
3743 callback->invalidate(CallbackBase::Error::OwnerWasInvalidated);
3744 return;
3745 }
3746
3747 Function<void(CallbackBase::Error)> didForceRepaintCallback = [this, callback = WTFMove(callback)](CallbackBase::Error error) mutable {
3748 if (error != CallbackBase::Error::None) {
3749 callback->invalidate(error);
3750 return;
3751 }
3752
3753 if (!hasRunningProcess()) {
3754 callback->invalidate(CallbackBase::Error::OwnerWasInvalidated);
3755 return;
3756 }
3757
3758 callAfterNextPresentationUpdate([callback = WTFMove(callback)](CallbackBase::Error error) {
3759 if (error != CallbackBase::Error::None) {
3760 callback->invalidate(error);
3761 return;
3762 }
3763
3764 callback->performCallback();
3765 });
3766 };
3767
3768 auto callbackID = m_callbacks.put(WTFMove(didForceRepaintCallback), m_process->throttler().backgroundActivityToken());
3769 m_drawingArea->waitForBackingStoreUpdateOnNextPaint();
3770 m_process->send(Messages::WebPage::ForceRepaint(callbackID), m_pageID);
3771}
3772
3773static OptionSet<IPC::SendOption> printingSendOptions(bool isPerformingDOMPrintOperation)
3774{
3775 if (isPerformingDOMPrintOperation)
3776 return IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply;
3777
3778 return { };
3779}
3780
3781void WebPageProxy::preferencesDidChange()
3782{
3783 if (!hasRunningProcess())
3784 return;
3785
3786 updateThrottleState();
3787 updateHiddenPageThrottlingAutoIncreases();
3788
3789 pageClient().preferencesDidChange();
3790
3791 // FIXME: It probably makes more sense to send individual preference changes.
3792 // However, WebKitTestRunner depends on getting a preference change notification
3793 // even if nothing changed in UI process, so that overrides get removed.
3794
3795 // Preferences need to be updated during synchronous printing to make "print backgrounds" preference work when toggled from a print dialog checkbox.
3796 m_process->send(Messages::WebPage::PreferencesDidChange(preferencesStore()), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation));
3797}
3798
3799void WebPageProxy::didCreateMainFrame(uint64_t frameID)
3800{
3801 // The DecidePolicyForNavigationActionSync IPC is synchronous and may therefore get processed before the DidCreateMainFrame one.
3802 // When this happens, decidePolicyForNavigationActionSync() calls didCreateMainFrame() and we need to ignore the DidCreateMainFrame
3803 // IPC when it later gets processed.
3804 if (m_mainFrame && m_mainFrame->frameID() == frameID)
3805 return;
3806
3807 PageClientProtector protector(pageClient());
3808
3809 MESSAGE_CHECK(m_process, !m_mainFrame);
3810 MESSAGE_CHECK(m_process, m_process->canCreateFrame(frameID));
3811
3812 m_mainFrame = WebFrameProxy::create(*this, frameID);
3813
3814 // Add the frame to the process wide map.
3815 m_process->frameCreated(frameID, *m_mainFrame);
3816}
3817
3818void WebPageProxy::didCreateSubframe(uint64_t frameID)
3819{
3820 PageClientProtector protector(pageClient());
3821
3822 MESSAGE_CHECK(m_process, m_mainFrame);
3823
3824 // The DecidePolicyForNavigationActionSync IPC is synchronous and may therefore get processed before the DidCreateSubframe one.
3825 // When this happens, decidePolicyForNavigationActionSync() calls didCreateSubframe() and we need to ignore the DidCreateSubframe
3826 // IPC when it later gets processed.
3827 if (m_process->webFrame(frameID))
3828 return;
3829
3830 MESSAGE_CHECK(m_process, m_process->canCreateFrame(frameID));
3831
3832 auto subFrame = WebFrameProxy::create(*this, frameID);
3833
3834 // Add the frame to the process wide map.
3835 m_process->frameCreated(frameID, subFrame.get());
3836}
3837
3838void WebPageProxy::didCreateWindow(uint64_t frameID, GlobalWindowIdentifier&& windowIdentifier)
3839{
3840}
3841
3842double WebPageProxy::estimatedProgress() const
3843{
3844 return m_pageLoadState.estimatedProgress();
3845}
3846
3847void WebPageProxy::didStartProgress()
3848{
3849 ASSERT(!m_isClosed);
3850
3851 PageClientProtector protector(pageClient());
3852
3853 auto transaction = m_pageLoadState.transaction();
3854 m_pageLoadState.didStartProgress(transaction);
3855
3856 m_pageLoadState.commitChanges();
3857}
3858
3859void WebPageProxy::didChangeProgress(double value)
3860{
3861 PageClientProtector protector(pageClient());
3862
3863 auto transaction = m_pageLoadState.transaction();
3864 m_pageLoadState.didChangeProgress(transaction, value);
3865
3866 m_pageLoadState.commitChanges();
3867}
3868
3869void WebPageProxy::didFinishProgress()
3870{
3871 PageClientProtector protector(pageClient());
3872
3873 auto transaction = m_pageLoadState.transaction();
3874 m_pageLoadState.didFinishProgress(transaction);
3875
3876 m_pageLoadState.commitChanges();
3877}
3878
3879void WebPageProxy::setNetworkRequestsInProgress(bool networkRequestsInProgress)
3880{
3881 auto transaction = m_pageLoadState.transaction();
3882 m_pageLoadState.setNetworkRequestsInProgress(transaction, networkRequestsInProgress);
3883}
3884
3885void WebPageProxy::hasInsecureContent(CompletionHandler<void(WebCore::HasInsecureContent)>&& completionHandler)
3886{
3887 completionHandler(m_pageLoadState.committedHasInsecureContent() ? HasInsecureContent::Yes : HasInsecureContent::No);
3888}
3889
3890void WebPageProxy::didDestroyNavigation(uint64_t navigationID)
3891{
3892 PageClientProtector protector(pageClient());
3893
3894 // On process-swap, the previous process tries to destroy the navigation but the provisional process is actually taking over the navigation.
3895 if (m_provisionalPage && m_provisionalPage->navigationID() == navigationID)
3896 return;
3897
3898 // FIXME: Message check the navigationID.
3899 m_navigationState->didDestroyNavigation(navigationID);
3900}
3901
3902void WebPageProxy::didStartProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, URL&& url, URL&& unreachableURL, const UserData& userData)
3903{
3904 didStartProvisionalLoadForFrameShared(m_process.copyRef(), frameID, navigationID, WTFMove(url), WTFMove(unreachableURL), userData);
3905}
3906
3907void WebPageProxy::didStartProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& process, uint64_t frameID, uint64_t navigationID, URL&& url, URL&& unreachableURL, const UserData& userData)
3908{
3909 PageClientProtector protector(pageClient());
3910
3911 WebFrameProxy* frame = process->webFrame(frameID);
3912 MESSAGE_CHECK(process, frame);
3913 MESSAGE_CHECK_URL(process, url);
3914
3915 // If the page starts a new main frame provisional load, then cancel any pending one in a provisional process.
3916 if (frame->isMainFrame() && m_provisionalPage && m_provisionalPage->mainFrame() != frame) {
3917 m_provisionalPage->cancel();
3918 m_provisionalPage = nullptr;
3919 }
3920
3921 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
3922 RefPtr<API::Navigation> navigation;
3923 if (frame->isMainFrame() && navigationID)
3924 navigation = navigationState().navigation(navigationID);
3925
3926 LOG(Loading, "WebPageProxy %" PRIu64 " in process pid %i didStartProvisionalLoadForFrame to frameID %" PRIu64 ", navigationID %" PRIu64 ", url %s", m_pageID, process->processIdentifier(), frameID, navigationID, url.string().utf8().data());
3927 RELEASE_LOG_IF_ALLOWED(Loading, "didStartProvisionalLoadForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64, process->processIdentifier(), m_pageID, frameID);
3928
3929 auto transaction = m_pageLoadState.transaction();
3930
3931 m_pageLoadState.clearPendingAPIRequestURL(transaction);
3932
3933 if (frame->isMainFrame()) {
3934 process->didStartProvisionalLoadForMainFrame(url);
3935 reportPageLoadResult(ResourceError { ResourceError::Type::Cancellation });
3936 m_pageLoadStart = MonotonicTime::now();
3937 m_pageLoadState.didStartProvisionalLoad(transaction, url, unreachableURL);
3938 pageClient().didStartProvisionalLoadForMainFrame();
3939 closeOverlayedViews();
3940 }
3941
3942 frame->setUnreachableURL(unreachableURL);
3943 frame->didStartProvisionalLoad(url);
3944
3945 m_pageLoadState.commitChanges();
3946 if (m_loaderClient)
3947 m_loaderClient->didStartProvisionalLoadForFrame(*this, *frame, navigation.get(), process->transformHandlesToObjects(userData.object()).get());
3948 else if (frame->isMainFrame())
3949 m_navigationClient->didStartProvisionalNavigation(*this, navigation.get(), process->transformHandlesToObjects(userData.object()).get());
3950}
3951
3952void WebPageProxy::didExplicitOpenForFrame(uint64_t frameID, URL&& url)
3953{
3954 auto* frame = m_process->webFrame(frameID);
3955 MESSAGE_CHECK(m_process, frame);
3956 MESSAGE_CHECK_URL(m_process, url);
3957
3958 auto transaction = m_pageLoadState.transaction();
3959
3960 if (frame->isMainFrame())
3961 m_pageLoadState.didExplicitOpen(transaction, url);
3962
3963 frame->didExplicitOpen(url);
3964
3965 m_hasCommittedAnyProvisionalLoads = true;
3966 m_process->didCommitProvisionalLoad();
3967
3968 m_pageLoadState.commitChanges();
3969}
3970
3971void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, ResourceRequest&& request, const UserData& userData)
3972{
3973 didReceiveServerRedirectForProvisionalLoadForFrameShared(m_process.copyRef(), frameID, navigationID, WTFMove(request), userData);
3974}
3975
3976void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& process, uint64_t frameID, uint64_t navigationID, ResourceRequest&& request, const UserData& userData)
3977{
3978 LOG(Loading, "WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame to frameID %" PRIu64 ", navigationID %" PRIu64 ", url %s", frameID, navigationID, request.url().string().utf8().data());
3979 RELEASE_LOG_IF_ALLOWED(Loading, "didReceiveServerRedirectForProvisionalLoadForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64, process->processIdentifier(), m_pageID, frameID);
3980
3981 PageClientProtector protector(pageClient());
3982
3983 WebFrameProxy* frame = process->webFrame(frameID);
3984 MESSAGE_CHECK(process, frame);
3985 MESSAGE_CHECK_URL(process, request.url());
3986
3987 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
3988 RefPtr<API::Navigation> navigation = navigationID ? navigationState().navigation(navigationID) : nullptr;
3989 if (navigation)
3990 navigation->appendRedirectionURL(request.url());
3991
3992 auto transaction = m_pageLoadState.transaction();
3993
3994 if (frame->isMainFrame())
3995 m_pageLoadState.didReceiveServerRedirectForProvisionalLoad(transaction, request.url());
3996
3997 frame->didReceiveServerRedirectForProvisionalLoad(request.url());
3998
3999 m_pageLoadState.commitChanges();
4000 if (m_loaderClient)
4001 m_loaderClient->didReceiveServerRedirectForProvisionalLoadForFrame(*this, *frame, frame->isMainFrame() ? navigation.get() : nullptr, process->transformHandlesToObjects(userData.object()).get());
4002 else if (frame->isMainFrame())
4003 m_navigationClient->didReceiveServerRedirectForProvisionalNavigation(*this, navigation.get(), process->transformHandlesToObjects(userData.object()).get());
4004}
4005
4006void WebPageProxy::willPerformClientRedirectForFrame(uint64_t frameID, const String& url, double delay, WebCore::LockBackForwardList)
4007{
4008 RELEASE_LOG_IF_ALLOWED(Loading, "willPerformClientRedirectForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64, m_process->processIdentifier(), m_pageID, frameID);
4009
4010 PageClientProtector protector(pageClient());
4011
4012 WebFrameProxy* frame = m_process->webFrame(frameID);
4013 MESSAGE_CHECK(m_process, frame);
4014
4015 if (frame->isMainFrame())
4016 m_navigationClient->willPerformClientRedirect(*this, url, delay);
4017}
4018
4019void WebPageProxy::didCancelClientRedirectForFrame(uint64_t frameID)
4020{
4021 RELEASE_LOG_IF_ALLOWED(Loading, "didCancelClientRedirectForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64, m_process->processIdentifier(), m_pageID, frameID);
4022
4023 PageClientProtector protector(pageClient());
4024
4025 WebFrameProxy* frame = m_process->webFrame(frameID);
4026 MESSAGE_CHECK(m_process, frame);
4027
4028 if (frame->isMainFrame())
4029 m_navigationClient->didCancelClientRedirect(*this);
4030}
4031
4032void WebPageProxy::didChangeProvisionalURLForFrame(uint64_t frameID, uint64_t navigationID, URL&& url)
4033{
4034 didChangeProvisionalURLForFrameShared(m_process.copyRef(), frameID, navigationID, WTFMove(url));
4035}
4036
4037void WebPageProxy::didChangeProvisionalURLForFrameShared(Ref<WebProcessProxy>&& process, uint64_t frameID, uint64_t, URL&& url)
4038{
4039 PageClientProtector protector(pageClient());
4040
4041 WebFrameProxy* frame = process->webFrame(frameID);
4042 MESSAGE_CHECK(process, frame);
4043 MESSAGE_CHECK(process, frame->frameLoadState().state() == FrameLoadState::State::Provisional);
4044 MESSAGE_CHECK_URL(process, url);
4045
4046 auto transaction = m_pageLoadState.transaction();
4047
4048 // Internally, we handle this the same way we handle a server redirect. There are no client callbacks
4049 // for this, but if this is the main frame, clients may observe a change to the page's URL.
4050 if (frame->isMainFrame())
4051 m_pageLoadState.didReceiveServerRedirectForProvisionalLoad(transaction, url);
4052
4053 frame->didReceiveServerRedirectForProvisionalLoad(url);
4054}
4055
4056void WebPageProxy::didFailProvisionalLoadForFrame(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const String& provisionalURL, const ResourceError& error, WillContinueLoading willContinueLoading, const UserData& userData)
4057{
4058 if (m_provisionalPage && m_provisionalPage->navigationID() == navigationID) {
4059 // The load did not fail, it is merely happening in a new provisional process.
4060 return;
4061 }
4062
4063 didFailProvisionalLoadForFrameShared(m_process.copyRef(), frameID, frameSecurityOrigin, navigationID, provisionalURL, error, willContinueLoading, userData);
4064}
4065
4066void WebPageProxy::didFailProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& process, uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const String& provisionalURL, const ResourceError& error, WillContinueLoading willContinueLoading, const UserData& userData)
4067{
4068 LOG(Loading, "(Loading) WebPageProxy %" PRIu64 " in web process pid %i didFailProvisionalLoadForFrame to provisionalURL %s", m_pageID, process->processIdentifier(), provisionalURL.utf8().data());
4069 RELEASE_LOG_IF_ALLOWED(Process, "didFailProvisionalLoadForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64 ", domain = %s, code = %d", process->processIdentifier(), m_pageID, frameID, error.domain().utf8().data(), error.errorCode());
4070
4071 PageClientProtector protector(pageClient());
4072
4073 WebFrameProxy* frame = process->webFrame(frameID);
4074 MESSAGE_CHECK(process, frame);
4075
4076 if (m_controlledByAutomation) {
4077 if (auto* automationSession = process->processPool().automationSession())
4078 automationSession->navigationOccurredForFrame(*frame);
4079 }
4080
4081 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
4082 RefPtr<API::Navigation> navigation;
4083 if (frame->isMainFrame() && navigationID)
4084 navigation = navigationState().takeNavigation(navigationID);
4085
4086 auto transaction = m_pageLoadState.transaction();
4087
4088 if (frame->isMainFrame()) {
4089 reportPageLoadResult(error);
4090 m_pageLoadState.didFailProvisionalLoad(transaction);
4091 pageClient().didFailProvisionalLoadForMainFrame();
4092 }
4093
4094 frame->didFailProvisionalLoad();
4095
4096 m_pageLoadState.commitChanges();
4097
4098 ASSERT(!m_failingProvisionalLoadURL);
4099 m_failingProvisionalLoadURL = provisionalURL;
4100
4101 if (m_loaderClient)
4102 m_loaderClient->didFailProvisionalLoadWithErrorForFrame(*this, *frame, navigation.get(), error, process->transformHandlesToObjects(userData.object()).get());
4103 else if (frame->isMainFrame())
4104 m_navigationClient->didFailProvisionalNavigationWithError(*this, *frame, navigation.get(), error, process->transformHandlesToObjects(userData.object()).get());
4105 else {
4106 // FIXME: Get the main frame's current navigation.
4107 m_navigationClient->didFailProvisionalLoadInSubframeWithError(*this, *frame, frameSecurityOrigin, nullptr, error, process->transformHandlesToObjects(userData.object()).get());
4108 }
4109
4110 m_failingProvisionalLoadURL = { };
4111
4112 // If the provisional page's load fails then we destroy the provisional page.
4113 if (m_provisionalPage && m_provisionalPage->mainFrame() == frame && willContinueLoading == WillContinueLoading::No)
4114 m_provisionalPage = nullptr;
4115}
4116
4117void WebPageProxy::clearLoadDependentCallbacks()
4118{
4119 HashSet<CallbackID> loadDependentStringCallbackIDs = WTFMove(m_loadDependentStringCallbackIDs);
4120 for (auto& callbackID : loadDependentStringCallbackIDs) {
4121 if (auto callback = m_callbacks.take<StringCallback>(callbackID))
4122 callback->invalidate();
4123 }
4124}
4125
4126#if ENABLE(RESOURCE_LOAD_STATISTICS)
4127static bool isNonUniqueNavigationWithLinkDecoration(const SecurityOriginData requesterOrigin, const URL& currentURL)
4128{
4129 return !requesterOrigin.securityOrigin()->isUnique() && (!currentURL.query().isEmpty() || !currentURL.fragmentIdentifier().isEmpty());
4130}
4131#endif
4132
4133void WebPageProxy::didCommitLoadForFrame(uint64_t frameID, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, uint32_t opaqueFrameLoadType, const WebCore::CertificateInfo& certificateInfo, bool containsPluginDocument, Optional<HasInsecureContent> hasInsecureContent, const UserData& userData)
4134{
4135 LOG(Loading, "(Loading) WebPageProxy %" PRIu64 " didCommitLoadForFrame in navigation %" PRIu64, m_pageID, navigationID);
4136 LOG(BackForward, "(Back/Forward) After load commit, back/forward list is now:%s", m_backForwardList->loggingString());
4137 RELEASE_LOG_IF_ALLOWED(Loading, "didCommitLoadForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64, m_process->processIdentifier(), m_pageID, frameID);
4138
4139 PageClientProtector protector(pageClient());
4140
4141 WebFrameProxy* frame = m_process->webFrame(frameID);
4142 MESSAGE_CHECK(m_process, frame);
4143
4144 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
4145 RefPtr<API::Navigation> navigation;
4146 if (frame->isMainFrame() && navigationID && (navigation = navigationState().navigation(navigationID))) {
4147#if ENABLE(RESOURCE_LOAD_STATISTICS)
4148 auto requesterOrigin = navigation->lastNavigationAction().requesterOrigin;
4149 auto currentURL = navigation->currentRequest().url();
4150 if (isNonUniqueNavigationWithLinkDecoration(requesterOrigin, currentURL)) {
4151 RegistrableDomain currentDomain { currentURL };
4152 URL requesterURL { URL(), requesterOrigin.toString() };
4153 if (!currentDomain.matches(requesterURL))
4154 m_process->processPool().committedCrossSiteLoadWithLinkDecoration(m_websiteDataStore->sessionID(), RegistrableDomain { requesterURL }, currentDomain, m_pageID);
4155 }
4156#endif
4157 }
4158
4159 m_hasCommittedAnyProvisionalLoads = true;
4160 m_process->didCommitProvisionalLoad();
4161
4162#if PLATFORM(IOS_FAMILY)
4163 if (frame->isMainFrame()) {
4164 m_hasReceivedLayerTreeTransactionAfterDidCommitLoad = false;
4165 m_firstLayerTreeTransactionIdAfterDidCommitLoad = downcast<RemoteLayerTreeDrawingAreaProxy>(*drawingArea()).nextLayerTreeTransactionID();
4166 }
4167#endif
4168
4169 auto transaction = m_pageLoadState.transaction();
4170 Ref<WebCertificateInfo> webCertificateInfo = WebCertificateInfo::create(certificateInfo);
4171 bool markPageInsecure = hasInsecureContent ? hasInsecureContent.value() == HasInsecureContent::Yes : m_treatsSHA1CertificatesAsInsecure && certificateInfo.containsNonRootSHA1SignedCertificate();
4172
4173 if (frame->isMainFrame()) {
4174 m_pageLoadState.didCommitLoad(transaction, webCertificateInfo, markPageInsecure);
4175 m_shouldSuppressNextAutomaticNavigationSnapshot = false;
4176 } else if (markPageInsecure)
4177 m_pageLoadState.didDisplayOrRunInsecureContent(transaction);
4178
4179#if USE(APPKIT)
4180 // FIXME (bug 59111): didCommitLoadForFrame comes too late when restoring a page from b/f cache, making us disable secure event mode in password fields.
4181 // FIXME: A load going on in one frame shouldn't affect text editing in other frames on the page.
4182 pageClient().resetSecureInputState();
4183#endif
4184
4185 clearLoadDependentCallbacks();
4186
4187 frame->didCommitLoad(mimeType, webCertificateInfo, containsPluginDocument);
4188
4189 if (navigation && frame->isMainFrame()) {
4190 if (auto& adClickAttribution = navigation->adClickAttribution()) {
4191 if (adClickAttribution->destination().matches(frame->url()))
4192 m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::StoreAdClickAttribution(m_websiteDataStore->sessionID(), *adClickAttribution));
4193 }
4194 }
4195
4196 if (frame->isMainFrame()) {
4197 m_mainFrameHasCustomContentProvider = frameHasCustomContentProvider;
4198
4199 if (m_mainFrameHasCustomContentProvider) {
4200 // Always assume that the main frame is pinned here, since the custom representation view will handle
4201 // any wheel events and dispatch them to the WKView when necessary.
4202 m_mainFrameIsPinnedToLeftSide = true;
4203 m_mainFrameIsPinnedToRightSide = true;
4204 m_mainFrameIsPinnedToTopSide = true;
4205 m_mainFrameIsPinnedToBottomSide = true;
4206
4207 m_uiClient->pinnedStateDidChange(*this);
4208 }
4209 pageClient().didCommitLoadForMainFrame(mimeType, frameHasCustomContentProvider);
4210 }
4211
4212 // Even if WebPage has the default pageScaleFactor (and therefore doesn't reset it),
4213 // WebPageProxy's cache of the value can get out of sync (e.g. in the case where a
4214 // plugin is handling page scaling itself) so we should reset it to the default
4215 // for standard main frame loads.
4216 if (frame->isMainFrame()) {
4217 if (static_cast<FrameLoadType>(opaqueFrameLoadType) == FrameLoadType::Standard) {
4218 m_pageScaleFactor = 1;
4219 m_pluginScaleFactor = 1;
4220 m_mainFramePluginHandlesPageScaleGesture = false;
4221 }
4222 }
4223
4224#if ENABLE(POINTER_LOCK)
4225 if (frame->isMainFrame())
4226 requestPointerUnlock();
4227#endif
4228
4229 m_pageLoadState.commitChanges();
4230 if (m_loaderClient)
4231 m_loaderClient->didCommitLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
4232 else if (frame->isMainFrame())
4233 m_navigationClient->didCommitNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
4234
4235#if ENABLE(ATTACHMENT_ELEMENT)
4236 if (frame->isMainFrame())
4237 invalidateAllAttachments();
4238#endif
4239
4240#if ENABLE(REMOTE_INSPECTOR)
4241 if (frame->isMainFrame())
4242 remoteInspectorInformationDidChange();
4243#endif
4244}
4245
4246void WebPageProxy::didFinishDocumentLoadForFrame(uint64_t frameID, uint64_t navigationID, const UserData& userData)
4247{
4248 RELEASE_LOG_IF_ALLOWED(Loading, "didFinishDocumentLoadForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64, m_process->processIdentifier(), m_pageID, frameID);
4249
4250 PageClientProtector protector(pageClient());
4251
4252 WebFrameProxy* frame = m_process->webFrame(frameID);
4253 MESSAGE_CHECK(m_process, frame);
4254
4255 if (m_controlledByAutomation) {
4256 if (auto* automationSession = process().processPool().automationSession())
4257 automationSession->documentLoadedForFrame(*frame);
4258 }
4259
4260 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
4261 RefPtr<API::Navigation> navigation;
4262 if (frame->isMainFrame() && navigationID)
4263 navigation = navigationState().navigation(navigationID);
4264
4265 if (frame->isMainFrame())
4266 m_navigationClient->didFinishDocumentLoad(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
4267}
4268
4269void WebPageProxy::didFinishLoadForFrame(uint64_t frameID, uint64_t navigationID, const UserData& userData)
4270{
4271 LOG(Loading, "WebPageProxy::didFinishLoadForFrame - WebPageProxy %p with navigationID %" PRIu64 " didFinishLoad", this, navigationID);
4272 RELEASE_LOG_IF_ALLOWED(Loading, "didFinishLoadForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64, m_process->processIdentifier(), m_pageID, frameID);
4273
4274 PageClientProtector protector(pageClient());
4275
4276 WebFrameProxy* frame = m_process->webFrame(frameID);
4277 MESSAGE_CHECK(m_process, frame);
4278
4279 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
4280 RefPtr<API::Navigation> navigation;
4281 if (frame->isMainFrame() && navigationID)
4282 navigation = navigationState().navigation(navigationID);
4283
4284 auto transaction = m_pageLoadState.transaction();
4285
4286 bool isMainFrame = frame->isMainFrame();
4287 if (isMainFrame)
4288 m_pageLoadState.didFinishLoad(transaction);
4289
4290 if (m_controlledByAutomation) {
4291 if (auto* automationSession = process().processPool().automationSession())
4292 automationSession->navigationOccurredForFrame(*frame);
4293 }
4294
4295 frame->didFinishLoad();
4296
4297 m_pageLoadState.commitChanges();
4298 if (m_loaderClient)
4299 m_loaderClient->didFinishLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
4300 else if (isMainFrame)
4301 m_navigationClient->didFinishNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
4302
4303 if (isMainFrame) {
4304 reportPageLoadResult();
4305 pageClient().didFinishLoadForMainFrame();
4306
4307 resetRecentCrashCountSoon();
4308
4309 notifyProcessPoolToPrewarm();
4310 }
4311
4312 m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = false;
4313}
4314
4315void WebPageProxy::didFailLoadForFrame(uint64_t frameID, uint64_t navigationID, const ResourceError& error, const UserData& userData)
4316{
4317 RELEASE_LOG_IF_ALLOWED(Loading, "didFailLoadForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64 ", domain = %s, code = %d", m_process->processIdentifier(), m_pageID, frameID, error.domain().utf8().data(), error.errorCode());
4318
4319 PageClientProtector protector(pageClient());
4320
4321 WebFrameProxy* frame = m_process->webFrame(frameID);
4322 MESSAGE_CHECK(m_process, frame);
4323
4324 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
4325 RefPtr<API::Navigation> navigation;
4326 if (frame->isMainFrame() && navigationID)
4327 navigation = navigationState().navigation(navigationID);
4328
4329 clearLoadDependentCallbacks();
4330
4331 auto transaction = m_pageLoadState.transaction();
4332
4333 bool isMainFrame = frame->isMainFrame();
4334
4335 if (isMainFrame)
4336 m_pageLoadState.didFailLoad(transaction);
4337
4338 if (m_controlledByAutomation) {
4339 if (auto* automationSession = process().processPool().automationSession())
4340 automationSession->navigationOccurredForFrame(*frame);
4341 }
4342
4343 frame->didFailLoad();
4344
4345 m_pageLoadState.commitChanges();
4346 if (m_loaderClient)
4347 m_loaderClient->didFailLoadWithErrorForFrame(*this, *frame, navigation.get(), error, m_process->transformHandlesToObjects(userData.object()).get());
4348 else if (frame->isMainFrame())
4349 m_navigationClient->didFailNavigationWithError(*this, *frame, navigation.get(), error, m_process->transformHandlesToObjects(userData.object()).get());
4350
4351 if (isMainFrame) {
4352 reportPageLoadResult(error);
4353 pageClient().didFailLoadForMainFrame();
4354 }
4355}
4356
4357void WebPageProxy::didSameDocumentNavigationForFrame(uint64_t frameID, uint64_t navigationID, uint32_t opaqueSameDocumentNavigationType, URL&& url, const UserData& userData)
4358{
4359 RELEASE_LOG_IF_ALLOWED(Loading, "didSameDocumentNavigationForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64, m_process->processIdentifier(), m_pageID, frameID);
4360
4361 PageClientProtector protector(pageClient());
4362
4363 WebFrameProxy* frame = m_process->webFrame(frameID);
4364 MESSAGE_CHECK(m_process, frame);
4365 MESSAGE_CHECK_URL(m_process, url);
4366
4367 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
4368 RefPtr<API::Navigation> navigation;
4369 if (frame->isMainFrame() && navigationID)
4370 navigation = navigationState().navigation(navigationID);
4371
4372 auto transaction = m_pageLoadState.transaction();
4373
4374 bool isMainFrame = frame->isMainFrame();
4375 if (isMainFrame)
4376 m_pageLoadState.didSameDocumentNavigation(transaction, url);
4377
4378 if (m_controlledByAutomation) {
4379 if (auto* automationSession = process().processPool().automationSession())
4380 automationSession->navigationOccurredForFrame(*frame);
4381 }
4382
4383 m_pageLoadState.clearPendingAPIRequestURL(transaction);
4384 frame->didSameDocumentNavigation(url);
4385
4386 m_pageLoadState.commitChanges();
4387
4388 SameDocumentNavigationType navigationType = static_cast<SameDocumentNavigationType>(opaqueSameDocumentNavigationType);
4389 if (isMainFrame)
4390 m_navigationClient->didSameDocumentNavigation(*this, navigation.get(), navigationType, m_process->transformHandlesToObjects(userData.object()).get());
4391
4392 if (isMainFrame)
4393 pageClient().didSameDocumentNavigationForMainFrame(navigationType);
4394}
4395
4396void WebPageProxy::didChangeMainDocument(uint64_t frameID)
4397{
4398#if ENABLE(MEDIA_STREAM)
4399 if (m_userMediaPermissionRequestManager)
4400 m_userMediaPermissionRequestManager->resetAccess(frameID);
4401#else
4402 UNUSED_PARAM(frameID);
4403#endif
4404 m_isQuotaIncreaseDenied = false;
4405}
4406
4407void WebPageProxy::viewIsBecomingVisible()
4408{
4409#if ENABLE(MEDIA_STREAM)
4410 if (m_userMediaPermissionRequestManager)
4411 m_userMediaPermissionRequestManager->viewIsBecomingVisible();
4412#endif
4413}
4414
4415void WebPageProxy::didReceiveTitleForFrame(uint64_t frameID, const String& title, const UserData& userData)
4416{
4417 PageClientProtector protector(pageClient());
4418
4419 WebFrameProxy* frame = m_process->webFrame(frameID);
4420 MESSAGE_CHECK(m_process, frame);
4421
4422 auto transaction = m_pageLoadState.transaction();
4423
4424 if (frame->isMainFrame())
4425 m_pageLoadState.setTitle(transaction, title);
4426
4427 frame->didChangeTitle(title);
4428
4429 m_pageLoadState.commitChanges();
4430
4431#if ENABLE(REMOTE_INSPECTOR)
4432 if (frame->isMainFrame())
4433 remoteInspectorInformationDidChange();
4434#endif
4435}
4436
4437void WebPageProxy::didFirstLayoutForFrame(uint64_t, const UserData& userData)
4438{
4439}
4440
4441void WebPageProxy::didFirstVisuallyNonEmptyLayoutForFrame(uint64_t frameID, const UserData& userData)
4442{
4443 PageClientProtector protector(pageClient());
4444
4445 WebFrameProxy* frame = m_process->webFrame(frameID);
4446 MESSAGE_CHECK(m_process, frame);
4447
4448 if (m_loaderClient)
4449 m_loaderClient->didFirstVisuallyNonEmptyLayoutForFrame(*this, *frame, m_process->transformHandlesToObjects(userData.object()).get());
4450
4451 if (frame->isMainFrame())
4452 pageClient().didFirstVisuallyNonEmptyLayoutForMainFrame();
4453}
4454
4455void WebPageProxy::didLayoutForCustomContentProvider()
4456{
4457 didReachLayoutMilestone({ DidFirstLayout, DidFirstVisuallyNonEmptyLayout, DidHitRelevantRepaintedObjectsAreaThreshold });
4458}
4459
4460void WebPageProxy::didReachLayoutMilestone(OptionSet<WebCore::LayoutMilestone> layoutMilestones)
4461{
4462 PageClientProtector protector(pageClient());
4463
4464 if (layoutMilestones.contains(DidFirstVisuallyNonEmptyLayout))
4465 pageClient().clearSafeBrowsingWarningIfForMainFrameNavigation();
4466
4467 if (m_loaderClient)
4468 m_loaderClient->didReachLayoutMilestone(*this, layoutMilestones);
4469 m_navigationClient->renderingProgressDidChange(*this, layoutMilestones);
4470}
4471
4472void WebPageProxy::didDisplayInsecureContentForFrame(uint64_t frameID, const UserData& userData)
4473{
4474 PageClientProtector protector(pageClient());
4475
4476 WebFrameProxy* frame = m_process->webFrame(frameID);
4477 MESSAGE_CHECK(m_process, frame);
4478
4479 auto transaction = m_pageLoadState.transaction();
4480 m_pageLoadState.didDisplayOrRunInsecureContent(transaction);
4481 m_pageLoadState.commitChanges();
4482
4483 m_navigationClient->didDisplayInsecureContent(*this, m_process->transformHandlesToObjects(userData.object()).get());
4484}
4485
4486void WebPageProxy::didRunInsecureContentForFrame(uint64_t frameID, const UserData& userData)
4487{
4488 PageClientProtector protector(pageClient());
4489
4490 WebFrameProxy* frame = m_process->webFrame(frameID);
4491 MESSAGE_CHECK(m_process, frame);
4492
4493 auto transaction = m_pageLoadState.transaction();
4494 m_pageLoadState.didDisplayOrRunInsecureContent(transaction);
4495 m_pageLoadState.commitChanges();
4496
4497 m_navigationClient->didRunInsecureContent(*this, m_process->transformHandlesToObjects(userData.object()).get());
4498}
4499
4500void WebPageProxy::didDetectXSSForFrame(uint64_t, const UserData&)
4501{
4502}
4503
4504void WebPageProxy::mainFramePluginHandlesPageScaleGestureDidChange(bool mainFramePluginHandlesPageScaleGesture)
4505{
4506 m_mainFramePluginHandlesPageScaleGesture = mainFramePluginHandlesPageScaleGesture;
4507}
4508
4509void WebPageProxy::frameDidBecomeFrameSet(uint64_t frameID, bool value)
4510{
4511 PageClientProtector protector(pageClient());
4512
4513 WebFrameProxy* frame = m_process->webFrame(frameID);
4514 MESSAGE_CHECK(m_process, frame);
4515
4516 frame->setIsFrameSet(value);
4517 if (frame->isMainFrame())
4518 m_frameSetLargestFrame = value ? m_mainFrame : 0;
4519}
4520
4521#if !PLATFORM(COCOA)
4522void WebPageProxy::beginSafeBrowsingCheck(const URL&, bool, WebFramePolicyListenerProxy& listener)
4523{
4524 listener.didReceiveSafeBrowsingResults({ });
4525}
4526#endif
4527
4528void WebPageProxy::decidePolicyForNavigationActionAsync(uint64_t frameID, WebCore::SecurityOriginData&& frameSecurityOrigin, PolicyCheckIdentifier identifier, uint64_t navigationID,
4529 NavigationActionData&& navigationActionData, FrameInfoData&& frameInfoData, uint64_t originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request,
4530 IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData& userData, uint64_t listenerID)
4531{
4532 decidePolicyForNavigationActionAsyncShared(m_process.copyRef(), frameID, WTFMove(frameSecurityOrigin), identifier, navigationID, WTFMove(navigationActionData),
4533 WTFMove(frameInfoData), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, listenerID);
4534}
4535
4536void WebPageProxy::decidePolicyForNavigationActionAsyncShared(Ref<WebProcessProxy>&& process, uint64_t frameID, WebCore::SecurityOriginData&& frameSecurityOrigin,
4537 WebCore::PolicyCheckIdentifier identifier, uint64_t navigationID, NavigationActionData&& navigationActionData, FrameInfoData&& frameInfoData, uint64_t originatingPageID,
4538 const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse,
4539 const UserData& userData, uint64_t listenerID)
4540{
4541 auto* frame = process->webFrame(frameID);
4542 MESSAGE_CHECK(process, frame);
4543
4544 auto sender = PolicyDecisionSender::create(identifier, [this, protectedThis = makeRef(*this), frameID, listenerID, process = process.copyRef()] (auto... args) {
4545 process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, args...), m_pageID);
4546 });
4547
4548 decidePolicyForNavigationAction(process.copyRef(), *frame, WTFMove(frameSecurityOrigin), navigationID, WTFMove(navigationActionData), WTFMove(frameInfoData), originatingPageID,
4549 originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, WTFMove(sender));
4550}
4551
4552void WebPageProxy::decidePolicyForNavigationAction(Ref<WebProcessProxy>&& process, WebFrameProxy& frame, WebCore::SecurityOriginData&& frameSecurityOrigin, uint64_t navigationID,
4553 NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfoData, uint64_t originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request,
4554 IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData& userData, Ref<PolicyDecisionSender>&& sender)
4555{
4556 LOG(Loading, "WebPageProxy::decidePolicyForNavigationAction - Original URL %s, current target URL %s", originalRequest.url().string().utf8().data(), request.url().string().utf8().data());
4557
4558 PageClientProtector protector(pageClient());
4559
4560 // Make the request whole again as we do not normally encode the request's body when sending it over IPC, for performance reasons.
4561 request.setHTTPBody(requestBody.takeData());
4562
4563 auto transaction = m_pageLoadState.transaction();
4564
4565 bool fromAPI = request.url() == m_pageLoadState.pendingAPIRequestURL();
4566 if (!fromAPI)
4567 m_pageLoadState.clearPendingAPIRequestURL(transaction);
4568
4569 if (!checkURLReceivedFromCurrentOrPreviousWebProcess(process, request.url())) {
4570 RELEASE_LOG_ERROR_IF_ALLOWED(Process, "Ignoring request to load this main resource because it is outside the sandbox");
4571 sender->send(PolicyAction::Ignore, 0, DownloadID(), WTF::nullopt);
4572 return;
4573 }
4574
4575 MESSAGE_CHECK_URL(process, originalRequest.url());
4576
4577 RefPtr<API::Navigation> navigation;
4578 if (navigationID)
4579 navigation = m_navigationState->navigation(navigationID);
4580
4581 // When process-swapping on a redirect, the navigationActionData / originatingFrameInfoData / frameSecurityOrigin provided by the fresh new WebProcess are inaccurate since
4582 // the new process does not have sufficient information. To address the issue, we restore the information we stored on the NavigationAction during the original request
4583 // policy decision.
4584 if (navigationActionData.isRedirect && navigation) {
4585 navigationActionData = navigation->lastNavigationAction();
4586 navigationActionData.isRedirect = true;
4587 originatingFrameInfoData = navigation->originatingFrameInfo();
4588 frameSecurityOrigin = navigation->destinationFrameSecurityOrigin();
4589 }
4590
4591 if (!navigation) {
4592 if (auto targetBackForwardItemIdentifier = navigationActionData.targetBackForwardItemIdentifier) {
4593 if (auto* item = m_backForwardList->itemForID(*targetBackForwardItemIdentifier)) {
4594 auto* fromItem = navigationActionData.sourceBackForwardItemIdentifier ? m_backForwardList->itemForID(*navigationActionData.sourceBackForwardItemIdentifier) : nullptr;
4595 if (!fromItem)
4596 fromItem = m_backForwardList->currentItem();
4597 navigation = m_navigationState->createBackForwardNavigation(*item, fromItem, FrameLoadType::IndexedBackForward);
4598 }
4599 }
4600 if (!navigation)
4601 navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem());
4602 }
4603
4604 navigationID = navigation->navigationID();
4605
4606 // Make sure the provisional page always has the latest navigationID.
4607 if (m_provisionalPage && &m_provisionalPage->process() == process.ptr())
4608 m_provisionalPage->setNavigationID(navigationID);
4609
4610 navigation->setCurrentRequest(ResourceRequest(request), process->coreProcessIdentifier());
4611 navigation->setLastNavigationAction(navigationActionData);
4612 navigation->setOriginatingFrameInfo(originatingFrameInfoData);
4613 navigation->setDestinationFrameSecurityOrigin(frameSecurityOrigin);
4614
4615#if ENABLE(CONTENT_FILTERING)
4616 if (frame.didHandleContentFilterUnblockNavigation(request))
4617 return receivedPolicyDecision(PolicyAction::Ignore, m_navigationState->navigation(navigationID), WTF::nullopt, WTFMove(sender));
4618#endif
4619
4620 ShouldExpectSafeBrowsingResult shouldExpectSafeBrowsingResult = ShouldExpectSafeBrowsingResult::Yes;
4621 if (!m_preferences->safeBrowsingEnabled())
4622 shouldExpectSafeBrowsingResult = ShouldExpectSafeBrowsingResult::No;
4623
4624 auto listener = makeRef(frame.setUpPolicyListenerProxy([this, protectedThis = makeRef(*this), frame = makeRef(frame), sender = WTFMove(sender), navigation] (PolicyAction policyAction, API::WebsitePolicies* policies, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning) mutable {
4625
4626 auto completionHandler = [this, protectedThis = protectedThis.copyRef(), frame = frame.copyRef(), sender = WTFMove(sender), navigation = WTFMove(navigation), processSwapRequestedByClient, policies = makeRefPtr(policies)] (PolicyAction policyAction) mutable {
4627 if (frame->isMainFrame()) {
4628 if (!policies) {
4629 if (auto* defaultPolicies = m_configuration->defaultWebsitePolicies())
4630 policies = defaultPolicies->copy();
4631 }
4632 if (policies)
4633 navigation->setEffectiveCompatibilityMode(effectiveCompatibilityModeAfterAdjustingPolicies(*policies, navigation->currentRequest()));
4634 }
4635 receivedNavigationPolicyDecision(policyAction, navigation.get(), processSwapRequestedByClient, frame, policies.get(), WTFMove(sender));
4636 };
4637
4638 if (!m_pageClient)
4639 return completionHandler(policyAction);
4640
4641 m_pageClient->clearSafeBrowsingWarning();
4642
4643 if (safeBrowsingWarning) {
4644 if (frame->isMainFrame() && safeBrowsingWarning->url().isValid()) {
4645 auto transaction = m_pageLoadState.transaction();
4646 m_pageLoadState.setPendingAPIRequestURL(transaction, safeBrowsingWarning->url());
4647 m_pageLoadState.commitChanges();
4648 }
4649
4650 m_pageClient->showSafeBrowsingWarning(*safeBrowsingWarning, [protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler), policyAction] (auto&& result) mutable {
4651 switchOn(result, [&] (const URL& url) {
4652 completionHandler(PolicyAction::Ignore);
4653 protectedThis->loadRequest({ url });
4654 }, [&] (ContinueUnsafeLoad continueUnsafeLoad) {
4655 switch (continueUnsafeLoad) {
4656 case ContinueUnsafeLoad::No:
4657 if (!protectedThis->hasCommittedAnyProvisionalLoads())
4658 protectedThis->m_uiClient->close(protectedThis.ptr());
4659 completionHandler(PolicyAction::Ignore);
4660 break;
4661 case ContinueUnsafeLoad::Yes:
4662 completionHandler(policyAction);
4663 break;
4664 }
4665 });
4666 });
4667 m_uiClient->didShowSafeBrowsingWarning();
4668 return;
4669 }
4670 completionHandler(policyAction);
4671
4672 }, shouldExpectSafeBrowsingResult));
4673 if (shouldExpectSafeBrowsingResult == ShouldExpectSafeBrowsingResult::Yes)
4674 beginSafeBrowsingCheck(request.url(), frame.isMainFrame(), listener);
4675
4676 API::Navigation* mainFrameNavigation = frame.isMainFrame() ? navigation.get() : nullptr;
4677 WebFrameProxy* originatingFrame = process->webFrame(originatingFrameInfoData.frameID);
4678
4679#if ENABLE(RESOURCE_LOAD_STATISTICS)
4680 if (auto* resourceLoadStatisticsStore = websiteDataStore().resourceLoadStatistics())
4681 resourceLoadStatisticsStore->logFrameNavigation(frame, URL(URL(), m_pageLoadState.url()), request, redirectResponse.url());
4682 logFrameNavigation(frame, URL(URL(), m_pageLoadState.url()), request, redirectResponse.url());
4683#endif
4684
4685 if (m_policyClient)
4686 m_policyClient->decidePolicyForNavigationAction(*this, &frame, WTFMove(navigationActionData), originatingFrame, originalRequest, WTFMove(request), WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
4687 else {
4688 auto destinationFrameInfo = API::FrameInfo::create(frame, frameSecurityOrigin.securityOrigin());
4689 RefPtr<API::FrameInfo> sourceFrameInfo;
4690 if (!fromAPI && originatingFrame == &frame)
4691 sourceFrameInfo = destinationFrameInfo.copyRef();
4692 else if (!fromAPI)
4693 sourceFrameInfo = API::FrameInfo::create(originatingFrameInfoData, originatingPageID ? process->webPage(originatingPageID) : nullptr);
4694
4695 auto userInitiatedActivity = process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
4696 bool shouldOpenAppLinks = !m_shouldSuppressAppLinksInNextNavigationPolicyDecision
4697 && destinationFrameInfo->isMainFrame()
4698 && (m_mainFrame ? !hostsAreEqual(m_mainFrame->url(), request.url()) : false)
4699 && navigationActionData.navigationType != WebCore::NavigationType::BackForward;
4700
4701 auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), sourceFrameInfo.get(), destinationFrameInfo.ptr(), WTF::nullopt, WTFMove(request), originalRequest.url(), shouldOpenAppLinks, WTFMove(userInitiatedActivity), mainFrameNavigation);
4702
4703#if HAVE(LOAD_OPTIMIZER)
4704WEBPAGEPROXY_LOADOPTIMIZER_ADDITIONS_3
4705#endif
4706
4707 m_navigationClient->decidePolicyForNavigationAction(*this, WTFMove(navigationAction), WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
4708 }
4709
4710 m_shouldSuppressAppLinksInNextNavigationPolicyDecision = false;
4711
4712#if HAVE(LOAD_OPTIMIZER)
4713WEBPAGEPROXY_LOADOPTIMIZER_ADDITIONS_4
4714#endif
4715}
4716
4717WebPageProxy* WebPageProxy::nonEphemeralWebPageProxy()
4718{
4719 auto processPools = WebProcessPool::allProcessPools();
4720 if (processPools.isEmpty())
4721 return nullptr;
4722
4723 auto processPool = processPools[0];
4724 if (!processPool)
4725 return nullptr;
4726
4727 for (auto& webProcess : processPool->processes()) {
4728 for (auto& page : webProcess->pages()) {
4729 if (page->sessionID().isEphemeral())
4730 continue;
4731 return page;
4732 }
4733 }
4734 return nullptr;
4735}
4736
4737#if ENABLE(RESOURCE_LOAD_STATISTICS)
4738void WebPageProxy::logFrameNavigation(const WebFrameProxy& frame, const URL& pageURL, const WebCore::ResourceRequest& request, const URL& redirectURL)
4739{
4740 ASSERT(RunLoop::isMain());
4741
4742 auto sourceURL = redirectURL;
4743 bool isRedirect = !redirectURL.isNull();
4744 if (!isRedirect) {
4745 sourceURL = frame.url();
4746 if (sourceURL.isNull())
4747 sourceURL = pageURL;
4748 }
4749
4750 auto& targetURL = request.url();
4751
4752 if (!targetURL.isValid() || !pageURL.isValid())
4753 return;
4754
4755 auto targetHost = targetURL.host();
4756 auto mainFrameHost = pageURL.host();
4757
4758 if (targetHost.isEmpty() || mainFrameHost.isEmpty() || targetHost == sourceURL.host())
4759 return;
4760
4761 m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::LogFrameNavigation(m_websiteDataStore->sessionID(), RegistrableDomain { targetURL }, RegistrableDomain { pageURL }, RegistrableDomain { sourceURL }, isRedirect, frame.isMainFrame()));
4762}
4763#endif
4764
4765void WebPageProxy::decidePolicyForNavigationActionSync(uint64_t frameID, bool isMainFrame, WebCore::SecurityOriginData&& frameSecurityOrigin, PolicyCheckIdentifier identifier,
4766 uint64_t navigationID, NavigationActionData&& navigationActionData, FrameInfoData&& frameInfoData, uint64_t originatingPageID,
4767 const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse,
4768 const UserData& userData, Messages::WebPageProxy::DecidePolicyForNavigationActionSync::DelayedReply&& reply)
4769{
4770 auto* frame = m_process->webFrame(frameID);
4771 if (!frame) {
4772 // This synchronous IPC message was processed before the asynchronous DidCreateMainFrame / DidCreateSubframe one so we do not know about this frameID yet.
4773 if (isMainFrame)
4774 didCreateMainFrame(frameID);
4775 else
4776 didCreateSubframe(frameID);
4777 }
4778
4779 decidePolicyForNavigationActionSyncShared(m_process.copyRef(), frameID, isMainFrame, WTFMove(frameSecurityOrigin), identifier, navigationID, WTFMove(navigationActionData),
4780 WTFMove(frameInfoData), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, WTFMove(reply));
4781}
4782
4783void WebPageProxy::decidePolicyForNavigationActionSyncShared(Ref<WebProcessProxy>&& process, uint64_t frameID, bool isMainFrame, WebCore::SecurityOriginData&& frameSecurityOrigin, PolicyCheckIdentifier identifier,
4784 uint64_t navigationID, NavigationActionData&& navigationActionData, FrameInfoData&& frameInfoData, uint64_t originatingPageID,
4785 const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse,
4786 const UserData& userData, Messages::WebPageProxy::DecidePolicyForNavigationActionSync::DelayedReply&& reply)
4787{
4788 auto sender = PolicyDecisionSender::create(identifier, WTFMove(reply));
4789
4790 auto* frame = process->webFrame(frameID);
4791 MESSAGE_CHECK(process, frame);
4792
4793 decidePolicyForNavigationAction(WTFMove(process), *frame, WTFMove(frameSecurityOrigin), navigationID, WTFMove(navigationActionData), WTFMove(frameInfoData),
4794 originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, sender.copyRef());
4795
4796 // If the client did not respond synchronously, proceed with the load.
4797 sender->send(PolicyAction::Use, navigationID, DownloadID(), WTF::nullopt);
4798}
4799
4800void WebPageProxy::decidePolicyForNewWindowAction(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, PolicyCheckIdentifier identifier,
4801 NavigationActionData&& navigationActionData, ResourceRequest&& request, const String& frameName, uint64_t listenerID, const UserData& userData)
4802{
4803 PageClientProtector protector(pageClient());
4804
4805 WebFrameProxy* frame = m_process->webFrame(frameID);
4806 MESSAGE_CHECK(m_process, frame);
4807 MESSAGE_CHECK_URL(m_process, request.url());
4808
4809 auto listener = makeRef(frame->setUpPolicyListenerProxy([this, protectedThis = makeRef(*this), identifier, listenerID, frameID] (PolicyAction policyAction, API::WebsitePolicies*, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning) mutable {
4810 // FIXME: Assert the API::WebsitePolicies* is nullptr here once clients of WKFramePolicyListenerUseWithPolicies go away.
4811 RELEASE_ASSERT(processSwapRequestedByClient == ProcessSwapRequestedByClient::No);
4812 ASSERT_UNUSED(safeBrowsingWarning, !safeBrowsingWarning);
4813
4814 auto sender = PolicyDecisionSender::create(identifier, [this, protectedThis = WTFMove(protectedThis), frameID, listenerID] (auto... args) {
4815 m_process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, args...), m_pageID);
4816 });
4817
4818 receivedPolicyDecision(policyAction, nullptr, WTF::nullopt, WTFMove(sender));
4819 }, ShouldExpectSafeBrowsingResult::No));
4820
4821 if (m_policyClient)
4822 m_policyClient->decidePolicyForNewWindowAction(*this, *frame, navigationActionData, request, frameName, WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get());
4823 else {
4824 RefPtr<API::FrameInfo> sourceFrameInfo;
4825 if (frame)
4826 sourceFrameInfo = API::FrameInfo::create(*frame, frameSecurityOrigin.securityOrigin());
4827
4828 auto userInitiatedActivity = m_process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
4829 bool shouldOpenAppLinks = m_mainFrame ? !hostsAreEqual(m_mainFrame->url(), request.url()) : false;
4830 auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), sourceFrameInfo.get(), nullptr, frameName, WTFMove(request), URL { }, shouldOpenAppLinks, WTFMove(userInitiatedActivity));
4831
4832 m_navigationClient->decidePolicyForNavigationAction(*this, navigationAction.get(), WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get());
4833
4834 }
4835
4836}
4837
4838void WebPageProxy::decidePolicyForResponse(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, PolicyCheckIdentifier identifier,
4839 uint64_t navigationID, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, const String& downloadAttribute, uint64_t listenerID, const UserData& userData)
4840{
4841 decidePolicyForResponseShared(m_process.copyRef(), frameID, frameSecurityOrigin, identifier, navigationID, response, request, canShowMIMEType, downloadAttribute, listenerID, userData);
4842}
4843
4844void WebPageProxy::decidePolicyForResponseShared(Ref<WebProcessProxy>&& process, uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, PolicyCheckIdentifier identifier,
4845 uint64_t navigationID, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, const String& downloadAttribute, uint64_t listenerID, const UserData& userData)
4846{
4847 PageClientProtector protector(pageClient());
4848
4849 m_decidePolicyForResponseRequest = request;
4850
4851 WebFrameProxy* frame = process->webFrame(frameID);
4852 MESSAGE_CHECK(process, frame);
4853 MESSAGE_CHECK_URL(process, request.url());
4854 MESSAGE_CHECK_URL(process, response.url());
4855
4856 RefPtr<API::Navigation> navigation = navigationID ? m_navigationState->navigation(navigationID) : nullptr;
4857 auto listener = makeRef(frame->setUpPolicyListenerProxy([this, protectedThis = makeRef(*this), frameID, identifier, listenerID, navigation = WTFMove(navigation),
4858 process = process.copyRef()] (PolicyAction policyAction, API::WebsitePolicies*, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning) mutable {
4859 // FIXME: Assert the API::WebsitePolicies* is nullptr here once clients of WKFramePolicyListenerUseWithPolicies go away.
4860 RELEASE_ASSERT(processSwapRequestedByClient == ProcessSwapRequestedByClient::No);
4861 ASSERT_UNUSED(safeBrowsingWarning, !safeBrowsingWarning);
4862
4863 auto sender = PolicyDecisionSender::create(identifier, [this, protectedThis = WTFMove(protectedThis), frameID, listenerID, process = WTFMove(process)] (auto... args) {
4864 process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, args...), m_pageID);
4865 });
4866
4867 receivedPolicyDecision(policyAction, navigation.get(), WTF::nullopt, WTFMove(sender));
4868 }, ShouldExpectSafeBrowsingResult::No));
4869
4870 if (m_policyClient)
4871 m_policyClient->decidePolicyForResponse(*this, *frame, response, request, canShowMIMEType, WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
4872 else {
4873 auto navigationResponse = API::NavigationResponse::create(API::FrameInfo::create(*frame, frameSecurityOrigin.securityOrigin()).get(), request, response, canShowMIMEType, downloadAttribute);
4874 m_navigationClient->decidePolicyForNavigationResponse(*this, WTFMove(navigationResponse), WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
4875 }
4876}
4877
4878void WebPageProxy::unableToImplementPolicy(uint64_t frameID, const ResourceError& error, const UserData& userData)
4879{
4880 PageClientProtector protector(pageClient());
4881
4882 WebFrameProxy* frame = m_process->webFrame(frameID);
4883 MESSAGE_CHECK(m_process, frame);
4884
4885 if (!m_policyClient)
4886 return;
4887 m_policyClient->unableToImplementPolicy(*this, *frame, error, m_process->transformHandlesToObjects(userData.object()).get());
4888}
4889
4890// FormClient
4891
4892void WebPageProxy::willSubmitForm(uint64_t frameID, uint64_t sourceFrameID, const Vector<std::pair<String, String>>& textFieldValues, uint64_t listenerID, const UserData& userData)
4893{
4894 WebFrameProxy* frame = m_process->webFrame(frameID);
4895 MESSAGE_CHECK(m_process, frame);
4896
4897 WebFrameProxy* sourceFrame = m_process->webFrame(sourceFrameID);
4898 MESSAGE_CHECK(m_process, sourceFrame);
4899
4900 m_formClient->willSubmitForm(*this, *frame, *sourceFrame, textFieldValues, m_process->transformHandlesToObjects(userData.object()).get(), [this, protectedThis = makeRef(*this), frameID, listenerID]() {
4901 m_process->send(Messages::WebPage::ContinueWillSubmitForm(frameID, listenerID), m_pageID);
4902 });
4903}
4904
4905void WebPageProxy::contentRuleListNotification(URL&& url, ContentRuleListResults&& results)
4906{
4907 m_navigationClient->contentRuleListNotification(*this, WTFMove(url), WTFMove(results));
4908}
4909
4910void WebPageProxy::didNavigateWithNavigationData(const WebNavigationDataStore& store, uint64_t frameID)
4911{
4912 didNavigateWithNavigationDataShared(m_process.copyRef(), store, frameID);
4913}
4914
4915void WebPageProxy::didNavigateWithNavigationDataShared(Ref<WebProcessProxy>&& process, const WebNavigationDataStore& store, uint64_t frameID)
4916{
4917 RELEASE_LOG_IF_ALLOWED(Loading, "didNavigateWithNavigationDataShared: webPID = %i, pageID = %" PRIu64, process->processIdentifier(), m_pageID);
4918
4919 PageClientProtector protector(pageClient());
4920
4921 WebFrameProxy* frame = process->webFrame(frameID);
4922 MESSAGE_CHECK(process, frame);
4923 MESSAGE_CHECK(process, frame->page() == this);
4924
4925 if (frame->isMainFrame())
4926 m_historyClient->didNavigateWithNavigationData(*this, store);
4927 process->processPool().historyClient().didNavigateWithNavigationData(process->processPool(), *this, store, *frame);
4928}
4929
4930void WebPageProxy::didPerformClientRedirect(const String& sourceURLString, const String& destinationURLString, uint64_t frameID)
4931{
4932 didPerformClientRedirectShared(m_process.copyRef(), sourceURLString, destinationURLString, frameID);
4933}
4934
4935void WebPageProxy::didPerformClientRedirectShared(Ref<WebProcessProxy>&& process, const String& sourceURLString, const String& destinationURLString, uint64_t frameID)
4936{
4937 RELEASE_LOG_IF_ALLOWED(Loading, "didPerformClientRedirectShared: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64, process->processIdentifier(), m_pageID, frameID);
4938
4939 PageClientProtector protector(pageClient());
4940
4941 if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
4942 return;
4943
4944 WebFrameProxy* frame = process->webFrame(frameID);
4945 MESSAGE_CHECK(process, frame);
4946 MESSAGE_CHECK(process, frame->page() == this);
4947 MESSAGE_CHECK_URL(process, sourceURLString);
4948 MESSAGE_CHECK_URL(process, destinationURLString);
4949
4950 if (frame->isMainFrame()) {
4951 m_historyClient->didPerformClientRedirect(*this, sourceURLString, destinationURLString);
4952 m_navigationClient->didPerformClientRedirect(*this, sourceURLString, destinationURLString);
4953 }
4954 process->processPool().historyClient().didPerformClientRedirect(process->processPool(), *this, sourceURLString, destinationURLString, *frame);
4955}
4956
4957void WebPageProxy::didPerformServerRedirect(const String& sourceURLString, const String& destinationURLString, uint64_t frameID)
4958{
4959 didPerformServerRedirectShared(m_process.copyRef(), sourceURLString, destinationURLString, frameID);
4960}
4961
4962void WebPageProxy::didPerformServerRedirectShared(Ref<WebProcessProxy>&& process, const String& sourceURLString, const String& destinationURLString, uint64_t frameID)
4963{
4964 RELEASE_LOG_IF_ALLOWED(Loading, "didPerformServerRedirect: webPID = %i, pageID = %" PRIu64, process->processIdentifier(), m_pageID);
4965
4966 PageClientProtector protector(pageClient());
4967
4968 if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
4969 return;
4970
4971 WebFrameProxy* frame = process->webFrame(frameID);
4972 MESSAGE_CHECK(process, frame);
4973 MESSAGE_CHECK(process, frame->page() == this);
4974
4975 MESSAGE_CHECK_URL(process, sourceURLString);
4976 MESSAGE_CHECK_URL(process, destinationURLString);
4977
4978 if (frame->isMainFrame())
4979 m_historyClient->didPerformServerRedirect(*this, sourceURLString, destinationURLString);
4980 process->processPool().historyClient().didPerformServerRedirect(process->processPool(), *this, sourceURLString, destinationURLString, *frame);
4981}
4982
4983void WebPageProxy::didUpdateHistoryTitle(const String& title, const String& url, uint64_t frameID)
4984{
4985 PageClientProtector protector(pageClient());
4986
4987 WebFrameProxy* frame = m_process->webFrame(frameID);
4988 MESSAGE_CHECK(m_process, frame);
4989 MESSAGE_CHECK(m_process, frame->page() == this);
4990
4991 MESSAGE_CHECK_URL(m_process, url);
4992
4993 if (frame->isMainFrame())
4994 m_historyClient->didUpdateHistoryTitle(*this, title, url);
4995 process().processPool().historyClient().didUpdateHistoryTitle(process().processPool(), *this, title, url, *frame);
4996}
4997
4998// UIClient
4999
5000using NewPageCallback = CompletionHandler<void(RefPtr<WebPageProxy>&&)>;
5001using UIClientCallback = Function<void(Ref<API::NavigationAction>&&, NewPageCallback&&)>;
5002static void tryOptimizingLoad(Ref<API::NavigationAction>&& navigationAction, WebPageProxy& page, NewPageCallback&& newPageCallback, UIClientCallback&& uiClientCallback)
5003{
5004#if HAVE(LOAD_OPTIMIZER)
5005WEBPAGEPROXY_LOADOPTIMIZER_ADDITIONS_6
5006#else
5007 ASSERT_UNUSED(page, page.pageID());
5008 uiClientCallback(WTFMove(navigationAction), WTFMove(newPageCallback));
5009#endif
5010}
5011
5012void WebPageProxy::createNewPage(const FrameInfoData& originatingFrameInfoData, uint64_t originatingPageID, ResourceRequest&& request, WindowFeatures&& windowFeatures, NavigationActionData&& navigationActionData, Messages::WebPageProxy::CreateNewPage::DelayedReply&& reply)
5013{
5014 MESSAGE_CHECK(m_process, m_process->webFrame(originatingFrameInfoData.frameID));
5015 auto originatingFrameInfo = API::FrameInfo::create(originatingFrameInfoData, m_process->webPage(originatingPageID));
5016 auto mainFrameURL = m_mainFrame ? m_mainFrame->url() : URL();
5017 auto completionHandler = [this, protectedThis = makeRef(*this), mainFrameURL, request, reply = WTFMove(reply)] (RefPtr<WebPageProxy> newPage) mutable {
5018 if (!newPage) {
5019 reply(0, WTF::nullopt);
5020 return;
5021 }
5022
5023 newPage->setOpenedByDOM();
5024
5025 reply(newPage->pageID(), newPage->creationParameters(m_process, *newPage->drawingArea()));
5026
5027 WebsiteDataStore::cloneSessionData(*this, *newPage);
5028 newPage->m_shouldSuppressAppLinksInNextNavigationPolicyDecision = hostsAreEqual(URL({ }, mainFrameURL), request.url());
5029
5030#if HAVE(LOAD_OPTIMIZER)
5031WEBPAGEPROXY_LOADOPTIMIZER_ADDITIONS_5
5032#endif
5033 };
5034
5035 auto userInitiatedActivity = m_process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
5036 bool shouldOpenAppLinks = !hostsAreEqual(originatingFrameInfo->request().url(), request.url());
5037 auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), originatingFrameInfo.ptr(), nullptr, WTF::nullopt, WTFMove(request), URL(), shouldOpenAppLinks, WTFMove(userInitiatedActivity));
5038
5039 tryOptimizingLoad(WTFMove(navigationAction), *this, WTFMove(completionHandler), [this, protectedThis = makeRef(*this), windowFeatures = WTFMove(windowFeatures)] (Ref<API::NavigationAction>&& navigationAction, CompletionHandler<void(RefPtr<WebPageProxy>&&)>&& completionHandler) mutable {
5040 m_uiClient->createNewPage(*this, WTFMove(windowFeatures), WTFMove(navigationAction), WTFMove(completionHandler));
5041 });
5042}
5043
5044void WebPageProxy::showPage()
5045{
5046 m_uiClient->showPage(this);
5047}
5048
5049void WebPageProxy::exitFullscreenImmediately()
5050{
5051#if ENABLE(FULLSCREEN_API)
5052 if (fullScreenManager())
5053 fullScreenManager()->close();
5054#endif
5055
5056#if (PLATFORM(IOS_FAMILY) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
5057 if (videoFullscreenManager())
5058 videoFullscreenManager()->requestHideAndExitFullscreen();
5059#endif
5060}
5061
5062void WebPageProxy::fullscreenMayReturnToInline()
5063{
5064 m_uiClient->fullscreenMayReturnToInline(this);
5065}
5066
5067void WebPageProxy::didEnterFullscreen()
5068{
5069 m_uiClient->didEnterFullscreen(this);
5070}
5071
5072void WebPageProxy::didExitFullscreen()
5073{
5074 m_uiClient->didExitFullscreen(this);
5075}
5076
5077void WebPageProxy::closePage(bool stopResponsivenessTimer)
5078{
5079 if (stopResponsivenessTimer)
5080 m_process->responsivenessTimer().stop();
5081
5082 pageClient().clearAllEditCommands();
5083 m_uiClient->close(this);
5084}
5085
5086void WebPageProxy::runJavaScriptAlert(uint64_t frameID, const SecurityOriginData& securityOrigin, const String& message, Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply&& reply)
5087{
5088 WebFrameProxy* frame = m_process->webFrame(frameID);
5089 MESSAGE_CHECK(m_process, frame);
5090
5091#if PLATFORM(IOS_FAMILY)
5092 exitFullscreenImmediately();
5093#endif
5094
5095 // Since runJavaScriptAlert() can spin a nested run loop we need to turn off the responsiveness timer.
5096 m_process->responsivenessTimer().stop();
5097
5098 if (m_controlledByAutomation) {
5099 if (auto* automationSession = process().processPool().automationSession())
5100 automationSession->willShowJavaScriptDialog(*this);
5101 }
5102 m_uiClient->runJavaScriptAlert(this, message, frame, securityOrigin, WTFMove(reply));
5103}
5104
5105void WebPageProxy::runJavaScriptConfirm(uint64_t frameID, const SecurityOriginData& securityOrigin, const String& message, Messages::WebPageProxy::RunJavaScriptConfirm::DelayedReply&& reply)
5106{
5107 WebFrameProxy* frame = m_process->webFrame(frameID);
5108 MESSAGE_CHECK(m_process, frame);
5109
5110#if PLATFORM(IOS_FAMILY)
5111 exitFullscreenImmediately();
5112#endif
5113
5114 // Since runJavaScriptConfirm() can spin a nested run loop we need to turn off the responsiveness timer.
5115 m_process->responsivenessTimer().stop();
5116
5117 if (m_controlledByAutomation) {
5118 if (auto* automationSession = process().processPool().automationSession())
5119 automationSession->willShowJavaScriptDialog(*this);
5120 }
5121
5122 m_uiClient->runJavaScriptConfirm(this, message, frame, securityOrigin, WTFMove(reply));
5123}
5124
5125void WebPageProxy::runJavaScriptPrompt(uint64_t frameID, const SecurityOriginData& securityOrigin, const String& message, const String& defaultValue, Messages::WebPageProxy::RunJavaScriptPrompt::DelayedReply&& reply)
5126{
5127 WebFrameProxy* frame = m_process->webFrame(frameID);
5128 MESSAGE_CHECK(m_process, frame);
5129
5130#if PLATFORM(IOS_FAMILY)
5131 exitFullscreenImmediately();
5132#endif
5133 // Since runJavaScriptPrompt() can spin a nested run loop we need to turn off the responsiveness timer.
5134 m_process->responsivenessTimer().stop();
5135
5136 if (m_controlledByAutomation) {
5137 if (auto* automationSession = process().processPool().automationSession())
5138 automationSession->willShowJavaScriptDialog(*this);
5139 }
5140
5141 m_uiClient->runJavaScriptPrompt(this, message, defaultValue, frame, securityOrigin, WTFMove(reply));
5142}
5143
5144void WebPageProxy::setStatusText(const String& text)
5145{
5146 m_uiClient->setStatusText(this, text);
5147}
5148
5149void WebPageProxy::mouseDidMoveOverElement(WebHitTestResultData&& hitTestResultData, uint32_t opaqueModifiers, UserData&& userData)
5150{
5151 m_lastMouseMoveHitTestResult = API::HitTestResult::create(hitTestResultData);
5152 auto modifiers = OptionSet<WebEvent::Modifier>::fromRaw(opaqueModifiers);
5153 m_uiClient->mouseDidMoveOverElement(*this, hitTestResultData, modifiers, m_process->transformHandlesToObjects(userData.object()).get());
5154}
5155
5156void WebPageProxy::connectionWillOpen(IPC::Connection& connection)
5157{
5158 ASSERT_UNUSED(connection, &connection == m_process->connection());
5159
5160 m_webProcessLifetimeTracker.webPageEnteringWebProcess(m_process);
5161}
5162
5163void WebPageProxy::webProcessWillShutDown()
5164{
5165 m_webProcessLifetimeTracker.webPageLeavingWebProcess(m_process);
5166}
5167
5168#if ENABLE(NETSCAPE_PLUGIN_API)
5169void WebPageProxy::unavailablePluginButtonClicked(uint32_t opaquePluginUnavailabilityReason, const String& mimeType, const String& pluginURLString, const String& pluginspageAttributeURLString, const String& frameURLString, const String& pageURLString)
5170{
5171 MESSAGE_CHECK_URL(m_process, pluginURLString);
5172 MESSAGE_CHECK_URL(m_process, pluginspageAttributeURLString);
5173 MESSAGE_CHECK_URL(m_process, frameURLString);
5174 MESSAGE_CHECK_URL(m_process, pageURLString);
5175
5176 String newMimeType = mimeType;
5177 PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL(URL(), pluginURLString));
5178 auto pluginInformation = createPluginInformationDictionary(plugin, frameURLString, mimeType, pageURLString, pluginspageAttributeURLString, pluginURLString);
5179
5180 WKPluginUnavailabilityReason pluginUnavailabilityReason = kWKPluginUnavailabilityReasonPluginMissing;
5181 switch (static_cast<RenderEmbeddedObject::PluginUnavailabilityReason>(opaquePluginUnavailabilityReason)) {
5182 case RenderEmbeddedObject::PluginMissing:
5183 pluginUnavailabilityReason = kWKPluginUnavailabilityReasonPluginMissing;
5184 break;
5185 case RenderEmbeddedObject::InsecurePluginVersion:
5186 pluginUnavailabilityReason = kWKPluginUnavailabilityReasonInsecurePluginVersion;
5187 break;
5188 case RenderEmbeddedObject::PluginCrashed:
5189 pluginUnavailabilityReason = kWKPluginUnavailabilityReasonPluginCrashed;
5190 break;
5191 case RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy:
5192 case RenderEmbeddedObject::UnsupportedPlugin:
5193 case RenderEmbeddedObject::PluginTooSmall:
5194 ASSERT_NOT_REACHED();
5195 }
5196
5197 m_uiClient->unavailablePluginButtonClicked(*this, pluginUnavailabilityReason, pluginInformation.get());
5198}
5199#endif // ENABLE(NETSCAPE_PLUGIN_API)
5200
5201#if ENABLE(WEBGL)
5202void WebPageProxy::webGLPolicyForURL(URL&& url, Messages::WebPageProxy::WebGLPolicyForURL::DelayedReply&& reply)
5203{
5204 m_navigationClient->webGLLoadPolicy(*this, url, [reply = WTFMove(reply)] (WebGLLoadPolicy policy) mutable {
5205 reply(static_cast<uint32_t>(policy));
5206 });
5207}
5208
5209void WebPageProxy::resolveWebGLPolicyForURL(URL&& url, Messages::WebPageProxy::ResolveWebGLPolicyForURL::DelayedReply&& reply)
5210{
5211 m_navigationClient->resolveWebGLLoadPolicy(*this, url, [reply = WTFMove(reply)] (WebGLLoadPolicy policy) mutable {
5212 reply(static_cast<uint32_t>(policy));
5213 });
5214}
5215#endif // ENABLE(WEBGL)
5216
5217void WebPageProxy::setToolbarsAreVisible(bool toolbarsAreVisible)
5218{
5219 m_uiClient->setToolbarsAreVisible(*this, toolbarsAreVisible);
5220}
5221
5222void WebPageProxy::getToolbarsAreVisible(Messages::WebPageProxy::GetToolbarsAreVisible::DelayedReply&& reply)
5223{
5224 m_uiClient->toolbarsAreVisible(*this, WTFMove(reply));
5225}
5226
5227void WebPageProxy::setMenuBarIsVisible(bool menuBarIsVisible)
5228{
5229 m_uiClient->setMenuBarIsVisible(*this, menuBarIsVisible);
5230}
5231
5232void WebPageProxy::getMenuBarIsVisible(Messages::WebPageProxy::GetMenuBarIsVisible::DelayedReply&& reply)
5233{
5234 m_uiClient->menuBarIsVisible(*this, WTFMove(reply));
5235}
5236
5237void WebPageProxy::setStatusBarIsVisible(bool statusBarIsVisible)
5238{
5239 m_uiClient->setStatusBarIsVisible(*this, statusBarIsVisible);
5240}
5241
5242void WebPageProxy::getStatusBarIsVisible(Messages::WebPageProxy::GetStatusBarIsVisible::DelayedReply&& reply)
5243{
5244 m_uiClient->statusBarIsVisible(*this, WTFMove(reply));
5245}
5246
5247void WebPageProxy::setIsResizable(bool isResizable)
5248{
5249 m_uiClient->setIsResizable(*this, isResizable);
5250}
5251
5252void WebPageProxy::setWindowFrame(const FloatRect& newWindowFrame)
5253{
5254 m_uiClient->setWindowFrame(*this, pageClient().convertToDeviceSpace(newWindowFrame));
5255}
5256
5257void WebPageProxy::getWindowFrame(Messages::WebPageProxy::GetWindowFrame::DelayedReply&& reply)
5258{
5259 m_uiClient->windowFrame(*this, [this, protectedThis = makeRef(*this), reply = WTFMove(reply)] (FloatRect frame) mutable {
5260 reply(pageClient().convertToUserSpace(frame));
5261 });
5262}
5263
5264void WebPageProxy::getWindowFrameWithCallback(Function<void(FloatRect)>&& completionHandler)
5265{
5266 m_uiClient->windowFrame(*this, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (FloatRect frame) {
5267 completionHandler(pageClient().convertToUserSpace(frame));
5268 });
5269}
5270
5271void WebPageProxy::screenToRootView(const IntPoint& screenPoint, Messages::WebPageProxy::ScreenToRootView::DelayedReply&& reply)
5272{
5273 reply(pageClient().screenToRootView(screenPoint));
5274}
5275
5276void WebPageProxy::rootViewToScreen(const IntRect& viewRect, Messages::WebPageProxy::RootViewToScreen::DelayedReply&& reply)
5277{
5278 reply(pageClient().rootViewToScreen(viewRect));
5279}
5280
5281IntRect WebPageProxy::syncRootViewToScreen(const IntRect& viewRect)
5282{
5283 return pageClient().rootViewToScreen(viewRect);
5284}
5285
5286void WebPageProxy::accessibilityScreenToRootView(const IntPoint& screenPoint, CompletionHandler<void(IntPoint)>&& completionHandler)
5287{
5288 completionHandler(pageClient().accessibilityScreenToRootView(screenPoint));
5289}
5290
5291void WebPageProxy::rootViewToAccessibilityScreen(const IntRect& viewRect, CompletionHandler<void(IntRect)>&& completionHandler)
5292{
5293 completionHandler(pageClient().rootViewToAccessibilityScreen(viewRect));
5294}
5295
5296void WebPageProxy::runBeforeUnloadConfirmPanel(uint64_t frameID, const SecurityOriginData& securityOrigin, const String& message, Messages::WebPageProxy::RunBeforeUnloadConfirmPanel::DelayedReply&& reply)
5297{
5298 WebFrameProxy* frame = m_process->webFrame(frameID);
5299 MESSAGE_CHECK(m_process, frame);
5300
5301 // Per §18 User Prompts in the WebDriver spec, "User prompts that are spawned from beforeunload
5302 // event handlers, are dismissed implicitly upon navigation or close window, regardless of the
5303 // defined user prompt handler." So, always allow the unload to proceed if the page is being automated.
5304 if (m_controlledByAutomation) {
5305 if (!!process().processPool().automationSession()) {
5306 reply(true);
5307 return;
5308 }
5309 }
5310
5311 // Since runBeforeUnloadConfirmPanel() can spin a nested run loop we need to turn off the responsiveness timer.
5312 m_process->responsivenessTimer().stop();
5313 m_uiClient->runBeforeUnloadConfirmPanel(this, message, frame, securityOrigin, WTFMove(reply));
5314}
5315
5316void WebPageProxy::didChangeViewportProperties(const ViewportAttributes& attr)
5317{
5318 pageClient().didChangeViewportProperties(attr);
5319}
5320
5321void WebPageProxy::pageDidScroll()
5322{
5323 m_uiClient->pageDidScroll(this);
5324
5325#if PLATFORM(IOS_FAMILY)
5326 // Do not hide the validation message if the scrolling was caused by the keyboard showing up.
5327 if (m_isKeyboardAnimatingIn)
5328 return;
5329#endif
5330
5331#if !PLATFORM(IOS_FAMILY)
5332 closeOverlayedViews();
5333#endif
5334}
5335
5336void WebPageProxy::runOpenPanel(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, const FileChooserSettings& settings)
5337{
5338 if (m_openPanelResultListener) {
5339 m_openPanelResultListener->invalidate();
5340 m_openPanelResultListener = nullptr;
5341 }
5342
5343 WebFrameProxy* frame = m_process->webFrame(frameID);
5344 MESSAGE_CHECK(m_process, frame);
5345
5346 Ref<API::OpenPanelParameters> parameters = API::OpenPanelParameters::create(settings);
5347 m_openPanelResultListener = WebOpenPanelResultListenerProxy::create(this);
5348
5349 if (m_controlledByAutomation) {
5350 if (auto* automationSession = process().processPool().automationSession())
5351 automationSession->handleRunOpenPanel(*this, *frame, parameters.get(), *m_openPanelResultListener);
5352
5353 // Don't show a file chooser, since automation will be unable to interact with it.
5354 return;
5355 }
5356
5357 // Since runOpenPanel() can spin a nested run loop we need to turn off the responsiveness timer.
5358 m_process->responsivenessTimer().stop();
5359
5360 if (!m_uiClient->runOpenPanel(this, frame, frameSecurityOrigin, parameters.ptr(), m_openPanelResultListener.get())) {
5361 if (!pageClient().handleRunOpenPanel(this, frame, parameters.ptr(), m_openPanelResultListener.get()))
5362 didCancelForOpenPanel();
5363 }
5364}
5365
5366void WebPageProxy::showShareSheet(const ShareDataWithParsedURL& shareData, ShareSheetCallbackID callbackID)
5367{
5368 CompletionHandler<void(bool)> completionHandler = [this, protectedThis = makeRef(*this), callbackID] (bool access) {
5369 m_process->send(Messages::WebPage::DidCompleteShareSheet(access, callbackID), m_pageID);
5370 };
5371
5372 pageClient().showShareSheet(shareData, WTFMove(completionHandler));
5373}
5374
5375void WebPageProxy::printFrame(uint64_t frameID, CompletionHandler<void()>&& completionHandler)
5376{
5377 ASSERT(!m_isPerformingDOMPrintOperation);
5378 m_isPerformingDOMPrintOperation = true;
5379
5380 WebFrameProxy* frame = m_process->webFrame(frameID);
5381 MESSAGE_CHECK(m_process, frame);
5382
5383 m_uiClient->printFrame(*this, *frame);
5384
5385 endPrinting(); // Send a message synchronously while m_isPerformingDOMPrintOperation is still true.
5386 m_isPerformingDOMPrintOperation = false;
5387
5388 completionHandler();
5389}
5390
5391void WebPageProxy::setMediaVolume(float volume)
5392{
5393 if (volume == m_mediaVolume)
5394 return;
5395
5396 m_mediaVolume = volume;
5397
5398 if (!hasRunningProcess())
5399 return;
5400
5401 m_process->send(Messages::WebPage::SetMediaVolume(volume), m_pageID);
5402}
5403
5404void WebPageProxy::setMuted(WebCore::MediaProducer::MutedStateFlags state)
5405{
5406 m_mutedState = state;
5407
5408 if (!hasRunningProcess())
5409 return;
5410
5411#if ENABLE(MEDIA_STREAM)
5412 bool hasMutedCaptureStreams = m_mediaState & WebCore::MediaProducer::MutedCaptureMask;
5413 if (hasMutedCaptureStreams && !(state & WebCore::MediaProducer::MediaStreamCaptureIsMuted))
5414 UserMediaProcessManager::singleton().muteCaptureMediaStreamsExceptIn(*this);
5415#endif
5416
5417 m_process->send(Messages::WebPage::SetMuted(state), m_pageID);
5418 activityStateDidChange({ ActivityState::IsAudible, ActivityState::IsCapturingMedia });
5419}
5420
5421void WebPageProxy::setMediaCaptureEnabled(bool enabled)
5422{
5423 m_mediaCaptureEnabled = enabled;
5424
5425 if (!hasRunningProcess())
5426 return;
5427
5428#if ENABLE(MEDIA_STREAM)
5429 UserMediaProcessManager::singleton().setCaptureEnabled(enabled);
5430#endif
5431}
5432
5433void WebPageProxy::stopMediaCapture()
5434{
5435 if (!hasRunningProcess())
5436 return;
5437
5438#if ENABLE(MEDIA_STREAM)
5439 m_process->send(Messages::WebPage::StopMediaCapture(), m_pageID);
5440#endif
5441}
5442
5443void WebPageProxy::stopAllMediaPlayback()
5444{
5445 if (!hasRunningProcess())
5446 return;
5447
5448 m_process->send(Messages::WebPage::StopAllMediaPlayback(), m_pageID);
5449}
5450
5451void WebPageProxy::suspendAllMediaPlayback()
5452{
5453 if (!hasRunningProcess())
5454 return;
5455
5456 m_process->send(Messages::WebPage::SuspendAllMediaPlayback(), m_pageID);
5457}
5458
5459void WebPageProxy::resumeAllMediaPlayback()
5460{
5461 if (!hasRunningProcess())
5462 return;
5463
5464 m_process->send(Messages::WebPage::ResumeAllMediaPlayback(), m_pageID);
5465}
5466
5467#if ENABLE(MEDIA_SESSION)
5468void WebPageProxy::handleMediaEvent(MediaEventType eventType)
5469{
5470 if (!hasRunningProcess())
5471 return;
5472
5473 m_process->send(Messages::WebPage::HandleMediaEvent(eventType), m_pageID);
5474}
5475
5476void WebPageProxy::setVolumeOfMediaElement(double volume, uint64_t elementID)
5477{
5478 if (!hasRunningProcess())
5479 return;
5480
5481 m_process->send(Messages::WebPage::SetVolumeOfMediaElement(volume, elementID), m_pageID);
5482}
5483#endif
5484
5485void WebPageProxy::setMayStartMediaWhenInWindow(bool mayStartMedia)
5486{
5487 if (mayStartMedia == m_mayStartMediaWhenInWindow)
5488 return;
5489
5490 m_mayStartMediaWhenInWindow = mayStartMedia;
5491
5492 if (!hasRunningProcess())
5493 return;
5494
5495 process().send(Messages::WebPage::SetMayStartMediaWhenInWindow(mayStartMedia), m_pageID);
5496}
5497
5498void WebPageProxy::handleDownloadRequest(DownloadProxy& download)
5499{
5500 pageClient().handleDownloadRequest(download);
5501}
5502
5503void WebPageProxy::didChangeContentSize(const IntSize& size)
5504{
5505 pageClient().didChangeContentSize(size);
5506}
5507
5508void WebPageProxy::didChangeIntrinsicContentSize(const IntSize& intrinsicContentSize)
5509{
5510#if USE(APPKIT)
5511 pageClient().intrinsicContentSizeDidChange(intrinsicContentSize);
5512#endif
5513}
5514
5515#if ENABLE(INPUT_TYPE_COLOR)
5516void WebPageProxy::showColorPicker(const WebCore::Color& initialColor, const IntRect& elementRect, Vector<WebCore::Color>&& suggestions)
5517{
5518 m_colorPicker = pageClient().createColorPicker(this, initialColor, elementRect, WTFMove(suggestions));
5519 m_colorPicker->showColorPicker(initialColor);
5520}
5521
5522void WebPageProxy::setColorPickerColor(const WebCore::Color& color)
5523{
5524 ASSERT(m_colorPicker);
5525
5526 m_colorPicker->setSelectedColor(color);
5527}
5528
5529void WebPageProxy::endColorPicker()
5530{
5531 if (!m_colorPicker)
5532 return;
5533
5534 m_colorPicker->endPicker();
5535}
5536
5537void WebPageProxy::didChooseColor(const WebCore::Color& color)
5538{
5539 if (!hasRunningProcess())
5540 return;
5541
5542 m_process->send(Messages::WebPage::DidChooseColor(color), m_pageID);
5543}
5544
5545void WebPageProxy::didEndColorPicker()
5546{
5547 m_colorPicker = nullptr;
5548 if (!hasRunningProcess())
5549 return;
5550
5551 m_process->send(Messages::WebPage::DidEndColorPicker(), m_pageID);
5552}
5553#endif
5554
5555#if ENABLE(DATALIST_ELEMENT)
5556
5557void WebPageProxy::showDataListSuggestions(WebCore::DataListSuggestionInformation&& info)
5558{
5559 if (!m_dataListSuggestionsDropdown)
5560 m_dataListSuggestionsDropdown = pageClient().createDataListSuggestionsDropdown(*this);
5561
5562 m_dataListSuggestionsDropdown->show(WTFMove(info));
5563}
5564
5565void WebPageProxy::handleKeydownInDataList(const String& key)
5566{
5567 if (!m_dataListSuggestionsDropdown)
5568 return;
5569
5570 m_dataListSuggestionsDropdown->handleKeydownWithIdentifier(key);
5571}
5572
5573void WebPageProxy::endDataListSuggestions()
5574{
5575 if (m_dataListSuggestionsDropdown)
5576 m_dataListSuggestionsDropdown->close();
5577}
5578
5579void WebPageProxy::didCloseSuggestions()
5580{
5581 if (!m_dataListSuggestionsDropdown)
5582 return;
5583
5584 m_dataListSuggestionsDropdown = nullptr;
5585 m_process->send(Messages::WebPage::DidCloseSuggestions(), m_pageID);
5586}
5587
5588void WebPageProxy::didSelectOption(const String& selectedOption)
5589{
5590 if (!hasRunningProcess())
5591 return;
5592
5593 m_process->send(Messages::WebPage::DidSelectDataListOption(selectedOption), m_pageID);
5594}
5595
5596#endif
5597
5598WebInspectorProxy* WebPageProxy::inspector() const
5599{
5600 if (isClosed())
5601 return nullptr;
5602 return m_inspector.get();
5603}
5604
5605#if ENABLE(FULLSCREEN_API)
5606WebFullScreenManagerProxy* WebPageProxy::fullScreenManager()
5607{
5608 return m_fullScreenManager.get();
5609}
5610
5611void WebPageProxy::setFullscreenClient(std::unique_ptr<API::FullscreenClient>&& client)
5612{
5613 if (!client) {
5614 m_fullscreenClient = std::make_unique<API::FullscreenClient>();
5615 return;
5616 }
5617
5618 m_fullscreenClient = WTFMove(client);
5619}
5620#endif
5621
5622#if (PLATFORM(IOS_FAMILY) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
5623PlaybackSessionManagerProxy* WebPageProxy::playbackSessionManager()
5624{
5625 return m_playbackSessionManager.get();
5626}
5627
5628VideoFullscreenManagerProxy* WebPageProxy::videoFullscreenManager()
5629{
5630 return m_videoFullscreenManager.get();
5631}
5632#endif
5633
5634#if PLATFORM(IOS_FAMILY)
5635bool WebPageProxy::allowsMediaDocumentInlinePlayback() const
5636{
5637 return m_allowsMediaDocumentInlinePlayback;
5638}
5639
5640void WebPageProxy::setAllowsMediaDocumentInlinePlayback(bool allows)
5641{
5642 if (m_allowsMediaDocumentInlinePlayback == allows)
5643 return;
5644 m_allowsMediaDocumentInlinePlayback = allows;
5645
5646 m_process->send(Messages::WebPage::SetAllowsMediaDocumentInlinePlayback(allows), m_pageID);
5647}
5648#endif
5649
5650void WebPageProxy::setHasHadSelectionChangesFromUserInteraction(bool hasHadUserSelectionChanges)
5651{
5652 m_hasHadSelectionChangesFromUserInteraction = hasHadUserSelectionChanges;
5653}
5654
5655void WebPageProxy::setIsTouchBarUpdateSupressedForHiddenContentEditable(bool ignoreTouchBarUpdate)
5656{
5657 m_isTouchBarUpdateSupressedForHiddenContentEditable = ignoreTouchBarUpdate;
5658}
5659
5660void WebPageProxy::setIsNeverRichlyEditableForTouchBar(bool isNeverRichlyEditable)
5661{
5662 m_isNeverRichlyEditableForTouchBar = isNeverRichlyEditable;
5663}
5664
5665void WebPageProxy::requestDOMPasteAccess(const WebCore::IntRect& elementRect, const String& originIdentifier, CompletionHandler<void(WebCore::DOMPasteAccessResponse)>&& completionHandler)
5666{
5667 m_pageClient->requestDOMPasteAccess(elementRect, originIdentifier, WTFMove(completionHandler));
5668}
5669
5670// BackForwardList
5671
5672void WebPageProxy::backForwardAddItem(BackForwardListItemState&& itemState)
5673{
5674 auto item = WebBackForwardListItem::create(WTFMove(itemState), pageID());
5675 m_backForwardList->addItem(WTFMove(item));
5676}
5677
5678void WebPageProxy::backForwardGoToItem(const BackForwardItemIdentifier& itemID, CompletionHandler<void(SandboxExtension::Handle&&)>&& completionHandler)
5679{
5680 // On process swap, we tell the previous process to ignore the load, which causes it so restore its current back forward item to its previous
5681 // value. Since the load is really going on in a new provisional process, we want to ignore such requests from the committed process.
5682 // Any real new load in the committed process would have cleared m_provisionalPage.
5683 if (m_provisionalPage)
5684 return completionHandler({ });
5685
5686 SandboxExtension::Handle sandboxExtensionHandle;
5687 backForwardGoToItemShared(m_process.copyRef(), itemID, WTFMove(completionHandler));
5688}
5689
5690void WebPageProxy::backForwardGoToItemShared(Ref<WebProcessProxy>&& process, const BackForwardItemIdentifier& itemID, CompletionHandler<void(SandboxExtension::Handle&&)>&& completionHandler)
5691{
5692 auto* item = m_backForwardList->itemForID(itemID);
5693 if (!item)
5694 return completionHandler({ });
5695
5696 SandboxExtension::Handle sandboxExtensionHandle;
5697 bool createdExtension = maybeInitializeSandboxExtensionHandle(process, URL(URL(), item->url()), sandboxExtensionHandle);
5698 if (createdExtension)
5699 willAcquireUniversalFileReadSandboxExtension(process);
5700 m_backForwardList->goToItem(*item);
5701 completionHandler(WTFMove(sandboxExtensionHandle));
5702}
5703
5704void WebPageProxy::backForwardItemAtIndex(int32_t index, CompletionHandler<void(Optional<BackForwardItemIdentifier>&&)>&& completionHandler)
5705{
5706 if (auto* item = m_backForwardList->itemAtIndex(index))
5707 completionHandler(item->itemID());
5708 else
5709 completionHandler(WTF::nullopt);
5710}
5711
5712void WebPageProxy::backForwardBackListCount(CompletionHandler<void(uint32_t)>&& completionHandler)
5713{
5714 completionHandler(m_backForwardList->backListCount());
5715}
5716
5717void WebPageProxy::backForwardForwardListCount(CompletionHandler<void(uint32_t)>&& completionHandler)
5718{
5719 completionHandler(m_backForwardList->forwardListCount());
5720}
5721
5722void WebPageProxy::compositionWasCanceled()
5723{
5724#if PLATFORM(COCOA)
5725 pageClient().notifyInputContextAboutDiscardedComposition();
5726#endif
5727}
5728
5729// Undo management
5730
5731void WebPageProxy::registerEditCommandForUndo(WebUndoStepID commandID, const String& label)
5732{
5733 registerEditCommand(WebEditCommandProxy::create(commandID, label, *this), UndoOrRedo::Undo);
5734}
5735
5736void WebPageProxy::registerInsertionUndoGrouping()
5737{
5738#if USE(INSERTION_UNDO_GROUPING)
5739 pageClient().registerInsertionUndoGrouping();
5740#endif
5741}
5742
5743void WebPageProxy::canUndoRedo(UndoOrRedo action, CompletionHandler<void(bool)>&& completionHandler)
5744{
5745 completionHandler(pageClient().canUndoRedo(action));
5746}
5747
5748void WebPageProxy::executeUndoRedo(UndoOrRedo action, CompletionHandler<void()>&& completionHandler)
5749{
5750 pageClient().executeUndoRedo(action);
5751 completionHandler();
5752}
5753
5754void WebPageProxy::clearAllEditCommands()
5755{
5756 pageClient().clearAllEditCommands();
5757}
5758
5759void WebPageProxy::didCountStringMatches(const String& string, uint32_t matchCount)
5760{
5761 m_findClient->didCountStringMatches(this, string, matchCount);
5762}
5763
5764void WebPageProxy::didGetImageForFindMatch(const ShareableBitmap::Handle& contentImageHandle, uint32_t matchIndex)
5765{
5766 auto bitmap = ShareableBitmap::create(contentImageHandle);
5767 if (!bitmap) {
5768 ASSERT_NOT_REACHED();
5769 return;
5770 }
5771 m_findMatchesClient->didGetImageForMatchResult(this, WebImage::create(bitmap.releaseNonNull()).ptr(), matchIndex);
5772}
5773
5774void WebPageProxy::setTextIndicator(const TextIndicatorData& indicatorData, uint64_t lifetime)
5775{
5776 // FIXME: Make TextIndicatorWindow a platform-independent presentational thing ("TextIndicatorPresentation"?).
5777#if PLATFORM(COCOA)
5778 pageClient().setTextIndicator(TextIndicator::create(indicatorData), static_cast<TextIndicatorWindowLifetime>(lifetime));
5779#else
5780 ASSERT_NOT_REACHED();
5781#endif
5782}
5783
5784void WebPageProxy::clearTextIndicator()
5785{
5786#if PLATFORM(COCOA)
5787 pageClient().clearTextIndicator(TextIndicatorWindowDismissalAnimation::FadeOut);
5788#else
5789 ASSERT_NOT_REACHED();
5790#endif
5791}
5792
5793void WebPageProxy::setTextIndicatorAnimationProgress(float progress)
5794{
5795#if PLATFORM(COCOA)
5796 pageClient().setTextIndicatorAnimationProgress(progress);
5797#else
5798 ASSERT_NOT_REACHED();
5799#endif
5800}
5801
5802void WebPageProxy::didFindString(const String& string, const Vector<WebCore::IntRect>& matchRects, uint32_t matchCount, int32_t matchIndex, bool didWrapAround)
5803{
5804 m_findClient->didFindString(this, string, matchRects, matchCount, matchIndex, didWrapAround);
5805}
5806
5807void WebPageProxy::didFindStringMatches(const String& string, const Vector<Vector<WebCore::IntRect>>& matchRects, int32_t firstIndexAfterSelection)
5808{
5809 m_findMatchesClient->didFindStringMatches(this, string, matchRects, firstIndexAfterSelection);
5810}
5811
5812void WebPageProxy::didFailToFindString(const String& string)
5813{
5814 m_findClient->didFailToFindString(this, string);
5815}
5816
5817bool WebPageProxy::sendMessage(std::unique_ptr<IPC::Encoder> encoder, OptionSet<IPC::SendOption> sendOptions)
5818{
5819 return m_process->sendMessage(WTFMove(encoder), sendOptions);
5820}
5821
5822IPC::Connection* WebPageProxy::messageSenderConnection() const
5823{
5824 return m_process->connection();
5825}
5826
5827uint64_t WebPageProxy::messageSenderDestinationID() const
5828{
5829 return m_pageID;
5830}
5831
5832void WebPageProxy::valueChangedForPopupMenu(WebPopupMenuProxy*, int32_t newSelectedIndex)
5833{
5834 m_process->send(Messages::WebPage::DidChangeSelectedIndexForActivePopupMenu(newSelectedIndex), m_pageID);
5835}
5836
5837void WebPageProxy::setTextFromItemForPopupMenu(WebPopupMenuProxy*, int32_t index)
5838{
5839 m_process->send(Messages::WebPage::SetTextForActivePopupMenu(index), m_pageID);
5840}
5841
5842bool WebPageProxy::isProcessingKeyboardEvents() const
5843{
5844 return !m_keyEventQueue.isEmpty();
5845}
5846
5847bool WebPageProxy::isProcessingMouseEvents() const
5848{
5849 return !m_mouseEventQueue.isEmpty();
5850}
5851
5852NativeWebMouseEvent* WebPageProxy::currentlyProcessedMouseDownEvent()
5853{
5854 // <https://bugs.webkit.org/show_bug.cgi?id=57904> We need to keep track of the mouse down event in the case where we
5855 // display a popup menu for select elements. When the user changes the selected item, we fake a mouseup event by
5856 // using this stored mousedown event and changing the event type. This trickery happens when WebProcess handles
5857 // a mousedown event that runs the default handler for HTMLSelectElement, so the triggering mousedown must be the first event.
5858
5859 if (m_mouseEventQueue.isEmpty())
5860 return nullptr;
5861
5862 auto& event = m_mouseEventQueue.first();
5863 if (event.type() != WebEvent::Type::MouseDown)
5864 return nullptr;
5865
5866 return &event;
5867}
5868
5869void WebPageProxy::postMessageToInjectedBundle(const String& messageName, API::Object* messageBody)
5870{
5871 // For backward-compatibility, make sure we launch the initial process if the client asks to post a message to its injected bundle before doing a load.
5872 launchInitialProcessIfNecessary();
5873
5874 process().send(Messages::WebPage::PostInjectedBundleMessage(messageName, UserData(process().transformObjectsToHandles(messageBody).get())), m_pageID);
5875}
5876
5877#if PLATFORM(GTK)
5878void WebPageProxy::failedToShowPopupMenu()
5879{
5880 m_process->send(Messages::WebPage::FailedToShowPopupMenu(), m_pageID);
5881}
5882#endif
5883
5884void WebPageProxy::showPopupMenu(const IntRect& rect, uint64_t textDirection, const Vector<WebPopupItem>& items, int32_t selectedIndex, const PlatformPopupMenuData& data)
5885{
5886 if (m_activePopupMenu) {
5887 m_activePopupMenu->hidePopupMenu();
5888 m_activePopupMenu->invalidate();
5889 m_activePopupMenu = nullptr;
5890 }
5891
5892 // If the page is controlled by automation, entering a nested run loop while the menu is open
5893 // can hang the page / WebDriver test. Since <option> elements are selected via a different
5894 // code path anyway, just don't show the native popup menu.
5895 if (auto* automationSession = process().processPool().automationSession()) {
5896 if (m_controlledByAutomation && automationSession->isSimulatingUserInteraction())
5897 return;
5898 }
5899
5900 m_activePopupMenu = pageClient().createPopupMenuProxy(*this);
5901
5902 if (!m_activePopupMenu)
5903 return;
5904
5905 // Since showPopupMenu() can spin a nested run loop we need to turn off the responsiveness timer.
5906 m_process->responsivenessTimer().stop();
5907
5908 // Showing a popup menu runs a nested runloop, which can handle messages that cause |this| to get closed.
5909 Ref<WebPageProxy> protect(*this);
5910 m_activePopupMenu->showPopupMenu(rect, static_cast<TextDirection>(textDirection), m_pageScaleFactor, items, data, selectedIndex);
5911}
5912
5913void WebPageProxy::hidePopupMenu()
5914{
5915 if (!m_activePopupMenu)
5916 return;
5917
5918 m_activePopupMenu->hidePopupMenu();
5919 m_activePopupMenu->invalidate();
5920 m_activePopupMenu = nullptr;
5921}
5922
5923#if ENABLE(CONTEXT_MENUS)
5924void WebPageProxy::showContextMenu(ContextMenuContextData&& contextMenuContextData, const UserData& userData)
5925{
5926 // Showing a context menu runs a nested runloop, which can handle messages that cause |this| to get closed.
5927 Ref<WebPageProxy> protect(*this);
5928
5929 // Discard any enqueued mouse events that have been delivered to the UIProcess whilst the WebProcess is still processing the
5930 // MouseDown event that triggered this ShowContextMenu message. This can happen if we take too long to enter the nested runloop.
5931 ASSERT(isProcessingMouseEvents());
5932 while (m_mouseEventQueue.size() > 1)
5933 m_mouseEventQueue.takeLast();
5934
5935 m_activeContextMenuContextData = contextMenuContextData;
5936
5937 m_activeContextMenu = pageClient().createContextMenuProxy(*this, WTFMove(contextMenuContextData), userData);
5938
5939 // Since showContextMenu() can spin a nested run loop we need to turn off the responsiveness timer.
5940 m_process->responsivenessTimer().stop();
5941
5942 // m_activeContextMenu might get cleared if WebPageProxy code is re-entered from the menu runloop or delegates.
5943 Ref<WebContextMenuProxy> protector(*m_activeContextMenu);
5944 m_activeContextMenu->show();
5945
5946 // No matter the result of internalShowContextMenu, always notify the WebProcess that the menu is hidden so it starts handling mouse events again.
5947 m_process->send(Messages::WebPage::ContextMenuHidden(), m_pageID);
5948}
5949
5950void WebPageProxy::contextMenuItemSelected(const WebContextMenuItemData& item)
5951{
5952 // Application custom items don't need to round-trip through to WebCore in the WebProcess.
5953 if (item.action() >= ContextMenuItemBaseApplicationTag) {
5954 m_contextMenuClient->customContextMenuItemSelected(*this, item);
5955 return;
5956 }
5957
5958#if PLATFORM(COCOA)
5959 if (item.action() == ContextMenuItemTagSmartCopyPaste) {
5960 setSmartInsertDeleteEnabled(!isSmartInsertDeleteEnabled());
5961 return;
5962 }
5963 if (item.action() == ContextMenuItemTagSmartQuotes) {
5964 TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled);
5965 m_process->updateTextCheckerState();
5966 return;
5967 }
5968 if (item.action() == ContextMenuItemTagSmartDashes) {
5969 TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled);
5970 m_process->updateTextCheckerState();
5971 return;
5972 }
5973 if (item.action() == ContextMenuItemTagSmartLinks) {
5974 TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled);
5975 m_process->updateTextCheckerState();
5976 return;
5977 }
5978 if (item.action() == ContextMenuItemTagTextReplacement) {
5979 TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled);
5980 m_process->updateTextCheckerState();
5981 return;
5982 }
5983 if (item.action() == ContextMenuItemTagCorrectSpellingAutomatically) {
5984 TextChecker::setAutomaticSpellingCorrectionEnabled(!TextChecker::state().isAutomaticSpellingCorrectionEnabled);
5985 m_process->updateTextCheckerState();
5986 return;
5987 }
5988 if (item.action() == ContextMenuItemTagShowSubstitutions) {
5989 TextChecker::toggleSubstitutionsPanelIsShowing();
5990 return;
5991 }
5992#endif
5993 if (item.action() == ContextMenuItemTagDownloadImageToDisk) {
5994 m_process->processPool().download(this, URL(URL(), m_activeContextMenuContextData.webHitTestResultData().absoluteImageURL));
5995 return;
5996 }
5997 if (item.action() == ContextMenuItemTagDownloadLinkToDisk) {
5998 auto& hitTestResult = m_activeContextMenuContextData.webHitTestResultData();
5999 m_process->processPool().download(this, URL(URL(), hitTestResult.absoluteLinkURL), hitTestResult.linkSuggestedFilename);
6000 return;
6001 }
6002 if (item.action() == ContextMenuItemTagDownloadMediaToDisk) {
6003 m_process->processPool().download(this, URL(URL(), m_activeContextMenuContextData.webHitTestResultData().absoluteMediaURL));
6004 return;
6005 }
6006 if (item.action() == ContextMenuItemTagCheckSpellingWhileTyping) {
6007 TextChecker::setContinuousSpellCheckingEnabled(!TextChecker::state().isContinuousSpellCheckingEnabled);
6008 m_process->updateTextCheckerState();
6009 return;
6010 }
6011 if (item.action() == ContextMenuItemTagCheckGrammarWithSpelling) {
6012 TextChecker::setGrammarCheckingEnabled(!TextChecker::state().isGrammarCheckingEnabled);
6013 m_process->updateTextCheckerState();
6014 return;
6015 }
6016 if (item.action() == ContextMenuItemTagShowSpellingPanel) {
6017 if (!TextChecker::spellingUIIsShowing())
6018 advanceToNextMisspelling(true);
6019 TextChecker::toggleSpellingUIIsShowing();
6020 return;
6021 }
6022 if (item.action() == ContextMenuItemTagLearnSpelling || item.action() == ContextMenuItemTagIgnoreSpelling)
6023 ++m_pendingLearnOrIgnoreWordMessageCount;
6024
6025 m_process->send(Messages::WebPage::DidSelectItemFromActiveContextMenu(item), m_pageID);
6026}
6027
6028void WebPageProxy::handleContextMenuKeyEvent()
6029{
6030 m_process->send(Messages::WebPage::ContextMenuForKeyEvent(), m_pageID);
6031}
6032#endif // ENABLE(CONTEXT_MENUS)
6033
6034#if PLATFORM(IOS_FAMILY)
6035void WebPageProxy::didChooseFilesForOpenPanelWithDisplayStringAndIcon(const Vector<String>& fileURLs, const String& displayString, const API::Data* iconData)
6036{
6037 if (!hasRunningProcess())
6038 return;
6039
6040#if ENABLE(SANDBOX_EXTENSIONS)
6041 SandboxExtension::HandleArray sandboxExtensionHandles;
6042 sandboxExtensionHandles.allocate(fileURLs.size());
6043 for (size_t i = 0; i < fileURLs.size(); ++i)
6044 SandboxExtension::createHandle(fileURLs[i], SandboxExtension::Type::ReadOnly, sandboxExtensionHandles[i]);
6045
6046 m_process->send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(sandboxExtensionHandles), m_pageID);
6047#endif
6048
6049 m_process->send(Messages::WebPage::DidChooseFilesForOpenPanelWithDisplayStringAndIcon(fileURLs, displayString, iconData ? iconData->dataReference() : IPC::DataReference()), m_pageID);
6050
6051 m_openPanelResultListener->invalidate();
6052 m_openPanelResultListener = nullptr;
6053}
6054#endif
6055
6056void WebPageProxy::didChooseFilesForOpenPanel(const Vector<String>& fileURLs)
6057{
6058 if (!hasRunningProcess())
6059 return;
6060
6061#if ENABLE(SANDBOX_EXTENSIONS)
6062 SandboxExtension::HandleArray sandboxExtensionHandles;
6063 sandboxExtensionHandles.allocate(fileURLs.size());
6064 for (size_t i = 0; i < fileURLs.size(); ++i) {
6065 bool createdExtension = SandboxExtension::createHandle(fileURLs[i], SandboxExtension::Type::ReadOnly, sandboxExtensionHandles[i]);
6066 if (!createdExtension) {
6067 // This can legitimately fail if a directory containing the file is deleted after the file was chosen.
6068 // We also have reports of cases where this likely fails for some unknown reason, <rdar://problem/10156710>.
6069 WTFLogAlways("WebPageProxy::didChooseFilesForOpenPanel: could not create a sandbox extension for '%s'\n", fileURLs[i].utf8().data());
6070 continue;
6071 }
6072 }
6073
6074 m_process->send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(sandboxExtensionHandles), m_pageID);
6075#endif
6076
6077 m_process->send(Messages::WebPage::DidChooseFilesForOpenPanel(fileURLs), m_pageID);
6078
6079 m_openPanelResultListener->invalidate();
6080 m_openPanelResultListener = nullptr;
6081}
6082
6083void WebPageProxy::didCancelForOpenPanel()
6084{
6085 if (!hasRunningProcess())
6086 return;
6087
6088 m_process->send(Messages::WebPage::DidCancelForOpenPanel(), m_pageID);
6089
6090 m_openPanelResultListener->invalidate();
6091 m_openPanelResultListener = nullptr;
6092}
6093
6094void WebPageProxy::advanceToNextMisspelling(bool startBeforeSelection)
6095{
6096 m_process->send(Messages::WebPage::AdvanceToNextMisspelling(startBeforeSelection), m_pageID);
6097}
6098
6099void WebPageProxy::changeSpellingToWord(const String& word)
6100{
6101 if (word.isEmpty())
6102 return;
6103
6104 m_process->send(Messages::WebPage::ChangeSpellingToWord(word), m_pageID);
6105}
6106
6107void WebPageProxy::registerEditCommand(Ref<WebEditCommandProxy>&& commandProxy, UndoOrRedo undoOrRedo)
6108{
6109 pageClient().registerEditCommand(WTFMove(commandProxy), undoOrRedo);
6110}
6111
6112void WebPageProxy::addEditCommand(WebEditCommandProxy& command)
6113{
6114 m_editCommandSet.add(&command);
6115}
6116
6117void WebPageProxy::removeEditCommand(WebEditCommandProxy& command)
6118{
6119 m_editCommandSet.remove(&command);
6120
6121 if (!hasRunningProcess())
6122 return;
6123 m_process->send(Messages::WebPage::DidRemoveEditCommand(command.commandID()), m_pageID);
6124}
6125
6126bool WebPageProxy::canUndo()
6127{
6128 return pageClient().canUndoRedo(UndoOrRedo::Undo);
6129}
6130
6131bool WebPageProxy::canRedo()
6132{
6133 return pageClient().canUndoRedo(UndoOrRedo::Redo);
6134}
6135
6136SpellDocumentTag WebPageProxy::spellDocumentTag()
6137{
6138 if (!m_spellDocumentTag)
6139 m_spellDocumentTag = TextChecker::uniqueSpellDocumentTag(this);
6140 return m_spellDocumentTag.value();
6141}
6142
6143#if USE(UNIFIED_TEXT_CHECKING)
6144void WebPageProxy::checkTextOfParagraph(const String& text, OptionSet<TextCheckingType> checkingTypes, int32_t insertionPoint, CompletionHandler<void(Vector<WebCore::TextCheckingResult>&&)>&& completionHandler)
6145{
6146 completionHandler(TextChecker::checkTextOfParagraph(spellDocumentTag(), text, insertionPoint, checkingTypes, m_initialCapitalizationEnabled));
6147}
6148#endif
6149
6150void WebPageProxy::checkSpellingOfString(const String& text, CompletionHandler<void(int32_t misspellingLocation, int32_t misspellingLength)>&& completionHandler)
6151{
6152 int32_t misspellingLocation = 0;
6153 int32_t misspellingLength = 0;
6154 TextChecker::checkSpellingOfString(spellDocumentTag(), text, misspellingLocation, misspellingLength);
6155 completionHandler(misspellingLocation, misspellingLength);
6156}
6157
6158void WebPageProxy::checkGrammarOfString(const String& text, CompletionHandler<void(Vector<WebCore::GrammarDetail>&&, int32_t badGrammarLocation, int32_t badGrammarLength)>&& completionHandler)
6159{
6160 Vector<GrammarDetail> grammarDetails;
6161 int32_t badGrammarLocation = 0;
6162 int32_t badGrammarLength = 0;
6163 TextChecker::checkGrammarOfString(spellDocumentTag(), text, grammarDetails, badGrammarLocation, badGrammarLength);
6164 completionHandler(WTFMove(grammarDetails), badGrammarLocation, badGrammarLength);
6165}
6166
6167void WebPageProxy::spellingUIIsShowing(CompletionHandler<void(bool)>&& completionHandler)
6168{
6169 completionHandler(TextChecker::spellingUIIsShowing());
6170}
6171
6172void WebPageProxy::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
6173{
6174 TextChecker::updateSpellingUIWithMisspelledWord(spellDocumentTag(), misspelledWord);
6175}
6176
6177void WebPageProxy::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
6178{
6179 TextChecker::updateSpellingUIWithGrammarString(spellDocumentTag(), badGrammarPhrase, grammarDetail);
6180}
6181
6182void WebPageProxy::getGuessesForWord(const String& word, const String& context, int32_t insertionPoint, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
6183{
6184 Vector<String> guesses;
6185 TextChecker::getGuessesForWord(spellDocumentTag(), word, context, insertionPoint, guesses, m_initialCapitalizationEnabled);
6186 completionHandler(WTFMove(guesses));
6187}
6188
6189void WebPageProxy::learnWord(const String& word)
6190{
6191 MESSAGE_CHECK(m_process, m_pendingLearnOrIgnoreWordMessageCount);
6192 --m_pendingLearnOrIgnoreWordMessageCount;
6193
6194 TextChecker::learnWord(spellDocumentTag(), word);
6195}
6196
6197void WebPageProxy::ignoreWord(const String& word)
6198{
6199 MESSAGE_CHECK(m_process, m_pendingLearnOrIgnoreWordMessageCount);
6200 --m_pendingLearnOrIgnoreWordMessageCount;
6201
6202 TextChecker::ignoreWord(spellDocumentTag(), word);
6203}
6204
6205void WebPageProxy::requestCheckingOfString(uint64_t requestID, const TextCheckingRequestData& request, int32_t insertionPoint)
6206{
6207 TextChecker::requestCheckingOfString(TextCheckerCompletion::create(requestID, request, this), insertionPoint);
6208}
6209
6210void WebPageProxy::didFinishCheckingText(uint64_t requestID, const Vector<WebCore::TextCheckingResult>& result)
6211{
6212 m_process->send(Messages::WebPage::DidFinishCheckingText(requestID, result), m_pageID);
6213}
6214
6215void WebPageProxy::didCancelCheckingText(uint64_t requestID)
6216{
6217 m_process->send(Messages::WebPage::DidCancelCheckingText(requestID), m_pageID);
6218}
6219// Other
6220
6221void WebPageProxy::setFocus(bool focused)
6222{
6223 if (focused)
6224 m_uiClient->focus(this);
6225 else
6226 m_uiClient->unfocus(this);
6227}
6228
6229void WebPageProxy::takeFocus(uint32_t direction)
6230{
6231 if (m_uiClient->takeFocus(this, (static_cast<FocusDirection>(direction) == FocusDirectionForward) ? kWKFocusDirectionForward : kWKFocusDirectionBackward))
6232 return;
6233
6234 pageClient().takeFocus(static_cast<FocusDirection>(direction));
6235}
6236
6237void WebPageProxy::setToolTip(const String& toolTip)
6238{
6239 String oldToolTip = m_toolTip;
6240 m_toolTip = toolTip;
6241 pageClient().toolTipChanged(oldToolTip, m_toolTip);
6242}
6243
6244void WebPageProxy::setCursor(const WebCore::Cursor& cursor)
6245{
6246 pageClient().setCursor(cursor);
6247}
6248
6249void WebPageProxy::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
6250{
6251 pageClient().setCursorHiddenUntilMouseMoves(hiddenUntilMouseMoves);
6252}
6253
6254void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled)
6255{
6256 WebEvent::Type type = static_cast<WebEvent::Type>(opaqueType);
6257
6258 switch (type) {
6259 case WebEvent::NoType:
6260 case WebEvent::MouseMove:
6261 case WebEvent::Wheel:
6262 break;
6263
6264 case WebEvent::MouseDown:
6265 case WebEvent::MouseUp:
6266 case WebEvent::MouseForceChanged:
6267 case WebEvent::MouseForceDown:
6268 case WebEvent::MouseForceUp:
6269 case WebEvent::KeyDown:
6270 case WebEvent::KeyUp:
6271 case WebEvent::RawKeyDown:
6272 case WebEvent::Char:
6273#if ENABLE(TOUCH_EVENTS)
6274 case WebEvent::TouchStart:
6275 case WebEvent::TouchMove:
6276 case WebEvent::TouchEnd:
6277 case WebEvent::TouchCancel:
6278#endif
6279#if ENABLE(MAC_GESTURE_EVENTS)
6280 case WebEvent::GestureStart:
6281 case WebEvent::GestureChange:
6282 case WebEvent::GestureEnd:
6283#endif
6284 m_process->responsivenessTimer().stop();
6285 break;
6286 }
6287
6288 switch (type) {
6289 case WebEvent::NoType:
6290 break;
6291 case WebEvent::MouseForceChanged:
6292 case WebEvent::MouseForceDown:
6293 case WebEvent::MouseForceUp:
6294 case WebEvent::MouseMove:
6295 case WebEvent::MouseDown:
6296 case WebEvent::MouseUp: {
6297 LOG(MouseHandling, "WebPageProxy::didReceiveEvent: %s (queue size %zu)", webMouseEventTypeString(type), m_mouseEventQueue.size());
6298
6299 // Retire the last sent event now that WebProcess is done handling it.
6300 MESSAGE_CHECK(m_process, !m_mouseEventQueue.isEmpty());
6301 NativeWebMouseEvent event = m_mouseEventQueue.takeFirst();
6302 MESSAGE_CHECK(m_process, type == event.type());
6303
6304 if (!m_mouseEventQueue.isEmpty()) {
6305 LOG(MouseHandling, " UIProcess: handling a queued mouse event from didReceiveEvent");
6306 processNextQueuedMouseEvent();
6307 } else {
6308 if (auto* automationSession = process().processPool().automationSession())
6309 automationSession->mouseEventsFlushedForPage(*this);
6310 pageClient().didFinishProcessingAllPendingMouseEvents();
6311 }
6312
6313 break;
6314 }
6315
6316 case WebEvent::Wheel: {
6317 MESSAGE_CHECK(m_process, !m_currentlyProcessedWheelEvents.isEmpty());
6318
6319 std::unique_ptr<Vector<NativeWebWheelEvent>> oldestCoalescedEvent = m_currentlyProcessedWheelEvents.takeFirst();
6320
6321 // FIXME: Dispatch additional events to the didNotHandleWheelEvent client function.
6322 if (!handled) {
6323 m_uiClient->didNotHandleWheelEvent(this, oldestCoalescedEvent->last());
6324 pageClient().wheelEventWasNotHandledByWebCore(oldestCoalescedEvent->last());
6325 }
6326
6327 if (!m_wheelEventQueue.isEmpty())
6328 processNextQueuedWheelEvent();
6329 break;
6330 }
6331
6332 case WebEvent::KeyDown:
6333 case WebEvent::KeyUp:
6334 case WebEvent::RawKeyDown:
6335 case WebEvent::Char: {
6336 LOG(KeyHandling, "WebPageProxy::didReceiveEvent: %s (queue empty %d)", webKeyboardEventTypeString(type), m_keyEventQueue.isEmpty());
6337
6338 MESSAGE_CHECK(m_process, !m_keyEventQueue.isEmpty());
6339 NativeWebKeyboardEvent event = m_keyEventQueue.takeFirst();
6340
6341 MESSAGE_CHECK(m_process, type == event.type());
6342
6343 bool canProcessMoreKeyEvents = !m_keyEventQueue.isEmpty();
6344 if (canProcessMoreKeyEvents) {
6345 LOG(KeyHandling, " UI process: sent keyEvent from didReceiveEvent");
6346 m_process->send(Messages::WebPage::KeyEvent(m_keyEventQueue.first()), m_pageID);
6347 }
6348
6349 // The call to doneWithKeyEvent may close this WebPage.
6350 // Protect against this being destroyed.
6351 Ref<WebPageProxy> protect(*this);
6352
6353 pageClient().doneWithKeyEvent(event, handled);
6354 if (!handled)
6355 m_uiClient->didNotHandleKeyEvent(this, event);
6356
6357 // Notify the session after -[NSApp sendEvent:] has a crack at turning the event into an action.
6358 if (!canProcessMoreKeyEvents) {
6359 if (auto* automationSession = process().processPool().automationSession())
6360 automationSession->keyboardEventsFlushedForPage(*this);
6361 }
6362 break;
6363 }
6364#if ENABLE(MAC_GESTURE_EVENTS)
6365 case WebEvent::GestureStart:
6366 case WebEvent::GestureChange:
6367 case WebEvent::GestureEnd: {
6368 MESSAGE_CHECK(m_process, !m_gestureEventQueue.isEmpty());
6369 NativeWebGestureEvent event = m_gestureEventQueue.takeFirst();
6370
6371 MESSAGE_CHECK(m_process, type == event.type());
6372
6373 if (!handled)
6374 pageClient().gestureEventWasNotHandledByWebCore(event);
6375 break;
6376 }
6377 break;
6378#endif
6379#if ENABLE(IOS_TOUCH_EVENTS)
6380 case WebEvent::TouchStart:
6381 case WebEvent::TouchMove:
6382 case WebEvent::TouchEnd:
6383 case WebEvent::TouchCancel:
6384 break;
6385#elif ENABLE(TOUCH_EVENTS)
6386 case WebEvent::TouchStart:
6387 case WebEvent::TouchMove:
6388 case WebEvent::TouchEnd:
6389 case WebEvent::TouchCancel: {
6390 MESSAGE_CHECK(m_process, !m_touchEventQueue.isEmpty());
6391 QueuedTouchEvents queuedEvents = m_touchEventQueue.takeFirst();
6392
6393 MESSAGE_CHECK(m_process, type == queuedEvents.forwardedEvent.type());
6394
6395 pageClient().doneWithTouchEvent(queuedEvents.forwardedEvent, handled);
6396 for (size_t i = 0; i < queuedEvents.deferredTouchEvents.size(); ++i) {
6397 bool isEventHandled = false;
6398 pageClient().doneWithTouchEvent(queuedEvents.deferredTouchEvents.at(i), isEventHandled);
6399 }
6400 break;
6401 }
6402#endif
6403 }
6404}
6405
6406void WebPageProxy::voidCallback(CallbackID callbackID)
6407{
6408 auto callback = m_callbacks.take<VoidCallback>(callbackID);
6409 if (!callback) {
6410 // FIXME: Log error or assert.
6411 return;
6412 }
6413
6414 callback->performCallback();
6415}
6416
6417void WebPageProxy::dataCallback(const IPC::DataReference& dataReference, CallbackID callbackID)
6418{
6419 auto callback = m_callbacks.take<DataCallback>(callbackID);
6420 if (!callback)
6421 return;
6422
6423 callback->performCallbackWithReturnValue(API::Data::create(dataReference.data(), dataReference.size()).ptr());
6424}
6425
6426void WebPageProxy::imageCallback(const ShareableBitmap::Handle& bitmapHandle, CallbackID callbackID)
6427{
6428 auto callback = m_callbacks.take<ImageCallback>(callbackID);
6429 if (!callback) {
6430 // FIXME: Log error or assert.
6431 return;
6432 }
6433
6434 callback->performCallbackWithReturnValue(bitmapHandle);
6435}
6436
6437void WebPageProxy::stringCallback(const String& resultString, CallbackID callbackID)
6438{
6439 auto callback = m_callbacks.take<StringCallback>(callbackID);
6440 if (!callback) {
6441 // FIXME: Log error or assert.
6442 // this can validly happen if a load invalidated the callback, though
6443 return;
6444 }
6445
6446 m_loadDependentStringCallbackIDs.remove(callbackID);
6447
6448 callback->performCallbackWithReturnValue(resultString.impl());
6449}
6450
6451void WebPageProxy::invalidateStringCallback(CallbackID callbackID)
6452{
6453 auto callback = m_callbacks.take<StringCallback>(callbackID);
6454 if (!callback) {
6455 // FIXME: Log error or assert.
6456 // this can validly happen if a load invalidated the callback, though
6457 return;
6458 }
6459
6460 m_loadDependentStringCallbackIDs.remove(callbackID);
6461
6462 callback->invalidate();
6463}
6464
6465void WebPageProxy::scriptValueCallback(const IPC::DataReference& dataReference, bool hadException, const ExceptionDetails& details, CallbackID callbackID)
6466{
6467 auto callback = m_callbacks.take<ScriptValueCallback>(callbackID);
6468 if (!callback) {
6469 // FIXME: Log error or assert.
6470 return;
6471 }
6472
6473 if (dataReference.isEmpty()) {
6474 callback->performCallbackWithReturnValue(nullptr, hadException, details);
6475 return;
6476 }
6477
6478 Vector<uint8_t> data;
6479 data.reserveInitialCapacity(dataReference.size());
6480 data.append(dataReference.data(), dataReference.size());
6481
6482 callback->performCallbackWithReturnValue(API::SerializedScriptValue::adopt(WTFMove(data)).ptr(), hadException, details);
6483}
6484
6485void WebPageProxy::computedPagesCallback(const Vector<IntRect>& pageRects, double totalScaleFactorForPrinting, const FloatBoxExtent& computedPageMargin, CallbackID callbackID)
6486{
6487 auto callback = m_callbacks.take<ComputedPagesCallback>(callbackID);
6488 if (!callback) {
6489 // FIXME: Log error or assert.
6490 return;
6491 }
6492
6493 callback->performCallbackWithReturnValue(pageRects, totalScaleFactorForPrinting, computedPageMargin);
6494}
6495
6496void WebPageProxy::validateCommandCallback(const String& commandName, bool isEnabled, int state, CallbackID callbackID)
6497{
6498 auto callback = m_callbacks.take<ValidateCommandCallback>(callbackID);
6499 if (!callback) {
6500 // FIXME: Log error or assert.
6501 return;
6502 }
6503
6504 callback->performCallbackWithReturnValue(commandName.impl(), isEnabled, state);
6505}
6506
6507void WebPageProxy::unsignedCallback(uint64_t result, CallbackID callbackID)
6508{
6509 auto callback = m_callbacks.take<UnsignedCallback>(callbackID);
6510 if (!callback) {
6511 // FIXME: Log error or assert.
6512 // this can validly happen if a load invalidated the callback, though
6513 return;
6514 }
6515
6516 callback->performCallbackWithReturnValue(result);
6517}
6518
6519void WebPageProxy::editingRangeCallback(const EditingRange& range, CallbackID callbackID)
6520{
6521 MESSAGE_CHECK(m_process, range.isValid());
6522
6523 auto callback = m_callbacks.take<EditingRangeCallback>(callbackID);
6524 if (!callback) {
6525 // FIXME: Log error or assert.
6526 // this can validly happen if a load invalidated the callback, though
6527 return;
6528 }
6529
6530 callback->performCallbackWithReturnValue(range);
6531}
6532
6533void WebPageProxy::editorStateChanged(const EditorState& editorState)
6534{
6535 updateEditorState(editorState);
6536 dispatchDidReceiveEditorStateAfterFocus();
6537}
6538
6539#if !PLATFORM(IOS_FAMILY)
6540
6541void WebPageProxy::dispatchDidReceiveEditorStateAfterFocus()
6542{
6543}
6544
6545#endif
6546
6547#if ENABLE(APPLICATION_MANIFEST)
6548void WebPageProxy::applicationManifestCallback(const Optional<WebCore::ApplicationManifest>& manifestOrNull, CallbackID callbackID)
6549{
6550 auto callback = m_callbacks.take<ApplicationManifestCallback>(callbackID);
6551 if (!callback)
6552 return;
6553
6554 callback->performCallbackWithReturnValue(manifestOrNull);
6555}
6556#endif
6557
6558#if PLATFORM(COCOA)
6559void WebPageProxy::machSendRightCallback(const MachSendRight& sendRight, CallbackID callbackID)
6560{
6561 auto callback = m_callbacks.take<MachSendRightCallback>(callbackID);
6562 if (!callback)
6563 return;
6564
6565 callback->performCallbackWithReturnValue(sendRight);
6566}
6567#endif
6568
6569inline API::DiagnosticLoggingClient* WebPageProxy::effectiveDiagnosticLoggingClient(ShouldSample shouldSample)
6570{
6571 // Diagnostic logging is disabled for ephemeral sessions for privacy reasons.
6572 if (sessionID().isEphemeral())
6573 return nullptr;
6574
6575 return DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample) ? diagnosticLoggingClient() : nullptr;
6576}
6577
6578void WebPageProxy::logDiagnosticMessage(const String& message, const String& description, WebCore::ShouldSample shouldSample)
6579{
6580 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
6581 if (!effectiveClient)
6582 return;
6583
6584 effectiveClient->logDiagnosticMessage(this, message, description);
6585}
6586
6587void WebPageProxy::logDiagnosticMessageWithResult(const String& message, const String& description, uint32_t result, WebCore::ShouldSample shouldSample)
6588{
6589 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
6590 if (!effectiveClient)
6591 return;
6592
6593 effectiveClient->logDiagnosticMessageWithResult(this, message, description, static_cast<WebCore::DiagnosticLoggingResultType>(result));
6594}
6595
6596void WebPageProxy::logDiagnosticMessageWithValue(const String& message, const String& description, double value, unsigned significantFigures, ShouldSample shouldSample)
6597{
6598 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
6599 if (!effectiveClient)
6600 return;
6601
6602 effectiveClient->logDiagnosticMessageWithValue(this, message, description, String::numberToStringFixedPrecision(value, significantFigures));
6603}
6604
6605void WebPageProxy::logDiagnosticMessageWithEnhancedPrivacy(const String& message, const String& description, ShouldSample shouldSample)
6606{
6607 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
6608 if (!effectiveClient)
6609 return;
6610
6611 effectiveClient->logDiagnosticMessageWithEnhancedPrivacy(this, message, description);
6612}
6613
6614void WebPageProxy::logDiagnosticMessageWithValueDictionary(const String& message, const String& description, const WebCore::DiagnosticLoggingClient::ValueDictionary& valueDictionary, WebCore::ShouldSample shouldSample)
6615{
6616 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
6617 if (!effectiveClient)
6618 return;
6619
6620 auto apiDictionary = API::Dictionary::create();
6621
6622 for (auto& keyValuePair : valueDictionary) {
6623 apiDictionary->add(keyValuePair.key, WTF::switchOn(keyValuePair.value,
6624 [](const String& value) -> Ref<Object> { return API::String::create(value); },
6625 [](uint64_t value) -> Ref<Object> { return API::UInt64::create(value); },
6626 [](int64_t value) -> Ref<Object> { return API::Int64::create(value); },
6627 [](bool value) -> Ref<Object> { return API::Boolean::create(value); },
6628 [](double value) -> Ref<Object> { return API::Double::create(value); }
6629 ));
6630 }
6631
6632 effectiveClient->logDiagnosticMessageWithValueDictionary(this, message, description, WTFMove(apiDictionary));
6633}
6634
6635void WebPageProxy::logScrollingEvent(uint32_t eventType, MonotonicTime timestamp, uint64_t data)
6636{
6637 PerformanceLoggingClient::ScrollingEvent event = static_cast<PerformanceLoggingClient::ScrollingEvent>(eventType);
6638
6639 switch (event) {
6640 case PerformanceLoggingClient::ScrollingEvent::ExposedTilelessArea:
6641 WTFLogAlways("SCROLLING: Exposed tileless area. Time: %f Unfilled Pixels: %llu\n", timestamp.secondsSinceEpoch().value(), (unsigned long long)data);
6642 break;
6643 case PerformanceLoggingClient::ScrollingEvent::FilledTile:
6644 WTFLogAlways("SCROLLING: Filled visible fresh tile. Time: %f Unfilled Pixels: %llu\n", timestamp.secondsSinceEpoch().value(), (unsigned long long)data);
6645 break;
6646 case PerformanceLoggingClient::ScrollingEvent::SwitchedScrollingMode:
6647 if (data)
6648 WTFLogAlways("SCROLLING: Switching to main-thread scrolling mode. Time: %f Reason(s): %s\n", timestamp.secondsSinceEpoch().value(), PerformanceLoggingClient::synchronousScrollingReasonsAsString(data).utf8().data());
6649 else
6650 WTFLogAlways("SCROLLING: Switching to threaded scrolling mode. Time: %f\n", timestamp.secondsSinceEpoch().value());
6651 break;
6652 }
6653}
6654
6655void WebPageProxy::rectForCharacterRangeCallback(const IntRect& rect, const EditingRange& actualRange, CallbackID callbackID)
6656{
6657 MESSAGE_CHECK(m_process, actualRange.isValid());
6658
6659 auto callback = m_callbacks.take<RectForCharacterRangeCallback>(callbackID);
6660 if (!callback) {
6661 // FIXME: Log error or assert.
6662 // this can validly happen if a load invalidated the callback, though
6663 return;
6664 }
6665
6666 callback->performCallbackWithReturnValue(rect, actualRange);
6667}
6668
6669#if PLATFORM(GTK)
6670void WebPageProxy::printFinishedCallback(const ResourceError& printError, CallbackID callbackID)
6671{
6672 auto callback = m_callbacks.take<PrintFinishedCallback>(callbackID);
6673 if (!callback) {
6674 // FIXME: Log error or assert.
6675 return;
6676 }
6677
6678 callback->performCallbackWithReturnValue(API::Error::create(printError).ptr());
6679}
6680#endif
6681
6682void WebPageProxy::focusedFrameChanged(uint64_t frameID)
6683{
6684 if (!frameID) {
6685 m_focusedFrame = nullptr;
6686 return;
6687 }
6688
6689 WebFrameProxy* frame = m_process->webFrame(frameID);
6690 MESSAGE_CHECK(m_process, frame);
6691
6692 m_focusedFrame = frame;
6693}
6694
6695void WebPageProxy::frameSetLargestFrameChanged(uint64_t frameID)
6696{
6697 if (!frameID) {
6698 m_frameSetLargestFrame = nullptr;
6699 return;
6700 }
6701
6702 WebFrameProxy* frame = m_process->webFrame(frameID);
6703 MESSAGE_CHECK(m_process, frame);
6704
6705 m_frameSetLargestFrame = frame;
6706}
6707
6708void WebPageProxy::processDidBecomeUnresponsive()
6709{
6710 RELEASE_LOG_IF_ALLOWED(Process, "processDidBecomeUnresponsive: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
6711
6712 if (!hasRunningProcess())
6713 return;
6714
6715 updateBackingStoreDiscardableState();
6716
6717 m_navigationClient->processDidBecomeUnresponsive(*this);
6718}
6719
6720void WebPageProxy::processDidBecomeResponsive()
6721{
6722 RELEASE_LOG_IF_ALLOWED(Process, "processDidBecomeResponsive: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID);
6723
6724 if (!hasRunningProcess())
6725 return;
6726
6727 updateBackingStoreDiscardableState();
6728
6729 m_navigationClient->processDidBecomeResponsive(*this);
6730}
6731
6732void WebPageProxy::willChangeProcessIsResponsive()
6733{
6734 m_pageLoadState.willChangeProcessIsResponsive();
6735}
6736
6737void WebPageProxy::didChangeProcessIsResponsive()
6738{
6739 m_pageLoadState.didChangeProcessIsResponsive();
6740}
6741
6742String WebPageProxy::currentURL() const
6743{
6744 String url = m_pageLoadState.activeURL();
6745 if (url.isEmpty() && m_backForwardList->currentItem())
6746 url = m_backForwardList->currentItem()->url();
6747 return url;
6748}
6749
6750void WebPageProxy::processDidTerminate(ProcessTerminationReason reason)
6751{
6752 if (reason != ProcessTerminationReason::NavigationSwap)
6753 RELEASE_LOG_IF_ALLOWED(Process, "processDidTerminate: (pid %d), reason %d", processIdentifier(), reason);
6754
6755 ASSERT(m_hasRunningProcess);
6756
6757#if PLATFORM(IOS_FAMILY)
6758 if (m_process->isUnderMemoryPressure()) {
6759 String domain = WebCore::topPrivatelyControlledDomain(URL({ }, currentURL()).host().toString());
6760 if (!domain.isEmpty())
6761 logDiagnosticMessageWithEnhancedPrivacy(WebCore::DiagnosticLoggingKeys::domainCausingJetsamKey(), domain, WebCore::ShouldSample::No);
6762 }
6763#endif
6764
6765 // There is a nested transaction in resetStateAfterProcessExited() that we don't want to commit before the client call.
6766 PageLoadState::Transaction transaction = m_pageLoadState.transaction();
6767
6768 resetStateAfterProcessExited(reason);
6769 stopAllURLSchemeTasks(m_process.ptr());
6770
6771 // For bringup of process swapping, NavigationSwap termination will not go out to clients.
6772 // If it does *during* process swapping, and the client triggers a reload, that causes bizarre WebKit re-entry.
6773 // FIXME: This might have to change
6774 if (reason == ProcessTerminationReason::NavigationSwap)
6775 m_webProcessLifetimeTracker.webPageLeavingWebProcess(m_process);
6776 else {
6777 navigationState().clearAllNavigations();
6778 dispatchProcessDidTerminate(reason);
6779 }
6780
6781 if (m_controlledByAutomation) {
6782 if (auto* automationSession = process().processPool().automationSession())
6783 automationSession->terminate();
6784 }
6785}
6786
6787void WebPageProxy::provisionalProcessDidTerminate()
6788{
6789 ASSERT(m_provisionalPage);
6790 m_provisionalPage = nullptr;
6791}
6792
6793static bool shouldReloadAfterProcessTermination(ProcessTerminationReason reason)
6794{
6795 switch (reason) {
6796 case ProcessTerminationReason::ExceededMemoryLimit:
6797 case ProcessTerminationReason::ExceededCPULimit:
6798 case ProcessTerminationReason::Crash:
6799 return true;
6800 case ProcessTerminationReason::NavigationSwap:
6801 case ProcessTerminationReason::RequestedByClient:
6802 break;
6803 }
6804 return false;
6805}
6806
6807void WebPageProxy::dispatchProcessDidTerminate(ProcessTerminationReason reason)
6808{
6809 RELEASE_LOG_IF_ALLOWED(Loading, "dispatchProcessDidTerminate: webPID = %i, reason = %d", m_process->processIdentifier(), reason);
6810
6811 bool handledByClient = false;
6812 if (m_loaderClient)
6813 handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this);
6814 else
6815 handledByClient = m_navigationClient->processDidTerminate(*this, reason);
6816
6817 if (!handledByClient && shouldReloadAfterProcessTermination(reason))
6818 tryReloadAfterProcessTermination();
6819}
6820
6821void WebPageProxy::tryReloadAfterProcessTermination()
6822{
6823 m_resetRecentCrashCountTimer.stop();
6824
6825 if (++m_recentCrashCount > maximumWebProcessRelaunchAttempts) {
6826 RELEASE_LOG_IF_ALLOWED(Process, "tryReloadAfterProcessTermination: process crashed and the client did not handle it, not reloading the page because we reached the maximum number of attempts");
6827 m_recentCrashCount = 0;
6828 return;
6829 }
6830 RELEASE_LOG_IF_ALLOWED(Process, "tryReloadAfterProcessTermination: process crashed and the client did not handle it, reloading the page");
6831 reload(ReloadOption::ExpiredOnly);
6832}
6833
6834void WebPageProxy::resetRecentCrashCountSoon()
6835{
6836 m_resetRecentCrashCountTimer.startOneShot(resetRecentCrashCountDelay);
6837}
6838
6839void WebPageProxy::resetRecentCrashCount()
6840{
6841 m_recentCrashCount = 0;
6842}
6843
6844void WebPageProxy::stopAllURLSchemeTasks(WebProcessProxy* process)
6845{
6846 HashSet<WebURLSchemeHandler*> handlers;
6847 for (auto& handler : m_urlSchemeHandlersByScheme.values())
6848 handlers.add(handler.ptr());
6849
6850 for (auto* handler : handlers)
6851 handler->stopAllTasksForPage(*this, process);
6852}
6853
6854#if PLATFORM(IOS_FAMILY)
6855void WebPageProxy::processWillBecomeSuspended()
6856{
6857 if (!hasRunningProcess())
6858 return;
6859
6860 m_hasNetworkRequestsOnSuspended = m_pageLoadState.networkRequestsInProgress();
6861 if (m_hasNetworkRequestsOnSuspended)
6862 setNetworkRequestsInProgress(false);
6863}
6864
6865void WebPageProxy::processWillBecomeForeground()
6866{
6867 if (!hasRunningProcess())
6868 return;
6869
6870 if (m_hasNetworkRequestsOnSuspended) {
6871 setNetworkRequestsInProgress(true);
6872 m_hasNetworkRequestsOnSuspended = false;
6873 }
6874}
6875#endif
6876
6877void WebPageProxy::resetState(ResetStateReason resetStateReason)
6878{
6879 m_mainFrame = nullptr;
6880 m_focusedFrame = nullptr;
6881 m_frameSetLargestFrame = nullptr;
6882 m_lastSuspendedPage = nullptr;
6883
6884#if PLATFORM(COCOA)
6885 m_scrollingPerformanceData = nullptr;
6886#endif
6887
6888 if (m_drawingArea) {
6889#if PLATFORM(COCOA)
6890 if (resetStateReason == ResetStateReason::NavigationSwap && is<RemoteLayerTreeDrawingAreaProxy>(*m_drawingArea)) {
6891 // Keep layers around in frozen state to avoid flashing during process swaps.
6892 m_frozenRemoteLayerTreeHost = downcast<RemoteLayerTreeDrawingAreaProxy>(*m_drawingArea).detachRemoteLayerTreeHost();
6893 }
6894#endif
6895 m_drawingArea = nullptr;
6896 }
6897 closeOverlayedViews();
6898
6899 m_inspector->reset();
6900
6901#if ENABLE(FULLSCREEN_API)
6902 if (m_fullScreenManager) {
6903 m_fullScreenManager->close();
6904 m_fullScreenManager = nullptr;
6905 }
6906#endif
6907
6908 if (m_openPanelResultListener) {
6909 m_openPanelResultListener->invalidate();
6910 m_openPanelResultListener = nullptr;
6911 }
6912
6913#if ENABLE(TOUCH_EVENTS)
6914 m_touchAndPointerEventTracking.reset();
6915#endif
6916
6917#if ENABLE(GEOLOCATION)
6918 m_geolocationPermissionRequestManager.invalidateRequests();
6919#endif
6920
6921 m_notificationPermissionRequestManager.invalidateRequests();
6922
6923 m_toolTip = String();
6924
6925 m_mainFrameHasHorizontalScrollbar = false;
6926 m_mainFrameHasVerticalScrollbar = false;
6927
6928 m_mainFrameIsPinnedToLeftSide = true;
6929 m_mainFrameIsPinnedToRightSide = true;
6930 m_mainFrameIsPinnedToTopSide = true;
6931 m_mainFrameIsPinnedToBottomSide = true;
6932
6933 m_visibleScrollerThumbRect = IntRect();
6934
6935#if (PLATFORM(IOS_FAMILY) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
6936 if (m_playbackSessionManager) {
6937 m_playbackSessionManager->invalidate();
6938 m_playbackSessionManager = nullptr;
6939 }
6940 if (m_videoFullscreenManager) {
6941 m_videoFullscreenManager->invalidate();
6942 m_videoFullscreenManager = nullptr;
6943 }
6944#endif
6945
6946#if PLATFORM(IOS_FAMILY)
6947 m_firstLayerTreeTransactionIdAfterDidCommitLoad = 0;
6948 m_lastVisibleContentRectUpdate = VisibleContentRectUpdateInfo();
6949 m_hasNetworkRequestsOnSuspended = false;
6950 m_isKeyboardAnimatingIn = false;
6951 m_isScrollingOrZooming = false;
6952#endif
6953
6954#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
6955 pageClient().mediaSessionManager().removeAllPlaybackTargetPickerClients(*this);
6956#endif
6957
6958#if ENABLE(APPLE_PAY)
6959 m_paymentCoordinator = nullptr;
6960#endif
6961
6962#if USE(SYSTEM_PREVIEW)
6963 m_systemPreviewController = nullptr;
6964#endif
6965
6966#if ENABLE(WEB_AUTHN)
6967 m_credentialsMessenger = nullptr;
6968#endif
6969
6970#if HAVE(PENCILKIT)
6971 m_editableImageController = nullptr;
6972#endif
6973
6974 CallbackBase::Error error;
6975 switch (resetStateReason) {
6976 case ResetStateReason::NavigationSwap:
6977 FALLTHROUGH;
6978 case ResetStateReason::PageInvalidated:
6979 error = CallbackBase::Error::OwnerWasInvalidated;
6980 break;
6981 case ResetStateReason::WebProcessExited:
6982 error = CallbackBase::Error::ProcessExited;
6983 break;
6984 }
6985
6986 m_callbacks.invalidate(error);
6987 m_loadDependentStringCallbackIDs.clear();
6988
6989 for (auto& editCommand : std::exchange(m_editCommandSet, { }))
6990 editCommand->invalidate();
6991
6992 m_activePopupMenu = nullptr;
6993
6994 updatePlayingMediaDidChange(MediaProducer::IsNotPlaying);
6995#if ENABLE(MEDIA_STREAM)
6996 m_userMediaPermissionRequestManager = nullptr;
6997#endif
6998
6999#if ENABLE(POINTER_LOCK)
7000 requestPointerUnlock();
7001#endif
7002}
7003
7004void WebPageProxy::resetStateAfterProcessExited(ProcessTerminationReason terminationReason)
7005{
7006 if (!hasRunningProcess())
7007 return;
7008
7009 PageClientProtector protector(pageClient());
7010
7011#if !ASSERT_DISABLED
7012 // FIXME: It's weird that resetStateAfterProcessExited() is called even though the process is launching.
7013 if (terminationReason != ProcessTerminationReason::NavigationSwap)
7014 ASSERT(m_process->state() == WebProcessProxy::State::Launching || m_process->state() == WebProcessProxy::State::Terminated);
7015#endif
7016
7017#if PLATFORM(IOS_FAMILY)
7018 m_waitingForPostLayoutEditorStateUpdateAfterFocusingElement = false;
7019 m_deferredElementDidFocusArguments = nullptr;
7020 m_activityToken = nullptr;
7021#endif
7022
7023 m_pageIsUserObservableCount = nullptr;
7024 m_visiblePageToken = nullptr;
7025
7026 m_hasRunningProcess = false;
7027 m_isPageSuspended = false;
7028
7029 m_editorState = EditorState();
7030 m_cachedFontAttributesAtSelectionStart.reset();
7031
7032 if (terminationReason == ProcessTerminationReason::NavigationSwap)
7033 pageClient().processWillSwap();
7034 else
7035 pageClient().processDidExit();
7036
7037 pageClient().clearAllEditCommands();
7038
7039 auto resetStateReason = terminationReason == ProcessTerminationReason::NavigationSwap ? ResetStateReason::NavigationSwap : ResetStateReason::WebProcessExited;
7040 resetState(resetStateReason);
7041
7042 m_pendingLearnOrIgnoreWordMessageCount = 0;
7043
7044 // Can't expect DidReceiveEvent notifications from a crashed web process.
7045 m_mouseEventQueue.clear();
7046 m_keyEventQueue.clear();
7047 m_wheelEventQueue.clear();
7048 m_currentlyProcessedWheelEvents.clear();
7049#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
7050 m_touchEventQueue.clear();
7051#endif
7052
7053#if ENABLE(ATTACHMENT_ELEMENT)
7054 invalidateAllAttachments();
7055#endif
7056
7057 if (terminationReason != ProcessTerminationReason::NavigationSwap) {
7058 PageLoadState::Transaction transaction = m_pageLoadState.transaction();
7059 m_pageLoadState.reset(transaction);
7060 }
7061
7062 updatePlayingMediaDidChange(MediaProducer::IsNotPlaying);
7063
7064 // FIXME: <rdar://problem/38676604> In case of process swaps, the old process should gracefully suspend instead of terminating.
7065 m_process->processTerminated();
7066}
7067
7068WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& process, DrawingAreaProxy& drawingArea)
7069{
7070 WebPageCreationParameters parameters;
7071
7072 parameters.viewSize = pageClient().viewSize();
7073 parameters.activityState = m_activityState;
7074 parameters.drawingAreaType = drawingArea.type();
7075 parameters.drawingAreaIdentifier = drawingArea.identifier();
7076 parameters.store = preferencesStore();
7077 parameters.pageGroupData = m_pageGroup->data();
7078 parameters.isEditable = m_isEditable;
7079 parameters.underlayColor = m_underlayColor;
7080 parameters.useFixedLayout = m_useFixedLayout;
7081 parameters.fixedLayoutSize = m_fixedLayoutSize;
7082 parameters.alwaysShowsHorizontalScroller = m_alwaysShowsHorizontalScroller;
7083 parameters.alwaysShowsVerticalScroller = m_alwaysShowsVerticalScroller;
7084 parameters.suppressScrollbarAnimations = m_suppressScrollbarAnimations;
7085 parameters.paginationMode = m_paginationMode;
7086 parameters.paginationBehavesLikeColumns = m_paginationBehavesLikeColumns;
7087 parameters.pageLength = m_pageLength;
7088 parameters.gapBetweenPages = m_gapBetweenPages;
7089 parameters.paginationLineGridEnabled = m_paginationLineGridEnabled;
7090 parameters.userAgent = userAgent();
7091 parameters.itemStates = m_backForwardList->itemStates();
7092 parameters.sessionID = process.websiteDataStore().sessionID();
7093 parameters.userContentControllerID = m_userContentController->identifier();
7094 parameters.visitedLinkTableID = m_visitedLinkStore->identifier();
7095 parameters.websiteDataStoreID = process.websiteDataStore().identifier();
7096 parameters.canRunBeforeUnloadConfirmPanel = m_uiClient->canRunBeforeUnloadConfirmPanel();
7097 parameters.canRunModal = m_canRunModal;
7098 parameters.deviceScaleFactor = deviceScaleFactor();
7099 parameters.viewScaleFactor = m_viewScaleFactor;
7100 parameters.textZoomFactor = m_textZoomFactor;
7101 parameters.pageZoomFactor = m_pageZoomFactor;
7102 parameters.topContentInset = m_topContentInset;
7103 parameters.mediaVolume = m_mediaVolume;
7104 parameters.muted = m_mutedState;
7105 parameters.mayStartMediaWhenInWindow = m_mayStartMediaWhenInWindow;
7106 parameters.viewLayoutSize = m_viewLayoutSize;
7107 parameters.autoSizingShouldExpandToViewHeight = m_autoSizingShouldExpandToViewHeight;
7108 parameters.viewportSizeForCSSViewportUnits = m_viewportSizeForCSSViewportUnits;
7109 parameters.scrollPinningBehavior = m_scrollPinningBehavior;
7110 if (m_scrollbarOverlayStyle)
7111 parameters.scrollbarOverlayStyle = m_scrollbarOverlayStyle.value();
7112 else
7113 parameters.scrollbarOverlayStyle = WTF::nullopt;
7114 parameters.backgroundExtendsBeyondPage = m_backgroundExtendsBeyondPage;
7115 parameters.layerHostingMode = m_layerHostingMode;
7116 parameters.controlledByAutomation = m_controlledByAutomation;
7117 parameters.useDarkAppearance = useDarkAppearance();
7118 parameters.useInactiveAppearance = useInactiveAppearance();
7119#if PLATFORM(MAC)
7120 parameters.colorSpace = pageClient().colorSpace();
7121 parameters.useSystemAppearance = m_useSystemAppearance;
7122#endif
7123#if PLATFORM(IOS_FAMILY)
7124 parameters.screenSize = screenSize();
7125 parameters.availableScreenSize = availableScreenSize();
7126 parameters.overrideScreenSize = overrideScreenSize();
7127 parameters.textAutosizingWidth = textAutosizingWidth();
7128 parameters.mimeTypesWithCustomContentProviders = pageClient().mimeTypesWithCustomContentProviders();
7129 parameters.ignoresViewportScaleLimits = m_forceAlwaysUserScalable;
7130 parameters.viewportConfigurationViewLayoutSize = m_viewportConfigurationViewLayoutSize;
7131 parameters.viewportConfigurationLayoutSizeScaleFactor = m_viewportConfigurationLayoutSizeScaleFactor;
7132 parameters.viewportConfigurationMinimumEffectiveDeviceWidth = m_viewportConfigurationMinimumEffectiveDeviceWidth;
7133 parameters.maximumUnobscuredSize = m_maximumUnobscuredSize;
7134 parameters.deviceOrientation = m_deviceOrientation;
7135 parameters.keyboardIsAttached = isInHardwareKeyboardMode();
7136 parameters.overrideViewportArguments = m_overrideViewportArguments;
7137 parameters.canShowWhileLocked = m_configuration->canShowWhileLocked();
7138#endif
7139
7140#if PLATFORM(MAC)
7141 parameters.appleMailPaginationQuirkEnabled = appleMailPaginationQuirkEnabled();
7142#else
7143 parameters.appleMailPaginationQuirkEnabled = false;
7144#endif
7145
7146#if PLATFORM(MAC)
7147 // FIXME: Need to support iOS too, but there is no isAppleMail for iOS.
7148 parameters.appleMailLinesClampEnabled = appleMailLinesClampEnabled();
7149#else
7150 parameters.appleMailLinesClampEnabled = false;
7151#endif
7152
7153#if PLATFORM(COCOA)
7154 parameters.smartInsertDeleteEnabled = m_isSmartInsertDeleteEnabled;
7155 parameters.additionalSupportedImageTypes = m_configuration->additionalSupportedImageTypes();
7156#endif
7157 parameters.shouldScaleViewToFitDocument = m_shouldScaleViewToFitDocument;
7158 parameters.userInterfaceLayoutDirection = pageClient().userInterfaceLayoutDirection();
7159 parameters.observedLayoutMilestones = m_observedLayoutMilestones;
7160 parameters.overrideContentSecurityPolicy = m_overrideContentSecurityPolicy;
7161 parameters.cpuLimit = m_cpuLimit;
7162
7163#if PLATFORM(WPE)
7164 parameters.hostFileDescriptor = pageClient().hostFileDescriptor();
7165#endif
7166
7167 for (auto& iterator : m_urlSchemeHandlersByScheme)
7168 parameters.urlSchemeHandlers.set(iterator.key, iterator.value->identifier());
7169
7170#if ENABLE(WEB_RTC)
7171 parameters.iceCandidateFilteringEnabled = m_preferences->iceCandidateFilteringEnabled();
7172#if USE(LIBWEBRTC)
7173 parameters.enumeratingAllNetworkInterfacesEnabled = m_preferences->enumeratingAllNetworkInterfacesEnabled();
7174#endif
7175#endif
7176
7177#if ENABLE(APPLICATION_MANIFEST)
7178 parameters.applicationManifest = m_configuration->applicationManifest() ? Optional<WebCore::ApplicationManifest>(m_configuration->applicationManifest()->applicationManifest()) : WTF::nullopt;
7179#endif
7180
7181#if ENABLE(SERVICE_WORKER)
7182 parameters.hasRegisteredServiceWorkers = process.processPool().mayHaveRegisteredServiceWorkers(process.websiteDataStore());
7183#endif
7184
7185 parameters.needsFontAttributes = m_needsFontAttributes;
7186 parameters.backgroundColor = m_backgroundColor;
7187
7188 process.addWebUserContentControllerProxy(m_userContentController, parameters);
7189
7190 return parameters;
7191}
7192
7193void WebPageProxy::isJITEnabled(CompletionHandler<void(bool)>&& completionHandler)
7194{
7195 m_process->connection()->sendWithAsyncReply(Messages::WebProcess::IsJITEnabled(), WTFMove(completionHandler));
7196}
7197
7198void WebPageProxy::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
7199{
7200#if PLATFORM(MAC)
7201 ASSERT(m_drawingArea->type() == DrawingAreaTypeTiledCoreAnimation);
7202#endif
7203 pageClient().enterAcceleratedCompositingMode(layerTreeContext);
7204
7205 if (m_lastSuspendedPage)
7206 m_lastSuspendedPage->pageEnteredAcceleratedCompositingMode();
7207}
7208
7209void WebPageProxy::exitAcceleratedCompositingMode()
7210{
7211 pageClient().exitAcceleratedCompositingMode();
7212}
7213
7214void WebPageProxy::updateAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
7215{
7216 pageClient().updateAcceleratedCompositingMode(layerTreeContext);
7217}
7218
7219void WebPageProxy::backForwardClear()
7220{
7221 m_backForwardList->clear();
7222}
7223
7224#if ENABLE(GAMEPAD)
7225
7226void WebPageProxy::gamepadActivity(const Vector<GamepadData>& gamepadDatas, bool shouldMakeGamepadsVisible)
7227{
7228 m_process->send(Messages::WebPage::GamepadActivity(gamepadDatas, shouldMakeGamepadsVisible), m_pageID);
7229}
7230
7231#endif
7232
7233WeakPtr<SecKeyProxyStore> WebPageProxy::secKeyProxyStore(const WebCore::AuthenticationChallenge& challenge)
7234{
7235#if HAVE(SEC_KEY_PROXY)
7236 if (challenge.protectionSpace().authenticationScheme() == ProtectionSpaceAuthenticationSchemeClientCertificateRequested) {
7237 auto secKeyProxyStore = SecKeyProxyStore::create();
7238 auto weakPointer = makeWeakPtr(secKeyProxyStore.get());
7239 m_websiteDataStore->addSecKeyProxyStore(WTFMove(secKeyProxyStore));
7240 return weakPointer;
7241 }
7242#endif
7243 return nullptr;
7244}
7245
7246void WebPageProxy::didReceiveAuthenticationChallengeProxy(uint64_t, Ref<AuthenticationChallengeProxy>&& authenticationChallenge)
7247{
7248 m_navigationClient->didReceiveAuthenticationChallenge(*this, authenticationChallenge.get());
7249}
7250
7251void WebPageProxy::exceededDatabaseQuota(uint64_t frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, Messages::WebPageProxy::ExceededDatabaseQuota::DelayedReply&& reply)
7252{
7253 requestStorageSpace(frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, [reply = WTFMove(reply)](auto quota) mutable {
7254 reply(quota);
7255 });
7256}
7257
7258void WebPageProxy::requestStorageSpace(uint64_t frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, CompletionHandler<void(uint64_t)>&& completionHandler)
7259{
7260 StorageRequests::singleton().processOrAppend([this, protectedThis = makeRef(*this), pageURL = currentURL(), frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, completionHandler = WTFMove(completionHandler)]() mutable {
7261 this->makeStorageSpaceRequest(frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, [this, protectedThis = WTFMove(protectedThis), pageURL = WTFMove(pageURL), completionHandler = WTFMove(completionHandler), currentQuota](auto quota) mutable {
7262 if (quota <= currentQuota && this->currentURL() == pageURL)
7263 m_isQuotaIncreaseDenied = true;
7264 completionHandler(quota);
7265 StorageRequests::singleton().processNextIfAny();
7266 });
7267 });
7268}
7269
7270void WebPageProxy::makeStorageSpaceRequest(uint64_t frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, CompletionHandler<void(uint64_t)>&& completionHandler)
7271{
7272 if (m_isQuotaIncreaseDenied) {
7273 completionHandler(currentQuota);
7274 return;
7275 }
7276
7277 WebFrameProxy* frame = m_process->webFrame(frameID);
7278 MESSAGE_CHECK(m_process, frame);
7279
7280 auto originData = SecurityOriginData::fromDatabaseIdentifier(originIdentifier);
7281 if (originData != SecurityOriginData::fromURL(URL { { }, currentURL() })) {
7282 completionHandler(currentQuota);
7283 return;
7284 }
7285
7286 auto origin = API::SecurityOrigin::create(originData->securityOrigin());
7287 m_uiClient->exceededDatabaseQuota(this, frame, origin.ptr(), databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, WTFMove(completionHandler));
7288}
7289
7290void WebPageProxy::reachedApplicationCacheOriginQuota(const String& originIdentifier, uint64_t currentQuota, uint64_t totalBytesNeeded, Messages::WebPageProxy::ReachedApplicationCacheOriginQuota::DelayedReply&& reply)
7291{
7292 Ref<SecurityOrigin> securityOrigin = SecurityOriginData::fromDatabaseIdentifier(originIdentifier)->securityOrigin();
7293 m_uiClient->reachedApplicationCacheOriginQuota(this, securityOrigin.get(), currentQuota, totalBytesNeeded, WTFMove(reply));
7294}
7295
7296void WebPageProxy::requestGeolocationPermissionForFrame(uint64_t geolocationID, uint64_t frameID, String originIdentifier)
7297{
7298 WebFrameProxy* frame = m_process->webFrame(frameID);
7299 MESSAGE_CHECK(m_process, frame);
7300
7301 // FIXME: Geolocation should probably be using toString() as its string representation instead of databaseIdentifier().
7302 auto origin = API::SecurityOrigin::create(SecurityOriginData::fromDatabaseIdentifier(originIdentifier)->securityOrigin());
7303 auto request = m_geolocationPermissionRequestManager.createRequest(geolocationID);
7304 Function<void(bool)> completionHandler = [request = WTFMove(request)](bool allowed) {
7305 if (allowed)
7306 request->allow();
7307 else
7308 request->deny();
7309 };
7310
7311 // FIXME: Once iOS migrates to the new WKUIDelegate SPI, clean this up
7312 // and make it one UIClient call that calls the completionHandler with false
7313 // if there is no delegate instead of returning the completionHandler
7314 // for other code paths to try.
7315 m_uiClient->decidePolicyForGeolocationPermissionRequest(*this, *frame, origin.get(), completionHandler);
7316#if PLATFORM(IOS_FAMILY)
7317 if (completionHandler)
7318 pageClient().decidePolicyForGeolocationPermissionRequest(*frame, origin.get(), completionHandler);
7319#endif
7320 if (completionHandler)
7321 completionHandler(false);
7322}
7323
7324#if ENABLE(MEDIA_STREAM)
7325UserMediaPermissionRequestManagerProxy& WebPageProxy::userMediaPermissionRequestManager()
7326{
7327 if (m_userMediaPermissionRequestManager)
7328 return *m_userMediaPermissionRequestManager;
7329
7330 m_userMediaPermissionRequestManager = std::make_unique<UserMediaPermissionRequestManagerProxy>(*this);
7331 return *m_userMediaPermissionRequestManager;
7332}
7333#endif
7334
7335void WebPageProxy::requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginData, const WebCore::SecurityOriginData& topLevelDocumentOriginData, WebCore::MediaStreamRequest&& request)
7336{
7337#if ENABLE(MEDIA_STREAM)
7338 MESSAGE_CHECK(m_process, m_process->webFrame(frameID));
7339
7340 userMediaPermissionRequestManager().requestUserMediaPermissionForFrame(userMediaID, frameID, userMediaDocumentOriginData.securityOrigin(), topLevelDocumentOriginData.securityOrigin(), WTFMove(request));
7341#else
7342 UNUSED_PARAM(userMediaID);
7343 UNUSED_PARAM(frameID);
7344 UNUSED_PARAM(userMediaDocumentOriginData);
7345 UNUSED_PARAM(topLevelDocumentOriginData);
7346 UNUSED_PARAM(request);
7347#endif
7348}
7349
7350void WebPageProxy::enumerateMediaDevicesForFrame(uint64_t userMediaID, uint64_t frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginData, const WebCore::SecurityOriginData& topLevelDocumentOriginData)
7351{
7352#if ENABLE(MEDIA_STREAM)
7353 WebFrameProxy* frame = m_process->webFrame(frameID);
7354 MESSAGE_CHECK(m_process, frame);
7355
7356 userMediaPermissionRequestManager().enumerateMediaDevicesForFrame(userMediaID, frameID, userMediaDocumentOriginData.securityOrigin(), topLevelDocumentOriginData.securityOrigin());
7357#else
7358 UNUSED_PARAM(userMediaID);
7359 UNUSED_PARAM(frameID);
7360 UNUSED_PARAM(userMediaDocumentOriginData);
7361 UNUSED_PARAM(topLevelDocumentOriginData);
7362#endif
7363}
7364
7365void WebPageProxy::beginMonitoringCaptureDevices()
7366{
7367#if ENABLE(MEDIA_STREAM)
7368 userMediaPermissionRequestManager().syncWithWebCorePrefs();
7369 UserMediaProcessManager::singleton().beginMonitoringCaptureDevices();
7370#endif
7371}
7372
7373void WebPageProxy::clearUserMediaState()
7374{
7375#if ENABLE(MEDIA_STREAM)
7376 if (m_userMediaPermissionRequestManager)
7377 m_userMediaPermissionRequestManager->clearCachedState();
7378#endif
7379}
7380
7381#if ENABLE(DEVICE_ORIENTATION)
7382void WebPageProxy::shouldAllowDeviceOrientationAndMotionAccess(uint64_t frameID, WebCore::SecurityOriginData&& originData, bool mayPrompt, CompletionHandler<void(DeviceOrientationOrMotionPermissionState)>&& completionHandler)
7383{
7384 WebFrameProxy* frame = m_process->webFrame(frameID);
7385 MESSAGE_CHECK(m_process, frame);
7386
7387 websiteDataStore().deviceOrientationAndMotionAccessController().shouldAllowAccess(*this, *frame, WTFMove(originData), mayPrompt, WTFMove(completionHandler));
7388}
7389#endif
7390
7391void WebPageProxy::requestNotificationPermission(uint64_t requestID, const String& originString)
7392{
7393 if (!isRequestIDValid(requestID))
7394 return;
7395
7396 auto origin = API::SecurityOrigin::createFromString(originString);
7397 auto request = m_notificationPermissionRequestManager.createRequest(requestID);
7398
7399 m_uiClient->decidePolicyForNotificationPermissionRequest(*this, origin.get(), [request = WTFMove(request)](bool allowed) {
7400 if (allowed)
7401 request->allow();
7402 else
7403 request->deny();
7404 });
7405}
7406
7407void WebPageProxy::showNotification(const String& title, const String& body, const String& iconURL, const String& tag, const String& lang, WebCore::NotificationDirection dir, const String& originString, uint64_t notificationID)
7408{
7409 m_process->processPool().supplement<WebNotificationManagerProxy>()->show(this, title, body, iconURL, tag, lang, dir, originString, notificationID);
7410}
7411
7412void WebPageProxy::cancelNotification(uint64_t notificationID)
7413{
7414 m_process->processPool().supplement<WebNotificationManagerProxy>()->cancel(this, notificationID);
7415}
7416
7417void WebPageProxy::clearNotifications(const Vector<uint64_t>& notificationIDs)
7418{
7419 m_process->processPool().supplement<WebNotificationManagerProxy>()->clearNotifications(this, notificationIDs);
7420}
7421
7422void WebPageProxy::didDestroyNotification(uint64_t notificationID)
7423{
7424 m_process->processPool().supplement<WebNotificationManagerProxy>()->didDestroyNotification(this, notificationID);
7425}
7426
7427float WebPageProxy::headerHeight(WebFrameProxy& frame)
7428{
7429 if (frame.isDisplayingPDFDocument())
7430 return 0;
7431 return m_uiClient->headerHeight(*this, frame);
7432}
7433
7434float WebPageProxy::footerHeight(WebFrameProxy& frame)
7435{
7436 if (frame.isDisplayingPDFDocument())
7437 return 0;
7438 return m_uiClient->footerHeight(*this, frame);
7439}
7440
7441void WebPageProxy::drawHeader(WebFrameProxy& frame, FloatRect&& rect)
7442{
7443 if (frame.isDisplayingPDFDocument())
7444 return;
7445 m_uiClient->drawHeader(*this, frame, WTFMove(rect));
7446}
7447
7448void WebPageProxy::drawFooter(WebFrameProxy& frame, FloatRect&& rect)
7449{
7450 if (frame.isDisplayingPDFDocument())
7451 return;
7452 m_uiClient->drawFooter(*this, frame, WTFMove(rect));
7453}
7454
7455void WebPageProxy::runModal()
7456{
7457 // Since runModal() can (and probably will) spin a nested run loop we need to turn off the responsiveness timer.
7458 m_process->responsivenessTimer().stop();
7459
7460 // Our Connection's run loop might have more messages waiting to be handled after this RunModal message.
7461 // To make sure they are handled inside of the nested modal run loop we must first signal the Connection's
7462 // run loop so we're guaranteed that it has a chance to wake up.
7463 // See http://webkit.org/b/89590 for more discussion.
7464 m_process->connection()->wakeUpRunLoop();
7465
7466 m_uiClient->runModal(*this);
7467}
7468
7469void WebPageProxy::notifyScrollerThumbIsVisibleInRect(const IntRect& scrollerThumb)
7470{
7471 m_visibleScrollerThumbRect = scrollerThumb;
7472}
7473
7474void WebPageProxy::recommendedScrollbarStyleDidChange(int32_t newStyle)
7475{
7476#if USE(APPKIT)
7477 pageClient().recommendedScrollbarStyleDidChange(static_cast<WebCore::ScrollbarStyle>(newStyle));
7478#else
7479 UNUSED_PARAM(newStyle);
7480#endif
7481}
7482
7483void WebPageProxy::didChangeScrollbarsForMainFrame(bool hasHorizontalScrollbar, bool hasVerticalScrollbar)
7484{
7485 m_mainFrameHasHorizontalScrollbar = hasHorizontalScrollbar;
7486 m_mainFrameHasVerticalScrollbar = hasVerticalScrollbar;
7487}
7488
7489void WebPageProxy::didChangeScrollOffsetPinningForMainFrame(bool pinnedToLeftSide, bool pinnedToRightSide, bool pinnedToTopSide, bool pinnedToBottomSide)
7490{
7491 pageClient().pinnedStateWillChange();
7492 m_mainFrameIsPinnedToLeftSide = pinnedToLeftSide;
7493 m_mainFrameIsPinnedToRightSide = pinnedToRightSide;
7494 m_mainFrameIsPinnedToTopSide = pinnedToTopSide;
7495 m_mainFrameIsPinnedToBottomSide = pinnedToBottomSide;
7496 pageClient().pinnedStateDidChange();
7497
7498 m_uiClient->pinnedStateDidChange(*this);
7499}
7500
7501void WebPageProxy::didChangePageCount(unsigned pageCount)
7502{
7503 m_pageCount = pageCount;
7504}
7505
7506void WebPageProxy::pageExtendedBackgroundColorDidChange(const Color& backgroundColor)
7507{
7508 m_pageExtendedBackgroundColor = backgroundColor;
7509}
7510
7511#if ENABLE(NETSCAPE_PLUGIN_API)
7512void WebPageProxy::didFailToInitializePlugin(const String& mimeType, const String& frameURLString, const String& pageURLString)
7513{
7514 m_navigationClient->didFailToInitializePlugIn(*this, createPluginInformationDictionary(mimeType, frameURLString, pageURLString).get());
7515}
7516
7517void WebPageProxy::didBlockInsecurePluginVersion(const String& mimeType, const String& pluginURLString, const String& frameURLString, const String& pageURLString, bool replacementObscured)
7518{
7519 String newMimeType = mimeType;
7520 PluginModuleInfo plugin = m_process->processPool().pluginInfoStore().findPlugin(newMimeType, URL(URL(), pluginURLString));
7521 auto pluginInformation = createPluginInformationDictionary(plugin, frameURLString, mimeType, pageURLString, String(), String(), replacementObscured);
7522
7523 m_navigationClient->didBlockInsecurePluginVersion(*this, pluginInformation.get());
7524}
7525#endif // ENABLE(NETSCAPE_PLUGIN_API)
7526
7527bool WebPageProxy::willHandleHorizontalScrollEvents() const
7528{
7529 return !m_canShortCircuitHorizontalWheelEvents;
7530}
7531
7532void WebPageProxy::updateWebsitePolicies(WebsitePoliciesData&& websitePolicies)
7533{
7534 m_process->send(Messages::WebPage::UpdateWebsitePolicies(websitePolicies), m_pageID);
7535}
7536
7537void WebPageProxy::didFinishLoadingDataForCustomContentProvider(const String& suggestedFilename, const IPC::DataReference& dataReference)
7538{
7539 pageClient().didFinishLoadingDataForCustomContentProvider(suggestedFilename, dataReference);
7540}
7541
7542void WebPageProxy::backForwardRemovedItem(const BackForwardItemIdentifier& itemID)
7543{
7544 m_process->send(Messages::WebPage::DidRemoveBackForwardItem(itemID), m_pageID);
7545}
7546
7547void WebPageProxy::setCanRunModal(bool canRunModal)
7548{
7549 // It's only possible to change the state for a WebPage which
7550 // already qualifies for running modal child web pages, otherwise
7551 // there's no other possibility than not allowing it.
7552 m_canRunModal = m_uiClient->canRunModal() && canRunModal;
7553
7554 if (!hasRunningProcess())
7555 return;
7556
7557 m_process->send(Messages::WebPage::SetCanRunModal(m_canRunModal), m_pageID);
7558}
7559
7560bool WebPageProxy::canRunModal()
7561{
7562 return hasRunningProcess() ? m_canRunModal : false;
7563}
7564
7565void WebPageProxy::beginPrinting(WebFrameProxy* frame, const PrintInfo& printInfo)
7566{
7567 if (m_isInPrintingMode)
7568 return;
7569
7570 m_isInPrintingMode = true;
7571 m_process->send(Messages::WebPage::BeginPrinting(frame->frameID(), printInfo), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation));
7572}
7573
7574void WebPageProxy::endPrinting()
7575{
7576 if (!m_isInPrintingMode)
7577 return;
7578
7579 m_isInPrintingMode = false;
7580 m_process->send(Messages::WebPage::EndPrinting(), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation));
7581}
7582
7583void WebPageProxy::computePagesForPrinting(WebFrameProxy* frame, const PrintInfo& printInfo, Ref<ComputedPagesCallback>&& callback)
7584{
7585 if (!hasRunningProcess()) {
7586 callback->invalidate();
7587 return;
7588 }
7589
7590 auto callbackID = callback->callbackID();
7591 m_callbacks.put(WTFMove(callback));
7592 m_isInPrintingMode = true;
7593 m_process->send(Messages::WebPage::ComputePagesForPrinting(frame->frameID(), printInfo, callbackID), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation));
7594}
7595
7596#if PLATFORM(COCOA)
7597void WebPageProxy::drawRectToImage(WebFrameProxy* frame, const PrintInfo& printInfo, const IntRect& rect, const WebCore::IntSize& imageSize, Ref<ImageCallback>&& callback)
7598{
7599 if (!hasRunningProcess()) {
7600 callback->invalidate();
7601 return;
7602 }
7603
7604 auto callbackID = callback->callbackID();
7605 m_callbacks.put(WTFMove(callback));
7606 m_process->send(Messages::WebPage::DrawRectToImage(frame->frameID(), printInfo, rect, imageSize, callbackID), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation));
7607}
7608
7609void WebPageProxy::drawPagesToPDF(WebFrameProxy* frame, const PrintInfo& printInfo, uint32_t first, uint32_t count, Ref<DataCallback>&& callback)
7610{
7611 if (!hasRunningProcess()) {
7612 callback->invalidate();
7613 return;
7614 }
7615
7616 auto callbackID = callback->callbackID();
7617 m_callbacks.put(WTFMove(callback));
7618 m_process->send(Messages::WebPage::DrawPagesToPDF(frame->frameID(), printInfo, first, count, callbackID), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation));
7619}
7620#elif PLATFORM(GTK)
7621void WebPageProxy::drawPagesForPrinting(WebFrameProxy* frame, const PrintInfo& printInfo, Ref<PrintFinishedCallback>&& callback)
7622{
7623 if (!hasRunningProcess()) {
7624 callback->invalidate();
7625 return;
7626 }
7627
7628 auto callbackID = callback->callbackID();
7629 m_callbacks.put(WTFMove(callback));
7630 m_isInPrintingMode = true;
7631 m_process->send(Messages::WebPage::DrawPagesForPrinting(frame->frameID(), printInfo, callbackID), m_pageID, printingSendOptions(m_isPerformingDOMPrintOperation));
7632}
7633#endif
7634
7635void WebPageProxy::updateBackingStoreDiscardableState()
7636{
7637 ASSERT(hasRunningProcess());
7638
7639 if (!m_drawingArea)
7640 return;
7641
7642 bool isDiscardable;
7643
7644 if (!m_process->isResponsive())
7645 isDiscardable = false;
7646 else
7647 isDiscardable = !pageClient().isViewWindowActive() || !isViewVisible();
7648
7649 m_drawingArea->setBackingStoreIsDiscardable(isDiscardable);
7650}
7651
7652void WebPageProxy::saveDataToFileInDownloadsFolder(String&& suggestedFilename, String&& mimeType, URL&& originatingURLString, API::Data& data)
7653{
7654 m_uiClient->saveDataToFileInDownloadsFolder(this, suggestedFilename, mimeType, originatingURLString, data);
7655}
7656
7657void WebPageProxy::savePDFToFileInDownloadsFolder(String&& suggestedFilename, URL&& originatingURL, const IPC::DataReference& dataReference)
7658{
7659 if (!suggestedFilename.endsWithIgnoringASCIICase(".pdf"))
7660 return;
7661
7662 saveDataToFileInDownloadsFolder(WTFMove(suggestedFilename), "application/pdf"_s, WTFMove(originatingURL),
7663 API::Data::create(dataReference.data(), dataReference.size()).get());
7664}
7665
7666void WebPageProxy::setViewLayoutSize(const IntSize& viewLayoutSize)
7667{
7668 if (m_viewLayoutSize == viewLayoutSize)
7669 return;
7670
7671 m_viewLayoutSize = viewLayoutSize;
7672
7673 if (!hasRunningProcess())
7674 return;
7675
7676 m_process->send(Messages::WebPage::SetViewLayoutSize(viewLayoutSize), m_pageID);
7677 m_drawingArea->viewLayoutSizeDidChange();
7678
7679#if USE(APPKIT)
7680 if (m_viewLayoutSize.width() <= 0)
7681 didChangeIntrinsicContentSize(IntSize(-1, -1));
7682#endif
7683}
7684
7685void WebPageProxy::setAutoSizingShouldExpandToViewHeight(bool shouldExpand)
7686{
7687 if (m_autoSizingShouldExpandToViewHeight == shouldExpand)
7688 return;
7689
7690 m_autoSizingShouldExpandToViewHeight = shouldExpand;
7691
7692 if (!hasRunningProcess())
7693 return;
7694
7695 m_process->send(Messages::WebPage::SetAutoSizingShouldExpandToViewHeight(shouldExpand), m_pageID);
7696}
7697
7698void WebPageProxy::setViewportSizeForCSSViewportUnits(const IntSize& viewportSize)
7699{
7700 if (m_viewportSizeForCSSViewportUnits && *m_viewportSizeForCSSViewportUnits == viewportSize)
7701 return;
7702
7703 m_viewportSizeForCSSViewportUnits = viewportSize;
7704
7705 if (!hasRunningProcess())
7706 return;
7707
7708 m_process->send(Messages::WebPage::SetViewportSizeForCSSViewportUnits(viewportSize), m_pageID);
7709}
7710
7711#if USE(AUTOMATIC_TEXT_REPLACEMENT)
7712
7713void WebPageProxy::toggleSmartInsertDelete()
7714{
7715 if (TextChecker::isTestingMode())
7716 TextChecker::setSmartInsertDeleteEnabled(!TextChecker::isSmartInsertDeleteEnabled());
7717}
7718
7719void WebPageProxy::toggleAutomaticQuoteSubstitution()
7720{
7721 if (TextChecker::isTestingMode())
7722 TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled);
7723}
7724
7725void WebPageProxy::toggleAutomaticLinkDetection()
7726{
7727 if (TextChecker::isTestingMode())
7728 TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled);
7729}
7730
7731void WebPageProxy::toggleAutomaticDashSubstitution()
7732{
7733 if (TextChecker::isTestingMode())
7734 TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled);
7735}
7736
7737void WebPageProxy::toggleAutomaticTextReplacement()
7738{
7739 if (TextChecker::isTestingMode())
7740 TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled);
7741}
7742
7743#endif
7744
7745#if PLATFORM(MAC)
7746
7747void WebPageProxy::substitutionsPanelIsShowing(CompletionHandler<void(bool)>&& completionHandler)
7748{
7749 completionHandler(TextChecker::substitutionsPanelIsShowing());
7750}
7751
7752void WebPageProxy::showCorrectionPanel(int32_t panelType, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings)
7753{
7754 // FIXME: Make AlternativeTextType an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
7755 pageClient().showCorrectionPanel((AlternativeTextType)panelType, boundingBoxOfReplacedString, replacedString, replacementString, alternativeReplacementStrings);
7756}
7757
7758void WebPageProxy::dismissCorrectionPanel(int32_t reason)
7759{
7760 // FIXME: Make ReasonForDismissingAlternativeText an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
7761 pageClient().dismissCorrectionPanel((ReasonForDismissingAlternativeText)reason);
7762}
7763
7764void WebPageProxy::dismissCorrectionPanelSoon(int32_t reason, CompletionHandler<void(String)>&& completionHandler)
7765{
7766 // FIXME: Make ReasonForDismissingAlternativeText an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
7767 completionHandler(pageClient().dismissCorrectionPanelSoon((ReasonForDismissingAlternativeText)reason));
7768}
7769
7770void WebPageProxy::recordAutocorrectionResponse(int32_t response, const String& replacedString, const String& replacementString)
7771{
7772 // FIXME: Make AutocorrectionResponse an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
7773 pageClient().recordAutocorrectionResponse(static_cast<AutocorrectionResponse>(response), replacedString, replacementString);
7774}
7775
7776void WebPageProxy::handleAlternativeTextUIResult(const String& result)
7777{
7778 if (!isClosed())
7779 m_process->send(Messages::WebPage::HandleAlternativeTextUIResult(result), m_pageID);
7780}
7781
7782#if USE(DICTATION_ALTERNATIVES)
7783void WebPageProxy::showDictationAlternativeUI(const WebCore::FloatRect& boundingBoxOfDictatedText, uint64_t dictationContext)
7784{
7785 pageClient().showDictationAlternativeUI(boundingBoxOfDictatedText, dictationContext);
7786}
7787
7788void WebPageProxy::removeDictationAlternatives(uint64_t dictationContext)
7789{
7790 pageClient().removeDictationAlternatives(dictationContext);
7791}
7792
7793void WebPageProxy::dictationAlternatives(uint64_t dictationContext, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
7794{
7795 completionHandler(pageClient().dictationAlternatives(dictationContext));
7796}
7797#endif
7798
7799void WebPageProxy::setEditableElementIsFocused(bool editableElementIsFocused)
7800{
7801 pageClient().setEditableElementIsFocused(editableElementIsFocused);
7802}
7803
7804#endif // PLATFORM(MAC)
7805
7806#if PLATFORM(COCOA) || PLATFORM(GTK)
7807RefPtr<ViewSnapshot> WebPageProxy::takeViewSnapshot()
7808{
7809 return pageClient().takeViewSnapshot();
7810}
7811#endif
7812
7813#if PLATFORM(GTK)
7814void WebPageProxy::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd)
7815{
7816 // FIXME: We need to find out how to proper handle the crashes case.
7817 if (!hasRunningProcess())
7818 return;
7819
7820 process().send(Messages::WebPage::SetComposition(text, underlines, selectionStart, selectionEnd, replacementRangeStart, replacementRangeEnd), m_pageID);
7821}
7822
7823void WebPageProxy::confirmComposition(const String& compositionString, int64_t selectionStart, int64_t selectionLength)
7824{
7825 if (!hasRunningProcess())
7826 return;
7827
7828 process().send(Messages::WebPage::ConfirmComposition(compositionString, selectionStart, selectionLength), m_pageID);
7829}
7830
7831void WebPageProxy::cancelComposition()
7832{
7833 if (!hasRunningProcess())
7834 return;
7835
7836 process().send(Messages::WebPage::CancelComposition(), m_pageID);
7837}
7838#endif // PLATFORM(GTK)
7839
7840void WebPageProxy::didSaveToPageCache()
7841{
7842 m_process->didSaveToPageCache();
7843}
7844
7845void WebPageProxy::setScrollPinningBehavior(ScrollPinningBehavior pinning)
7846{
7847 if (m_scrollPinningBehavior == pinning)
7848 return;
7849
7850 m_scrollPinningBehavior = pinning;
7851
7852 if (hasRunningProcess())
7853 m_process->send(Messages::WebPage::SetScrollPinningBehavior(pinning), m_pageID);
7854}
7855
7856void WebPageProxy::setOverlayScrollbarStyle(Optional<WebCore::ScrollbarOverlayStyle> scrollbarStyle)
7857{
7858 if (!m_scrollbarOverlayStyle && !scrollbarStyle)
7859 return;
7860
7861 if ((m_scrollbarOverlayStyle && scrollbarStyle) && m_scrollbarOverlayStyle.value() == scrollbarStyle.value())
7862 return;
7863
7864 m_scrollbarOverlayStyle = scrollbarStyle;
7865
7866 Optional<uint32_t> scrollbarStyleForMessage;
7867 if (scrollbarStyle)
7868 scrollbarStyleForMessage = static_cast<ScrollbarOverlayStyle>(scrollbarStyle.value());
7869
7870 if (hasRunningProcess())
7871 m_process->send(Messages::WebPage::SetScrollbarOverlayStyle(scrollbarStyleForMessage), m_pageID);
7872}
7873
7874#if ENABLE(WEB_CRYPTO)
7875void WebPageProxy::wrapCryptoKey(const Vector<uint8_t>& key, CompletionHandler<void(bool, Vector<uint8_t>&&)>&& completionHandler)
7876{
7877 PageClientProtector protector(pageClient());
7878
7879 Vector<uint8_t> masterKey;
7880
7881 if (auto keyData = m_navigationClient->webCryptoMasterKey(*this))
7882 masterKey = keyData->dataReference().vector();
7883
7884 Vector<uint8_t> wrappedKey;
7885 bool succeeded = wrapSerializedCryptoKey(masterKey, key, wrappedKey);
7886 completionHandler(succeeded, WTFMove(wrappedKey));
7887}
7888
7889void WebPageProxy::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, CompletionHandler<void(bool, Vector<uint8_t>&&)>&& completionHandler)
7890{
7891 PageClientProtector protector(pageClient());
7892
7893 Vector<uint8_t> masterKey;
7894
7895 if (auto keyData = m_navigationClient->webCryptoMasterKey(*this))
7896 masterKey = keyData->dataReference().vector();
7897
7898 Vector<uint8_t> key;
7899 bool succeeded = unwrapSerializedCryptoKey(masterKey, wrappedKey, key);
7900 completionHandler(succeeded, WTFMove(key));
7901}
7902#endif
7903
7904void WebPageProxy::signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challengeString, const URL& url, CompletionHandler<void(String)>&& completionHandler)
7905{
7906 PageClientProtector protector(pageClient());
7907
7908 if (auto apiString = m_navigationClient->signedPublicKeyAndChallengeString(*this, keySizeIndex, API::String::create(challengeString), url))
7909 return completionHandler(apiString->string());
7910
7911 completionHandler({ });
7912}
7913
7914void WebPageProxy::addMIMETypeWithCustomContentProvider(const String& mimeType)
7915{
7916 m_process->send(Messages::WebPage::AddMIMETypeWithCustomContentProvider(mimeType), m_pageID);
7917}
7918
7919void WebPageProxy::changeFontAttributes(WebCore::FontAttributeChanges&& changes)
7920{
7921 if (!hasRunningProcess())
7922 return;
7923
7924 process().send(Messages::WebPage::ChangeFontAttributes(WTFMove(changes)), m_pageID);
7925}
7926
7927void WebPageProxy::changeFont(WebCore::FontChanges&& changes)
7928{
7929 if (!hasRunningProcess())
7930 return;
7931
7932 process().send(Messages::WebPage::ChangeFont(WTFMove(changes)), m_pageID);
7933}
7934
7935#if PLATFORM(COCOA)
7936
7937void WebPageProxy::setTextAsync(const String& text)
7938{
7939 if (hasRunningProcess())
7940 process().send(Messages::WebPage::SetTextAsync(text), m_pageID);
7941}
7942
7943void WebPageProxy::insertTextAsync(const String& text, const EditingRange& replacementRange, InsertTextOptions&& options)
7944{
7945 if (!hasRunningProcess())
7946 return;
7947
7948 process().send(Messages::WebPage::InsertTextAsync(text, replacementRange, WTFMove(options)), m_pageID);
7949}
7950
7951void WebPageProxy::getMarkedRangeAsync(WTF::Function<void (EditingRange, CallbackBase::Error)>&& callbackFunction)
7952{
7953 if (!hasRunningProcess()) {
7954 callbackFunction(EditingRange(), CallbackBase::Error::Unknown);
7955 return;
7956 }
7957
7958 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
7959 process().send(Messages::WebPage::GetMarkedRangeAsync(callbackID), m_pageID);
7960}
7961
7962void WebPageProxy::getSelectedRangeAsync(WTF::Function<void (EditingRange, CallbackBase::Error)>&& callbackFunction)
7963{
7964 if (!hasRunningProcess()) {
7965 callbackFunction(EditingRange(), CallbackBase::Error::Unknown);
7966 return;
7967 }
7968
7969 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
7970 process().send(Messages::WebPage::GetSelectedRangeAsync(callbackID), m_pageID);
7971}
7972
7973void WebPageProxy::characterIndexForPointAsync(const WebCore::IntPoint& point, WTF::Function<void (uint64_t, CallbackBase::Error)>&& callbackFunction)
7974{
7975 if (!hasRunningProcess()) {
7976 callbackFunction(0, CallbackBase::Error::Unknown);
7977 return;
7978 }
7979
7980 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
7981 process().send(Messages::WebPage::CharacterIndexForPointAsync(point, callbackID), m_pageID);
7982}
7983
7984void WebPageProxy::firstRectForCharacterRangeAsync(const EditingRange& range, WTF::Function<void (const WebCore::IntRect&, const EditingRange&, CallbackBase::Error)>&& callbackFunction)
7985{
7986 if (!hasRunningProcess()) {
7987 callbackFunction(WebCore::IntRect(), EditingRange(), CallbackBase::Error::Unknown);
7988 return;
7989 }
7990
7991 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
7992 process().send(Messages::WebPage::FirstRectForCharacterRangeAsync(range, callbackID), m_pageID);
7993}
7994
7995void WebPageProxy::setCompositionAsync(const String& text, const Vector<CompositionUnderline>& underlines, const EditingRange& selectionRange, const EditingRange& replacementRange)
7996{
7997 if (!hasRunningProcess()) {
7998 // If this fails, we should call -discardMarkedText on input context to notify the input method.
7999 // This will happen naturally later, as part of reloading the page.
8000 return;
8001 }
8002
8003 process().send(Messages::WebPage::SetCompositionAsync(text, underlines, selectionRange, replacementRange), m_pageID);
8004}
8005
8006void WebPageProxy::confirmCompositionAsync()
8007{
8008 if (!hasRunningProcess())
8009 return;
8010
8011 process().send(Messages::WebPage::ConfirmCompositionAsync(), m_pageID);
8012}
8013
8014void WebPageProxy::setScrollPerformanceDataCollectionEnabled(bool enabled)
8015{
8016 if (enabled == m_scrollPerformanceDataCollectionEnabled)
8017 return;
8018
8019 m_scrollPerformanceDataCollectionEnabled = enabled;
8020
8021 if (m_scrollPerformanceDataCollectionEnabled && !m_scrollingPerformanceData)
8022 m_scrollingPerformanceData = std::make_unique<RemoteLayerTreeScrollingPerformanceData>(downcast<RemoteLayerTreeDrawingAreaProxy>(*m_drawingArea));
8023 else if (!m_scrollPerformanceDataCollectionEnabled)
8024 m_scrollingPerformanceData = nullptr;
8025}
8026#endif
8027
8028void WebPageProxy::takeSnapshot(IntRect rect, IntSize bitmapSize, SnapshotOptions options, WTF::Function<void (const ShareableBitmap::Handle&, CallbackBase::Error)>&& callbackFunction)
8029{
8030 if (!hasRunningProcess()) {
8031 callbackFunction(ShareableBitmap::Handle(), CallbackBase::Error::Unknown);
8032 return;
8033 }
8034
8035 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
8036 m_process->send(Messages::WebPage::TakeSnapshot(rect, bitmapSize, options, callbackID), m_pageID);
8037}
8038
8039void WebPageProxy::navigationGestureDidBegin()
8040{
8041 PageClientProtector protector(pageClient());
8042
8043 m_isShowingNavigationGestureSnapshot = true;
8044 pageClient().navigationGestureDidBegin();
8045
8046 m_navigationClient->didBeginNavigationGesture(*this);
8047}
8048
8049void WebPageProxy::navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem& item)
8050{
8051 PageClientProtector protector(pageClient());
8052
8053 pageClient().navigationGestureWillEnd(willNavigate, item);
8054
8055 m_navigationClient->willEndNavigationGesture(*this, willNavigate, item);
8056}
8057
8058void WebPageProxy::navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem& item)
8059{
8060 PageClientProtector protector(pageClient());
8061
8062 pageClient().navigationGestureDidEnd(willNavigate, item);
8063
8064 m_navigationClient->didEndNavigationGesture(*this, willNavigate, item);
8065}
8066
8067void WebPageProxy::navigationGestureDidEnd()
8068{
8069 PageClientProtector protector(pageClient());
8070
8071 pageClient().navigationGestureDidEnd();
8072}
8073
8074void WebPageProxy::willRecordNavigationSnapshot(WebBackForwardListItem& item)
8075{
8076 PageClientProtector protector(pageClient());
8077
8078 pageClient().willRecordNavigationSnapshot(item);
8079}
8080
8081void WebPageProxy::navigationGestureSnapshotWasRemoved()
8082{
8083 m_isShowingNavigationGestureSnapshot = false;
8084
8085 // The ViewGestureController may call this method on a WebPageProxy whose view has been destroyed. In such case,
8086 // we need to return early as the pageClient will not be valid below.
8087 if (m_isClosed)
8088 return;
8089
8090 pageClient().didRemoveNavigationGestureSnapshot();
8091
8092 m_navigationClient->didRemoveNavigationGestureSnapshot(*this);
8093}
8094
8095void WebPageProxy::isPlayingMediaDidChange(MediaProducer::MediaStateFlags newState, uint64_t sourceElementID)
8096{
8097#if ENABLE(MEDIA_SESSION)
8098 WebMediaSessionFocusManager* focusManager = process().processPool().supplement<WebMediaSessionFocusManager>();
8099 ASSERT(focusManager);
8100 focusManager->updatePlaybackAttributesFromMediaState(this, sourceElementID, newState);
8101#endif
8102 if (!m_isClosed)
8103 updatePlayingMediaDidChange(newState);
8104}
8105
8106void WebPageProxy::updatePlayingMediaDidChange(MediaProducer::MediaStateFlags newState)
8107{
8108 if (newState == m_mediaState)
8109 return;
8110
8111#if ENABLE(MEDIA_STREAM)
8112 WebCore::MediaProducer::MediaStateFlags oldMediaCaptureState = m_mediaState & WebCore::MediaProducer::MediaCaptureMask;
8113 WebCore::MediaProducer::MediaStateFlags newMediaCaptureState = newState & WebCore::MediaProducer::MediaCaptureMask;
8114#endif
8115
8116 MediaProducer::MediaStateFlags playingMediaMask = MediaProducer::IsPlayingAudio | MediaProducer::IsPlayingVideo;
8117 MediaProducer::MediaStateFlags oldState = m_mediaState;
8118
8119 bool playingAudioChanges = (oldState & MediaProducer::IsPlayingAudio) != (newState & MediaProducer::IsPlayingAudio);
8120 if (playingAudioChanges)
8121 pageClient().isPlayingAudioWillChange();
8122 m_mediaState = newState;
8123 if (playingAudioChanges)
8124 pageClient().isPlayingAudioDidChange();
8125
8126#if ENABLE(MEDIA_STREAM)
8127 if (oldMediaCaptureState != newMediaCaptureState) {
8128 m_uiClient->mediaCaptureStateDidChange(m_mediaState);
8129 m_userMediaPermissionRequestManager->captureStateChanged(oldMediaCaptureState, newMediaCaptureState);
8130 }
8131#endif
8132
8133 activityStateDidChange({ ActivityState::IsAudible, ActivityState::IsCapturingMedia });
8134
8135 playingMediaMask |= WebCore::MediaProducer::MediaCaptureMask;
8136 if ((oldState & playingMediaMask) != (m_mediaState & playingMediaMask))
8137 m_uiClient->isPlayingMediaDidChange(*this);
8138
8139 if ((oldState & MediaProducer::HasAudioOrVideo) != (m_mediaState & MediaProducer::HasAudioOrVideo))
8140 videoControlsManagerDidChange();
8141
8142 m_process->webPageMediaStateDidChange(*this);
8143}
8144
8145void WebPageProxy::videoControlsManagerDidChange()
8146{
8147 pageClient().videoControlsManagerDidChange();
8148}
8149
8150bool WebPageProxy::hasActiveVideoForControlsManager() const
8151{
8152#if (PLATFORM(IOS_FAMILY) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
8153 return m_playbackSessionManager && m_playbackSessionManager->controlsManagerInterface();
8154#else
8155 return false;
8156#endif
8157}
8158
8159void WebPageProxy::requestControlledElementID() const
8160{
8161#if (PLATFORM(IOS_FAMILY) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
8162 if (m_playbackSessionManager)
8163 m_playbackSessionManager->requestControlledElementID();
8164#endif
8165}
8166
8167void WebPageProxy::handleControlledElementIDResponse(const String& identifier) const
8168{
8169#if PLATFORM(MAC)
8170 pageClient().handleControlledElementIDResponse(identifier);
8171#endif
8172}
8173
8174bool WebPageProxy::isPlayingVideoInEnhancedFullscreen() const
8175{
8176#if (PLATFORM(IOS_FAMILY) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
8177 return m_videoFullscreenManager && m_videoFullscreenManager->isPlayingVideoInEnhancedFullscreen();
8178#else
8179 return false;
8180#endif
8181}
8182
8183#if PLATFORM(COCOA)
8184void WebPageProxy::requestActiveNowPlayingSessionInfo(Ref<NowPlayingInfoCallback>&& callback)
8185{
8186 if (!hasRunningProcess()) {
8187 callback->invalidate();
8188 return;
8189 }
8190
8191 auto callbackID = callback->callbackID();
8192 m_callbacks.put(WTFMove(callback));
8193
8194 m_process->send(Messages::WebPage::RequestActiveNowPlayingSessionInfo(callbackID), m_pageID);
8195}
8196
8197void WebPageProxy::nowPlayingInfoCallback(bool hasActiveSession, bool registeredAsNowPlayingApplication, const String& title, double duration, double elapsedTime, uint64_t uniqueIdentifier, CallbackID callbackID)
8198{
8199 auto callback = m_callbacks.take<NowPlayingInfoCallback>(callbackID);
8200 if (!callback) {
8201 // FIXME: Log error or assert.
8202 return;
8203 }
8204
8205 callback->performCallbackWithReturnValue(hasActiveSession, registeredAsNowPlayingApplication, title, duration, elapsedTime, uniqueIdentifier);
8206}
8207#endif
8208
8209#if ENABLE(MEDIA_SESSION)
8210void WebPageProxy::hasMediaSessionWithActiveMediaElementsDidChange(bool state)
8211{
8212 m_hasMediaSessionWithActiveMediaElements = state;
8213}
8214
8215void WebPageProxy::mediaSessionMetadataDidChange(const WebCore::MediaSessionMetadata& metadata)
8216{
8217 Ref<WebMediaSessionMetadata> webMetadata = WebMediaSessionMetadata::create(metadata);
8218 m_uiClient->mediaSessionMetadataDidChange(*this, webMetadata.ptr());
8219}
8220
8221void WebPageProxy::focusedContentMediaElementDidChange(uint64_t elementID)
8222{
8223 WebMediaSessionFocusManager* focusManager = process().processPool().supplement<WebMediaSessionFocusManager>();
8224 ASSERT(focusManager);
8225 focusManager->setFocusedMediaElement(*this, elementID);
8226}
8227#endif
8228
8229void WebPageProxy::handleAutoplayEvent(WebCore::AutoplayEvent event, OptionSet<AutoplayEventFlags> flags)
8230{
8231 m_uiClient->handleAutoplayEvent(*this, event, flags);
8232}
8233
8234#if PLATFORM(MAC)
8235void WebPageProxy::performImmediateActionHitTestAtLocation(FloatPoint point)
8236{
8237 m_process->send(Messages::WebPage::PerformImmediateActionHitTestAtLocation(point), m_pageID);
8238}
8239
8240void WebPageProxy::immediateActionDidUpdate()
8241{
8242 m_process->send(Messages::WebPage::ImmediateActionDidUpdate(), m_pageID);
8243}
8244
8245void WebPageProxy::immediateActionDidCancel()
8246{
8247 m_process->send(Messages::WebPage::ImmediateActionDidCancel(), m_pageID);
8248}
8249
8250void WebPageProxy::immediateActionDidComplete()
8251{
8252 m_process->send(Messages::WebPage::ImmediateActionDidComplete(), m_pageID);
8253}
8254
8255void WebPageProxy::didPerformImmediateActionHitTest(const WebHitTestResultData& result, bool contentPreventsDefault, const UserData& userData)
8256{
8257 pageClient().didPerformImmediateActionHitTest(result, contentPreventsDefault, m_process->transformHandlesToObjects(userData.object()).get());
8258}
8259
8260NSObject *WebPageProxy::immediateActionAnimationControllerForHitTestResult(RefPtr<API::HitTestResult> hitTestResult, uint64_t type, RefPtr<API::Object> userData)
8261{
8262 return pageClient().immediateActionAnimationControllerForHitTestResult(hitTestResult, type, userData);
8263}
8264
8265void WebPageProxy::handleAcceptedCandidate(WebCore::TextCheckingResult acceptedCandidate)
8266{
8267 m_process->send(Messages::WebPage::HandleAcceptedCandidate(acceptedCandidate), m_pageID);
8268}
8269
8270void WebPageProxy::didHandleAcceptedCandidate()
8271{
8272 pageClient().didHandleAcceptedCandidate();
8273}
8274
8275void WebPageProxy::setUseSystemAppearance(bool useSystemAppearance)
8276{
8277 if (useSystemAppearance == m_useSystemAppearance)
8278 return;
8279
8280 m_useSystemAppearance = useSystemAppearance;
8281
8282 if (!hasRunningProcess())
8283 return;
8284
8285 m_process->send(Messages::WebPage::SetUseSystemAppearance(useSystemAppearance), m_pageID);
8286}
8287
8288void WebPageProxy::setHeaderBannerHeightForTesting(int height)
8289{
8290 m_process->send(Messages::WebPage::SetHeaderBannerHeightForTesting(height), m_pageID);
8291}
8292
8293void WebPageProxy::setFooterBannerHeightForTesting(int height)
8294{
8295 m_process->send(Messages::WebPage::SetFooterBannerHeightForTesting(height), m_pageID);
8296}
8297
8298#endif
8299
8300void WebPageProxy::installActivityStateChangeCompletionHandler(Function<void()>&& completionHandler)
8301{
8302 if (!hasRunningProcess()) {
8303 completionHandler();
8304 return;
8305 }
8306
8307 auto voidCallback = VoidCallback::create([completionHandler = WTFMove(completionHandler)] (auto) {
8308 completionHandler();
8309 }, m_process->throttler().backgroundActivityToken());
8310 auto callbackID = m_callbacks.put(WTFMove(voidCallback));
8311 m_nextActivityStateChangeCallbacks.append(callbackID);
8312}
8313
8314void WebPageProxy::imageOrMediaDocumentSizeChanged(const WebCore::IntSize& newSize)
8315{
8316 m_uiClient->imageOrMediaDocumentSizeChanged(newSize);
8317}
8318
8319void WebPageProxy::setShouldDispatchFakeMouseMoveEvents(bool shouldDispatchFakeMouseMoveEvents)
8320{
8321 m_process->send(Messages::WebPage::SetShouldDispatchFakeMouseMoveEvents(shouldDispatchFakeMouseMoveEvents), m_pageID);
8322}
8323
8324void WebPageProxy::handleAutoFillButtonClick(const UserData& userData)
8325{
8326 m_uiClient->didClickAutoFillButton(*this, m_process->transformHandlesToObjects(userData.object()).get());
8327}
8328
8329void WebPageProxy::didResignInputElementStrongPasswordAppearance(const UserData& userData)
8330{
8331 m_uiClient->didResignInputElementStrongPasswordAppearance(*this, m_process->transformHandlesToObjects(userData.object()).get());
8332}
8333
8334#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
8335void WebPageProxy::addPlaybackTargetPickerClient(uint64_t contextId)
8336{
8337 pageClient().mediaSessionManager().addPlaybackTargetPickerClient(*this, contextId);
8338}
8339
8340void WebPageProxy::removePlaybackTargetPickerClient(uint64_t contextId)
8341{
8342 pageClient().mediaSessionManager().removePlaybackTargetPickerClient(*this, contextId);
8343}
8344
8345void WebPageProxy::showPlaybackTargetPicker(uint64_t contextId, const WebCore::FloatRect& rect, bool hasVideo)
8346{
8347 pageClient().mediaSessionManager().showPlaybackTargetPicker(*this, contextId, pageClient().rootViewToScreen(IntRect(rect)), hasVideo, useDarkAppearance());
8348}
8349
8350void WebPageProxy::playbackTargetPickerClientStateDidChange(uint64_t contextId, WebCore::MediaProducer::MediaStateFlags state)
8351{
8352 pageClient().mediaSessionManager().clientStateDidChange(*this, contextId, state);
8353}
8354
8355void WebPageProxy::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
8356{
8357 pageClient().mediaSessionManager().setMockMediaPlaybackTargetPickerEnabled(enabled);
8358}
8359
8360void WebPageProxy::setMockMediaPlaybackTargetPickerState(const String& name, WebCore::MediaPlaybackTargetContext::State state)
8361{
8362 pageClient().mediaSessionManager().setMockMediaPlaybackTargetPickerState(name, state);
8363}
8364
8365void WebPageProxy::setPlaybackTarget(uint64_t contextId, Ref<MediaPlaybackTarget>&& target)
8366{
8367 if (!hasRunningProcess())
8368 return;
8369
8370 m_process->send(Messages::WebPage::PlaybackTargetSelected(contextId, target->targetContext()), m_pageID);
8371}
8372
8373void WebPageProxy::externalOutputDeviceAvailableDidChange(uint64_t contextId, bool available)
8374{
8375 if (!hasRunningProcess())
8376 return;
8377
8378 m_process->send(Messages::WebPage::PlaybackTargetAvailabilityDidChange(contextId, available), m_pageID);
8379}
8380
8381void WebPageProxy::setShouldPlayToPlaybackTarget(uint64_t contextId, bool shouldPlay)
8382{
8383 if (!hasRunningProcess())
8384 return;
8385
8386 m_process->send(Messages::WebPage::SetShouldPlayToPlaybackTarget(contextId, shouldPlay), m_pageID);
8387}
8388#endif
8389
8390void WebPageProxy::didExceedInactiveMemoryLimitWhileActive()
8391{
8392 RELEASE_LOG_IF_ALLOWED(PerformanceLogging, "didExceedInactiveMemoryLimitWhileActive");
8393 m_uiClient->didExceedBackgroundResourceLimitWhileInForeground(*this, kWKResourceLimitMemory);
8394}
8395
8396void WebPageProxy::didExceedBackgroundCPULimitWhileInForeground()
8397{
8398 RELEASE_LOG_IF_ALLOWED(PerformanceLogging, "didExceedBackgroundCPULimitWhileInForeground");
8399 m_uiClient->didExceedBackgroundResourceLimitWhileInForeground(*this, kWKResourceLimitCPU);
8400}
8401
8402void WebPageProxy::didChangeBackgroundColor()
8403{
8404 pageClient().didChangeBackgroundColor();
8405}
8406
8407void WebPageProxy::clearWheelEventTestTrigger()
8408{
8409 if (!hasRunningProcess())
8410 return;
8411
8412 m_process->send(Messages::WebPage::ClearWheelEventTestTrigger(), m_pageID);
8413}
8414
8415void WebPageProxy::callAfterNextPresentationUpdate(WTF::Function<void (CallbackBase::Error)>&& callback)
8416{
8417 if (!hasRunningProcess() || !m_drawingArea) {
8418 callback(CallbackBase::Error::OwnerWasInvalidated);
8419 return;
8420 }
8421
8422 m_drawingArea->dispatchAfterEnsuringDrawing(WTFMove(callback));
8423}
8424
8425void WebPageProxy::setShouldScaleViewToFitDocument(bool shouldScaleViewToFitDocument)
8426{
8427 if (m_shouldScaleViewToFitDocument == shouldScaleViewToFitDocument)
8428 return;
8429
8430 m_shouldScaleViewToFitDocument = shouldScaleViewToFitDocument;
8431
8432 if (!hasRunningProcess())
8433 return;
8434
8435 m_process->send(Messages::WebPage::SetShouldScaleViewToFitDocument(shouldScaleViewToFitDocument), m_pageID);
8436}
8437
8438void WebPageProxy::didRestoreScrollPosition()
8439{
8440 pageClient().didRestoreScrollPosition();
8441}
8442
8443void WebPageProxy::getLoadDecisionForIcon(const WebCore::LinkIcon& icon, CallbackID loadIdentifier)
8444{
8445 m_iconLoadingClient->getLoadDecisionForIcon(icon, [this, protectedThis = RefPtr<WebPageProxy>(this), loadIdentifier](WTF::Function<void (API::Data*, CallbackBase::Error)>&& callbackFunction) {
8446 if (!hasRunningProcess()) {
8447 if (callbackFunction)
8448 callbackFunction(nullptr, CallbackBase::Error::Unknown);
8449 return;
8450 }
8451
8452 bool decision = (bool)callbackFunction;
8453 auto newCallbackIdentifier = decision ? OptionalCallbackID(m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken())) : OptionalCallbackID();
8454
8455 m_process->send(Messages::WebPage::DidGetLoadDecisionForIcon(decision, loadIdentifier, newCallbackIdentifier), m_pageID);
8456 });
8457}
8458
8459void WebPageProxy::finishedLoadingIcon(CallbackID callbackID, const IPC::DataReference& data)
8460{
8461 dataCallback(data, callbackID);
8462}
8463
8464void WebPageProxy::setResourceCachingDisabled(bool disabled)
8465{
8466 if (m_isResourceCachingDisabled == disabled)
8467 return;
8468
8469 m_isResourceCachingDisabled = disabled;
8470
8471 if (!hasRunningProcess())
8472 return;
8473
8474 m_process->send(Messages::WebPage::SetResourceCachingDisabled(disabled), m_pageID);
8475}
8476
8477WebCore::UserInterfaceLayoutDirection WebPageProxy::userInterfaceLayoutDirection()
8478{
8479 return pageClient().userInterfaceLayoutDirection();
8480}
8481
8482void WebPageProxy::setUserInterfaceLayoutDirection(WebCore::UserInterfaceLayoutDirection userInterfaceLayoutDirection)
8483{
8484 if (!hasRunningProcess())
8485 return;
8486
8487 m_process->send(Messages::WebPage::SetUserInterfaceLayoutDirection(static_cast<uint32_t>(userInterfaceLayoutDirection)), m_pageID);
8488}
8489
8490void WebPageProxy::hideValidationMessage()
8491{
8492#if PLATFORM(COCOA)
8493 m_validationBubble = nullptr;
8494#endif
8495}
8496
8497// FIXME: Consolidate with dismissContentRelativeChildWindows
8498void WebPageProxy::closeOverlayedViews()
8499{
8500 hideValidationMessage();
8501
8502#if ENABLE(DATALIST_ELEMENT)
8503 endDataListSuggestions();
8504#endif
8505
8506#if ENABLE(INPUT_TYPE_COLOR)
8507 endColorPicker();
8508#endif
8509}
8510
8511#if ENABLE(POINTER_LOCK)
8512void WebPageProxy::requestPointerLock()
8513{
8514 ASSERT(!m_isPointerLockPending);
8515 ASSERT(!m_isPointerLocked);
8516 m_isPointerLockPending = true;
8517
8518 if (!isViewVisible() || !(m_activityState & ActivityState::IsFocused)) {
8519 didDenyPointerLock();
8520 return;
8521 }
8522 m_uiClient->requestPointerLock(this);
8523}
8524
8525void WebPageProxy::didAllowPointerLock()
8526{
8527 ASSERT(m_isPointerLockPending && !m_isPointerLocked);
8528 m_isPointerLocked = true;
8529 m_isPointerLockPending = false;
8530#if PLATFORM(MAC)
8531 CGDisplayHideCursor(CGMainDisplayID());
8532 CGAssociateMouseAndMouseCursorPosition(false);
8533#endif
8534 m_process->send(Messages::WebPage::DidAcquirePointerLock(), m_pageID);
8535}
8536
8537void WebPageProxy::didDenyPointerLock()
8538{
8539 ASSERT(m_isPointerLockPending && !m_isPointerLocked);
8540 m_isPointerLockPending = false;
8541 m_process->send(Messages::WebPage::DidNotAcquirePointerLock(), m_pageID);
8542}
8543
8544void WebPageProxy::requestPointerUnlock()
8545{
8546 if (m_isPointerLocked) {
8547#if PLATFORM(MAC)
8548 CGAssociateMouseAndMouseCursorPosition(true);
8549 CGDisplayShowCursor(CGMainDisplayID());
8550#endif
8551 m_uiClient->didLosePointerLock(this);
8552 m_process->send(Messages::WebPage::DidLosePointerLock(), m_pageID);
8553 }
8554
8555 if (m_isPointerLockPending) {
8556 m_uiClient->didLosePointerLock(this);
8557 m_process->send(Messages::WebPage::DidNotAcquirePointerLock(), m_pageID);
8558 }
8559
8560 m_isPointerLocked = false;
8561 m_isPointerLockPending = false;
8562}
8563#endif
8564
8565void WebPageProxy::setURLSchemeHandlerForScheme(Ref<WebURLSchemeHandler>&& handler, const String& scheme)
8566{
8567 auto canonicalizedScheme = WTF::URLParser::maybeCanonicalizeScheme(scheme);
8568 ASSERT(canonicalizedScheme);
8569 ASSERT(!WTF::URLParser::isSpecialScheme(canonicalizedScheme.value()));
8570
8571 auto schemeResult = m_urlSchemeHandlersByScheme.add(canonicalizedScheme.value(), handler.get());
8572 ASSERT_UNUSED(schemeResult, schemeResult.isNewEntry);
8573
8574 auto identifier = handler->identifier();
8575 auto identifierResult = m_urlSchemeHandlersByIdentifier.add(identifier, WTFMove(handler));
8576 ASSERT_UNUSED(identifierResult, identifierResult.isNewEntry);
8577
8578 m_process->send(Messages::WebPage::RegisterURLSchemeHandler(identifier, canonicalizedScheme.value()), m_pageID);
8579}
8580
8581WebURLSchemeHandler* WebPageProxy::urlSchemeHandlerForScheme(const String& scheme)
8582{
8583 return scheme.isNull() ? nullptr : m_urlSchemeHandlersByScheme.get(scheme);
8584}
8585
8586void WebPageProxy::startURLSchemeTask(URLSchemeTaskParameters&& parameters)
8587{
8588 startURLSchemeTaskShared(m_process.copyRef(), WTFMove(parameters));
8589}
8590
8591void WebPageProxy::startURLSchemeTaskShared(Ref<WebProcessProxy>&& process, URLSchemeTaskParameters&& parameters)
8592{
8593 auto iterator = m_urlSchemeHandlersByIdentifier.find(parameters.handlerIdentifier);
8594 MESSAGE_CHECK(process, iterator != m_urlSchemeHandlersByIdentifier.end());
8595
8596 iterator->value->startTask(*this, process, parameters.taskIdentifier, WTFMove(parameters.request), nullptr);
8597}
8598
8599void WebPageProxy::stopURLSchemeTask(uint64_t handlerIdentifier, uint64_t taskIdentifier)
8600{
8601 auto iterator = m_urlSchemeHandlersByIdentifier.find(handlerIdentifier);
8602 MESSAGE_CHECK(m_process, iterator != m_urlSchemeHandlersByIdentifier.end());
8603
8604 iterator->value->stopTask(*this, taskIdentifier);
8605}
8606
8607void WebPageProxy::loadSynchronousURLSchemeTask(URLSchemeTaskParameters&& parameters, Messages::WebPageProxy::LoadSynchronousURLSchemeTask::DelayedReply&& reply)
8608{
8609 auto iterator = m_urlSchemeHandlersByIdentifier.find(parameters.handlerIdentifier);
8610 MESSAGE_CHECK(m_process, iterator != m_urlSchemeHandlersByIdentifier.end());
8611
8612 iterator->value->startTask(*this, m_process, parameters.taskIdentifier, WTFMove(parameters.request), WTFMove(reply));
8613}
8614
8615#if ENABLE(RESOURCE_LOAD_STATISTICS)
8616void WebPageProxy::requestStorageAccessConfirm(const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, uint64_t frameID, CompletionHandler<void(bool)>&& completionHandler)
8617{
8618 m_uiClient->requestStorageAccessConfirm(*this, m_process->webFrame(frameID), subFrameDomain, topFrameDomain, WTFMove(completionHandler));
8619}
8620#endif
8621
8622bool WebPageProxy::useDarkAppearance() const
8623{
8624 return pageClient().effectiveAppearanceIsDark();
8625}
8626
8627bool WebPageProxy::useInactiveAppearance() const
8628{
8629 return pageClient().effectiveAppearanceIsInactive();
8630}
8631
8632void WebPageProxy::effectiveAppearanceDidChange()
8633{
8634 if (!hasRunningProcess())
8635 return;
8636
8637 m_process->send(Messages::WebPage::EffectiveAppearanceDidChange(useDarkAppearance(), useInactiveAppearance()), m_pageID);
8638}
8639
8640#if PLATFORM(COCOA)
8641void WebPageProxy::touchBarMenuDataChanged(const TouchBarMenuData& touchBarMenuData)
8642{
8643 m_touchBarMenuData = touchBarMenuData;
8644}
8645
8646void WebPageProxy::touchBarMenuItemDataAdded(const TouchBarMenuItemData& touchBarMenuItemData)
8647{
8648 m_touchBarMenuData.addMenuItem(touchBarMenuItemData);
8649}
8650
8651void WebPageProxy::touchBarMenuItemDataRemoved(const TouchBarMenuItemData& touchBarMenuItemData)
8652{
8653 m_touchBarMenuData.removeMenuItem(touchBarMenuItemData);
8654}
8655#endif
8656
8657#if ENABLE(ATTACHMENT_ELEMENT)
8658
8659RefPtr<API::Attachment> WebPageProxy::attachmentForIdentifier(const String& identifier) const
8660{
8661 if (identifier.isEmpty())
8662 return nullptr;
8663
8664 return m_attachmentIdentifierToAttachmentMap.get(identifier);
8665}
8666
8667void WebPageProxy::insertAttachment(Ref<API::Attachment>&& attachment, Function<void(CallbackBase::Error)>&& callback)
8668{
8669 if (!hasRunningProcess()) {
8670 callback(CallbackBase::Error::OwnerWasInvalidated);
8671 return;
8672 }
8673
8674 auto attachmentIdentifier = attachment->identifier();
8675 auto callbackID = m_callbacks.put(WTFMove(callback), m_process->throttler().backgroundActivityToken());
8676 m_process->send(Messages::WebPage::InsertAttachment(attachmentIdentifier, attachment->fileSizeForDisplay(), attachment->fileName(), attachment->contentType(), callbackID), m_pageID);
8677 m_attachmentIdentifierToAttachmentMap.set(attachmentIdentifier, WTFMove(attachment));
8678}
8679
8680void WebPageProxy::updateAttachmentAttributes(const API::Attachment& attachment, Function<void(CallbackBase::Error)>&& callback)
8681{
8682 if (!hasRunningProcess()) {
8683 callback(CallbackBase::Error::OwnerWasInvalidated);
8684 return;
8685 }
8686
8687 IPC::SharedBufferDataReference dataReference;
8688 if (auto data = attachment.enclosingImageData())
8689 dataReference = { *data };
8690
8691 auto callbackID = m_callbacks.put(WTFMove(callback), m_process->throttler().backgroundActivityToken());
8692 m_process->send(Messages::WebPage::UpdateAttachmentAttributes(attachment.identifier(), attachment.fileSizeForDisplay(), attachment.contentType(), attachment.fileName(), WTFMove(dataReference), callbackID), m_pageID);
8693}
8694
8695void WebPageProxy::registerAttachmentIdentifierFromData(const String& identifier, const String& contentType, const String& preferredFileName, const IPC::DataReference& data)
8696{
8697 if (attachmentForIdentifier(identifier))
8698 return;
8699
8700 auto attachment = ensureAttachment(identifier);
8701 attachment->setContentType(contentType);
8702 m_attachmentIdentifierToAttachmentMap.set(identifier, attachment.copyRef());
8703
8704 platformRegisterAttachment(WTFMove(attachment), preferredFileName, data);
8705}
8706
8707void WebPageProxy::registerAttachmentIdentifierFromFilePath(const String& identifier, const String& contentType, const String& filePath)
8708{
8709 if (attachmentForIdentifier(identifier))
8710 return;
8711
8712 auto attachment = ensureAttachment(identifier);
8713 attachment->setContentType(contentType);
8714 attachment->setFilePath(filePath);
8715 m_attachmentIdentifierToAttachmentMap.set(identifier, attachment.copyRef());
8716
8717 platformRegisterAttachment(WTFMove(attachment), filePath);
8718}
8719
8720void WebPageProxy::registerAttachmentIdentifier(const String& identifier)
8721{
8722 if (!attachmentForIdentifier(identifier))
8723 m_attachmentIdentifierToAttachmentMap.set(identifier, ensureAttachment(identifier));
8724}
8725
8726void WebPageProxy::registerAttachmentsFromSerializedData(Vector<WebCore::SerializedAttachmentData>&& data)
8727{
8728 for (auto& serializedData : data) {
8729 auto identifier = WTFMove(serializedData.identifier);
8730 if (!attachmentForIdentifier(identifier))
8731 ensureAttachment(identifier)->updateFromSerializedRepresentation(WTFMove(serializedData.data), WTFMove(serializedData.mimeType));
8732 }
8733}
8734
8735void WebPageProxy::cloneAttachmentData(const String& fromIdentifier, const String& toIdentifier)
8736{
8737 auto newAttachment = ensureAttachment(toIdentifier);
8738 auto existingAttachment = attachmentForIdentifier(fromIdentifier);
8739 if (!existingAttachment) {
8740 ASSERT_NOT_REACHED();
8741 return;
8742 }
8743
8744 newAttachment->setContentType(existingAttachment->contentType());
8745 newAttachment->setFilePath(existingAttachment->filePath());
8746
8747 platformCloneAttachment(existingAttachment.releaseNonNull(), WTFMove(newAttachment));
8748}
8749
8750void WebPageProxy::invalidateAllAttachments()
8751{
8752 for (auto& attachment : m_attachmentIdentifierToAttachmentMap.values()) {
8753 if (attachment->insertionState() == API::Attachment::InsertionState::Inserted)
8754 didRemoveAttachment(attachment.get());
8755 attachment->invalidate();
8756 }
8757 m_attachmentIdentifierToAttachmentMap.clear();
8758}
8759
8760void WebPageProxy::serializedAttachmentDataForIdentifiers(const Vector<String>& identifiers, CompletionHandler<void(Vector<WebCore::SerializedAttachmentData>&&)>&& completionHandler)
8761{
8762 Vector<WebCore::SerializedAttachmentData> serializedData;
8763 for (const auto& identifier : identifiers) {
8764 auto attachment = attachmentForIdentifier(identifier);
8765 if (!attachment)
8766 continue;
8767
8768 auto data = attachment->createSerializedRepresentation();
8769 if (!data)
8770 continue;
8771
8772 serializedData.append({ identifier, attachment->mimeType(), data.releaseNonNull() });
8773 }
8774 completionHandler(WTFMove(serializedData));
8775}
8776
8777void WebPageProxy::didInvalidateDataForAttachment(API::Attachment& attachment)
8778{
8779 pageClient().didInvalidateDataForAttachment(attachment);
8780}
8781
8782WebPageProxy::ShouldUpdateAttachmentAttributes WebPageProxy::willUpdateAttachmentAttributes(const API::Attachment& attachment)
8783{
8784#if HAVE(PENCILKIT)
8785 return m_editableImageController->willUpdateAttachmentAttributes(attachment);
8786#else
8787 return ShouldUpdateAttachmentAttributes::Yes;
8788#endif
8789}
8790
8791#if !PLATFORM(COCOA)
8792
8793void WebPageProxy::platformRegisterAttachment(Ref<API::Attachment>&&, const String&, const IPC::DataReference&)
8794{
8795}
8796
8797void WebPageProxy::platformRegisterAttachment(Ref<API::Attachment>&&, const String&)
8798{
8799}
8800
8801void WebPageProxy::platformCloneAttachment(Ref<API::Attachment>&&, Ref<API::Attachment>&&)
8802{
8803}
8804
8805#endif
8806
8807void WebPageProxy::didInsertAttachmentWithIdentifier(const String& identifier, const String& source, bool hasEnclosingImage)
8808{
8809 auto attachment = ensureAttachment(identifier);
8810 attachment->setHasEnclosingImage(hasEnclosingImage);
8811 attachment->setInsertionState(API::Attachment::InsertionState::Inserted);
8812 pageClient().didInsertAttachment(attachment.get(), source);
8813
8814 if (!attachment->isEmpty() && hasEnclosingImage)
8815 updateAttachmentAttributes(attachment.get(), [] (auto) { });
8816}
8817
8818void WebPageProxy::didRemoveAttachmentWithIdentifier(const String& identifier)
8819{
8820 if (auto attachment = attachmentForIdentifier(identifier))
8821 didRemoveAttachment(*attachment);
8822}
8823
8824void WebPageProxy::didRemoveAttachment(API::Attachment& attachment)
8825{
8826 attachment.setInsertionState(API::Attachment::InsertionState::NotInserted);
8827 pageClient().didRemoveAttachment(attachment);
8828}
8829
8830Ref<API::Attachment> WebPageProxy::ensureAttachment(const String& identifier)
8831{
8832 if (auto existingAttachment = attachmentForIdentifier(identifier))
8833 return *existingAttachment;
8834
8835 auto attachment = API::Attachment::create(identifier, *this);
8836 m_attachmentIdentifierToAttachmentMap.set(identifier, attachment.copyRef());
8837 return attachment;
8838}
8839
8840#endif // ENABLE(ATTACHMENT_ELEMENT)
8841
8842#if ENABLE(APPLICATION_MANIFEST)
8843void WebPageProxy::getApplicationManifest(Function<void(const Optional<WebCore::ApplicationManifest>&, CallbackBase::Error)>&& callbackFunction)
8844{
8845 if (!hasRunningProcess()) {
8846 callbackFunction(WTF::nullopt, CallbackBase::Error::Unknown);
8847 return;
8848 }
8849
8850 auto callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
8851 m_loadDependentStringCallbackIDs.add(callbackID);
8852 m_process->send(Messages::WebPage::GetApplicationManifest(callbackID), m_pageID);
8853}
8854#endif
8855
8856namespace {
8857enum class CompletionCondition {
8858 Cancellation,
8859 Error,
8860 Success,
8861 Timeout,
8862};
8863struct MessageType {
8864 CompletionCondition condition;
8865 Seconds seconds;
8866 String message;
8867};
8868}
8869
8870void WebPageProxy::reportPageLoadResult(const ResourceError& error)
8871{
8872 static const NeverDestroyed<Vector<MessageType>> messages(std::initializer_list<MessageType> {
8873 { CompletionCondition::Cancellation, 2_s, DiagnosticLoggingKeys::canceledLessThan2SecondsKey() },
8874 { CompletionCondition::Cancellation, 5_s, DiagnosticLoggingKeys::canceledLessThan5SecondsKey() },
8875 { CompletionCondition::Cancellation, 20_s, DiagnosticLoggingKeys::canceledLessThan20SecondsKey() },
8876 { CompletionCondition::Cancellation, Seconds::infinity(), DiagnosticLoggingKeys::canceledMoreThan20SecondsKey() },
8877
8878 { CompletionCondition::Error, 2_s, DiagnosticLoggingKeys::failedLessThan2SecondsKey() },
8879 { CompletionCondition::Error, 5_s, DiagnosticLoggingKeys::failedLessThan5SecondsKey() },
8880 { CompletionCondition::Error, 20_s, DiagnosticLoggingKeys::failedLessThan20SecondsKey() },
8881 { CompletionCondition::Error, Seconds::infinity(), DiagnosticLoggingKeys::failedMoreThan20SecondsKey() },
8882
8883 { CompletionCondition::Success, 2_s, DiagnosticLoggingKeys::succeededLessThan2SecondsKey() },
8884 { CompletionCondition::Success, 5_s, DiagnosticLoggingKeys::succeededLessThan5SecondsKey() },
8885 { CompletionCondition::Success, 20_s, DiagnosticLoggingKeys::succeededLessThan20SecondsKey() },
8886 { CompletionCondition::Success, Seconds::infinity(), DiagnosticLoggingKeys::succeededMoreThan20SecondsKey() },
8887
8888 { CompletionCondition::Timeout, Seconds::infinity(), DiagnosticLoggingKeys::timedOutKey() }
8889 });
8890
8891 if (!m_pageLoadStart)
8892 return;
8893
8894 auto pageLoadTime = MonotonicTime::now() - *m_pageLoadStart;
8895 m_pageLoadStart = WTF::nullopt;
8896
8897 CompletionCondition condition { CompletionCondition::Success };
8898 if (error.isCancellation())
8899 condition = CompletionCondition::Cancellation;
8900 else if (error.isTimeout())
8901 condition = CompletionCondition::Timeout;
8902 else if (!error.isNull() || error.errorCode())
8903 condition = CompletionCondition::Error;
8904
8905 for (auto& messageItem : messages.get()) {
8906 if (condition == messageItem.condition && pageLoadTime < messageItem.seconds) {
8907 logDiagnosticMessage(DiagnosticLoggingKeys::telemetryPageLoadKey(), messageItem.message, ShouldSample::No);
8908 logDiagnosticMessage(DiagnosticLoggingKeys::telemetryPageLoadKey(), DiagnosticLoggingKeys::occurredKey(), ShouldSample::No);
8909 break;
8910 }
8911 }
8912}
8913
8914void WebPageProxy::setDefersLoadingForTesting(bool defersLoading)
8915{
8916 m_process->send(Messages::WebPage::SetDefersLoading(defersLoading), m_pageID);
8917}
8918
8919void WebPageProxy::getIsViewVisible(bool& result)
8920{
8921 result = isViewVisible();
8922}
8923
8924void WebPageProxy::updateCurrentModifierState()
8925{
8926#if PLATFORM(MAC) && ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING) || PLATFORM(IOS_FAMILY)
8927 auto modifiers = PlatformKeyboardEvent::currentStateOfModifierKeys();
8928 m_process->send(Messages::WebPage::UpdateCurrentModifierState(modifiers), m_pageID);
8929#endif
8930}
8931
8932bool WebPageProxy::checkURLReceivedFromCurrentOrPreviousWebProcess(WebProcessProxy& process, const String& urlString)
8933{
8934 return checkURLReceivedFromCurrentOrPreviousWebProcess(process, URL(URL(), urlString));
8935}
8936
8937bool WebPageProxy::checkURLReceivedFromCurrentOrPreviousWebProcess(WebProcessProxy& process, const URL& url)
8938{
8939 if (!url.isLocalFile())
8940 return true;
8941
8942 if (m_mayHaveUniversalFileReadSandboxExtension)
8943 return true;
8944
8945 String path = url.fileSystemPath();
8946 auto startsWithURLPath = [&path](const String& visitedPath) {
8947 return path.startsWith(visitedPath);
8948 };
8949
8950 auto localPathsEnd = m_previouslyVisitedPaths.end();
8951 if (std::find_if(m_previouslyVisitedPaths.begin(), localPathsEnd, startsWithURLPath) != localPathsEnd)
8952 return true;
8953
8954 return process.checkURLReceivedFromWebProcess(url);
8955}
8956
8957void WebPageProxy::addPreviouslyVisitedPath(const String& path)
8958{
8959 m_previouslyVisitedPaths.add(path);
8960}
8961
8962void WebPageProxy::willAcquireUniversalFileReadSandboxExtension(WebProcessProxy& process)
8963{
8964 m_mayHaveUniversalFileReadSandboxExtension = true;
8965 process.willAcquireUniversalFileReadSandboxExtension();
8966}
8967
8968void WebPageProxy::simulateDeviceOrientationChange(double alpha, double beta, double gamma)
8969{
8970 m_process->send(Messages::WebPage::SimulateDeviceOrientationChange(alpha, beta, gamma), m_pageID);
8971}
8972
8973#if ENABLE(DATA_DETECTION)
8974
8975void WebPageProxy::detectDataInAllFrames(WebCore::DataDetectorTypes types, CompletionHandler<void(const DataDetectionResult&)>&& completionHandler)
8976{
8977 m_process->connection()->sendWithAsyncReply(Messages::WebPage::DetectDataInAllFrames(static_cast<uint64_t>(types)), WTFMove(completionHandler), m_pageID);
8978}
8979
8980void WebPageProxy::removeDataDetectedLinks(CompletionHandler<void(const DataDetectionResult&)>&& completionHandler)
8981{
8982 m_process->connection()->sendWithAsyncReply(Messages::WebPage::RemoveDataDetectedLinks(), WTFMove(completionHandler), m_pageID);
8983}
8984
8985#endif
8986
8987void WebPageProxy::dumpAdClickAttribution(CompletionHandler<void(const String&)>&& completionHandler)
8988{
8989 if (auto* networkProcess = m_process->processPool().networkProcess()) {
8990 if (!networkProcess->canSendMessage()) {
8991 completionHandler(emptyString());
8992 return;
8993 }
8994 networkProcess->sendWithAsyncReply(Messages::NetworkProcess::DumpAdClickAttribution(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
8995 }
8996}
8997
8998void WebPageProxy::clearAdClickAttribution(CompletionHandler<void()>&& completionHandler)
8999{
9000 if (auto* networkProcess = m_process->processPool().networkProcess()) {
9001 if (!networkProcess->canSendMessage()) {
9002 completionHandler();
9003 return;
9004 }
9005 networkProcess->sendWithAsyncReply(Messages::NetworkProcess::ClearAdClickAttribution(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
9006 }
9007}
9008
9009void WebPageProxy::setAdClickAttributionOverrideTimerForTesting(bool value, CompletionHandler<void()>&& completionHandler)
9010{
9011 if (auto* networkProcess = m_process->processPool().networkProcess()) {
9012 if (!networkProcess->canSendMessage()) {
9013 completionHandler();
9014 return;
9015 }
9016 networkProcess->sendWithAsyncReply(Messages::NetworkProcess::SetAdClickAttributionOverrideTimerForTesting(m_websiteDataStore->sessionID(), value), WTFMove(completionHandler));
9017 }
9018}
9019
9020void WebPageProxy::setAdClickAttributionConversionURLForTesting(const URL& url, CompletionHandler<void()>&& completionHandler)
9021{
9022 if (auto* networkProcess = m_process->processPool().networkProcess()) {
9023 if (!networkProcess->canSendMessage()) {
9024 completionHandler();
9025 return;
9026 }
9027 networkProcess->sendWithAsyncReply(Messages::NetworkProcess::SetAdClickAttributionConversionURLForTesting(m_websiteDataStore->sessionID(), url), WTFMove(completionHandler));
9028 }
9029}
9030
9031void WebPageProxy::markAdClickAttributionsAsExpiredForTesting(CompletionHandler<void()>&& completionHandler)
9032{
9033 if (auto* networkProcess = m_process->processPool().networkProcess()) {
9034 if (!networkProcess->canSendMessage()) {
9035 completionHandler();
9036 return;
9037 }
9038 networkProcess->sendWithAsyncReply(Messages::NetworkProcess::MarkAdClickAttributionsAsExpiredForTesting(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
9039 }
9040}
9041
9042#if ENABLE(SPEECH_SYNTHESIS)
9043WebPageProxy::SpeechSynthesisData& WebPageProxy::speechSynthesisData()
9044{
9045 if (!m_speechSynthesisData)
9046 m_speechSynthesisData = SpeechSynthesisData { std::make_unique<PlatformSpeechSynthesizer>(this), nullptr, nullptr, nullptr, nullptr };
9047 return *m_speechSynthesisData;
9048}
9049
9050void WebPageProxy::speechSynthesisVoiceList(CompletionHandler<void(Vector<WebSpeechSynthesisVoice>&&)>&& completionHandler)
9051{
9052 auto& voiceList = speechSynthesisData().synthesizer->voiceList();
9053 Vector<WebSpeechSynthesisVoice> result;
9054 result.reserveInitialCapacity(voiceList.size());
9055 for (auto& voice : voiceList)
9056 result.uncheckedAppend(WebSpeechSynthesisVoice { voice->voiceURI(), voice->name(), voice->lang(), voice->localService(), voice->isDefault() });
9057 completionHandler(WTFMove(result));
9058}
9059
9060void WebPageProxy::speechSynthesisSpeak(const String& text, const String& lang, float volume, float rate, float pitch, MonotonicTime startTime, const String& voiceURI, const String& voiceName, const String& voiceLang, bool localService, bool defaultVoice, CompletionHandler<void()>&& completionHandler)
9061{
9062 auto voice = WebCore::PlatformSpeechSynthesisVoice::create(voiceURI, voiceName, voiceLang, localService, defaultVoice);
9063 auto utterance = WebCore::PlatformSpeechSynthesisUtterance::create(*this);
9064 utterance->setText(text);
9065 utterance->setLang(lang);
9066 utterance->setVolume(volume);
9067 utterance->setRate(rate);
9068 utterance->setPitch(pitch);
9069 utterance->setVoice(&voice.get());
9070
9071 speechSynthesisData().utterance = WTFMove(utterance);
9072 speechSynthesisData().speakingFinishedCompletionHandler = WTFMove(completionHandler);
9073 speechSynthesisData().synthesizer->speak(m_speechSynthesisData->utterance.get());
9074}
9075
9076void WebPageProxy::speechSynthesisCancel()
9077{
9078 speechSynthesisData().synthesizer->cancel();
9079}
9080
9081void WebPageProxy::speechSynthesisPause(CompletionHandler<void()>&& completionHandler)
9082{
9083 speechSynthesisData().speakingPausedCompletionHandler = WTFMove(completionHandler);
9084 speechSynthesisData().synthesizer->pause();
9085}
9086
9087void WebPageProxy::speechSynthesisResume(CompletionHandler<void()>&& completionHandler)
9088{
9089 speechSynthesisData().speakingResumedCompletionHandler = WTFMove(completionHandler);
9090 speechSynthesisData().synthesizer->resume();
9091}
9092#endif // ENABLE(SPEECH_SYNTHESIS)
9093
9094#if !PLATFORM(IOS_FAMILY) || !USE(APPLE_INTERNAL_SDK)
9095
9096WebCompatibilityMode WebPageProxy::effectiveCompatibilityModeAfterAdjustingPolicies(API::WebsitePolicies&, const WebCore::ResourceRequest&)
9097{
9098 return WebCompatibilityMode::Recommended;
9099}
9100
9101#endif // !PLATFORM(IOS_FAMILY) || !USE(APPLE_INTERNAL_SDK)
9102
9103void WebPageProxy::addObserver(WebViewDidMoveToWindowObserver& observer)
9104{
9105 auto result = m_webViewDidMoveToWindowObservers.add(&observer, makeWeakPtr(observer));
9106 ASSERT_UNUSED(result, result.isNewEntry);
9107}
9108
9109void WebPageProxy::removeObserver(WebViewDidMoveToWindowObserver& observer)
9110{
9111 auto result = m_webViewDidMoveToWindowObservers.remove(&observer);
9112 ASSERT_UNUSED(result, result);
9113}
9114
9115void WebPageProxy::webViewDidMoveToWindow()
9116{
9117 auto observersCopy = m_webViewDidMoveToWindowObservers;
9118 for (const auto& observer : observersCopy) {
9119 if (!observer.value)
9120 continue;
9121 observer.value->webViewDidMoveToWindow();
9122 }
9123}
9124
9125void WebPageProxy::textInputContextsInRect(WebCore::FloatRect rect, CompletionHandler<void(const Vector<WebKit::TextInputContext>&)>&& completionHandler)
9126{
9127 if (!hasRunningProcess()) {
9128 completionHandler({ });
9129 return;
9130 }
9131
9132 m_process->connection()->sendWithAsyncReply(Messages::WebPage::TextInputContextsInRect(rect), WTFMove(completionHandler), m_pageID);
9133}
9134
9135void WebPageProxy::focusTextInputContext(const TextInputContext& context, CompletionHandler<void(bool)>&& completionHandler)
9136{
9137 if (!hasRunningProcess()) {
9138 completionHandler(false);
9139 return;
9140 }
9141
9142 m_process->connection()->sendWithAsyncReply(Messages::WebPage::FocusTextInputContext(context), WTFMove(completionHandler), m_pageID);
9143}
9144
9145Logger& WebPageProxy::logger()
9146{
9147 if (!m_logger) {
9148 m_logger = Logger::create(this);
9149 m_logger->setEnabled(this, isAlwaysOnLoggingAllowed());
9150 }
9151
9152 return *m_logger;
9153}
9154
9155void WebPageProxy::configureLoggingChannel(const String& channelName, WTFLogChannelState state, WTFLogLevel level)
9156{
9157#if !RELEASE_LOG_DISABLED
9158 auto* channel = getLogChannel(channelName);
9159 if (!channel)
9160 return;
9161
9162 channel->state = state;
9163 channel->level = level;
9164#else
9165 UNUSED_PARAM(channelName);
9166 UNUSED_PARAM(state);
9167 UNUSED_PARAM(level);
9168#endif
9169}
9170
9171} // namespace WebKit
9172
9173#undef MERGE_WHEEL_EVENTS
9174#undef MESSAGE_CHECK
9175#undef MESSAGE_CHECK_URL
9176#undef RELEASE_LOG_IF_ALLOWED
9177