source: webkit/trunk/Source/WebKit/UIProcess/WebPageProxy.cpp

Last change on this file was 295778, checked in by Chris Dumez, 3 years ago

Ignore history items added by JS without user interaction when navigation back/forward via the WKWebView API
https://bugs.webkit.org/show_bug.cgi?id=241885
<rdar://94838657>

Reviewed by Geoffrey Garen.

Ignore history items added by JS without user interaction when navigation
back/forward via the WKWebView API. This is a behavior similar to the
intervention made in Chrome (https://bugs.chromium.org/p/chromium/issues/detail?id=907167)
to prevent websites from hijacking the back/forward list.

When an history item is added by JS via history.pushState() and without a user
gesture, we now set a flag on that HistoryItem to remember this. Later on, when
calling [WKWebView goBack] or [WKWebView goForward], we will skip the history
item that have this flag set. This behavior occurs behind a linked-on-after
check to reduce the compatibility risk.

Also, navigations via other means (e.g. via JavaScript) are not impacted and will
ignore this new flag.

  • Source/WTF/wtf/cocoa/RuntimeApplicationChecksCocoa.h:
  • Source/WebCore/history/HistoryItem.h:

(WebCore::HistoryItem::setWasCreatedByJSWithoutUserInteraction):
(WebCore::HistoryItem::wasCreatedByJSWithoutUserInteraction const):

  • Source/WebCore/loader/HistoryController.cpp:

(WebCore::FrameLoader::HistoryController::pushState):

  • Source/WebKit/Shared/SessionState.cpp:

(WebKit::PageState::encode const):
(WebKit::PageState::decode):

  • Source/WebKit/Shared/SessionState.h:
  • Source/WebKit/Shared/WebBackForwardListItem.h:

(WebKit::WebBackForwardListItem::wasCreatedByJSWithoutUserInteraction const):

  • Source/WebKit/UIProcess/WebPageProxy.cpp:

(WebKit::itemSkippingBackForwardItemsAddedByJSWithoutUserGesture):
(WebKit::WebPageProxy::goForward):
(WebKit::WebPageProxy::goBack):

  • Source/WebKit/WebProcess/WebCoreSupport/SessionStateConversion.cpp:

(WebKit::toBackForwardListItemState):

  • Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
  • Tools/TestWebKitAPI/Tests/WebKit/WKBackForwardList.mm:

(TEST):

  • Tools/TestWebKitAPI/cocoa/TestNavigationDelegate.h:
  • Tools/TestWebKitAPI/cocoa/TestNavigationDelegate.mm:

(-[TestNavigationDelegate _webView:navigation:didSameDocumentNavigation:]):
(-[TestNavigationDelegate waitForDidFinishNavigationOrSameDocumentNavigation]):
(-[WKWebView _test_waitForDidFinishNavigationOrSameDocumentNavigation]):

Canonical link: https://commits.webkit.org/251783@main

  • Property svn:eol-style set to native
File size: 445.4 KB
Line 
1/*
2 * Copyright (C) 2010-2022 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 "APIContentWorld.h"
33#include "APIContextMenuClient.h"
34#include "APIDictionary.h"
35#include "APIFindClient.h"
36#include "APIFindMatchesClient.h"
37#include "APIFormClient.h"
38#include "APIFrameInfo.h"
39#include "APIFullscreenClient.h"
40#include "APIGeometry.h"
41#include "APIHistoryClient.h"
42#include "APIHitTestResult.h"
43#include "APIIconLoadingClient.h"
44#include "APILegacyContextHistoryClient.h"
45#include "APILoaderClient.h"
46#include "APINavigation.h"
47#include "APINavigationAction.h"
48#include "APINavigationClient.h"
49#include "APINavigationResponse.h"
50#include "APIOpenPanelParameters.h"
51#include "APIPageConfiguration.h"
52#include "APIPolicyClient.h"
53#include "APIResourceLoadClient.h"
54#include "APISecurityOrigin.h"
55#include "APIUIClient.h"
56#include "APIURLRequest.h"
57#include "APIWebsitePolicies.h"
58#include "AuthenticationChallengeProxy.h"
59#include "AuthenticationDecisionListener.h"
60#include "AuthenticationManager.h"
61#include "AuthenticatorManager.h"
62#include "DownloadManager.h"
63#include "DownloadProxy.h"
64#include "DrawingAreaMessages.h"
65#include "DrawingAreaProxy.h"
66#include "EventDispatcherMessages.h"
67#include "FormDataReference.h"
68#include "FrameInfoData.h"
69#include "LegacyGlobalSettings.h"
70#include "LoadParameters.h"
71#include "LogInitialization.h"
72#include "Logging.h"
73#include "NativeWebGestureEvent.h"
74#include "NativeWebKeyboardEvent.h"
75#include "NativeWebMouseEvent.h"
76#include "NativeWebWheelEvent.h"
77#include "NavigationActionData.h"
78#include "NetworkProcessMessages.h"
79#include "NetworkProcessProxy.h"
80#include "NotificationManagerMessageHandlerMessages.h"
81#include "NotificationPermissionRequest.h"
82#include "NotificationPermissionRequestManager.h"
83#include "PageClient.h"
84#include "PrintInfo.h"
85#include "ProcessThrottler.h"
86#include "ProvisionalPageProxy.h"
87#include "SafeBrowsingWarning.h"
88#include "SpeechRecognitionPermissionManager.h"
89#include "SpeechRecognitionRemoteRealtimeMediaSource.h"
90#include "SpeechRecognitionRemoteRealtimeMediaSourceManager.h"
91#include "SyntheticEditingCommandType.h"
92#include "TextChecker.h"
93#include "TextCheckerState.h"
94#include "TextRecognitionUpdateResult.h"
95#include "URLSchemeTaskParameters.h"
96#include "UndoOrRedo.h"
97#include "UserMediaPermissionRequestProxy.h"
98#include "UserMediaProcessManager.h"
99#include "WKContextPrivate.h"
100#include "WebAutomationSession.h"
101#include "WebBackForwardCache.h"
102#include "WebBackForwardList.h"
103#include "WebBackForwardListCounts.h"
104#include "WebBackForwardListItem.h"
105#include "WebCertificateInfo.h"
106#include "WebContextMenuItem.h"
107#include "WebContextMenuProxy.h"
108#include "WebCoreArgumentCoders.h"
109#include "WebEditCommandProxy.h"
110#include "WebEventConversion.h"
111#include "WebFoundTextRange.h"
112#include "WebFrame.h"
113#include "WebFramePolicyListenerProxy.h"
114#include "WebFullScreenManagerProxy.h"
115#include "WebFullScreenManagerProxyMessages.h"
116#include "WebImage.h"
117#include "WebInspectorUIProxy.h"
118#include "WebInspectorUtilities.h"
119#include "WebKeyboardEvent.h"
120#include "WebNavigationDataStore.h"
121#include "WebNavigationState.h"
122#include "WebNotificationManagerProxy.h"
123#include "WebOpenPanelResultListenerProxy.h"
124#include "WebPage.h"
125#include "WebPageCreationParameters.h"
126#include "WebPageDebuggable.h"
127#include "WebPageGroup.h"
128#include "WebPageGroupData.h"
129#include "WebPageInspectorController.h"
130#include "WebPageMessages.h"
131#include "WebPageNetworkParameters.h"
132#include "WebPageProxyMessages.h"
133#include "WebPasteboardProxy.h"
134#include "WebPaymentCoordinatorProxy.h"
135#include "WebPopupItem.h"
136#include "WebPopupMenuProxy.h"
137#include "WebPreferences.h"
138#include "WebPreferencesKeys.h"
139#include "WebProcess.h"
140#include "WebProcessMessages.h"
141#include "WebProcessPool.h"
142#include "WebProcessProxy.h"
143#include "WebProtectionSpace.h"
144#include "WebResourceLoadStatisticsStore.h"
145#include "WebURLSchemeHandler.h"
146#include "WebUserContentControllerProxy.h"
147#include "WebViewDidMoveToWindowObserver.h"
148#include "WebWheelEventCoalescer.h"
149#include "WebsiteDataStore.h"
150#include <WebCore/AppHighlight.h>
151#include <WebCore/BitmapImage.h>
152#include <WebCore/CompositionHighlight.h>
153#include <WebCore/CrossSiteNavigationDataTransfer.h>
154#include <WebCore/DOMPasteAccess.h>
155#include <WebCore/DeprecatedGlobalSettings.h>
156#include <WebCore/DiagnosticLoggingClient.h>
157#include <WebCore/DiagnosticLoggingKeys.h>
158#include <WebCore/DragController.h>
159#include <WebCore/DragData.h>
160#include <WebCore/ElementContext.h>
161#include <WebCore/EventNames.h>
162#include <WebCore/ExceptionDetails.h>
163#include <WebCore/FloatRect.h>
164#include <WebCore/FocusDirection.h>
165#include <WebCore/FontAttributeChanges.h>
166#include <WebCore/FrameLoader.h>
167#include <WebCore/GlobalFrameIdentifier.h>
168#include <WebCore/GlobalWindowIdentifier.h>
169#include <WebCore/LengthBox.h>
170#include <WebCore/MIMETypeRegistry.h>
171#include <WebCore/MediaStreamRequest.h>
172#include <WebCore/ModalContainerTypes.h>
173#include <WebCore/PerformanceLoggingClient.h>
174#include <WebCore/PermissionState.h>
175#include <WebCore/PlatformEvent.h>
176#include <WebCore/PrivateClickMeasurement.h>
177#include <WebCore/PublicSuffix.h>
178#include <WebCore/RealtimeMediaSourceCenter.h>
179#include <WebCore/RenderEmbeddedObject.h>
180#include <WebCore/ResourceLoadStatistics.h>
181#include <WebCore/RuntimeApplicationChecks.h>
182#include <WebCore/RuntimeEnabledFeatures.h>
183#include <WebCore/SSLKeyGenerator.h>
184#include <WebCore/SerializedCryptoKeyWrap.h>
185#include <WebCore/ShareData.h>
186#include <WebCore/SharedBuffer.h>
187#include <WebCore/ShouldTreatAsContinuingLoad.h>
188#include <WebCore/StoredCredentialsPolicy.h>
189#include <WebCore/TextCheckerClient.h>
190#include <WebCore/TextIndicator.h>
191#include <WebCore/ValidationBubble.h>
192#include <WebCore/WindowFeatures.h>
193#include <WebCore/WritingDirection.h>
194#include <stdio.h>
195#include <wtf/CallbackAggregator.h>
196#include <wtf/NeverDestroyed.h>
197#include <wtf/Scope.h>
198#include <wtf/SystemTracing.h>
199#include <wtf/URL.h>
200#include <wtf/URLParser.h>
201#include <wtf/WeakPtr.h>
202#include <wtf/text/StringView.h>
203#include <wtf/text/TextStream.h>
204
205#if ENABLE(APPLICATION_MANIFEST)
206#include "APIApplicationManifest.h"
207#endif
208
209#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
210#include "RemoteScrollingCoordinatorProxy.h"
211#endif
212
213#ifndef NDEBUG
214#include <wtf/RefCountedLeakCounter.h>
215#endif
216
217#if PLATFORM(COCOA)
218#include "InsertTextOptions.h"
219#include "RemoteLayerTreeDrawingAreaProxy.h"
220#include "RemoteLayerTreeScrollingPerformanceData.h"
221#include "UserMediaCaptureManagerProxy.h"
222#include "VideoFullscreenManagerProxy.h"
223#include "VideoFullscreenManagerProxyMessages.h"
224#include <WebCore/AttributedString.h>
225#include <WebCore/CoreAudioCaptureDeviceManager.h>
226#include <WebCore/RunLoopObserver.h>
227#include <WebCore/SystemBattery.h>
228#include <wtf/MachSendRight.h>
229#include <wtf/cocoa/Entitlements.h>
230#include <wtf/cocoa/RuntimeApplicationChecksCocoa.h>
231#endif
232
233#if PLATFORM(MAC)
234#include "DisplayLink.h"
235#include <WebCore/ImageUtilities.h>
236#include <WebCore/UTIUtilities.h>
237#endif
238
239#if HAVE(TOUCH_BAR)
240#include "TouchBarMenuData.h"
241#include "TouchBarMenuItemData.h"
242#endif
243
244#if PLATFORM(COCOA) || PLATFORM(GTK)
245#include "ViewSnapshotStore.h"
246#endif
247
248#if PLATFORM(GTK)
249#include "GtkSettingsManager.h"
250#include <WebCore/SelectionData.h>
251#endif
252
253#if USE(CAIRO)
254#include <WebCore/CairoUtilities.h>
255#endif
256
257#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
258#include <WebCore/MediaPlaybackTarget.h>
259#include <WebCore/WebMediaSessionManager.h>
260#endif
261
262#if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
263#include "PlaybackSessionManagerProxy.h"
264#endif
265
266#if ENABLE(WEB_AUTHN)
267#include "WebAuthenticatorCoordinatorProxy.h"
268#endif
269
270#if ENABLE(REMOTE_INSPECTOR)
271#include <JavaScriptCore/RemoteInspector.h>
272#endif
273
274#if HAVE(SEC_KEY_PROXY)
275#include "SecKeyProxyStore.h"
276#endif
277
278#if HAVE(APP_SSO)
279#include "SOAuthorizationCoordinator.h"
280#endif
281
282#if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION)
283#include "WebDeviceOrientationUpdateProviderProxy.h"
284#endif
285
286#if ENABLE(DATA_DETECTION)
287#include "DataDetectionResult.h"
288#endif
289
290#if ENABLE(MEDIA_USAGE)
291#include "MediaUsageManager.h"
292#endif
293
294#if PLATFORM(COCOA)
295#include "DefaultWebBrowserChecks.h"
296#endif
297
298#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
299#include "WebDateTimePicker.h"
300#endif
301
302#if ENABLE(MEDIA_SESSION_COORDINATOR)
303#include "MediaSessionCoordinatorProxyPrivate.h"
304#include "RemoteMediaSessionCoordinatorProxy.h"
305#endif
306
307#if HAVE(GROUP_ACTIVITIES)
308#include "GroupActivitiesSessionNotifier.h"
309#endif
310
311#if ENABLE(APP_HIGHLIGHTS)
312#include <WebCore/HighlightVisibility.h>
313#endif
314
315#if HAVE(SCREEN_CAPTURE_KIT)
316#import "DisplayCaptureSessionManager.h"
317#endif
318
319#if HAVE(SC_CONTENT_SHARING_SESSION)
320#import <WebCore/ScreenCaptureKitSharingSessionManager.h>
321#endif
322
323#if USE(QUICK_LOOK)
324#include <WebCore/PreviewConverter.h>
325#endif
326
327#define MESSAGE_CHECK(process, assertion) MESSAGE_CHECK_BASE(assertion, process->connection())
328#define MESSAGE_CHECK_URL(process, url) MESSAGE_CHECK_BASE(checkURLReceivedFromCurrentOrPreviousWebProcess(process, url), process->connection())
329#define MESSAGE_CHECK_COMPLETION(process, assertion, completion) MESSAGE_CHECK_COMPLETION_BASE(assertion, process->connection(), completion)
330
331#define WEBPAGEPROXY_RELEASE_LOG(channel, fmt, ...) RELEASE_LOG(channel, "%p - [pageProxyID=%" PRIu64 ", webPageID=%" PRIu64 ", PID=%i] WebPageProxy::" fmt, this, m_identifier.toUInt64(), m_webPageID.toUInt64(), m_process->processIdentifier(), ##__VA_ARGS__)
332#define WEBPAGEPROXY_RELEASE_LOG_ERROR(channel, fmt, ...) RELEASE_LOG_ERROR(channel, "%p - [pageProxyID=%" PRIu64 ", webPageID=%" PRIu64 ", PID=%i] WebPageProxy::" fmt, this, m_identifier.toUInt64(), m_webPageID.toUInt64(), m_process->processIdentifier(), ##__VA_ARGS__)
333
334// Represents the number of wheel events we can hold in the queue before we start pushing them preemptively.
335static const unsigned wheelEventQueueSizeThreshold = 10;
336
337static const Seconds resetRecentCrashCountDelay = 30_s;
338static unsigned maximumWebProcessRelaunchAttempts = 1;
339static const Seconds audibleActivityClearDelay = 10_s;
340static const Seconds tryCloseTimeoutDelay = 50_ms;
341
342namespace WebKit {
343using namespace WebCore;
344
345DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageProxyCounter, ("WebPageProxy"));
346
347class StorageRequests {
348 WTF_MAKE_NONCOPYABLE(StorageRequests); WTF_MAKE_FAST_ALLOCATED;
349 friend NeverDestroyed<StorageRequests>;
350public:
351 static StorageRequests& singleton();
352
353 void processOrAppend(CompletionHandler<void()>&& completionHandler)
354 {
355 if (m_requestsAreBeingProcessed) {
356 m_requests.append(WTFMove(completionHandler));
357 return;
358 }
359 m_requestsAreBeingProcessed = true;
360 completionHandler();
361 }
362
363 void processNextIfAny()
364 {
365 if (m_requests.isEmpty()) {
366 m_requestsAreBeingProcessed = false;
367 return;
368 }
369 m_requests.takeFirst()();
370 }
371
372private:
373 StorageRequests() { }
374 ~StorageRequests() { }
375
376 Deque<CompletionHandler<void()>> m_requests;
377 bool m_requestsAreBeingProcessed { false };
378};
379
380StorageRequests& StorageRequests::singleton()
381{
382 static NeverDestroyed<StorageRequests> requests;
383 return requests;
384}
385
386#if !LOG_DISABLED
387static const char* webMouseEventTypeString(WebEvent::Type type)
388{
389 switch (type) {
390 case WebEvent::MouseDown:
391 return "MouseDown";
392 case WebEvent::MouseUp:
393 return "MouseUp";
394 case WebEvent::MouseMove:
395 return "MouseMove";
396 case WebEvent::MouseForceChanged:
397 return "MouseForceChanged";
398 case WebEvent::MouseForceDown:
399 return "MouseForceDown";
400 case WebEvent::MouseForceUp:
401 return "MouseForceUp";
402 default:
403 ASSERT_NOT_REACHED();
404 return "<unknown>";
405 }
406}
407
408static const char* webKeyboardEventTypeString(WebEvent::Type type)
409{
410 switch (type) {
411 case WebEvent::KeyDown:
412 return "KeyDown";
413 case WebEvent::KeyUp:
414 return "KeyUp";
415 case WebEvent::RawKeyDown:
416 return "RawKeyDown";
417 case WebEvent::Char:
418 return "Char";
419 default:
420 ASSERT_NOT_REACHED();
421 return "<unknown>";
422 }
423}
424#endif // !LOG_DISABLED
425
426class PageClientProtector {
427 WTF_MAKE_NONCOPYABLE(PageClientProtector);
428public:
429 PageClientProtector(PageClient& pageClient)
430 : m_pageClient(pageClient)
431 {
432 m_pageClient->refView();
433 }
434
435 ~PageClientProtector()
436 {
437 ASSERT(m_pageClient);
438 m_pageClient->derefView();
439 }
440
441private:
442 WeakPtr<PageClient> m_pageClient;
443};
444
445void WebPageProxy::forMostVisibleWebPageIfAny(PAL::SessionID sessionID, const SecurityOriginData& origin, CompletionHandler<void(WebPageProxy*)>&& completionHandler)
446{
447 // 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.
448 WebPageProxy* selectedPage = nullptr;
449 WebProcessProxy::forWebPagesWithOrigin(sessionID, origin, [&](auto& page) {
450 if (!page.mainFrame())
451 return;
452 if (page.isViewVisible() && (!selectedPage || !selectedPage->isViewVisible())) {
453 selectedPage = &page;
454 return;
455 }
456 if (page.isViewFocused() && (!selectedPage || !selectedPage->isViewFocused())) {
457 selectedPage = &page;
458 return;
459 }
460 });
461 completionHandler(selectedPage);
462}
463
464Ref<WebPageProxy> WebPageProxy::create(PageClient& pageClient, WebProcessProxy& process, Ref<API::PageConfiguration>&& configuration)
465{
466 return adoptRef(*new WebPageProxy(pageClient, process, WTFMove(configuration)));
467}
468
469WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, Ref<API::PageConfiguration>&& configuration)
470 : m_identifier(Identifier::generate())
471 , m_webPageID(PageIdentifier::generate())
472 , m_pageClient(pageClient)
473 , m_configuration(WTFMove(configuration))
474 , m_navigationClient(makeUniqueRef<API::NavigationClient>())
475 , m_historyClient(makeUniqueRef<API::HistoryClient>())
476 , m_iconLoadingClient(makeUnique<API::IconLoadingClient>())
477 , m_formClient(makeUnique<API::FormClient>())
478 , m_uiClient(makeUnique<API::UIClient>())
479 , m_findClient(makeUnique<API::FindClient>())
480 , m_findMatchesClient(makeUnique<API::FindMatchesClient>())
481#if ENABLE(CONTEXT_MENUS)
482 , m_contextMenuClient(makeUnique<API::ContextMenuClient>())
483#endif
484 , m_navigationState(makeUnique<WebNavigationState>())
485 , m_process(process)
486 , m_pageGroup(*m_configuration->pageGroup())
487 , m_preferences(*m_configuration->preferences())
488 , m_userContentController(*m_configuration->userContentController())
489 , m_visitedLinkStore(*m_configuration->visitedLinkStore())
490 , m_websiteDataStore(*m_configuration->websiteDataStore())
491 , m_userAgent(standardUserAgent())
492 , m_overrideContentSecurityPolicy { m_configuration->overrideContentSecurityPolicy() }
493#if ENABLE(FULLSCREEN_API)
494 , m_fullscreenClient(makeUnique<API::FullscreenClient>())
495#endif
496 , m_geolocationPermissionRequestManager(*this)
497#if PLATFORM(IOS_FAMILY)
498 , m_audibleActivityTimer(RunLoop::main(), this, &WebPageProxy::clearAudibleActivity)
499#endif
500 , m_initialCapitalizationEnabled(m_configuration->initialCapitalizationEnabled())
501 , m_cpuLimit(m_configuration->cpuLimit())
502 , m_backForwardList(WebBackForwardList::create(*this))
503 , m_waitsForPaintAfterViewDidMoveToWindow(m_configuration->waitsForPaintAfterViewDidMoveToWindow())
504 , m_hasRunningProcess(process.state() != WebProcessProxy::State::Terminated)
505#if HAVE(CVDISPLAYLINK)
506 , m_wheelEventActivityHysteresis([this](PAL::HysteresisState state) { wheelEventHysteresisUpdated(state); })
507#endif
508 , m_controlledByAutomation(m_configuration->isControlledByAutomation())
509#if PLATFORM(COCOA)
510 , m_isSmartInsertDeleteEnabled(TextChecker::isSmartInsertDeleteEnabled())
511#endif
512 , m_pageLoadState(*this)
513 , m_updateReportedMediaCaptureStateTimer(RunLoop::main(), this, &WebPageProxy::updateReportedMediaCaptureState)
514 , m_inspectorController(makeUnique<WebPageInspectorController>(*this))
515#if ENABLE(REMOTE_INSPECTOR)
516 , m_inspectorDebuggable(makeUnique<WebPageDebuggable>(*this))
517#endif
518 , m_resetRecentCrashCountTimer(RunLoop::main(), this, &WebPageProxy::resetRecentCrashCount)
519 , m_tryCloseTimeoutTimer(RunLoop::main(), this, &WebPageProxy::tryCloseTimedOut)
520 , m_corsDisablingPatterns(m_configuration->corsDisablingPatterns())
521#if ENABLE(APP_BOUND_DOMAINS)
522 , m_ignoresAppBoundDomains(m_configuration->ignoresAppBoundDomains())
523 , m_limitsNavigationsToAppBoundDomains(m_configuration->limitsNavigationsToAppBoundDomains())
524#endif
525 , m_notificationManagerMessageHandler(*this)
526#if ENABLE(VIDEO_PRESENTATION_MODE)
527 , m_fullscreenVideoTextRecognitionTimer(RunLoop::main(), this, &WebPageProxy::fullscreenVideoTextRecognitionTimerFired)
528#endif
529{
530 WEBPAGEPROXY_RELEASE_LOG(Loading, "constructor:");
531
532 if (!m_configuration->drawsBackground())
533 m_backgroundColor = Color(Color::transparentBlack);
534
535 updateActivityState();
536 updateThrottleState();
537 updateHiddenPageThrottlingAutoIncreases();
538
539#if HAVE(OUT_OF_PROCESS_LAYER_HOSTING)
540 m_layerHostingMode = m_activityState & ActivityState::IsInWindow ? WebPageProxy::pageClient().viewLayerHostingMode() : LayerHostingMode::OutOfProcess;
541#endif
542
543 platformInitialize();
544
545#ifndef NDEBUG
546 webPageProxyCounter.increment();
547#endif
548
549 WebProcessPool::statistics().wkPageCount++;
550
551 m_preferences->addPage(*this);
552 m_pageGroup->addPage(*this);
553
554 m_inspector = WebInspectorUIProxy::create(*this);
555
556 if (hasRunningProcess())
557 didAttachToRunningProcess();
558
559 addAllMessageReceivers();
560
561#if PLATFORM(IOS_FAMILY)
562 DeprecatedGlobalSettings::setDisableScreenSizeOverride(m_preferences->disableScreenSizeOverride());
563
564 if (m_configuration->preferences()->serviceWorkerEntitlementDisabledForTesting())
565 disableServiceWorkerEntitlementInNetworkProcess();
566#endif
567
568#if PLATFORM(COCOA)
569 m_activityStateChangeDispatcher = makeUnique<RunLoopObserver>(static_cast<CFIndex>(RunLoopObserver::WellKnownRunLoopOrders::ActivityStateChange), [this] {
570 this->dispatchActivityStateChange();
571 });
572#endif
573
574#if ENABLE(REMOTE_INSPECTOR)
575 m_inspectorDebuggable->setRemoteDebuggingAllowed(true);
576 m_inspectorDebuggable->init();
577#endif
578 m_inspectorController->init();
579
580#if ENABLE(IPC_TESTING_API)
581 if (m_preferences->ipcTestingAPIEnabled())
582 process.setIgnoreInvalidMessageForTesting();
583#endif
584
585#if ENABLE(MEDIA_SESSION_COORDINATOR) && HAVE(GROUP_ACTIVITIES)
586 if (m_preferences->mediaSessionCoordinatorEnabled())
587 GroupActivitiesSessionNotifier::sharedNotifier().addWebPage(*this);
588#endif
589}
590
591WebPageProxy::~WebPageProxy()
592{
593 WEBPAGEPROXY_RELEASE_LOG(Loading, "destructor:");
594
595 ASSERT(m_process->webPage(m_identifier) != this);
596#if ASSERT_ENABLED
597 for (WebPageProxy* page : m_process->pages())
598 ASSERT(page != this);
599#endif
600
601 setPageLoadStateObserver(nullptr);
602
603 if (!m_isClosed)
604 close();
605
606 WebProcessPool::statistics().wkPageCount--;
607
608 if (m_spellDocumentTag)
609 TextChecker::closeSpellDocumentWithTag(m_spellDocumentTag.value());
610
611 m_preferences->removePage(*this);
612 m_pageGroup->removePage(*this);
613
614#ifndef NDEBUG
615 webPageProxyCounter.decrement();
616#endif
617
618#if PLATFORM(MACCATALYST)
619 EndowmentStateTracker::singleton().removeClient(*this);
620#endif
621
622 for (auto& callback : m_nextActivityStateChangeCallbacks)
623 callback();
624
625 if (auto* networkProcess = websiteDataStore().networkProcessIfExists())
626 networkProcess->send(Messages::NetworkProcess::RemoveWebPageNetworkParameters(sessionID(), m_identifier), 0);
627
628#if ENABLE(MEDIA_SESSION_COORDINATOR) && HAVE(GROUP_ACTIVITIES)
629 if (m_preferences->mediaSessionCoordinatorEnabled())
630 GroupActivitiesSessionNotifier::sharedNotifier().removeWebPage(*this);
631#endif
632}
633
634void WebPageProxy::addAllMessageReceivers()
635{
636 m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID, *this);
637 m_process->addMessageReceiver(Messages::NotificationManagerMessageHandler::messageReceiverName(), m_webPageID, m_notificationManagerMessageHandler);
638}
639
640void WebPageProxy::removeAllMessageReceivers()
641{
642 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID);
643 m_process->removeMessageReceiver(Messages::NotificationManagerMessageHandler::messageReceiverName(), m_webPageID);
644}
645
646// FIXME: Should return a const PageClient& and add a separate non-const
647// version of this function, but several PageClient methods will need to become
648// const for this to be possible.
649PageClient& WebPageProxy::pageClient() const
650{
651 ASSERT(m_pageClient);
652 return *m_pageClient;
653}
654
655PAL::SessionID WebPageProxy::sessionID() const
656{
657 return m_websiteDataStore->sessionID();
658}
659
660DrawingAreaProxy* WebPageProxy::provisionalDrawingArea() const
661{
662 if (m_provisionalPage && m_provisionalPage->drawingArea())
663 return m_provisionalPage->drawingArea();
664 return drawingArea();
665}
666
667const API::PageConfiguration& WebPageProxy::configuration() const
668{
669 return m_configuration.get();
670}
671
672ProcessID WebPageProxy::gpuProcessIdentifier() const
673{
674 if (m_isClosed)
675 return 0;
676
677#if ENABLE(GPU_PROCESS)
678 if (auto* gpuProcess = process().processPool().gpuProcess())
679 return gpuProcess->processIdentifier();
680#endif
681
682 return 0;
683}
684
685ProcessID WebPageProxy::processIdentifier() const
686{
687 if (m_isClosed)
688 return 0;
689
690 return m_process->processIdentifier();
691}
692
693bool WebPageProxy::hasRunningProcess() const
694{
695 // A page that has been explicitly closed is never valid.
696 if (m_isClosed)
697 return false;
698
699 return m_hasRunningProcess;
700}
701
702void WebPageProxy::notifyProcessPoolToPrewarm()
703{
704 m_process->processPool().didReachGoodTimeToPrewarm();
705}
706
707void WebPageProxy::setPreferences(WebPreferences& preferences)
708{
709 if (&preferences == m_preferences.ptr())
710 return;
711
712 m_preferences->removePage(*this);
713 m_preferences = preferences;
714 m_preferences->addPage(*this);
715
716 preferencesDidChange();
717}
718
719void WebPageProxy::setHistoryClient(UniqueRef<API::HistoryClient>&& historyClient)
720{
721 m_historyClient = WTFMove(historyClient);
722}
723
724void WebPageProxy::setNavigationClient(UniqueRef<API::NavigationClient>&& navigationClient)
725{
726 m_navigationClient = WTFMove(navigationClient);
727}
728
729void WebPageProxy::setLoaderClient(std::unique_ptr<API::LoaderClient>&& loaderClient)
730{
731 m_loaderClient = WTFMove(loaderClient);
732}
733
734void WebPageProxy::setPolicyClient(std::unique_ptr<API::PolicyClient>&& policyClient)
735{
736 m_policyClient = WTFMove(policyClient);
737}
738
739void WebPageProxy::setFormClient(std::unique_ptr<API::FormClient>&& formClient)
740{
741 if (!formClient) {
742 m_formClient = makeUnique<API::FormClient>();
743 return;
744 }
745
746 m_formClient = WTFMove(formClient);
747}
748
749void WebPageProxy::setUIClient(std::unique_ptr<API::UIClient>&& uiClient)
750{
751 if (!uiClient) {
752 m_uiClient = makeUnique<API::UIClient>();
753 return;
754 }
755
756 m_uiClient = WTFMove(uiClient);
757
758 if (hasRunningProcess())
759 send(Messages::WebPage::SetCanRunBeforeUnloadConfirmPanel(m_uiClient->canRunBeforeUnloadConfirmPanel()));
760
761 setCanRunModal(m_uiClient->canRunModal());
762 setNeedsFontAttributes(m_uiClient->needsFontAttributes());
763}
764
765void WebPageProxy::setIconLoadingClient(std::unique_ptr<API::IconLoadingClient>&& iconLoadingClient)
766{
767 bool hasClient = iconLoadingClient.get();
768 if (!iconLoadingClient)
769 m_iconLoadingClient = makeUnique<API::IconLoadingClient>();
770 else
771 m_iconLoadingClient = WTFMove(iconLoadingClient);
772
773 if (!hasRunningProcess())
774 return;
775
776 send(Messages::WebPage::SetUseIconLoadingClient(hasClient));
777}
778
779void WebPageProxy::setPageLoadStateObserver(std::unique_ptr<PageLoadState::Observer>&& observer)
780{
781 if (m_pageLoadStateObserver)
782 pageLoadState().removeObserver(*m_pageLoadStateObserver);
783 m_pageLoadStateObserver = WTFMove(observer);
784 if (m_pageLoadStateObserver)
785 pageLoadState().addObserver(*m_pageLoadStateObserver);
786}
787
788void WebPageProxy::setFindClient(std::unique_ptr<API::FindClient>&& findClient)
789{
790 if (!findClient) {
791 m_findClient = makeUnique<API::FindClient>();
792 return;
793 }
794
795 m_findClient = WTFMove(findClient);
796}
797
798void WebPageProxy::setFindMatchesClient(std::unique_ptr<API::FindMatchesClient>&& findMatchesClient)
799{
800 if (!findMatchesClient) {
801 m_findMatchesClient = makeUnique<API::FindMatchesClient>();
802 return;
803 }
804
805 m_findMatchesClient = WTFMove(findMatchesClient);
806}
807
808void WebPageProxy::setDiagnosticLoggingClient(std::unique_ptr<API::DiagnosticLoggingClient>&& diagnosticLoggingClient)
809{
810 m_diagnosticLoggingClient = WTFMove(diagnosticLoggingClient);
811}
812
813#if ENABLE(CONTEXT_MENUS)
814void WebPageProxy::setContextMenuClient(std::unique_ptr<API::ContextMenuClient>&& contextMenuClient)
815{
816 if (!contextMenuClient) {
817 m_contextMenuClient = makeUnique<API::ContextMenuClient>();
818 return;
819 }
820
821 m_contextMenuClient = WTFMove(contextMenuClient);
822}
823#endif
824
825void WebPageProxy::setInjectedBundleClient(const WKPageInjectedBundleClientBase* client)
826{
827 if (!client) {
828 m_injectedBundleClient = nullptr;
829 return;
830 }
831
832 m_injectedBundleClient = makeUnique<WebPageInjectedBundleClient>();
833 m_injectedBundleClient->initialize(client);
834}
835
836void WebPageProxy::setResourceLoadClient(std::unique_ptr<API::ResourceLoadClient>&& client)
837{
838 bool hadResourceLoadClient = !!m_resourceLoadClient;
839 m_resourceLoadClient = WTFMove(client);
840 bool hasResourceLoadClient = !!m_resourceLoadClient;
841 if (hadResourceLoadClient != hasResourceLoadClient)
842 send(Messages::WebPage::SetHasResourceLoadClient(hasResourceLoadClient));
843}
844
845void WebPageProxy::handleMessage(IPC::Connection& connection, const String& messageName, const WebKit::UserData& messageBody)
846{
847 ASSERT(m_process->connection() == &connection);
848
849 if (!m_injectedBundleClient)
850 return;
851
852 m_injectedBundleClient->didReceiveMessageFromInjectedBundle(this, messageName, m_process->transformHandlesToObjects(messageBody.object()).get());
853}
854
855void WebPageProxy::handleSynchronousMessage(IPC::Connection& connection, const String& messageName, const UserData& messageBody, CompletionHandler<void(UserData&&)>&& completionHandler)
856{
857 ASSERT(m_process->connection() == &connection);
858
859 if (!m_injectedBundleClient)
860 return completionHandler({ });
861
862 RefPtr<API::Object> returnData;
863 m_injectedBundleClient->didReceiveSynchronousMessageFromInjectedBundle(this, messageName, m_process->transformHandlesToObjects(messageBody.object()).get(), [completionHandler = WTFMove(completionHandler), process = m_process] (RefPtr<API::Object>&& returnData) mutable {
864 completionHandler(UserData(process->transformObjectsToHandles(returnData.get())));
865 });
866}
867
868void WebPageProxy::launchProcess(const RegistrableDomain& registrableDomain, ProcessLaunchReason reason)
869{
870 ASSERT(!m_isClosed);
871 ASSERT(!hasRunningProcess());
872
873 WEBPAGEPROXY_RELEASE_LOG(Loading, "launchProcess:");
874
875 // In case we are currently connected to the dummy process, we need to make sure the inspector proxy
876 // disconnects from the dummy process first.
877 m_inspector->reset();
878
879 m_process->removeWebPage(*this, WebProcessProxy::EndsUsingDataStore::Yes);
880 removeAllMessageReceivers();
881
882 auto& processPool = m_process->processPool();
883
884 auto* relatedPage = m_configuration->relatedPage();
885 if (relatedPage && !relatedPage->isClosed())
886 m_process = relatedPage->ensureRunningProcess();
887 else
888 m_process = processPool.processForRegistrableDomain(m_websiteDataStore.get(), registrableDomain, shouldEnableCaptivePortalMode() ? WebProcessProxy::CaptivePortalMode::Enabled : WebProcessProxy::CaptivePortalMode::Disabled);
889
890 m_hasRunningProcess = true;
891 m_shouldReloadDueToCrashWhenVisible = false;
892 m_isCaptivePortalModeExplicitlySet = m_configuration->isCaptivePortalModeExplicitlySet();
893
894 m_process->addExistingWebPage(*this, WebProcessProxy::BeginsUsingDataStore::Yes);
895 addAllMessageReceivers();
896
897#if ENABLE(IPC_TESTING_API)
898 if (m_preferences->store().getBoolValueForKey(WebPreferencesKey::ipcTestingAPIEnabledKey()))
899 m_process->setIgnoreInvalidMessageForTesting();
900#endif
901
902 finishAttachingToWebProcess(reason);
903
904 auto pendingInjectedBundleMessage = WTFMove(m_pendingInjectedBundleMessages);
905 for (auto& message : pendingInjectedBundleMessage)
906 send(Messages::WebPage::PostInjectedBundleMessage(message.messageName, UserData(process().transformObjectsToHandles(message.messageBody.get()).get())));
907}
908
909bool WebPageProxy::suspendCurrentPageIfPossible(API::Navigation& navigation, std::optional<FrameIdentifier> mainFrameID, ProcessSwapRequestedByClient processSwapRequestedByClient, ShouldDelayClosingUntilFirstLayerFlush shouldDelayClosingUntilFirstLayerFlush)
910{
911 m_suspendedPageKeptToPreventFlashing = nullptr;
912 m_lastSuspendedPage = nullptr;
913
914 if (!mainFrameID)
915 return false;
916
917 if (!hasCommittedAnyProvisionalLoads()) {
918 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because has not committed any load yet", m_process->processIdentifier());
919 return false;
920 }
921
922 if (isPageOpenedByDOMShowingInitialEmptyDocument()) {
923 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because it is showing the initial empty document", m_process->processIdentifier());
924 return false;
925 }
926
927 auto* fromItem = navigation.fromItem();
928
929 // If the source and the destination back / forward list items are the same, then this is a client-side redirect. In this case,
930 // there is no need to suspend the previous page as there will be no way to get back to it.
931 if (fromItem && fromItem == m_backForwardList->currentItem()) {
932 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because this is a client-side redirect", m_process->processIdentifier());
933 return false;
934 }
935
936 if (fromItem && fromItem->url() != pageLoadState().url()) {
937 WEBPAGEPROXY_RELEASE_LOG_ERROR(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i because fromItem's URL does not match the page URL.", m_process->processIdentifier());
938 return false;
939 }
940
941 bool needsSuspendedPageToPreventFlashing = shouldDelayClosingUntilFirstLayerFlush == ShouldDelayClosingUntilFirstLayerFlush::Yes;
942 if (!needsSuspendedPageToPreventFlashing && (!fromItem || !shouldUseBackForwardCache())) {
943 if (!fromItem)
944 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i there is no associated WebBackForwardListItem", m_process->processIdentifier());
945 else
946 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Not suspending current page for process pid %i the back / forward cache is disabled", m_process->processIdentifier());
947 return false;
948 }
949
950 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "suspendCurrentPageIfPossible: Suspending current page for process pid %i", m_process->processIdentifier());
951 auto suspendedPage = makeUnique<SuspendedPageProxy>(*this, m_process.copyRef(), *mainFrameID, shouldDelayClosingUntilFirstLayerFlush);
952
953 LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " created suspended page %s for process pid %i, back/forward item %s" PRIu64, identifier().toUInt64(), suspendedPage->loggingString(), m_process->processIdentifier(), fromItem ? fromItem->itemID().logString() : 0);
954
955 m_lastSuspendedPage = *suspendedPage;
956
957 if (fromItem && shouldUseBackForwardCache())
958 backForwardCache().addEntry(*fromItem, WTFMove(suspendedPage));
959 else {
960 ASSERT(needsSuspendedPageToPreventFlashing);
961 m_suspendedPageKeptToPreventFlashing = WTFMove(suspendedPage);
962 }
963
964 return true;
965}
966
967WebBackForwardCache& WebPageProxy::backForwardCache() const
968{
969 return process().processPool().backForwardCache();
970}
971
972bool WebPageProxy::shouldUseBackForwardCache() const
973{
974 return m_preferences->usesBackForwardCache() && backForwardCache().capacity() > 0;
975}
976
977void WebPageProxy::swapToProvisionalPage(std::unique_ptr<ProvisionalPageProxy> provisionalPage)
978{
979 ASSERT(!m_isClosed);
980 WEBPAGEPROXY_RELEASE_LOG(Loading, "swapToProvisionalPage: newWebPageID=%" PRIu64, provisionalPage->webPageID().toUInt64());
981
982 m_process = provisionalPage->process();
983 m_webPageID = provisionalPage->webPageID();
984 pageClient().didChangeWebPageID();
985 ASSERT(m_process->websiteDataStore());
986 m_websiteDataStore = *m_process->websiteDataStore();
987
988#if HAVE(VISIBILITY_PROPAGATION_VIEW)
989 m_contextIDForVisibilityPropagationInWebProcess = provisionalPage->contextIDForVisibilityPropagationInWebProcess();
990#if ENABLE(GPU_PROCESS)
991 m_contextIDForVisibilityPropagationInGPUProcess = provisionalPage->contextIDForVisibilityPropagationInGPUProcess();
992#endif
993#endif
994
995 // FIXME: Do we really need to disable this logging in ephemeral sessions?
996 if (m_logger)
997 m_logger->setEnabled(this, !sessionID().isEphemeral());
998
999 m_hasRunningProcess = true;
1000
1001 ASSERT(!m_drawingArea);
1002 setDrawingArea(provisionalPage->takeDrawingArea());
1003 ASSERT(!m_mainFrame);
1004 m_mainFrame = provisionalPage->mainFrame();
1005
1006 m_process->addExistingWebPage(*this, WebProcessProxy::BeginsUsingDataStore::No);
1007 addAllMessageReceivers();
1008
1009 finishAttachingToWebProcess(ProcessLaunchReason::ProcessSwap);
1010
1011#if PLATFORM(COCOA)
1012 auto accessibilityToken = provisionalPage->takeAccessibilityToken();
1013 if (!accessibilityToken.isEmpty())
1014 registerWebProcessAccessibilityToken({ accessibilityToken.data(), accessibilityToken.size() });
1015#endif
1016#if PLATFORM(GTK) || PLATFORM(WPE)
1017 auto accessibilityPlugID = provisionalPage->accessibilityPlugID();
1018 if (!accessibilityPlugID.isEmpty())
1019 bindAccessibilityTree(accessibilityPlugID);
1020#endif
1021}
1022
1023void WebPageProxy::finishAttachingToWebProcess(ProcessLaunchReason reason)
1024{
1025 ASSERT(m_process->state() != AuxiliaryProcessProxy::State::Terminated);
1026
1027 updateActivityState();
1028 updateThrottleState();
1029
1030 didAttachToRunningProcess();
1031
1032 // In the process-swap case, the ProvisionalPageProxy already took care of initializing the WebPage in the WebProcess.
1033 if (reason != ProcessLaunchReason::ProcessSwap)
1034 initializeWebPage();
1035
1036 m_inspector->updateForNewPageProcess(*this);
1037
1038#if ENABLE(REMOTE_INSPECTOR)
1039 remoteInspectorInformationDidChange();
1040#endif
1041
1042 updateWheelEventActivityAfterProcessSwap();
1043
1044 pageClient().didRelaunchProcess();
1045 m_pageLoadState.didSwapWebProcesses();
1046 if (reason != ProcessLaunchReason::InitialProcess)
1047 m_drawingArea->waitForBackingStoreUpdateOnNextPaint();
1048}
1049
1050void WebPageProxy::didAttachToRunningProcess()
1051{
1052 ASSERT(hasRunningProcess());
1053
1054#if ENABLE(FULLSCREEN_API)
1055 ASSERT(!m_fullScreenManager);
1056 m_fullScreenManager = makeUnique<WebFullScreenManagerProxy>(*this, pageClient().fullScreenManagerProxyClient());
1057#endif
1058#if ENABLE(VIDEO_PRESENTATION_MODE)
1059 ASSERT(!m_playbackSessionManager);
1060 m_playbackSessionManager = PlaybackSessionManagerProxy::create(*this);
1061 ASSERT(!m_videoFullscreenManager);
1062 m_videoFullscreenManager = VideoFullscreenManagerProxy::create(*this, *m_playbackSessionManager);
1063 if (m_videoFullscreenManager)
1064 m_videoFullscreenManager->setMockVideoPresentationModeEnabled(m_mockVideoPresentationModeEnabled);
1065#endif
1066
1067#if ENABLE(APPLE_PAY)
1068 ASSERT(!m_paymentCoordinator);
1069 m_paymentCoordinator = makeUnique<WebPaymentCoordinatorProxy>(*this);
1070#endif
1071
1072#if USE(SYSTEM_PREVIEW)
1073 ASSERT(!m_systemPreviewController);
1074 m_systemPreviewController = makeUnique<SystemPreviewController>(*this);
1075#endif
1076
1077#if ENABLE(ARKIT_INLINE_PREVIEW)
1078 if (m_preferences->modelElementEnabled()) {
1079 ASSERT(!m_modelElementController);
1080 m_modelElementController = makeUnique<ModelElementController>(*this);
1081 }
1082#endif
1083
1084#if ENABLE(WEB_AUTHN)
1085 ASSERT(!m_credentialsMessenger);
1086 m_credentialsMessenger = makeUnique<WebAuthenticatorCoordinatorProxy>(*this);
1087#endif
1088
1089#if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION)
1090 ASSERT(!m_webDeviceOrientationUpdateProviderProxy);
1091 m_webDeviceOrientationUpdateProviderProxy = makeUnique<WebDeviceOrientationUpdateProviderProxy>(*this);
1092#endif
1093
1094#if ENABLE(WEBXR) && !USE(OPENXR)
1095 ASSERT(!m_xrSystem);
1096 m_xrSystem = makeUnique<PlatformXRSystem>(*this);
1097#endif
1098}
1099
1100RefPtr<API::Navigation> WebPageProxy::launchProcessForReload()
1101{
1102 WEBPAGEPROXY_RELEASE_LOG(Loading, "launchProcessForReload:");
1103
1104 if (m_isClosed) {
1105 WEBPAGEPROXY_RELEASE_LOG(Loading, "launchProcessForReload: page is closed");
1106 return nullptr;
1107 }
1108
1109 ASSERT(!hasRunningProcess());
1110 auto registrableDomain = m_backForwardList->currentItem() ? RegistrableDomain { URL { m_backForwardList->currentItem()->url() } } : RegistrableDomain { };
1111 launchProcess(registrableDomain, ProcessLaunchReason::Crash);
1112
1113 if (!m_backForwardList->currentItem()) {
1114 WEBPAGEPROXY_RELEASE_LOG(Loading, "launchProcessForReload: no current item to reload");
1115 return nullptr;
1116 }
1117
1118 auto navigation = m_navigationState->createReloadNavigation(m_backForwardList->currentItem());
1119
1120 String url = currentURL();
1121 if (!url.isEmpty()) {
1122 auto transaction = m_pageLoadState.transaction();
1123 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), url });
1124 }
1125
1126 // We allow stale content when reloading a WebProcess that's been killed or crashed.
1127 send(Messages::WebPage::GoToBackForwardItem(navigation->navigationID(), m_backForwardList->currentItem()->itemID(), FrameLoadType::IndexedBackForward, ShouldTreatAsContinuingLoad::No, std::nullopt, m_lastNavigationWasAppInitiated, std::nullopt));
1128 m_process->startResponsivenessTimer();
1129
1130 return navigation;
1131}
1132
1133void WebPageProxy::setDrawingArea(std::unique_ptr<DrawingAreaProxy>&& drawingArea)
1134{
1135 m_drawingArea = WTFMove(drawingArea);
1136 if (!m_drawingArea)
1137 return;
1138
1139 m_drawingArea->startReceivingMessages();
1140 m_drawingArea->setSize(viewSize());
1141
1142#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
1143 if (m_drawingArea->type() == DrawingAreaType::RemoteLayerTree) {
1144 m_scrollingCoordinatorProxy = makeUnique<RemoteScrollingCoordinatorProxy>(*this);
1145#if PLATFORM(IOS_FAMILY)
1146 // On iOS, main frame scrolls are sent in terms of visible rect updates.
1147 m_scrollingCoordinatorProxy->setPropagatesMainFrameScrolls(false);
1148#endif
1149 }
1150#endif
1151}
1152
1153void WebPageProxy::initializeWebPage()
1154{
1155 if (!hasRunningProcess())
1156 return;
1157
1158 setDrawingArea(pageClient().createDrawingAreaProxy(m_process));
1159 ASSERT(m_drawingArea);
1160
1161#if ENABLE(REMOTE_INSPECTOR)
1162 // Initialize remote inspector connection now that we have a sub-process that is hosting one of our web views.
1163 Inspector::RemoteInspector::singleton();
1164#endif
1165
1166 if (auto& attributedBundleIdentifier = m_configuration->attributedBundleIdentifier(); !!attributedBundleIdentifier) {
1167 WebPageNetworkParameters parameters { attributedBundleIdentifier };
1168 websiteDataStore().networkProcess().send(Messages::NetworkProcess::AddWebPageNetworkParameters(sessionID(), m_identifier, WTFMove(parameters)), 0);
1169 }
1170
1171 send(Messages::WebProcess::CreateWebPage(m_webPageID, creationParameters(m_process, *m_drawingArea)), 0);
1172
1173 m_process->addVisitedLinkStoreUser(visitedLinkStore(), m_identifier);
1174}
1175
1176void WebPageProxy::close()
1177{
1178 if (m_isClosed)
1179 return;
1180
1181 WEBPAGEPROXY_RELEASE_LOG(Loading, "close:");
1182
1183 m_isClosed = true;
1184
1185 reportPageLoadResult(ResourceError { ResourceError::Type::Cancellation });
1186
1187 if (m_activePopupMenu)
1188 m_activePopupMenu->cancelTracking();
1189
1190 if (m_controlledByAutomation) {
1191 if (auto* automationSession = process().processPool().automationSession())
1192 automationSession->willClosePage(*this);
1193 }
1194
1195#if ENABLE(CONTEXT_MENUS)
1196 m_activeContextMenu = nullptr;
1197#endif
1198
1199 m_provisionalPage = nullptr;
1200
1201 m_inspector->invalidate();
1202
1203 m_backForwardList->pageClosed();
1204 m_inspectorController->pageClosed();
1205#if ENABLE(REMOTE_INSPECTOR)
1206 m_inspectorDebuggable = nullptr;
1207#endif
1208 pageClient().pageClosed();
1209
1210 m_process->disconnectFramesFromPage(this);
1211
1212 m_loaderClient = nullptr;
1213 m_navigationClient = makeUniqueRef<API::NavigationClient>();
1214 m_policyClient = nullptr;
1215 m_iconLoadingClient = makeUnique<API::IconLoadingClient>();
1216 m_formClient = makeUnique<API::FormClient>();
1217 m_uiClient = makeUnique<API::UIClient>();
1218 m_findClient = makeUnique<API::FindClient>();
1219 m_findMatchesClient = makeUnique<API::FindMatchesClient>();
1220 m_diagnosticLoggingClient = nullptr;
1221#if ENABLE(CONTEXT_MENUS)
1222 m_contextMenuClient = makeUnique<API::ContextMenuClient>();
1223#endif
1224#if ENABLE(FULLSCREEN_API)
1225 m_fullscreenClient = makeUnique<API::FullscreenClient>();
1226#endif
1227
1228 resetState(ResetStateReason::PageInvalidated);
1229
1230 m_process->processPool().backForwardCache().removeEntriesForPage(*this);
1231
1232 RunLoop::current().dispatch([destinationID = messageSenderDestinationID(), protectedProcess = m_process.copyRef(), preventProcessShutdownScope = m_process->shutdownPreventingScope()] {
1233 protectedProcess->send(Messages::WebPage::Close(), destinationID);
1234 });
1235 m_process->removeWebPage(*this, WebProcessProxy::EndsUsingDataStore::Yes);
1236 removeAllMessageReceivers();
1237 m_process->processPool().supplement<WebNotificationManagerProxy>()->clearNotifications(this);
1238
1239 // Null out related WebPageProxy to avoid leaks.
1240 m_configuration->setRelatedPage(nullptr);
1241
1242#if PLATFORM(IOS_FAMILY)
1243 // Make sure we don't hold a process assertion after getting closed.
1244 m_isVisibleActivity = nullptr;
1245 m_isAudibleActivity = nullptr;
1246 m_isCapturingActivity = nullptr;
1247 m_openingAppLinkActivity = nullptr;
1248 m_audibleActivityTimer.stop();
1249#endif
1250
1251 stopAllURLSchemeTasks();
1252 updatePlayingMediaDidChange(MediaProducer::IsNotPlaying);
1253}
1254
1255bool WebPageProxy::tryClose()
1256{
1257 if (!hasRunningProcess())
1258 return true;
1259
1260 WEBPAGEPROXY_RELEASE_LOG(Process, "tryClose:");
1261
1262 // Close without delay if the process allows it. Our goal is to terminate
1263 // the process, so we check a per-process status bit.
1264 if (m_process->isSuddenTerminationEnabled())
1265 return true;
1266
1267 m_tryCloseTimeoutTimer.startOneShot(tryCloseTimeoutDelay);
1268 sendWithAsyncReply(Messages::WebPage::TryClose(), [this, weakThis = WeakPtr { *this }](bool shouldClose) {
1269 if (!weakThis)
1270 return;
1271
1272 // If we timed out, don't ask the client to close again.
1273 if (!m_tryCloseTimeoutTimer.isActive())
1274 return;
1275
1276 m_tryCloseTimeoutTimer.stop();
1277 if (shouldClose)
1278 closePage();
1279 });
1280 return false;
1281}
1282
1283void WebPageProxy::tryCloseTimedOut()
1284{
1285 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "tryCloseTimedOut: Timed out waiting for the process to respond to the WebPage::TryClose IPC, closing the page now");
1286 closePage();
1287}
1288
1289void WebPageProxy::maybeInitializeSandboxExtensionHandle(WebProcessProxy& process, const URL& url, const URL& resourceDirectoryURL, SandboxExtension::Handle& sandboxExtensionHandle, bool checkAssumedReadAccessToResourceURL)
1290{
1291 if (!url.isLocalFile())
1292 return;
1293
1294#if HAVE(AUDIT_TOKEN)
1295 // If the process is still launching then it does not have a PID yet. We will take care of creating the sandbox extension
1296 // once the process has finished launching.
1297 if (process.isLaunching() || process.wasTerminated())
1298 return;
1299#endif
1300
1301 if (!resourceDirectoryURL.isEmpty()) {
1302 if (checkAssumedReadAccessToResourceURL && process.hasAssumedReadAccessToURL(resourceDirectoryURL))
1303 return;
1304
1305 bool createdExtension = false;
1306#if HAVE(AUDIT_TOKEN)
1307 ASSERT(process.connection() && process.connection()->getAuditToken());
1308 if (process.connection() && process.connection()->getAuditToken()) {
1309 if (auto handle = SandboxExtension::createHandleForReadByAuditToken(resourceDirectoryURL.fileSystemPath(), *(process.connection()->getAuditToken()))) {
1310 sandboxExtensionHandle = WTFMove(*handle);
1311 createdExtension = true;
1312 }
1313 } else
1314#endif
1315 {
1316 if (auto handle = SandboxExtension::createHandle(resourceDirectoryURL.fileSystemPath(), SandboxExtension::Type::ReadOnly)) {
1317 sandboxExtensionHandle = WTFMove(*handle);
1318 createdExtension = true;
1319 }
1320 }
1321
1322 if (createdExtension) {
1323 process.assumeReadAccessToBaseURL(*this, resourceDirectoryURL.string());
1324 return;
1325 }
1326 }
1327
1328 if (process.hasAssumedReadAccessToURL(url))
1329 return;
1330
1331 // Inspector resources are in a directory with assumed access.
1332 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!WebKit::isInspectorPage(*this));
1333
1334 bool createdExtension = false;
1335#if HAVE(AUDIT_TOKEN)
1336 ASSERT(process.connection() && process.connection()->getAuditToken());
1337 if (process.connection() && process.connection()->getAuditToken()) {
1338 if (auto handle = SandboxExtension::createHandleForReadByAuditToken("/"_s, *(process.connection()->getAuditToken()))) {
1339 createdExtension = true;
1340 sandboxExtensionHandle = WTFMove(*handle);
1341 }
1342 } else
1343#endif
1344 {
1345 if (auto handle = SandboxExtension::createHandle("/"_s, SandboxExtension::Type::ReadOnly)) {
1346 createdExtension = true;
1347 sandboxExtensionHandle = WTFMove(*handle);
1348 }
1349 }
1350
1351 if (createdExtension) {
1352 willAcquireUniversalFileReadSandboxExtension(process);
1353 return;
1354 }
1355
1356#if PLATFORM(COCOA)
1357 if (!linkedOnOrAfterSDKWithBehavior(SDKAlignedBehavior::NoUnconditionalUniversalSandboxExtension))
1358 willAcquireUniversalFileReadSandboxExtension(process);
1359#endif
1360
1361 // We failed to issue an universal file read access sandbox, fall back to issuing one for the base URL instead.
1362 auto baseURL = url.truncatedForUseAsBase();
1363 auto basePath = baseURL.fileSystemPath();
1364 if (basePath.isNull())
1365 return;
1366#if HAVE(AUDIT_TOKEN)
1367 if (process.connection() && process.connection()->getAuditToken()) {
1368 if (auto handle = SandboxExtension::createHandleForReadByAuditToken(basePath, *(process.connection()->getAuditToken()))) {
1369 sandboxExtensionHandle = WTFMove(*handle);
1370 createdExtension = true;
1371 }
1372 } else
1373#endif
1374 {
1375 if (auto handle = SandboxExtension::createHandle(basePath, SandboxExtension::Type::ReadOnly)) {
1376 sandboxExtensionHandle = WTFMove(*handle);
1377 createdExtension = true;
1378 }
1379 }
1380
1381 if (createdExtension)
1382 process.assumeReadAccessToBaseURL(*this, baseURL.string());
1383}
1384
1385#if !PLATFORM(COCOA)
1386
1387void WebPageProxy::addPlatformLoadParameters(WebProcessProxy&, LoadParameters&)
1388{
1389}
1390
1391#endif
1392
1393WebProcessProxy& WebPageProxy::ensureRunningProcess()
1394{
1395 if (!hasRunningProcess())
1396 launchProcess({ }, ProcessLaunchReason::InitialProcess);
1397
1398 return m_process;
1399}
1400
1401RefPtr<API::Navigation> WebPageProxy::loadRequest(ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData)
1402{
1403 if (m_isClosed)
1404 return nullptr;
1405
1406 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadRequest:");
1407
1408 if (!hasRunningProcess())
1409 launchProcess(RegistrableDomain { request.url() }, ProcessLaunchReason::InitialProcess);
1410
1411 auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem());
1412
1413 if (shouldForceForegroundPriorityForClientNavigation())
1414 navigation->setClientNavigationActivity(process().throttler().foregroundActivity("Client navigation"_s));
1415
1416#if PLATFORM(COCOA)
1417 setLastNavigationWasAppInitiated(request);
1418#endif
1419
1420 loadRequestWithNavigationShared(m_process.copyRef(), m_webPageID, navigation.get(), WTFMove(request), shouldOpenExternalURLsPolicy, userData, ShouldTreatAsContinuingLoad::No, isNavigatingToAppBoundDomain());
1421 return navigation;
1422}
1423
1424void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& process, WebCore::PageIdentifier webPageID, API::Navigation& navigation, ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, std::optional<WebsitePoliciesData>&& websitePolicies, std::optional<NetworkResourceLoadIdentifier> existingNetworkResourceLoadIdentifierToResume)
1425{
1426 ASSERT(!m_isClosed);
1427
1428 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadRequestWithNavigationShared:");
1429
1430 auto transaction = m_pageLoadState.transaction();
1431
1432 auto url = request.url();
1433 if (shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::No)
1434 m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), url.string() });
1435
1436 LoadParameters loadParameters;
1437 loadParameters.navigationID = navigation.navigationID();
1438 loadParameters.request = WTFMove(request);
1439 loadParameters.shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
1440 loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1441 loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad;
1442 loadParameters.websitePolicies = WTFMove(websitePolicies);
1443 loadParameters.lockHistory = navigation.lockHistory();
1444 loadParameters.lockBackForwardList = navigation.lockBackForwardList();
1445 loadParameters.clientRedirectSourceForHistory = navigation.clientRedirectSourceForHistory();
1446 loadParameters.effectiveSandboxFlags = navigation.effectiveSandboxFlags();
1447 loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
1448 loadParameters.existingNetworkResourceLoadIdentifierToResume = existingNetworkResourceLoadIdentifierToResume;
1449 maybeInitializeSandboxExtensionHandle(process, url, m_pageLoadState.resourceDirectoryURL(), loadParameters.sandboxExtensionHandle);
1450
1451 addPlatformLoadParameters(process, loadParameters);
1452
1453 if (shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::No)
1454 preconnectTo(url, predictedUserAgentForRequest(loadParameters.request));
1455
1456 navigation.setIsLoadedWithNavigationShared(true);
1457
1458 process->markProcessAsRecentlyUsed();
1459
1460 if (!process->isLaunching() || !url.isLocalFile())
1461 process->send(Messages::WebPage::LoadRequest(loadParameters), webPageID);
1462 else
1463 process->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(loadParameters, m_pageLoadState.resourceDirectoryURL(), m_identifier, true), webPageID);
1464 process->startResponsivenessTimer();
1465}
1466
1467RefPtr<API::Navigation> WebPageProxy::loadFile(const String& fileURLString, const String& resourceDirectoryURLString, bool isAppInitiated, API::Object* userData)
1468{
1469 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadFile:");
1470
1471 if (m_isClosed) {
1472 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadFile: page is closed");
1473 return nullptr;
1474 }
1475
1476#if PLATFORM(MAC)
1477 if (isQuarantinedAndNotUserApproved(fileURLString)) {
1478 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadFile: file cannot be opened because it is from an unidentified developer.");
1479 return nullptr;
1480 }
1481#endif
1482
1483 if (!hasRunningProcess())
1484 launchProcess({ }, ProcessLaunchReason::InitialProcess);
1485
1486 URL fileURL { fileURLString };
1487 if (!fileURL.isLocalFile()) {
1488 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadFile: file is not local");
1489 return nullptr;
1490 }
1491
1492 URL resourceDirectoryURL;
1493 if (resourceDirectoryURLString.isNull())
1494 resourceDirectoryURL = URL({ }, "file:///"_s);
1495 else {
1496 resourceDirectoryURL = URL { resourceDirectoryURLString };
1497 if (!resourceDirectoryURL.isLocalFile()) {
1498 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadFile: resource URL is not local");
1499 return nullptr;
1500 }
1501 }
1502
1503 auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(fileURL), m_backForwardList->currentItem());
1504
1505 if (shouldForceForegroundPriorityForClientNavigation())
1506 navigation->setClientNavigationActivity(process().throttler().foregroundActivity("Client navigation"_s));
1507
1508 auto transaction = m_pageLoadState.transaction();
1509
1510 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), fileURLString }, resourceDirectoryURL);
1511
1512 auto request = ResourceRequest(fileURL);
1513 request.setIsAppInitiated(isAppInitiated);
1514 m_lastNavigationWasAppInitiated = isAppInitiated;
1515
1516 LoadParameters loadParameters;
1517 loadParameters.navigationID = navigation->navigationID();
1518 loadParameters.request = WTFMove(request);
1519 loadParameters.shouldOpenExternalURLsPolicy = ShouldOpenExternalURLsPolicy::ShouldNotAllow;
1520 loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1521 const bool checkAssumedReadAccessToResourceURL = false;
1522 maybeInitializeSandboxExtensionHandle(m_process, fileURL, resourceDirectoryURL, loadParameters.sandboxExtensionHandle, checkAssumedReadAccessToResourceURL);
1523 addPlatformLoadParameters(m_process, loadParameters);
1524
1525 m_process->markProcessAsRecentlyUsed();
1526 if (m_process->isLaunching())
1527 send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(loadParameters, resourceDirectoryURL, m_identifier, checkAssumedReadAccessToResourceURL));
1528 else
1529 send(Messages::WebPage::LoadRequest(loadParameters));
1530 m_process->startResponsivenessTimer();
1531
1532 return navigation;
1533}
1534
1535RefPtr<API::Navigation> WebPageProxy::loadData(const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
1536{
1537 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadData:");
1538
1539#if ENABLE(APP_BOUND_DOMAINS)
1540 if (MIMEType == "text/html"_s && !isFullWebBrowser())
1541 m_limitsNavigationsToAppBoundDomains = true;
1542#endif
1543
1544 if (m_isClosed) {
1545 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadData: page is closed");
1546 return nullptr;
1547 }
1548
1549 if (!hasRunningProcess())
1550 launchProcess({ }, ProcessLaunchReason::InitialProcess);
1551
1552 auto navigation = m_navigationState->createLoadDataNavigation(makeUnique<API::SubstituteData>(Vector(data), MIMEType, encoding, baseURL, userData));
1553
1554 if (shouldForceForegroundPriorityForClientNavigation())
1555 navigation->setClientNavigationActivity(process().throttler().foregroundActivity("Client navigation"_s));
1556
1557 loadDataWithNavigationShared(m_process.copyRef(), m_webPageID, navigation, data, MIMEType, encoding, baseURL, userData, ShouldTreatAsContinuingLoad::No, isNavigatingToAppBoundDomain(), std::nullopt, shouldOpenExternalURLsPolicy, SubstituteData::SessionHistoryVisibility::Hidden);
1558 return navigation;
1559}
1560
1561void WebPageProxy::loadDataWithNavigationShared(Ref<WebProcessProxy>&& process, WebCore::PageIdentifier webPageID, API::Navigation& navigation, const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, std::optional<WebsitePoliciesData>&& websitePolicies, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, SubstituteData::SessionHistoryVisibility sessionHistoryVisibility)
1562{
1563 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadDataWithNavigation");
1564
1565 ASSERT(!m_isClosed);
1566
1567 auto transaction = m_pageLoadState.transaction();
1568
1569 m_pageLoadState.setPendingAPIRequest(transaction, { navigation.navigationID(), !baseURL.isEmpty() ? baseURL : aboutBlankURL().string() });
1570
1571 LoadParameters loadParameters;
1572 loadParameters.sessionHistoryVisibility = sessionHistoryVisibility;
1573 loadParameters.navigationID = navigation.navigationID();
1574 loadParameters.data = data;
1575 loadParameters.MIMEType = MIMEType;
1576 loadParameters.encodingName = encoding;
1577 loadParameters.baseURLString = baseURL;
1578 loadParameters.shouldTreatAsContinuingLoad = shouldTreatAsContinuingLoad;
1579 loadParameters.userData = UserData(process->transformObjectsToHandles(userData).get());
1580 loadParameters.websitePolicies = WTFMove(websitePolicies);
1581 loadParameters.shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
1582 loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
1583 loadParameters.isServiceWorkerLoad = isServiceWorkerPage();
1584 addPlatformLoadParameters(process, loadParameters);
1585
1586 process->markProcessAsRecentlyUsed();
1587 process->assumeReadAccessToBaseURL(*this, baseURL);
1588 process->send(Messages::WebPage::LoadData(loadParameters), webPageID);
1589 process->startResponsivenessTimer();
1590}
1591
1592RefPtr<API::Navigation> WebPageProxy::loadSimulatedRequest(WebCore::ResourceRequest&& simulatedRequest, WebCore::ResourceResponse&& simulatedResponse, const IPC::DataReference& data)
1593{
1594 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadSimulatedRequest:");
1595
1596#if PLATFORM(COCOA)
1597 setLastNavigationWasAppInitiated(simulatedRequest);
1598#endif
1599
1600#if ENABLE(APP_BOUND_DOMAINS)
1601 if (simulatedResponse.mimeType() == "text/html"_s && !isFullWebBrowser())
1602 m_limitsNavigationsToAppBoundDomains = true;
1603#endif
1604
1605 if (m_isClosed) {
1606 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadSimulatedRequest: page is closed");
1607 return nullptr;
1608 }
1609
1610 if (!hasRunningProcess())
1611 launchProcess(RegistrableDomain { simulatedRequest.url() }, ProcessLaunchReason::InitialProcess);
1612
1613 auto navigation = m_navigationState->createSimulatedLoadWithDataNavigation(ResourceRequest(simulatedRequest), makeUnique<API::SubstituteData>(Vector(data), ResourceResponse(simulatedResponse), WebCore::SubstituteData::SessionHistoryVisibility::Visible), m_backForwardList->currentItem());
1614
1615 if (shouldForceForegroundPriorityForClientNavigation())
1616 navigation->setClientNavigationActivity(process().throttler().foregroundActivity("Client navigation"_s));
1617
1618 auto transaction = m_pageLoadState.transaction();
1619
1620 auto baseURL = simulatedRequest.url().string();
1621 simulatedResponse.setURL(simulatedRequest.url()); // These should always match for simulated load
1622
1623 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), !baseURL.isEmpty() ? baseURL : aboutBlankURL().string() });
1624
1625 LoadParameters loadParameters;
1626 loadParameters.navigationID = navigation->navigationID();
1627 loadParameters.request = WTFMove(simulatedRequest);
1628 loadParameters.data = data;
1629 loadParameters.MIMEType = simulatedResponse.mimeType();
1630 loadParameters.encodingName = simulatedResponse.textEncodingName();
1631 loadParameters.baseURLString = baseURL;
1632 loadParameters.shouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow;
1633 loadParameters.shouldTreatAsContinuingLoad = ShouldTreatAsContinuingLoad::No;
1634 loadParameters.lockHistory = navigation->lockHistory();
1635 loadParameters.lockBackForwardList = navigation->lockBackForwardList();
1636 loadParameters.clientRedirectSourceForHistory = navigation->clientRedirectSourceForHistory();
1637 loadParameters.effectiveSandboxFlags = navigation->effectiveSandboxFlags();
1638 loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain();
1639
1640 simulatedResponse.setExpectedContentLength(data.size());
1641 simulatedResponse.includeCertificateInfo();
1642
1643 addPlatformLoadParameters(m_process, loadParameters);
1644
1645 m_process->markProcessAsRecentlyUsed();
1646 m_process->assumeReadAccessToBaseURL(*this, baseURL);
1647 m_process->send(Messages::WebPage::LoadSimulatedRequestAndResponse(loadParameters, simulatedResponse), m_webPageID);
1648 m_process->startResponsivenessTimer();
1649 return navigation;
1650}
1651
1652void WebPageProxy::loadAlternateHTML(const IPC::DataReference& htmlData, const String& encoding, const URL& baseURL, const URL& unreachableURL, API::Object* userData)
1653{
1654 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadAlternateHTML");
1655
1656 // When the UIProcess is in the process of handling a failing provisional load, do not attempt to
1657 // start a second alternative HTML load as this will prevent the page load state from being
1658 // handled properly.
1659 if (m_isClosed || m_isLoadingAlternateHTMLStringForFailingProvisionalLoad) {
1660 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadAlternateHTML: page is closed (or other)");
1661 return;
1662 }
1663
1664 if (!m_failingProvisionalLoadURL.isEmpty())
1665 m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = true;
1666
1667 if (!hasRunningProcess())
1668 launchProcess(RegistrableDomain { baseURL }, ProcessLaunchReason::InitialProcess);
1669
1670 auto transaction = m_pageLoadState.transaction();
1671
1672 m_pageLoadState.setPendingAPIRequest(transaction, { 0, unreachableURL.string() });
1673 m_pageLoadState.setUnreachableURL(transaction, unreachableURL.string());
1674
1675 if (m_mainFrame)
1676 m_mainFrame->setUnreachableURL(unreachableURL);
1677
1678 LoadParameters loadParameters;
1679 loadParameters.navigationID = 0;
1680 loadParameters.data = htmlData;
1681 loadParameters.MIMEType = "text/html"_s;
1682 loadParameters.encodingName = encoding;
1683 loadParameters.baseURLString = baseURL.string();
1684 loadParameters.unreachableURLString = unreachableURL.string();
1685 loadParameters.provisionalLoadErrorURLString = m_failingProvisionalLoadURL;
1686 loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1687 addPlatformLoadParameters(process(), loadParameters);
1688
1689 m_process->markProcessAsRecentlyUsed();
1690 m_process->assumeReadAccessToBaseURL(*this, baseURL.string());
1691 m_process->assumeReadAccessToBaseURL(*this, unreachableURL.string());
1692 send(Messages::WebPage::LoadAlternateHTML(loadParameters));
1693 m_process->startResponsivenessTimer();
1694}
1695
1696void WebPageProxy::loadWebArchiveData(API::Data* webArchiveData, API::Object* userData)
1697{
1698 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadWebArchiveData:");
1699
1700 if (m_isClosed) {
1701 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadWebArchiveData: page is closed");
1702 return;
1703 }
1704
1705 if (!hasRunningProcess())
1706 launchProcess({ }, ProcessLaunchReason::InitialProcess);
1707
1708 auto transaction = m_pageLoadState.transaction();
1709 m_pageLoadState.setPendingAPIRequest(transaction, { 0, aboutBlankURL().string() });
1710
1711 LoadParameters loadParameters;
1712 loadParameters.navigationID = 0;
1713 loadParameters.data = webArchiveData->dataReference();
1714 loadParameters.MIMEType = "application/x-webarchive"_s;
1715 loadParameters.encodingName = "utf-16"_s;
1716 loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
1717 addPlatformLoadParameters(process(), loadParameters);
1718
1719 m_process->markProcessAsRecentlyUsed();
1720 send(Messages::WebPage::LoadData(loadParameters));
1721 m_process->startResponsivenessTimer();
1722}
1723
1724void WebPageProxy::navigateToPDFLinkWithSimulatedClick(const String& urlString, IntPoint documentPoint, IntPoint screenPoint)
1725{
1726 WEBPAGEPROXY_RELEASE_LOG(Loading, "navigateToPDFLinkWithSimulatedClick:");
1727
1728 if (m_isClosed) {
1729 WEBPAGEPROXY_RELEASE_LOG(Loading, "navigateToPDFLinkWithSimulatedClick: page is closed:");
1730 return;
1731 }
1732
1733 if (WTF::protocolIsJavaScript(urlString))
1734 return;
1735
1736 if (!hasRunningProcess())
1737 launchProcess(RegistrableDomain { URL { urlString } }, ProcessLaunchReason::InitialProcess);
1738
1739 send(Messages::WebPage::NavigateToPDFLinkWithSimulatedClick(urlString, documentPoint, screenPoint));
1740 m_process->startResponsivenessTimer();
1741}
1742
1743void WebPageProxy::stopLoading()
1744{
1745 WEBPAGEPROXY_RELEASE_LOG(Loading, "stopLoading:");
1746
1747 if (!hasRunningProcess()) {
1748 WEBPAGEPROXY_RELEASE_LOG(Loading, "navigateToPDFLinkWithSimulatedClick: page is not valid");
1749 return;
1750 }
1751
1752 send(Messages::WebPage::StopLoading());
1753 if (m_provisionalPage) {
1754 m_provisionalPage->cancel();
1755 m_provisionalPage = nullptr;
1756 }
1757 m_process->startResponsivenessTimer();
1758}
1759
1760RefPtr<API::Navigation> WebPageProxy::reload(OptionSet<WebCore::ReloadOption> options)
1761{
1762 WEBPAGEPROXY_RELEASE_LOG(Loading, "reload:");
1763
1764 // Make sure the Network & GPU processes are still responsive. This is so that reload() gets us out of the bad state if one of these
1765 // processes is hung.
1766 websiteDataStore().networkProcess().checkForResponsiveness();
1767#if ENABLE(GPU_PROCESS)
1768 if (auto* gpuProcess = process().processPool().gpuProcess())
1769 gpuProcess->checkForResponsiveness();
1770#endif
1771
1772 SandboxExtension::Handle sandboxExtensionHandle;
1773
1774 String url = currentURL();
1775 if (!url.isEmpty()) {
1776 // We may not have an extension yet if back/forward list was reinstated after a WebProcess crash or a browser relaunch
1777 maybeInitializeSandboxExtensionHandle(m_process, URL { url }, currentResourceDirectoryURL(), sandboxExtensionHandle);
1778 }
1779
1780 if (!hasRunningProcess())
1781 return launchProcessForReload();
1782
1783 auto navigation = m_navigationState->createReloadNavigation(m_backForwardList->currentItem());
1784
1785 if (!url.isEmpty()) {
1786 auto transaction = m_pageLoadState.transaction();
1787 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), url });
1788 }
1789
1790 // Store decision to reload without content blockers on the navigation so that we can later set the corresponding
1791 // WebsitePolicies flag in WebPageProxy::receivedNavigationPolicyDecision().
1792 if (options.contains(WebCore::ReloadOption::DisableContentBlockers))
1793 navigation->setUserContentExtensionsEnabled(false);
1794
1795 m_process->markProcessAsRecentlyUsed();
1796 send(Messages::WebPage::Reload(navigation->navigationID(), options.toRaw(), sandboxExtensionHandle));
1797 m_process->startResponsivenessTimer();
1798
1799#if ENABLE(SPEECH_SYNTHESIS)
1800 resetSpeechSynthesizer();
1801#endif
1802
1803 return navigation;
1804}
1805
1806void WebPageProxy::recordAutomaticNavigationSnapshot()
1807{
1808 if (m_shouldSuppressNextAutomaticNavigationSnapshot)
1809 return;
1810
1811 if (WebBackForwardListItem* item = m_backForwardList->currentItem())
1812 recordNavigationSnapshot(*item);
1813}
1814
1815void WebPageProxy::recordNavigationSnapshot(WebBackForwardListItem& item)
1816{
1817 if (!m_shouldRecordNavigationSnapshots)
1818 return;
1819
1820#if PLATFORM(COCOA) || PLATFORM(GTK)
1821 ViewSnapshotStore::singleton().recordSnapshot(*this, item);
1822#else
1823 UNUSED_PARAM(item);
1824#endif
1825}
1826
1827enum class NavigationDirection { Backward, Forward };
1828static WebBackForwardListItem* itemSkippingBackForwardItemsAddedByJSWithoutUserGesture(const WebBackForwardList& backForwardList, NavigationDirection direction)
1829{
1830 auto delta = direction == NavigationDirection::Backward ? -1 : 1;
1831 int itemIndex = delta;
1832 auto* item = backForwardList.itemAtIndex(itemIndex);
1833 if (!item)
1834 return nullptr;
1835
1836#if PLATFORM(COCOA)
1837 if (!linkedOnOrAfterSDKWithBehavior(SDKAlignedBehavior::UIBackForwardSkipsHistoryItemsWithoutUserGesture))
1838 return item;
1839#endif
1840
1841 auto* originalItem = item;
1842 while (item->wasCreatedByJSWithoutUserInteraction()) {
1843 itemIndex += delta;
1844 item = backForwardList.itemAtIndex(itemIndex);
1845 if (!item)
1846 return originalItem;
1847 RELEASE_LOG(Loading, "UI Navigation is skipping a WebBackForwardListItem because it was added by JavaScript without user interaction");
1848 }
1849 return item;
1850}
1851
1852RefPtr<API::Navigation> WebPageProxy::goForward()
1853{
1854 WEBPAGEPROXY_RELEASE_LOG(Loading, "goForward:");
1855 auto* forwardItem = itemSkippingBackForwardItemsAddedByJSWithoutUserGesture(m_backForwardList, NavigationDirection::Forward);
1856 if (!forwardItem)
1857 return nullptr;
1858
1859 return goToBackForwardItem(*forwardItem, FrameLoadType::Forward);
1860}
1861
1862RefPtr<API::Navigation> WebPageProxy::goBack()
1863{
1864 WEBPAGEPROXY_RELEASE_LOG(Loading, "goBack:");
1865 auto* backItem = itemSkippingBackForwardItemsAddedByJSWithoutUserGesture(m_backForwardList, NavigationDirection::Backward);
1866 if (!backItem)
1867 return nullptr;
1868
1869 return goToBackForwardItem(*backItem, FrameLoadType::Back);
1870}
1871
1872RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item)
1873{
1874 return goToBackForwardItem(item, FrameLoadType::IndexedBackForward);
1875}
1876
1877RefPtr<API::Navigation> WebPageProxy::goToBackForwardItem(WebBackForwardListItem& item, FrameLoadType frameLoadType)
1878{
1879 WEBPAGEPROXY_RELEASE_LOG(Loading, "goToBackForwardItem:");
1880 LOG(Loading, "WebPageProxy %p goToBackForwardItem to item URL %s", this, item.url().utf8().data());
1881
1882 if (m_isClosed) {
1883 WEBPAGEPROXY_RELEASE_LOG(Loading, "goToBackForwardItem: page is closed");
1884 return nullptr;
1885 }
1886
1887 if (!hasRunningProcess()) {
1888 launchProcess(RegistrableDomain { URL { item.url() } }, ProcessLaunchReason::InitialProcess);
1889
1890 if (&item != m_backForwardList->currentItem())
1891 m_backForwardList->goToItem(item);
1892 }
1893
1894 RefPtr<API::Navigation> navigation;
1895 if (!m_backForwardList->currentItem()->itemIsInSameDocument(item))
1896 navigation = m_navigationState->createBackForwardNavigation(item, m_backForwardList->currentItem(), frameLoadType);
1897
1898 auto transaction = m_pageLoadState.transaction();
1899 m_pageLoadState.setPendingAPIRequest(transaction, { navigation ? navigation->navigationID() : 0, item.url() });
1900
1901 m_process->markProcessAsRecentlyUsed();
1902 send(Messages::WebPage::GoToBackForwardItem(navigation ? navigation->navigationID() : 0, item.itemID(), frameLoadType, ShouldTreatAsContinuingLoad::No, std::nullopt, m_lastNavigationWasAppInitiated, std::nullopt));
1903 m_process->startResponsivenessTimer();
1904
1905 return navigation;
1906}
1907
1908void WebPageProxy::tryRestoreScrollPosition()
1909{
1910 WEBPAGEPROXY_RELEASE_LOG(Loading, "tryRestoreScrollPosition:");
1911
1912 if (!hasRunningProcess()) {
1913 WEBPAGEPROXY_RELEASE_LOG(Loading, "tryRestoreScrollPosition: page is not valid");
1914 return;
1915 }
1916
1917 send(Messages::WebPage::TryRestoreScrollPosition());
1918}
1919
1920void WebPageProxy::didChangeBackForwardList(WebBackForwardListItem* added, Vector<Ref<WebBackForwardListItem>>&& removed)
1921{
1922 PageClientProtector protector(pageClient());
1923
1924 if (!m_navigationClient->didChangeBackForwardList(*this, added, removed) && m_loaderClient)
1925 m_loaderClient->didChangeBackForwardList(*this, added, WTFMove(removed));
1926
1927 auto transaction = m_pageLoadState.transaction();
1928
1929 m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
1930 m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
1931}
1932
1933void WebPageProxy::willGoToBackForwardListItem(const BackForwardItemIdentifier& itemID, bool inBackForwardCache)
1934{
1935 PageClientProtector protector(pageClient());
1936
1937 if (auto* item = m_backForwardList->itemForID(itemID))
1938 m_navigationClient->willGoToBackForwardListItem(*this, *item, inBackForwardCache);
1939}
1940
1941bool WebPageProxy::shouldKeepCurrentBackForwardListItemInList(WebBackForwardListItem& item)
1942{
1943 PageClientProtector protector(pageClient());
1944
1945 return !m_loaderClient || m_loaderClient->shouldKeepCurrentBackForwardListItemInList(*this, item);
1946}
1947
1948bool WebPageProxy::canShowMIMEType(const String& mimeType)
1949{
1950 if (MIMETypeRegistry::canShowMIMEType(mimeType))
1951 return true;
1952
1953 if (m_preferences->pdfJSViewerEnabled() && MIMETypeRegistry::isPDFMIMEType(mimeType))
1954 return true;
1955
1956#if PLATFORM(COCOA)
1957 // On Mac, we can show PDFs.
1958 if (MIMETypeRegistry::isPDFOrPostScriptMIMEType(mimeType) && !WebProcessPool::omitPDFSupport())
1959 return true;
1960#endif // PLATFORM(COCOA)
1961
1962 return false;
1963}
1964
1965void WebPageProxy::setControlledByAutomation(bool controlled)
1966{
1967 if (m_controlledByAutomation == controlled)
1968 return;
1969
1970 m_controlledByAutomation = controlled;
1971
1972 if (!hasRunningProcess())
1973 return;
1974
1975 send(Messages::WebPage::SetControlledByAutomation(controlled));
1976 websiteDataStore().networkProcess().send(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation), 0);
1977}
1978
1979void WebPageProxy::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type)
1980{
1981 MESSAGE_CHECK(m_process, !targetId.isEmpty());
1982 m_inspectorController->createInspectorTarget(targetId, type);
1983}
1984
1985void WebPageProxy::destroyInspectorTarget(const String& targetId)
1986{
1987 MESSAGE_CHECK(m_process, !targetId.isEmpty());
1988 m_inspectorController->destroyInspectorTarget(targetId);
1989}
1990
1991void WebPageProxy::sendMessageToInspectorFrontend(const String& targetId, const String& message)
1992{
1993 m_inspectorController->sendMessageToInspectorFrontend(targetId, message);
1994}
1995
1996#if ENABLE(REMOTE_INSPECTOR)
1997void WebPageProxy::setIndicating(bool indicating)
1998{
1999 if (!hasRunningProcess())
2000 return;
2001
2002 send(Messages::WebPage::SetIndicating(indicating));
2003}
2004
2005bool WebPageProxy::allowsRemoteInspection() const
2006{
2007 return m_inspectorDebuggable->remoteDebuggingAllowed();
2008}
2009
2010void WebPageProxy::setAllowsRemoteInspection(bool allow)
2011{
2012 m_inspectorDebuggable->setRemoteDebuggingAllowed(allow);
2013}
2014
2015String WebPageProxy::remoteInspectionNameOverride() const
2016{
2017 return m_inspectorDebuggable->nameOverride();
2018}
2019
2020void WebPageProxy::setRemoteInspectionNameOverride(const String& name)
2021{
2022 m_inspectorDebuggable->setNameOverride(name);
2023}
2024
2025void WebPageProxy::remoteInspectorInformationDidChange()
2026{
2027 m_inspectorDebuggable->update();
2028}
2029#endif
2030
2031void WebPageProxy::setBackgroundColor(const std::optional<Color>& color)
2032{
2033 if (m_backgroundColor == color)
2034 return;
2035
2036 m_backgroundColor = color;
2037 if (hasRunningProcess())
2038 send(Messages::WebPage::SetBackgroundColor(color));
2039}
2040
2041void WebPageProxy::setTopContentInset(float contentInset)
2042{
2043 if (m_topContentInset == contentInset)
2044 return;
2045
2046 m_topContentInset = contentInset;
2047
2048 if (!hasRunningProcess())
2049 return;
2050#if PLATFORM(COCOA)
2051 send(Messages::WebPage::SetTopContentInsetFenced(contentInset, m_drawingArea->createFence()));
2052#else
2053 send(Messages::WebPage::SetTopContentInset(contentInset));
2054#endif
2055}
2056
2057void WebPageProxy::setUnderlayColor(const Color& color)
2058{
2059 if (m_underlayColor == color)
2060 return;
2061
2062 m_underlayColor = color;
2063
2064 if (hasRunningProcess())
2065 send(Messages::WebPage::SetUnderlayColor(color));
2066}
2067
2068Color WebPageProxy::underPageBackgroundColor() const
2069{
2070 if (m_underPageBackgroundColorOverride.isValid())
2071 return m_underPageBackgroundColorOverride;
2072
2073 if (m_pageExtendedBackgroundColor.isValid())
2074 return m_pageExtendedBackgroundColor;
2075
2076 return platformUnderPageBackgroundColor();
2077}
2078
2079void WebPageProxy::setUnderPageBackgroundColorOverride(Color&& newUnderPageBackgroundColorOverride)
2080{
2081 if (newUnderPageBackgroundColorOverride == m_underPageBackgroundColorOverride)
2082 return;
2083
2084 auto oldUnderPageBackgroundColor = underPageBackgroundColor();
2085 auto oldUnderPageBackgroundColorOverride = std::exchange(m_underPageBackgroundColorOverride, newUnderPageBackgroundColorOverride);
2086 bool changesUnderPageBackgroundColor = !equalIgnoringSemanticColor(oldUnderPageBackgroundColor, underPageBackgroundColor());
2087 m_underPageBackgroundColorOverride = WTFMove(oldUnderPageBackgroundColorOverride);
2088
2089 if (changesUnderPageBackgroundColor)
2090 pageClient().underPageBackgroundColorWillChange();
2091
2092 m_underPageBackgroundColorOverride = WTFMove(newUnderPageBackgroundColorOverride);
2093
2094 if (changesUnderPageBackgroundColor)
2095 pageClient().underPageBackgroundColorDidChange();
2096
2097 if (m_hasPendingUnderPageBackgroundColorOverrideToDispatch)
2098 return;
2099
2100 m_hasPendingUnderPageBackgroundColorOverrideToDispatch = true;
2101
2102 RunLoop::main().dispatch([this, weakThis = WeakPtr { *this }] {
2103 if (!weakThis)
2104 return;
2105
2106 if (!m_hasPendingUnderPageBackgroundColorOverrideToDispatch)
2107 return;
2108
2109 m_hasPendingUnderPageBackgroundColorOverrideToDispatch = false;
2110
2111 if (m_pageClient)
2112 m_pageClient->didChangeBackgroundColor();
2113
2114 if (hasRunningProcess())
2115 send(Messages::WebPage::SetUnderPageBackgroundColorOverride(m_underPageBackgroundColorOverride));
2116 });
2117}
2118
2119void WebPageProxy::viewWillStartLiveResize()
2120{
2121 if (!hasRunningProcess())
2122 return;
2123
2124 closeOverlayedViews();
2125 send(Messages::WebPage::ViewWillStartLiveResize());
2126}
2127
2128void WebPageProxy::viewWillEndLiveResize()
2129{
2130 if (!hasRunningProcess())
2131 return;
2132 send(Messages::WebPage::ViewWillEndLiveResize());
2133}
2134
2135void WebPageProxy::setViewNeedsDisplay(const Region& region)
2136{
2137 pageClient().setViewNeedsDisplay(region);
2138}
2139
2140void WebPageProxy::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin, ScrollIsAnimated animated)
2141{
2142 pageClient().requestScroll(scrollPosition, scrollOrigin, animated);
2143}
2144
2145WebCore::FloatPoint WebPageProxy::viewScrollPosition() const
2146{
2147 return pageClient().viewScrollPosition();
2148}
2149
2150void WebPageProxy::setSuppressVisibilityUpdates(bool flag)
2151{
2152 if (m_suppressVisibilityUpdates == flag)
2153 return;
2154 m_suppressVisibilityUpdates = flag;
2155
2156 if (!m_suppressVisibilityUpdates) {
2157#if PLATFORM(COCOA)
2158 scheduleActivityStateUpdate();
2159#else
2160 dispatchActivityStateChange();
2161#endif
2162 }
2163}
2164
2165void WebPageProxy::updateActivityState(OptionSet<ActivityState::Flag> flagsToUpdate)
2166{
2167 bool wasVisible = isViewVisible();
2168 m_activityState.remove(flagsToUpdate);
2169 if (flagsToUpdate & ActivityState::IsFocused && pageClient().isViewFocused())
2170 m_activityState.add(ActivityState::IsFocused);
2171 if (flagsToUpdate & ActivityState::WindowIsActive && pageClient().isViewWindowActive())
2172 m_activityState.add(ActivityState::WindowIsActive);
2173 if (flagsToUpdate & ActivityState::IsVisible) {
2174 bool isNowVisible = pageClient().isViewVisible();
2175 if (isNowVisible)
2176 m_activityState.add(ActivityState::IsVisible);
2177 if (wasVisible != isNowVisible)
2178 WEBPAGEPROXY_RELEASE_LOG(ViewState, "updateActivityState: view visibility state changed %d -> %d", wasVisible, isNowVisible);
2179 }
2180 if (flagsToUpdate & ActivityState::IsVisibleOrOccluded && pageClient().isViewVisibleOrOccluded())
2181 m_activityState.add(ActivityState::IsVisibleOrOccluded);
2182 if (flagsToUpdate & ActivityState::IsInWindow && pageClient().isViewInWindow())
2183 m_activityState.add(ActivityState::IsInWindow);
2184 if (flagsToUpdate & ActivityState::IsVisuallyIdle && pageClient().isVisuallyIdle())
2185 m_activityState.add(ActivityState::IsVisuallyIdle);
2186 if (flagsToUpdate & ActivityState::IsAudible && m_mediaState.contains(MediaProducerMediaState::IsPlayingAudio) && !(m_mutedState.contains(MediaProducerMutedState::AudioIsMuted)))
2187 m_activityState.add(ActivityState::IsAudible);
2188 if (flagsToUpdate & ActivityState::IsLoading && m_pageLoadState.isLoading())
2189 m_activityState.add(ActivityState::IsLoading);
2190 if (flagsToUpdate & ActivityState::IsCapturingMedia && m_mediaState.containsAny({ MediaProducerMediaState::HasActiveAudioCaptureDevice, MediaProducerMediaState::HasActiveVideoCaptureDevice }))
2191 m_activityState.add(ActivityState::IsCapturingMedia);
2192}
2193
2194void WebPageProxy::activityStateDidChange(OptionSet<ActivityState::Flag> mayHaveChanged, ActivityStateChangeDispatchMode dispatchMode, ActivityStateChangeReplyMode replyMode)
2195{
2196 LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " activityStateDidChange - mayHaveChanged " << mayHaveChanged);
2197
2198 m_potentiallyChangedActivityStateFlags.add(mayHaveChanged);
2199 m_activityStateChangeWantsSynchronousReply = m_activityStateChangeWantsSynchronousReply || replyMode == ActivityStateChangeReplyMode::Synchronous;
2200
2201 // We need to do this here instead of inside dispatchActivityStateChange() or viewIsBecomingVisible() because these don't run when the view doesn't
2202 // have a running WebProcess. For the same reason, we need to rely on PageClient::isViewVisible() instead of WebPageProxy::isViewVisible().
2203 if (m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible && m_shouldReloadDueToCrashWhenVisible && pageClient().isViewVisible()) {
2204 RunLoop::main().dispatch([this, weakThis = WeakPtr { *this }] {
2205 if (weakThis && std::exchange(m_shouldReloadDueToCrashWhenVisible, false)) {
2206 WEBPAGEPROXY_RELEASE_LOG(ViewState, "activityStateDidChange: view is becoming visible after a crash, attempt a reload");
2207 tryReloadAfterProcessTermination();
2208 }
2209 });
2210 }
2211
2212 if (m_suppressVisibilityUpdates && dispatchMode != ActivityStateChangeDispatchMode::Immediate)
2213 return;
2214
2215#if PLATFORM(COCOA)
2216 bool isNewlyInWindow = !isInWindow() && (mayHaveChanged & ActivityState::IsInWindow) && pageClient().isViewInWindow();
2217 if (dispatchMode == ActivityStateChangeDispatchMode::Immediate || isNewlyInWindow) {
2218 dispatchActivityStateChange();
2219 return;
2220 }
2221 scheduleActivityStateUpdate();
2222#else
2223 UNUSED_PARAM(dispatchMode);
2224 dispatchActivityStateChange();
2225#endif
2226}
2227
2228void WebPageProxy::viewDidLeaveWindow()
2229{
2230 closeOverlayedViews();
2231#if ENABLE(VIDEO_PRESENTATION_MODE)
2232 // When leaving the current page, close the video fullscreen.
2233 if (m_videoFullscreenManager && m_videoFullscreenManager->hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModeStandard))
2234 m_videoFullscreenManager->requestHideAndExitFullscreen();
2235#endif
2236}
2237
2238void WebPageProxy::viewDidEnterWindow()
2239{
2240 LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
2241 if (m_layerHostingMode != layerHostingMode) {
2242 m_layerHostingMode = layerHostingMode;
2243 send(Messages::WebPage::SetLayerHostingMode(layerHostingMode));
2244 }
2245}
2246
2247void WebPageProxy::dispatchActivityStateChange()
2248{
2249#if PLATFORM(COCOA)
2250 if (m_activityStateChangeDispatcher->isScheduled())
2251 m_activityStateChangeDispatcher->invalidate();
2252 m_hasScheduledActivityStateUpdate = false;
2253#endif
2254
2255 if (!hasRunningProcess())
2256 return;
2257
2258 LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " dispatchActivityStateChange - potentiallyChangedActivityStateFlags " << m_potentiallyChangedActivityStateFlags);
2259
2260 // If the visibility state may have changed, then so may the visually idle & occluded agnostic state.
2261 if (m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible)
2262 m_potentiallyChangedActivityStateFlags.add({ ActivityState::IsVisibleOrOccluded, ActivityState::IsVisuallyIdle });
2263
2264 // Record the prior view state, update the flags that may have changed,
2265 // and check which flags have actually changed.
2266 auto previousActivityState = m_activityState;
2267 updateActivityState(m_potentiallyChangedActivityStateFlags);
2268 auto changed = m_activityState ^ previousActivityState;
2269
2270 if (changed)
2271 LOG_WITH_STREAM(ActivityState, stream << "WebPageProxy " << identifier() << " dispatchActivityStateChange: state changed from " << previousActivityState << " to " << m_activityState);
2272
2273 if ((changed & ActivityState::WindowIsActive) && isViewWindowActive())
2274 updateCurrentModifierState();
2275
2276 if ((m_potentiallyChangedActivityStateFlags & ActivityState::IsVisible)) {
2277 if (isViewVisible())
2278 viewIsBecomingVisible();
2279 else
2280 m_process->pageIsBecomingInvisible(m_webPageID);
2281 }
2282
2283 if (m_potentiallyChangedActivityStateFlags & ActivityState::IsConnectedToHardwareConsole)
2284 isConnectedToHardwareConsoleDidChange();
2285
2286 bool isNowInWindow = (changed & ActivityState::IsInWindow) && isInWindow();
2287 // We always want to wait for the Web process to reply if we've been in-window before and are coming back in-window.
2288 if (m_viewWasEverInWindow && isNowInWindow) {
2289 if (m_drawingArea->hasVisibleContent() && m_waitsForPaintAfterViewDidMoveToWindow && !m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow)
2290 m_activityStateChangeWantsSynchronousReply = true;
2291 m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow = false;
2292 }
2293
2294 // Don't wait synchronously if the view state is not visible. (This matters in particular on iOS, where a hidden page may be suspended.)
2295 if (!(m_activityState & ActivityState::IsVisible))
2296 m_activityStateChangeWantsSynchronousReply = false;
2297
2298 auto activityStateChangeID = m_activityStateChangeWantsSynchronousReply ? takeNextActivityStateChangeID() : static_cast<ActivityStateChangeID>(ActivityStateChangeAsynchronous);
2299
2300 if (changed || activityStateChangeID != ActivityStateChangeAsynchronous || !m_nextActivityStateChangeCallbacks.isEmpty()) {
2301 sendWithAsyncReply(Messages::WebPage::SetActivityState(m_activityState, activityStateChangeID), [callbacks = std::exchange(m_nextActivityStateChangeCallbacks, { })] () mutable {
2302 for (auto& callback : callbacks)
2303 callback();
2304 });
2305 }
2306
2307 // This must happen after the SetActivityState message is sent, to ensure the page visibility event can fire.
2308 updateThrottleState();
2309
2310#if ENABLE(POINTER_LOCK)
2311 if (((changed & ActivityState::IsVisible) && !isViewVisible()) || ((changed & ActivityState::WindowIsActive) && !pageClient().isViewWindowActive())
2312 || ((changed & ActivityState::IsFocused) && !(m_activityState & ActivityState::IsFocused)))
2313 requestPointerUnlock();
2314#endif
2315
2316 if (changed & ActivityState::IsVisible) {
2317 if (isViewVisible())
2318 m_visiblePageToken = m_process->visiblePageToken();
2319 else {
2320 m_visiblePageToken = nullptr;
2321
2322 // If we've started the responsiveness timer as part of telling the web process to update the backing store
2323 // state, it might not send back a reply (since it won't paint anything if the web page is hidden) so we
2324 // stop the unresponsiveness timer here.
2325 m_process->stopResponsivenessTimer();
2326 }
2327 }
2328
2329 if (changed & ActivityState::IsInWindow) {
2330 if (isInWindow())
2331 viewDidEnterWindow();
2332 else
2333 viewDidLeaveWindow();
2334 }
2335
2336 updateBackingStoreDiscardableState();
2337
2338 if (activityStateChangeID != ActivityStateChangeAsynchronous)
2339 waitForDidUpdateActivityState(activityStateChangeID);
2340
2341 m_potentiallyChangedActivityStateFlags = { };
2342 m_activityStateChangeWantsSynchronousReply = false;
2343 m_viewWasEverInWindow |= isNowInWindow;
2344
2345#if PLATFORM(COCOA)
2346 for (auto& callback : m_activityStateUpdateCallbacks)
2347 callback();
2348 m_activityStateUpdateCallbacks.clear();
2349#endif
2350}
2351
2352void WebPageProxy::updateThrottleState()
2353{
2354 bool processSuppressionEnabled = m_preferences->pageVisibilityBasedProcessSuppressionEnabled();
2355
2356 // If process suppression is not enabled take a token on the process pool to disable suppression of support processes.
2357 if (!processSuppressionEnabled)
2358 m_preventProcessSuppressionCount = m_process->processPool().processSuppressionDisabledForPageCount();
2359 else if (!m_preventProcessSuppressionCount)
2360 m_preventProcessSuppressionCount = nullptr;
2361
2362 if (m_activityState & ActivityState::IsVisuallyIdle)
2363 m_pageIsUserObservableCount = nullptr;
2364 else if (!m_pageIsUserObservableCount)
2365 m_pageIsUserObservableCount = m_process->processPool().userObservablePageCount();
2366
2367#if PLATFORM(IOS_FAMILY)
2368 if (isViewVisible()) {
2369 if (!m_isVisibleActivity || !m_isVisibleActivity->isValid()) {
2370 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because the view is visible");
2371 m_isVisibleActivity = m_process->throttler().foregroundActivity("View is visible"_s).moveToUniquePtr();
2372 }
2373 } else if (m_isVisibleActivity) {
2374 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because the view is no longer visible");
2375 m_isVisibleActivity = nullptr;
2376 }
2377
2378 bool isAudible = m_activityState.contains(ActivityState::IsAudible);
2379 if (isAudible) {
2380 if (!m_isAudibleActivity || !m_isAudibleActivity->isValid()) {
2381 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because we are playing audio");
2382 m_isAudibleActivity = m_process->throttler().foregroundActivity("View is playing audio"_s).moveToUniquePtr();
2383 }
2384 m_audibleActivityTimer.stop();
2385 } else if (m_isAudibleActivity) {
2386 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess will release a foreground assertion in %g seconds because we are no longer playing audio", audibleActivityClearDelay.seconds());
2387 if (!m_audibleActivityTimer.isActive())
2388 m_audibleActivityTimer.startOneShot(audibleActivityClearDelay);
2389 }
2390
2391 bool isCapturingMedia = m_activityState.contains(ActivityState::IsCapturingMedia);
2392 if (isCapturingMedia) {
2393 if (!m_isCapturingActivity || !m_isCapturingActivity->isValid()) {
2394 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is taking a foreground assertion because media capture is active");
2395 m_isCapturingActivity = m_process->throttler().foregroundActivity("View is capturing media"_s).moveToUniquePtr();
2396 }
2397 } else if (m_isCapturingActivity) {
2398 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because media capture is no longer active");
2399 m_isCapturingActivity = nullptr;
2400 }
2401#endif
2402}
2403
2404#if PLATFORM(IOS_FAMILY)
2405void WebPageProxy::clearAudibleActivity()
2406{
2407 WEBPAGEPROXY_RELEASE_LOG(ProcessSuspension, "updateThrottleState: UIProcess is releasing a foreground assertion because we are no longer playing audio");
2408 m_isAudibleActivity = nullptr;
2409}
2410#endif
2411
2412void WebPageProxy::updateHiddenPageThrottlingAutoIncreases()
2413{
2414 if (!m_preferences->hiddenPageDOMTimerThrottlingAutoIncreases())
2415 m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = nullptr;
2416 else if (!m_hiddenPageDOMTimerThrottlingAutoIncreasesCount)
2417 m_hiddenPageDOMTimerThrottlingAutoIncreasesCount = m_process->processPool().hiddenPageThrottlingAutoIncreasesCount();
2418}
2419
2420void WebPageProxy::layerHostingModeDidChange()
2421{
2422 LayerHostingMode layerHostingMode = pageClient().viewLayerHostingMode();
2423 if (m_layerHostingMode == layerHostingMode)
2424 return;
2425
2426 m_layerHostingMode = layerHostingMode;
2427
2428 if (hasRunningProcess())
2429 send(Messages::WebPage::SetLayerHostingMode(layerHostingMode));
2430}
2431
2432void WebPageProxy::waitForDidUpdateActivityState(ActivityStateChangeID activityStateChangeID)
2433{
2434 if (!hasRunningProcess())
2435 return;
2436
2437 if (m_process->state() != WebProcessProxy::State::Running)
2438 return;
2439
2440 // If we have previously timed out with no response from the WebProcess, don't block the UIProcess again until it starts responding.
2441 if (m_waitingForDidUpdateActivityState)
2442 return;
2443
2444#if PLATFORM(IOS_FAMILY)
2445 // Hail Mary check. Should not be possible (dispatchActivityStateChange should force async if not visible,
2446 // and if visible we should be holding an assertion) - but we should never block on a suspended process.
2447 if (!m_isVisibleActivity) {
2448 ASSERT_NOT_REACHED();
2449 return;
2450 }
2451#endif
2452
2453 m_waitingForDidUpdateActivityState = true;
2454
2455 m_drawingArea->waitForDidUpdateActivityState(activityStateChangeID);
2456}
2457
2458IntSize WebPageProxy::viewSize() const
2459{
2460 return pageClient().viewSize();
2461}
2462
2463void WebPageProxy::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& keyboardEvent, CompletionHandler<void()>&& callbackFunction)
2464{
2465 if (!hasRunningProcess()) {
2466 callbackFunction();
2467 return;
2468 }
2469
2470 sendWithAsyncReply(Messages::WebPage::SetInitialFocus(forward, isKeyboardEventValid, keyboardEvent), [callbackFunction = WTFMove(callbackFunction), backgroundActivity = m_process->throttler().backgroundActivity("WebPageProxy::setInitialFocus"_s)] () mutable {
2471 callbackFunction();
2472 });
2473}
2474
2475void WebPageProxy::clearSelection()
2476{
2477 if (!hasRunningProcess())
2478 return;
2479 send(Messages::WebPage::ClearSelection());
2480}
2481
2482void WebPageProxy::restoreSelectionInFocusedEditableElement()
2483{
2484 if (!hasRunningProcess())
2485 return;
2486 send(Messages::WebPage::RestoreSelectionInFocusedEditableElement());
2487}
2488
2489void WebPageProxy::validateCommand(const String& commandName, CompletionHandler<void(bool, int32_t)>&& callbackFunction)
2490{
2491 if (!hasRunningProcess())
2492 return callbackFunction(false, 0);
2493
2494 sendWithAsyncReply(Messages::WebPage::ValidateCommand(commandName), WTFMove(callbackFunction));
2495}
2496
2497void WebPageProxy::increaseListLevel()
2498{
2499 if (!hasRunningProcess())
2500 return;
2501
2502 send(Messages::WebPage::IncreaseListLevel());
2503}
2504
2505void WebPageProxy::decreaseListLevel()
2506{
2507 if (!hasRunningProcess())
2508 return;
2509
2510 send(Messages::WebPage::DecreaseListLevel());
2511}
2512
2513void WebPageProxy::changeListType()
2514{
2515 if (!hasRunningProcess())
2516 return;
2517
2518 send(Messages::WebPage::ChangeListType());
2519}
2520
2521void WebPageProxy::setBaseWritingDirection(WritingDirection direction)
2522{
2523 if (!hasRunningProcess())
2524 return;
2525
2526 send(Messages::WebPage::SetBaseWritingDirection(direction));
2527}
2528
2529void WebPageProxy::updateFontAttributesAfterEditorStateChange()
2530{
2531 m_cachedFontAttributesAtSelectionStart.reset();
2532
2533 if (m_editorState.isMissingPostLayoutData)
2534 return;
2535
2536 if (auto fontAttributes = m_editorState.postLayoutData().fontAttributes) {
2537 m_uiClient->didChangeFontAttributes(*fontAttributes);
2538 m_cachedFontAttributesAtSelectionStart = WTFMove(fontAttributes);
2539 }
2540}
2541
2542void WebPageProxy::setNeedsFontAttributes(bool needsFontAttributes)
2543{
2544 if (m_needsFontAttributes == needsFontAttributes)
2545 return;
2546
2547 m_needsFontAttributes = needsFontAttributes;
2548
2549 if (hasRunningProcess())
2550 send(Messages::WebPage::SetNeedsFontAttributes(needsFontAttributes));
2551}
2552
2553bool WebPageProxy::maintainsInactiveSelection() const
2554{
2555 // Regardless of what the client wants to do, keep selections if a local Inspector is open.
2556 // Otherwise, there is no way to use the console to inspect the state of a selection.
2557 if (inspector() && inspector()->isVisible())
2558 return true;
2559
2560 return m_maintainsInactiveSelection;
2561}
2562
2563void WebPageProxy::setMaintainsInactiveSelection(bool newValue)
2564{
2565 m_maintainsInactiveSelection = newValue;
2566}
2567
2568void WebPageProxy::scheduleFullEditorStateUpdate()
2569{
2570 if (!hasRunningProcess())
2571 return;
2572
2573 send(Messages::WebPage::ScheduleFullEditorStateUpdate());
2574}
2575
2576void WebPageProxy::selectAll()
2577{
2578 if (!hasRunningProcess())
2579 return;
2580
2581 send(Messages::WebPage::SelectAll());
2582}
2583
2584static std::optional<DOMPasteAccessCategory> pasteAccessCategoryForCommand(const String& commandName)
2585{
2586 static NeverDestroyed<HashMap<String, DOMPasteAccessCategory, ASCIICaseInsensitiveHash>> pasteCommandNames = HashMap<String, DOMPasteAccessCategory, ASCIICaseInsensitiveHash> {
2587 { "Paste"_s, DOMPasteAccessCategory::General },
2588 { "PasteAndMatchStyle"_s, DOMPasteAccessCategory::General },
2589 { "PasteAsQuotation"_s, DOMPasteAccessCategory::General },
2590 { "PasteAsPlainText"_s, DOMPasteAccessCategory::General },
2591 { "PasteFont"_s, DOMPasteAccessCategory::Fonts },
2592 };
2593
2594 auto it = pasteCommandNames->find(commandName);
2595 if (it != pasteCommandNames->end())
2596 return it->value;
2597
2598 return std::nullopt;
2599}
2600
2601void WebPageProxy::executeEditCommand(const String& commandName, const String& argument, CompletionHandler<void()>&& callbackFunction)
2602{
2603 if (!hasRunningProcess()) {
2604 callbackFunction();
2605 return;
2606 }
2607
2608 if (auto pasteAccessCategory = pasteAccessCategoryForCommand(commandName))
2609 willPerformPasteCommand(*pasteAccessCategory);
2610
2611 sendWithAsyncReply(Messages::WebPage::ExecuteEditCommandWithCallback(commandName, argument), [callbackFunction = WTFMove(callbackFunction), backgroundActivity = m_process->throttler().backgroundActivity("WebPageProxy::executeEditCommand"_s)] () mutable {
2612 callbackFunction();
2613 });
2614}
2615
2616void WebPageProxy::executeEditCommand(const String& commandName, const String& argument)
2617{
2618 static NeverDestroyed<String> ignoreSpellingCommandName(MAKE_STATIC_STRING_IMPL("ignoreSpelling"));
2619
2620 if (!hasRunningProcess())
2621 return;
2622
2623 if (auto pasteAccessCategory = pasteAccessCategoryForCommand(commandName))
2624 willPerformPasteCommand(*pasteAccessCategory);
2625
2626 if (commandName == ignoreSpellingCommandName)
2627 ++m_pendingLearnOrIgnoreWordMessageCount;
2628
2629 send(Messages::WebPage::ExecuteEditCommand(commandName, argument));
2630}
2631
2632void WebPageProxy::requestFontAttributesAtSelectionStart(CompletionHandler<void(const WebCore::FontAttributes&)>&& callback)
2633{
2634 if (!hasRunningProcess())
2635 return callback({ });
2636
2637 if (auto attributes = m_cachedFontAttributesAtSelectionStart) {
2638 callback(*attributes);
2639 return;
2640 }
2641
2642 sendWithAsyncReply(Messages::WebPage::RequestFontAttributesAtSelectionStart(), [this, protectedThis = Ref { *this }, callback = WTFMove(callback)] (const WebCore::FontAttributes& attributes) mutable {
2643 m_cachedFontAttributesAtSelectionStart = attributes;
2644 callback(attributes);
2645 });
2646}
2647
2648void WebPageProxy::setEditable(bool editable)
2649{
2650 if (editable == m_isEditable)
2651 return;
2652
2653 m_isEditable = editable;
2654
2655 if (!hasRunningProcess())
2656 return;
2657
2658 send(Messages::WebPage::SetEditable(editable));
2659}
2660
2661void WebPageProxy::setMediaStreamCaptureMuted(bool muted)
2662{
2663 auto state = m_mutedState;
2664 if (muted)
2665 state.add(WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2666 else
2667 state.remove(WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2668 setMuted(state);
2669}
2670
2671void WebPageProxy::isConnectedToHardwareConsoleDidChange()
2672{
2673 SetForScope<bool> isProcessing(m_isProcessingIsConnectedToHardwareConsoleDidChangeNotification, true);
2674 if (m_process->isConnectedToHardwareConsole()) {
2675 if (!m_captureWasMutedWhenHardwareConsoleDisconnected)
2676 setMediaStreamCaptureMuted(false);
2677
2678 m_captureWasMutedWhenHardwareConsoleDisconnected = false;
2679 return;
2680 }
2681
2682 m_captureWasMutedWhenHardwareConsoleDisconnected = m_mutedState.containsAny(WebCore::MediaProducer::MediaStreamCaptureIsMuted);
2683 setMediaStreamCaptureMuted(true);
2684}
2685
2686bool WebPageProxy::isAllowedToChangeMuteState() const
2687{
2688 return m_isProcessingIsConnectedToHardwareConsoleDidChangeNotification || m_process->isConnectedToHardwareConsole();
2689}
2690
2691void WebPageProxy::activateMediaStreamCaptureInPage()
2692{
2693#if ENABLE(MEDIA_STREAM)
2694 WebProcessProxy::muteCaptureInPagesExcept(m_webPageID);
2695#endif
2696 setMediaStreamCaptureMuted(false);
2697}
2698
2699#if !PLATFORM(IOS_FAMILY)
2700void WebPageProxy::didCommitLayerTree(const RemoteLayerTreeTransaction&)
2701{
2702}
2703
2704void WebPageProxy::layerTreeCommitComplete()
2705{
2706}
2707#endif
2708
2709void WebPageProxy::didUpdateRenderingAfterCommittingLoad()
2710{
2711 if (m_hasUpdatedRenderingAfterDidCommitLoad)
2712 return;
2713
2714 m_hasUpdatedRenderingAfterDidCommitLoad = true;
2715 stopMakingViewBlankDueToLackOfRenderingUpdateIfNecessary();
2716}
2717
2718void WebPageProxy::stopMakingViewBlankDueToLackOfRenderingUpdateIfNecessary()
2719{
2720 if (!m_madeViewBlankDueToLackOfRenderingUpdate)
2721 return;
2722
2723 ASSERT(m_hasUpdatedRenderingAfterDidCommitLoad);
2724 WEBPAGEPROXY_RELEASE_LOG(Process, "stopMakingViewBlankDueToLackOfRenderingUpdateIfNecessary:");
2725 pageClient().makeViewBlank(false);
2726 m_madeViewBlankDueToLackOfRenderingUpdate = false;
2727}
2728
2729// If we have not painted yet since the last load commit, then we are likely still displaying the previous page.
2730// Displaying a JS prompt for the new page with the old page behind would be confusing so we make the view blank
2731// until the next paint in such case.
2732void WebPageProxy::makeViewBlankIfUnpaintedSinceLastLoadCommit()
2733{
2734 if (!m_hasUpdatedRenderingAfterDidCommitLoad) {
2735#if PLATFORM(COCOA)
2736 static bool shouldMakeViewBlank = linkedOnOrAfterSDKWithBehavior(SDKAlignedBehavior::BlanksViewOnJSPrompt);
2737#else
2738 static bool shouldMakeViewBlank = true;
2739#endif
2740 if (shouldMakeViewBlank) {
2741 WEBPAGEPROXY_RELEASE_LOG(Process, "makeViewBlankIfUnpaintedSinceLastLoadCommit: Making the view blank because of a JS prompt before the first paint for its page");
2742 pageClient().makeViewBlank(true);
2743 m_madeViewBlankDueToLackOfRenderingUpdate = true;
2744 }
2745 }
2746}
2747
2748void WebPageProxy::discardQueuedMouseEvents()
2749{
2750 while (m_mouseEventQueue.size() > 1)
2751 m_mouseEventQueue.removeLast();
2752}
2753
2754#if ENABLE(DRAG_SUPPORT)
2755void WebPageProxy::dragEntered(DragData& dragData, const String& dragStorageName)
2756{
2757#if PLATFORM(COCOA)
2758 WebPasteboardProxy::singleton().grantAccessToCurrentTypes(m_process.get(), dragStorageName);
2759#endif
2760 launchInitialProcessIfNecessary();
2761 performDragControllerAction(DragControllerAction::Entered, dragData, dragStorageName, { }, { });
2762}
2763
2764void WebPageProxy::dragUpdated(DragData& dragData, const String& dragStorageName)
2765{
2766#if PLATFORM(COCOA)
2767 WebPasteboardProxy::singleton().grantAccessToCurrentTypes(m_process.get(), dragStorageName);
2768#endif
2769 performDragControllerAction(DragControllerAction::Updated, dragData, dragStorageName, { }, { });
2770}
2771
2772void WebPageProxy::dragExited(DragData& dragData, const String& dragStorageName)
2773{
2774 performDragControllerAction(DragControllerAction::Exited, dragData, dragStorageName, { }, { });
2775}
2776
2777void WebPageProxy::performDragOperation(DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, Vector<SandboxExtension::Handle>&& sandboxExtensionsForUpload)
2778{
2779 performDragControllerAction(DragControllerAction::PerformDragOperation, dragData, dragStorageName, WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionsForUpload));
2780}
2781
2782void WebPageProxy::performDragControllerAction(DragControllerAction action, DragData& dragData, const String& dragStorageName, SandboxExtension::Handle&& sandboxExtensionHandle, Vector<SandboxExtension::Handle>&& sandboxExtensionsForUpload)
2783{
2784 if (!hasRunningProcess())
2785 return;
2786#if PLATFORM(GTK)
2787 UNUSED_PARAM(dragStorageName);
2788 UNUSED_PARAM(sandboxExtensionHandle);
2789 UNUSED_PARAM(sandboxExtensionsForUpload);
2790
2791 String url = dragData.asURL();
2792 if (!url.isEmpty())
2793 m_process->assumeReadAccessToBaseURL(*this, url);
2794
2795 ASSERT(dragData.platformData());
2796 send(Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), *dragData.platformData(), dragData.flags()));
2797#else
2798 send(Messages::WebPage::PerformDragControllerAction(action, dragData, sandboxExtensionHandle, sandboxExtensionsForUpload));
2799#endif
2800}
2801
2802void WebPageProxy::didPerformDragControllerAction(std::optional<WebCore::DragOperation> dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect, const IntRect& editableElementRect)
2803{
2804 m_currentDragOperation = dragOperation;
2805 m_currentDragHandlingMethod = dragHandlingMethod;
2806 m_currentDragIsOverFileInput = mouseIsOverFileInput;
2807 m_currentDragNumberOfFilesToBeAccepted = numberOfItemsToBeAccepted;
2808 m_currentDragCaretEditableElementRect = editableElementRect;
2809 setDragCaretRect(insertionRect);
2810 pageClient().didPerformDragControllerAction();
2811}
2812
2813#if PLATFORM(GTK)
2814void WebPageProxy::startDrag(SelectionData&& selectionData, OptionSet<WebCore::DragOperation> dragOperationMask, const ShareableBitmap::Handle& dragImageHandle, IntPoint&& dragImageHotspot)
2815{
2816 RefPtr<ShareableBitmap> dragImage = !dragImageHandle.isNull() ? ShareableBitmap::create(dragImageHandle) : nullptr;
2817 pageClient().startDrag(WTFMove(selectionData), dragOperationMask, WTFMove(dragImage), WTFMove(dragImageHotspot));
2818
2819 didStartDrag();
2820}
2821#endif
2822
2823void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet<WebCore::DragOperation> dragOperationMask)
2824{
2825 if (!hasRunningProcess())
2826 return;
2827 send(Messages::WebPage::DragEnded(clientPosition, globalPosition, dragOperationMask));
2828 setDragCaretRect({ });
2829}
2830
2831void WebPageProxy::didPerformDragOperation(bool handled)
2832{
2833 pageClient().didPerformDragOperation(handled);
2834}
2835
2836void WebPageProxy::didStartDrag()
2837{
2838 if (!hasRunningProcess())
2839 return;
2840
2841 discardQueuedMouseEvents();
2842 send(Messages::WebPage::DidStartDrag());
2843}
2844
2845void WebPageProxy::dragCancelled()
2846{
2847 if (hasRunningProcess())
2848 send(Messages::WebPage::DragCancelled());
2849}
2850
2851void WebPageProxy::didEndDragging()
2852{
2853 resetCurrentDragInformation();
2854}
2855
2856void WebPageProxy::resetCurrentDragInformation()
2857{
2858 m_currentDragOperation = std::nullopt;
2859 m_currentDragHandlingMethod = DragHandlingMethod::None;
2860 m_currentDragIsOverFileInput = false;
2861 m_currentDragNumberOfFilesToBeAccepted = 0;
2862 setDragCaretRect({ });
2863}
2864
2865#if !PLATFORM(IOS_FAMILY) || !ENABLE(DRAG_SUPPORT)
2866
2867void WebPageProxy::setDragCaretRect(const IntRect& dragCaretRect)
2868{
2869 m_currentDragCaretRect = dragCaretRect;
2870}
2871
2872#endif
2873
2874#endif // ENABLE(DRAG_SUPPORT)
2875
2876static bool removeOldRedundantEvent(Deque<NativeWebMouseEvent>& queue, WebEvent::Type incomingEventType)
2877{
2878 if (incomingEventType != WebEvent::MouseMove && incomingEventType != WebEvent::MouseForceChanged)
2879 return false;
2880
2881 auto it = queue.rbegin();
2882 auto end = queue.rend();
2883
2884 // Must not remove the first event in the deque, since it is already being dispatched.
2885 if (it != end)
2886 --end;
2887
2888 for (; it != end; ++it) {
2889 auto type = it->type();
2890 if (type == incomingEventType) {
2891 queue.remove(--it.base());
2892 return true;
2893 }
2894 if (type != WebEvent::MouseMove && type != WebEvent::MouseForceChanged)
2895 break;
2896 }
2897 return false;
2898}
2899
2900void WebPageProxy::handleMouseEvent(const NativeWebMouseEvent& event)
2901{
2902 if (event.type() == WebEvent::MouseDown)
2903 launchInitialProcessIfNecessary();
2904
2905 if (!hasRunningProcess())
2906 return;
2907
2908#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2909 if (m_scrollingCoordinatorProxy)
2910 m_scrollingCoordinatorProxy->handleMouseEvent(platform(event));
2911#endif
2912
2913 // If we receive multiple mousemove or mouseforcechanged events and the most recent mousemove or mouseforcechanged event
2914 // (respectively) has not yet been sent to WebProcess for processing, remove the pending mouse event and insert the new
2915 // event in the queue.
2916 bool didRemoveEvent = removeOldRedundantEvent(m_mouseEventQueue, event.type());
2917 m_mouseEventQueue.append(event);
2918
2919#if LOG_DISABLED
2920 UNUSED_PARAM(didRemoveEvent);
2921#else
2922 LOG(MouseHandling, "UIProcess: %s mouse event %s (queue size %zu)", didRemoveEvent ? "replaced" : "enqueued", webMouseEventTypeString(event.type()), m_mouseEventQueue.size());
2923#endif
2924
2925 if (m_mouseEventQueue.size() == 1) // Otherwise, called from DidReceiveEvent message handler.
2926 processNextQueuedMouseEvent();
2927}
2928
2929void WebPageProxy::processNextQueuedMouseEvent()
2930{
2931 if (!hasRunningProcess())
2932 return;
2933
2934 ASSERT(!m_mouseEventQueue.isEmpty());
2935
2936 const NativeWebMouseEvent& event = m_mouseEventQueue.first();
2937
2938 if (pageClient().windowIsFrontWindowUnderMouse(event))
2939 setToolTip(String());
2940
2941 WebEvent::Type eventType = event.type();
2942 if (eventType == WebEvent::MouseDown || eventType == WebEvent::MouseForceChanged || eventType == WebEvent::MouseForceDown)
2943 m_process->startResponsivenessTimer(WebProcessProxy::UseLazyStop::Yes);
2944 else if (eventType != WebEvent::MouseMove) {
2945 // NOTE: This does not start the responsiveness timer because mouse move should not indicate interaction.
2946 m_process->startResponsivenessTimer();
2947 }
2948
2949 std::optional<Vector<SandboxExtension::Handle>> sandboxExtensions;
2950
2951#if PLATFORM(MAC)
2952 bool eventMayStartDrag = !m_currentDragOperation && eventType == WebEvent::MouseMove && event.button() != WebMouseEvent::Button::NoButton;
2953 if (eventMayStartDrag)
2954 sandboxExtensions = SandboxExtension::createHandlesForMachLookup({ "com.apple.iconservices"_s, "com.apple.iconservices.store"_s }, process().auditToken(), SandboxExtension::MachBootstrapOptions::EnableMachBootstrap);
2955#endif
2956
2957 LOG(MouseHandling, "UIProcess: sent mouse event %s (queue size %zu)", webMouseEventTypeString(eventType), m_mouseEventQueue.size());
2958 send(Messages::WebPage::MouseEvent(event, sandboxExtensions));
2959}
2960
2961void WebPageProxy::doAfterProcessingAllPendingMouseEvents(WTF::Function<void ()>&& action)
2962{
2963 if (!isProcessingMouseEvents()) {
2964 action();
2965 return;
2966 }
2967
2968 m_callbackHandlersAfterProcessingPendingMouseEvents.append(WTFMove(action));
2969}
2970
2971void WebPageProxy::didFinishProcessingAllPendingMouseEvents()
2972{
2973 flushPendingMouseEventCallbacks();
2974}
2975
2976void WebPageProxy::flushPendingMouseEventCallbacks()
2977{
2978 for (auto& callback : m_callbackHandlersAfterProcessingPendingMouseEvents)
2979 callback();
2980
2981 m_callbackHandlersAfterProcessingPendingMouseEvents.clear();
2982}
2983
2984void WebPageProxy::dispatchWheelEventWithoutScrolling(const WebWheelEvent& event, CompletionHandler<void(bool)>&& completionHandler)
2985{
2986 sendWithAsyncReply(Messages::WebPage::DispatchWheelEventWithoutScrolling(event), WTFMove(completionHandler));
2987}
2988
2989void WebPageProxy::handleWheelEvent(const NativeWebWheelEvent& event)
2990{
2991#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
2992 if (m_scrollingCoordinatorProxy && m_scrollingCoordinatorProxy->handleWheelEvent(platform(event)))
2993 return;
2994#endif
2995
2996 if (!hasRunningProcess())
2997 return;
2998
2999 closeOverlayedViews();
3000
3001#if ENABLE(MOMENTUM_EVENT_DISPATCHER)
3002 // FIXME: We should not have to look this up repeatedly, but it can also change occasionally.
3003 if (event.momentumPhase() == WebWheelEvent::PhaseBegan && preferences().momentumScrollingAnimatorEnabled())
3004 m_scrollingAccelerationCurve = ScrollingAccelerationCurve::fromNativeWheelEvent(event);
3005#endif
3006
3007 if (wheelEventCoalescer().shouldDispatchEvent(event)) {
3008 auto event = wheelEventCoalescer().nextEventToDispatch();
3009 sendWheelEvent(*event);
3010 }
3011}
3012
3013#if HAVE(CVDISPLAYLINK)
3014void WebPageProxy::wheelEventHysteresisUpdated(PAL::HysteresisState)
3015{
3016 updateDisplayLinkFrequency();
3017}
3018
3019void WebPageProxy::updateDisplayLinkFrequency()
3020{
3021 if (!m_process->hasConnection() || !m_displayID)
3022 return;
3023
3024 bool wantsFullSpeedUpdates = m_hasActiveAnimatedScroll || m_wheelEventActivityHysteresis.state() == PAL::HysteresisState::Started;
3025 if (wantsFullSpeedUpdates != m_registeredForFullSpeedUpdates) {
3026 process().processPool().setDisplayLinkForDisplayWantsFullSpeedUpdates(*m_process->connection(), *m_displayID, wantsFullSpeedUpdates);
3027 m_registeredForFullSpeedUpdates = wantsFullSpeedUpdates;
3028 }
3029}
3030#endif
3031
3032void WebPageProxy::updateWheelEventActivityAfterProcessSwap()
3033{
3034#if HAVE(CVDISPLAYLINK)
3035 updateDisplayLinkFrequency();
3036#endif
3037}
3038
3039void WebPageProxy::sendWheelEvent(const WebWheelEvent& event)
3040{
3041#if HAVE(CVDISPLAYLINK)
3042 m_wheelEventActivityHysteresis.impulse();
3043#endif
3044
3045 auto* connection = messageSenderConnection();
3046 if (!connection)
3047 return;
3048
3049 auto rubberBandableEdges = this->rubberBandableEdges();
3050 if (shouldUseImplicitRubberBandControl()) {
3051 rubberBandableEdges.setLeft(!m_backForwardList->backItem());
3052 rubberBandableEdges.setRight(!m_backForwardList->forwardItem());
3053 }
3054
3055#if ENABLE(MOMENTUM_EVENT_DISPATCHER)
3056 if (event.momentumPhase() == WebWheelEvent::PhaseBegan && m_scrollingAccelerationCurve != m_lastSentScrollingAccelerationCurve) {
3057 connection->send(Messages::EventDispatcher::SetScrollingAccelerationCurve(m_webPageID, m_scrollingAccelerationCurve), 0, { }, Thread::QOS::UserInteractive);
3058 m_lastSentScrollingAccelerationCurve = m_scrollingAccelerationCurve;
3059 }
3060#endif
3061
3062 connection->send(Messages::EventDispatcher::WheelEvent(m_webPageID, event, rubberBandableEdges), 0, { }, Thread::QOS::UserInteractive);
3063
3064 // Manually ping the web process to check for responsiveness since our wheel
3065 // event will dispatch to a non-main thread, which always responds.
3066 m_process->isResponsiveWithLazyStop();
3067}
3068
3069WebWheelEventCoalescer& WebPageProxy::wheelEventCoalescer()
3070{
3071 if (!m_wheelEventCoalescer)
3072 m_wheelEventCoalescer = makeUnique<WebWheelEventCoalescer>();
3073
3074 return *m_wheelEventCoalescer;
3075}
3076
3077bool WebPageProxy::hasQueuedKeyEvent() const
3078{
3079 return !m_keyEventQueue.isEmpty();
3080}
3081
3082const NativeWebKeyboardEvent& WebPageProxy::firstQueuedKeyEvent() const
3083{
3084 return m_keyEventQueue.first();
3085}
3086
3087bool WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event)
3088{
3089 if (!hasRunningProcess())
3090 return false;
3091
3092 LOG(KeyHandling, "WebPageProxy::handleKeyboardEvent: %s", webKeyboardEventTypeString(event.type()));
3093
3094 m_keyEventQueue.append(event);
3095
3096 m_process->startResponsivenessTimer(event.type() == WebEvent::KeyDown ? WebProcessProxy::UseLazyStop::Yes : WebProcessProxy::UseLazyStop::No);
3097
3098 if (m_keyEventQueue.size() == 1) { // Otherwise, sent from DidReceiveEvent message handler.
3099 LOG(KeyHandling, " UI process: sent keyEvent from handleKeyboardEvent");
3100 send(Messages::WebPage::KeyEvent(event));
3101 }
3102
3103 return true;
3104}
3105
3106WebPreferencesStore WebPageProxy::preferencesStore() const
3107{
3108 return m_preferences->store();
3109}
3110
3111#if ENABLE(TOUCH_EVENTS)
3112
3113static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b)
3114{
3115 if (static_cast<uintptr_t>(b) > static_cast<uintptr_t>(a))
3116 return b;
3117 return a;
3118}
3119
3120void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent)
3121{
3122#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
3123 for (auto& touchPoint : touchStartEvent.touchPoints()) {
3124 IntPoint location = touchPoint.location();
3125 auto updateTrackingType = [this, location](TrackingType& trackingType, EventTrackingRegions::EventType eventType) {
3126 if (trackingType == TrackingType::Synchronous)
3127 return;
3128
3129 TrackingType trackingTypeForLocation = m_scrollingCoordinatorProxy->eventTrackingTypeForPoint(eventType, location);
3130
3131 trackingType = mergeTrackingTypes(trackingType, trackingTypeForLocation);
3132 };
3133 updateTrackingType(m_touchAndPointerEventTracking.touchForceChangedTracking, EventTrackingRegions::EventType::Touchforcechange);
3134 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, EventTrackingRegions::EventType::Touchstart);
3135 updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, EventTrackingRegions::EventType::Touchmove);
3136 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, EventTrackingRegions::EventType::Touchend);
3137 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, EventTrackingRegions::EventType::Pointerover);
3138 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, EventTrackingRegions::EventType::Pointerenter);
3139 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, EventTrackingRegions::EventType::Pointerdown);
3140 updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, EventTrackingRegions::EventType::Pointermove);
3141 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, EventTrackingRegions::EventType::Pointerup);
3142 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, EventTrackingRegions::EventType::Pointerout);
3143 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, EventTrackingRegions::EventType::Pointerleave);
3144 updateTrackingType(m_touchAndPointerEventTracking.touchStartTracking, EventTrackingRegions::EventType::Mousedown);
3145 updateTrackingType(m_touchAndPointerEventTracking.touchMoveTracking, EventTrackingRegions::EventType::Mousemove);
3146 updateTrackingType(m_touchAndPointerEventTracking.touchEndTracking, EventTrackingRegions::EventType::Mouseup);
3147 }
3148#else
3149 UNUSED_PARAM(touchStartEvent);
3150 m_touchAndPointerEventTracking.touchForceChangedTracking = TrackingType::Synchronous;
3151 m_touchAndPointerEventTracking.touchStartTracking = TrackingType::Synchronous;
3152 m_touchAndPointerEventTracking.touchMoveTracking = TrackingType::Synchronous;
3153 m_touchAndPointerEventTracking.touchEndTracking = TrackingType::Synchronous;
3154#endif // ENABLE(ASYNC_SCROLLING)
3155}
3156
3157TrackingType WebPageProxy::touchEventTrackingType(const WebTouchEvent& touchStartEvent) const
3158{
3159 // We send all events if any type is needed, we just do it asynchronously for the types that are not tracked.
3160 //
3161 // Touch events define a sequence with strong dependencies. For example, we can expect
3162 // a TouchMove to only appear after a TouchStart, and the ids of the touch points is consistent between
3163 // the two.
3164 //
3165 // WebCore should not have to set up its state correctly after some events were dismissed.
3166 // For example, we don't want to send a TouchMoved without a TouchPressed.
3167 // We send everything, WebCore updates its internal state and dispatch what is needed to the page.
3168 TrackingType globalTrackingType = m_touchAndPointerEventTracking.isTrackingAnything() ? TrackingType::Asynchronous : TrackingType::NotTracking;
3169
3170 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchForceChangedTracking);
3171 for (auto& touchPoint : touchStartEvent.touchPoints()) {
3172 switch (touchPoint.state()) {
3173 case WebPlatformTouchPoint::TouchReleased:
3174 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchEndTracking);
3175 break;
3176 case WebPlatformTouchPoint::TouchPressed:
3177 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchStartTracking);
3178 break;
3179 case WebPlatformTouchPoint::TouchMoved:
3180 case WebPlatformTouchPoint::TouchStationary:
3181 globalTrackingType = mergeTrackingTypes(globalTrackingType, m_touchAndPointerEventTracking.touchMoveTracking);
3182 break;
3183 case WebPlatformTouchPoint::TouchCancelled:
3184 globalTrackingType = mergeTrackingTypes(globalTrackingType, TrackingType::Asynchronous);
3185 break;
3186 }
3187 }
3188
3189 return globalTrackingType;
3190}
3191
3192#endif
3193
3194#if ENABLE(MAC_GESTURE_EVENTS)
3195void WebPageProxy::handleGestureEvent(const NativeWebGestureEvent& event)
3196{
3197 if (!hasRunningProcess())
3198 return;
3199
3200 m_gestureEventQueue.append(event);
3201 // FIXME: Consider doing some coalescing here.
3202
3203 m_process->startResponsivenessTimer((event.type() == WebEvent::GestureStart || event.type() == WebEvent::GestureChange) ? WebProcessProxy::UseLazyStop::Yes : WebProcessProxy::UseLazyStop::No);
3204
3205 send(Messages::EventDispatcher::GestureEvent(m_webPageID, event), 0);
3206}
3207#endif
3208
3209#if ENABLE(IOS_TOUCH_EVENTS)
3210void WebPageProxy::handlePreventableTouchEvent(NativeWebTouchEvent& event)
3211{
3212 if (!hasRunningProcess())
3213 return;
3214
3215 TraceScope scope(SyncTouchEventStart, SyncTouchEventEnd);
3216
3217 updateTouchEventTracking(event);
3218
3219 auto handleAllTouchPointsReleased = WTF::makeScopeExit([&] {
3220 if (!event.allTouchPointsAreReleased())
3221 return;
3222
3223 m_touchAndPointerEventTracking.reset();
3224 didReleaseAllTouchPoints();
3225 });
3226
3227 bool isTouchStart = event.type() == WebEvent::TouchStart;
3228 bool isTouchEnd = event.type() == WebEvent::TouchEnd;
3229
3230 TrackingType touchEventsTrackingType = touchEventTrackingType(event);
3231 if (touchEventsTrackingType == TrackingType::NotTracking) {
3232 if (isTouchStart)
3233 pageClient().doneDeferringTouchStart(false);
3234 if (isTouchEnd)
3235 pageClient().doneDeferringTouchEnd(false);
3236 return;
3237 }
3238
3239 if (touchEventsTrackingType == TrackingType::Asynchronous) {
3240 // We can end up here if a native gesture has not started but the event handlers are passive.
3241 //
3242 // The client of WebPageProxy asks the event to be sent synchronously since the touch event
3243 // can prevent a native gesture.
3244 // But, here we know that all events handlers that can handle this events are passive.
3245 // We can use asynchronous dispatch and pretend to the client that the page does nothing with the events.
3246 event.setCanPreventNativeGestures(false);
3247 handleUnpreventableTouchEvent(event);
3248 didReceiveEvent(event.type(), false);
3249 if (isTouchStart)
3250 pageClient().doneDeferringTouchStart(false);
3251 if (isTouchEnd)
3252 pageClient().doneDeferringTouchEnd(false);
3253 return;
3254 }
3255
3256 if (isTouchStart || isTouchEnd) {
3257 if (isTouchStart)
3258 ++m_handlingPreventableTouchStartCount;
3259
3260 if (isTouchEnd)
3261 ++m_handlingPreventableTouchEndCount;
3262
3263 sendWithAsyncReply(Messages::EventDispatcher::TouchEvent(m_webPageID, event), [this, weakThis = WeakPtr { *this }, event] (bool handled) {
3264 RefPtr protectedThis { weakThis.get() };
3265 if (!protectedThis)
3266 return;
3267
3268 bool didFinishDeferringTouchStart = false;
3269 ASSERT_IMPLIES(event.type() == WebEvent::TouchStart, m_handlingPreventableTouchStartCount);
3270 if (event.type() == WebEvent::TouchStart && m_handlingPreventableTouchStartCount)
3271 didFinishDeferringTouchStart = !--m_handlingPreventableTouchStartCount;
3272
3273 bool didFinishDeferringTouchEnd = false;
3274 ASSERT_IMPLIES(event.type() == WebEvent::TouchEnd, m_handlingPreventableTouchEndCount);
3275 if (event.type() == WebEvent::TouchEnd && m_handlingPreventableTouchEndCount)
3276 didFinishDeferringTouchEnd = !--m_handlingPreventableTouchEndCount;
3277
3278 bool handledOrFailedWithError = handled || m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart;
3279 if (!isHandlingPreventableTouchStart())
3280 m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart = false;
3281
3282 didReceiveEvent(event.type(), handledOrFailedWithError);
3283 if (!m_pageClient)
3284 return;
3285
3286 pageClient().doneWithTouchEvent(event, handledOrFailedWithError);
3287
3288 if (didFinishDeferringTouchStart)
3289 pageClient().doneDeferringTouchStart(handledOrFailedWithError);
3290
3291 if (didFinishDeferringTouchEnd)
3292 pageClient().doneDeferringTouchEnd(handledOrFailedWithError);
3293 });
3294 return;
3295 }
3296
3297 m_process->startResponsivenessTimer();
3298 bool handled = false;
3299 bool replyReceived = !!sendSync(Messages::WebPage::TouchEventSync(event), Messages::WebPage::TouchEventSync::Reply(handled), 1_s, IPC::SendSyncOption::ForceDispatchWhenDestinationIsWaitingForUnboundedSyncReply);
3300 // 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.
3301 if (!replyReceived)
3302 handled = true;
3303 didReceiveEvent(event.type(), handled);
3304 pageClient().doneWithTouchEvent(event, handled);
3305 if (!isHandlingPreventableTouchStart())
3306 pageClient().doneDeferringTouchStart(handled);
3307 else if (handled)
3308 m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart = true;
3309 m_process->stopResponsivenessTimer();
3310}
3311
3312void WebPageProxy::resetPotentialTapSecurityOrigin()
3313{
3314 if (!hasRunningProcess())
3315 return;
3316
3317 send(Messages::WebPage::ResetPotentialTapSecurityOrigin());
3318}
3319
3320void WebPageProxy::handleUnpreventableTouchEvent(const NativeWebTouchEvent& event)
3321{
3322 if (!hasRunningProcess())
3323 return;
3324
3325 TrackingType touchEventsTrackingType = touchEventTrackingType(event);
3326 if (touchEventsTrackingType == TrackingType::NotTracking)
3327 return;
3328
3329 send(Messages::EventDispatcher::TouchEventWithoutCallback(m_webPageID, event), 0);
3330
3331 if (event.allTouchPointsAreReleased()) {
3332 m_touchAndPointerEventTracking.reset();
3333 didReleaseAllTouchPoints();
3334 }
3335}
3336
3337#elif ENABLE(TOUCH_EVENTS)
3338void WebPageProxy::handleTouchEvent(const NativeWebTouchEvent& event)
3339{
3340 if (!hasRunningProcess())
3341 return;
3342
3343 updateTouchEventTracking(event);
3344
3345 if (touchEventTrackingType(event) == TrackingType::NotTracking)
3346 return;
3347
3348 // If the page is suspended, which should be the case during panning, pinching
3349 // and animation on the page itself (kinetic scrolling, tap to zoom) etc, then
3350 // we do not send any of the events to the page even if is has listeners.
3351 if (!m_areActiveDOMObjectsAndAnimationsSuspended) {
3352 m_touchEventQueue.append(event);
3353 m_process->startResponsivenessTimer();
3354 send(Messages::WebPage::TouchEvent(event));
3355 } else {
3356 if (m_touchEventQueue.isEmpty()) {
3357 bool isEventHandled = false;
3358 pageClient().doneWithTouchEvent(event, isEventHandled);
3359 } else {
3360 // We attach the incoming events to the newest queued event so that all
3361 // the events are delivered in the correct order when the event is dequed.
3362 QueuedTouchEvents& lastEvent = m_touchEventQueue.last();
3363 lastEvent.deferredTouchEvents.append(event);
3364 }
3365 }
3366
3367 if (event.allTouchPointsAreReleased()) {
3368 m_touchAndPointerEventTracking.reset();
3369 didReleaseAllTouchPoints();
3370 }
3371}
3372#endif // ENABLE(TOUCH_EVENTS)
3373
3374void WebPageProxy::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint)
3375{
3376 send(Messages::WebPage::CancelPointer(pointerId, documentPoint));
3377}
3378
3379void WebPageProxy::touchWithIdentifierWasRemoved(WebCore::PointerID pointerId)
3380{
3381 send(Messages::WebPage::TouchWithIdentifierWasRemoved(pointerId));
3382}
3383
3384void WebPageProxy::scrollBy(ScrollDirection direction, ScrollGranularity granularity)
3385{
3386 if (!hasRunningProcess())
3387 return;
3388
3389 send(Messages::WebPage::ScrollBy(direction, granularity));
3390}
3391
3392void WebPageProxy::centerSelectionInVisibleArea()
3393{
3394 if (!hasRunningProcess())
3395 return;
3396
3397 send(Messages::WebPage::CenterSelectionInVisibleArea());
3398}
3399
3400class WebPageProxy::PolicyDecisionSender : public RefCounted<PolicyDecisionSender> {
3401public:
3402 using SendFunction = CompletionHandler<void(PolicyDecision&&)>;
3403
3404 static Ref<PolicyDecisionSender> create(PolicyCheckIdentifier identifier, SendFunction&& sendFunction)
3405 {
3406 return adoptRef(*new PolicyDecisionSender(identifier, WTFMove(sendFunction)));
3407 }
3408
3409 void send(PolicyDecision&& policyDecision)
3410 {
3411 if (m_sendFunction)
3412 m_sendFunction(WTFMove(policyDecision));
3413 }
3414
3415 PolicyCheckIdentifier identifier() { return m_identifier; }
3416
3417private:
3418 PolicyDecisionSender(PolicyCheckIdentifier identifier, SendFunction sendFunction)
3419 : m_sendFunction(WTFMove(sendFunction))
3420 , m_identifier(identifier)
3421 { }
3422
3423 SendFunction m_sendFunction;
3424 PolicyCheckIdentifier m_identifier;
3425};
3426
3427#if ENABLE(APP_BOUND_DOMAINS)
3428static bool shouldTreatURLProtocolAsAppBound(const URL& requestURL, bool isRunningTest)
3429{
3430 return !isRunningTest
3431 && (SecurityOrigin::isLocalHostOrLoopbackIPAddress(requestURL.host())
3432 || requestURL.protocolIsAbout()
3433 || requestURL.protocolIsData()
3434 || requestURL.protocolIsBlob()
3435 || requestURL.isLocalFile()
3436 || requestURL.protocolIsJavaScript());
3437}
3438
3439bool WebPageProxy::setIsNavigatingToAppBoundDomainAndCheckIfPermitted(bool isMainFrame, const URL& requestURL, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain)
3440{
3441 if (isFullWebBrowser()) {
3442 if (hasProhibitedUsageStrings())
3443 m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::No;
3444 return true;
3445 }
3446
3447 if (!isNavigatingToAppBoundDomain) {
3448 m_isNavigatingToAppBoundDomain = std::nullopt;
3449 return true;
3450 }
3451 if (m_ignoresAppBoundDomains)
3452 return true;
3453
3454 if (isMainFrame && shouldTreatURLProtocolAsAppBound(requestURL, websiteDataStore().configuration().enableInAppBrowserPrivacyForTesting())) {
3455 isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::Yes;
3456 m_limitsNavigationsToAppBoundDomains = true;
3457 }
3458 if (m_limitsNavigationsToAppBoundDomains) {
3459 if (*isNavigatingToAppBoundDomain == NavigatingToAppBoundDomain::No) {
3460 if (isMainFrame)
3461 return false;
3462 m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::No;
3463 return true;
3464 }
3465 m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::Yes;
3466 } else {
3467 if (m_hasExecutedAppBoundBehaviorBeforeNavigation)
3468 return false;
3469 m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::No;
3470 }
3471 return true;
3472}
3473
3474void WebPageProxy::isNavigatingToAppBoundDomainTesting(CompletionHandler<void(bool)>&& completionHandler)
3475{
3476 completionHandler(m_isNavigatingToAppBoundDomain && (*m_isNavigatingToAppBoundDomain == NavigatingToAppBoundDomain::Yes));
3477}
3478
3479void WebPageProxy::isForcedIntoAppBoundModeTesting(CompletionHandler<void(bool)>&& completionHandler)
3480{
3481 completionHandler(m_limitsNavigationsToAppBoundDomains);
3482}
3483#endif
3484
3485void WebPageProxy::disableServiceWorkerEntitlementInNetworkProcess()
3486{
3487#if ENABLE(APP_BOUND_DOMAINS) && !PLATFORM(MACCATALYST)
3488 websiteDataStore().networkProcess().send(Messages::NetworkProcess::DisableServiceWorkerEntitlement(), 0);
3489#endif
3490}
3491
3492void WebPageProxy::clearServiceWorkerEntitlementOverride(CompletionHandler<void()>&& completionHandler)
3493{
3494#if ENABLE(APP_BOUND_DOMAINS) && !PLATFORM(MACCATALYST)
3495 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
3496 sendWithAsyncReply(Messages::WebPage::ClearServiceWorkerEntitlementOverride(), [callbackAggregator] { });
3497 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::ClearServiceWorkerEntitlementOverride(), [callbackAggregator] { });
3498#else
3499 completionHandler();
3500#endif
3501}
3502
3503void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, API::Navigation* navigation, Ref<API::NavigationAction>&& navigationAction, ProcessSwapRequestedByClient processSwapRequestedByClient, WebFrameProxy& frame, const FrameInfoData& frameInfo, Ref<PolicyDecisionSender>&& sender)
3504{
3505 WEBPAGEPROXY_RELEASE_LOG(Loading, "receivedNavigationPolicyDecision: frameID=%llu, isMainFrame=%d, navigationID=%llu, policyAction=%u", frame.frameID().toUInt64(), frame.isMainFrame(), navigation ? navigation->navigationID() : 0, (unsigned)policyAction);
3506
3507 Ref<WebsiteDataStore> websiteDataStore = m_websiteDataStore.copyRef();
3508 if (auto* policies = navigation->websitePolicies()) {
3509 if (policies->websiteDataStore() && policies->websiteDataStore() != websiteDataStore.ptr()) {
3510 websiteDataStore = *policies->websiteDataStore();
3511 processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
3512 }
3513 if (policies->userContentController() && policies->userContentController() != m_userContentController.ptr())
3514 processSwapRequestedByClient = ProcessSwapRequestedByClient::Yes;
3515 }
3516
3517 if (navigation && !navigation->userContentExtensionsEnabled()) {
3518 if (!navigation->websitePolicies())
3519 navigation->setWebsitePolicies(API::WebsitePolicies::create());
3520 navigation->websitePolicies()->setContentBlockersEnabled(false);
3521 }
3522
3523#if ENABLE(DEVICE_ORIENTATION)
3524 if (navigation && (!navigation->websitePolicies() || navigation->websitePolicies()->deviceOrientationAndMotionAccessState() == WebCore::DeviceOrientationOrMotionPermissionState::Prompt)) {
3525 auto deviceOrientationPermission = websiteDataStore->deviceOrientationAndMotionAccessController().cachedDeviceOrientationPermission(SecurityOriginData::fromURL(navigation->currentRequest().url()));
3526 if (deviceOrientationPermission != WebCore::DeviceOrientationOrMotionPermissionState::Prompt) {
3527 if (!navigation->websitePolicies())
3528 navigation->setWebsitePolicies(API::WebsitePolicies::create());
3529 navigation->websitePolicies()->setDeviceOrientationAndMotionAccessState(deviceOrientationPermission);
3530 }
3531 }
3532#endif
3533
3534#if PLATFORM(COCOA)
3535 static const bool forceDownloadFromDownloadAttribute = false;
3536#else
3537 static const bool forceDownloadFromDownloadAttribute = true;
3538#endif
3539 if (policyAction == PolicyAction::Use && navigation && (navigation->isSystemPreview() || (forceDownloadFromDownloadAttribute && navigation->shouldPerformDownload())))
3540 policyAction = PolicyAction::Download;
3541
3542 if (policyAction != PolicyAction::Use || !frame.isMainFrame() || !navigation) {
3543 receivedPolicyDecision(policyAction, navigation, navigation->websitePolicies(), WTFMove(navigationAction), WTFMove(sender));
3544 return;
3545 }
3546
3547 Ref<WebProcessProxy> sourceProcess = process();
3548 URL sourceURL { pageLoadState().url() };
3549 if (auto* provisionalPage = provisionalPageProxy()) {
3550 if (provisionalPage->navigationID() == navigation->navigationID()) {
3551 sourceProcess = provisionalPage->process();
3552 sourceURL = provisionalPage->provisionalURL();
3553 }
3554 }
3555
3556 m_isCaptivePortalModeExplicitlySet = (navigation->websitePolicies() && navigation->websitePolicies()->isCaptivePortalModeExplicitlySet()) || m_configuration->isCaptivePortalModeExplicitlySet();
3557 auto captivePortalMode = (navigation->websitePolicies() ? navigation->websitePolicies()->captivePortalModeEnabled() : shouldEnableCaptivePortalMode()) ? WebProcessProxy::CaptivePortalMode::Enabled : WebProcessProxy::CaptivePortalMode::Disabled;
3558 process().processPool().processForNavigation(*this, *navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, captivePortalMode, frameInfo, WTFMove(websiteDataStore), [this, protectedThis = Ref { *this }, policyAction, navigation = Ref { *navigation }, navigationAction = WTFMove(navigationAction), sourceProcess = sourceProcess.copyRef(), sender = WTFMove(sender), processSwapRequestedByClient] (Ref<WebProcessProxy>&& processForNavigation, SuspendedPageProxy* destinationSuspendedPage, const String& reason) mutable {
3559 // If the navigation has been destroyed, then no need to proceed.
3560 if (isClosed() || !navigationState().hasNavigation(navigation->navigationID())) {
3561 receivedPolicyDecision(policyAction, navigation.ptr(), navigation->websitePolicies(), WTFMove(navigationAction), WTFMove(sender));
3562 return;
3563 }
3564
3565 bool shouldProcessSwap = processForNavigation.ptr() != sourceProcess.ptr();
3566 if (shouldProcessSwap) {
3567 policyAction = PolicyAction::StopAllLoads;
3568 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "decidePolicyForNavigationAction, swapping process %i with process %i for navigation, reason=%" PUBLIC_LOG_STRING, processIdentifier(), processForNavigation->processIdentifier(), reason.utf8().data());
3569 LOG(ProcessSwapping, "(ProcessSwapping) Switching from process %i to new process (%i) for navigation %" PRIu64 " '%s'", processIdentifier(), processForNavigation->processIdentifier(), navigation->navigationID(), navigation->loggingString());
3570 } else
3571 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "decidePolicyForNavigationAction: keep using process %i for navigation, reason=%" PUBLIC_LOG_STRING, processIdentifier(), reason.utf8().data());
3572
3573 if (shouldProcessSwap) {
3574 // Make sure the process to be used for the navigation does not get shutDown now due to destroying SuspendedPageProxy or ProvisionalPageProxy objects.
3575 auto preventNavigationProcessShutdown = processForNavigation->shutdownPreventingScope();
3576
3577 ASSERT(!destinationSuspendedPage || navigation->targetItem());
3578 auto suspendedPage = destinationSuspendedPage ? backForwardCache().takeSuspendedPage(*navigation->targetItem()) : nullptr;
3579
3580 // It is difficult to get history right if we have several WebPage objects inside a single WebProcess for the same WebPageProxy. As a result, if we make sure to
3581 // clear any SuspendedPageProxy for the current page that are backed by the destination process before we proceed with the navigation. This makes sure the WebPage
3582 // we are about to create in the destination process will be the only one associated with this WebPageProxy.
3583 if (!destinationSuspendedPage)
3584 backForwardCache().removeEntriesForPageAndProcess(*this, processForNavigation);
3585
3586 ASSERT(suspendedPage.get() == destinationSuspendedPage);
3587 if (suspendedPage && suspendedPage->pageIsClosedOrClosing())
3588 suspendedPage = nullptr;
3589
3590 continueNavigationInNewProcess(navigation, WTFMove(suspendedPage), WTFMove(processForNavigation), processSwapRequestedByClient, ShouldTreatAsContinuingLoad::YesAfterNavigationPolicyDecision);
3591
3592 receivedPolicyDecision(policyAction, navigation.ptr(), nullptr, WTFMove(navigationAction), WTFMove(sender), WillContinueLoadInNewProcess::Yes);
3593 return;
3594 }
3595
3596 auto item = navigation->reloadItem() ? navigation->reloadItem() : navigation->targetItem();
3597 std::optional<SandboxExtension::Handle> optionalHandle;
3598 if (policyAction == PolicyAction::Use && item) {
3599 URL fullURL { item->url() };
3600 if (fullURL.protocolIs("file"_s)) {
3601 SandboxExtension::Handle sandboxExtensionHandle;
3602 maybeInitializeSandboxExtensionHandle(processForNavigation.get(), fullURL, item->resourceDirectoryURL(), sandboxExtensionHandle);
3603 optionalHandle = WTFMove(sandboxExtensionHandle);
3604 }
3605 }
3606
3607 receivedPolicyDecision(policyAction, navigation.ptr(), navigation->websitePolicies(), WTFMove(navigationAction), WTFMove(sender), WillContinueLoadInNewProcess::No, WTFMove(optionalHandle));
3608 });
3609}
3610
3611void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, RefPtr<API::WebsitePolicies>&& websitePolicies, std::variant<Ref<API::NavigationResponse>, Ref<API::NavigationAction>>&& navigationActionOrResponse, Ref<PolicyDecisionSender>&& sender, WillContinueLoadInNewProcess willContinueLoadInNewProcess, std::optional<SandboxExtension::Handle> sandboxExtensionHandle)
3612{
3613 if (!hasRunningProcess()) {
3614 sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), PolicyAction::Ignore, 0, std::nullopt, std::nullopt });
3615 return;
3616 }
3617
3618 auto transaction = m_pageLoadState.transaction();
3619
3620 if (action == PolicyAction::Ignore && willContinueLoadInNewProcess == WillContinueLoadInNewProcess::No && navigation && navigation->navigationID() == m_pageLoadState.pendingAPIRequest().navigationID)
3621 m_pageLoadState.clearPendingAPIRequest(transaction);
3622
3623 std::optional<DownloadID> downloadID;
3624 if (action == PolicyAction::Download) {
3625 // Create a download proxy.
3626 auto& download = m_process->processPool().createDownloadProxy(m_websiteDataStore, m_decidePolicyForResponseRequest, this, navigation ? navigation->originatingFrameInfo() : FrameInfoData { });
3627 download.setDidStartCallback([this, weakThis = WeakPtr { *this }, navigationActionOrResponse = WTFMove(navigationActionOrResponse)] (auto* downloadProxy) {
3628 if (!weakThis || !downloadProxy)
3629 return;
3630 WTF::switchOn(navigationActionOrResponse,
3631 [&] (const Ref<API::NavigationResponse>& response) {
3632 if (!response->downloadAttribute().isNull())
3633 downloadProxy->setSuggestedFilename(response->downloadAttribute());
3634 m_navigationClient->navigationResponseDidBecomeDownload(*this, response.get(), *downloadProxy);
3635 }, [&] (const Ref<API::NavigationAction>& action) {
3636 m_navigationClient->navigationActionDidBecomeDownload(*this, action.get(), *downloadProxy);
3637 }
3638 );
3639 });
3640 if (navigation) {
3641 download.setWasUserInitiated(navigation->wasUserInitiated());
3642 download.setRedirectChain(navigation->takeRedirectChain());
3643 }
3644
3645 downloadID = download.downloadID();
3646 handleDownloadRequest(download);
3647 m_decidePolicyForResponseRequest = { };
3648 }
3649
3650 std::optional<WebsitePoliciesData> websitePoliciesData;
3651 if (websitePolicies)
3652 websitePoliciesData = websitePolicies->data();
3653
3654 sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), action, navigation ? navigation->navigationID() : 0, downloadID, WTFMove(websitePoliciesData), WTFMove(sandboxExtensionHandle) });
3655}
3656
3657void WebPageProxy::commitProvisionalPage(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, WebCore::FrameLoadType frameLoadType, const WebCore::CertificateInfo& certificateInfo, bool usedLegacyTLS, bool containsPluginDocument, std::optional<WebCore::HasInsecureContent> forcedHasInsecureContent, WebCore::MouseEventPolicy mouseEventPolicy, const UserData& userData)
3658{
3659 ASSERT(m_provisionalPage);
3660 WEBPAGEPROXY_RELEASE_LOG(Loading, "commitProvisionalPage: newPID=%i", m_provisionalPage->process().processIdentifier());
3661
3662 std::optional<FrameIdentifier> mainFrameIDInPreviousProcess = m_mainFrame ? std::make_optional(m_mainFrame->frameID()) : std::nullopt;
3663
3664 ASSERT(m_process.ptr() != &m_provisionalPage->process());
3665
3666 auto shouldDelayClosingUntilFirstLayerFlush = ShouldDelayClosingUntilFirstLayerFlush::No;
3667#if PLATFORM(MAC)
3668 // 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
3669 // entered accelerated compositing for the new page or we will flash on navigation.
3670 if (drawingArea()->type() == DrawingAreaType::TiledCoreAnimation)
3671 shouldDelayClosingUntilFirstLayerFlush = ShouldDelayClosingUntilFirstLayerFlush::Yes;
3672#endif
3673
3674 if (m_isLayerTreeFrozenDueToSwipeAnimation)
3675 send(Messages::WebPage::UnfreezeLayerTreeDueToSwipeAnimation());
3676
3677 resetStateAfterProcessTermination(ProcessTerminationReason::NavigationSwap);
3678
3679 removeAllMessageReceivers();
3680 auto* navigation = navigationState().navigation(m_provisionalPage->navigationID());
3681 bool didSuspendPreviousPage = navigation && !m_provisionalPage->isProcessSwappingOnNavigationResponse() ? suspendCurrentPageIfPossible(*navigation, mainFrameIDInPreviousProcess, m_provisionalPage->processSwapRequestedByClient(), shouldDelayClosingUntilFirstLayerFlush) : false;
3682 m_process->removeWebPage(*this, m_websiteDataStore.ptr() == m_provisionalPage->process().websiteDataStore() ? WebProcessProxy::EndsUsingDataStore::No : WebProcessProxy::EndsUsingDataStore::Yes);
3683
3684 // There is no way we'll be able to return to the page in the previous page so close it.
3685 if (!didSuspendPreviousPage)
3686 send(Messages::WebPage::Close());
3687
3688 const auto oldWebPageID = m_webPageID;
3689 swapToProvisionalPage(std::exchange(m_provisionalPage, nullptr));
3690
3691 didCommitLoadForFrame(frameID, WTFMove(frameInfo), WTFMove(request), navigationID, mimeType, frameHasCustomContentProvider, frameLoadType, certificateInfo, usedLegacyTLS, containsPluginDocument, forcedHasInsecureContent, mouseEventPolicy, userData);
3692
3693 m_inspectorController->didCommitProvisionalPage(oldWebPageID, m_webPageID);
3694}
3695
3696void WebPageProxy::destroyProvisionalPage()
3697{
3698 m_provisionalPage = nullptr;
3699}
3700
3701void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, std::unique_ptr<SuspendedPageProxy>&& suspendedPage, Ref<WebProcessProxy>&& newProcess, ProcessSwapRequestedByClient processSwapRequestedByClient, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, std::optional<NetworkResourceLoadIdentifier> existingNetworkResourceLoadIdentifierToResume)
3702{
3703 WEBPAGEPROXY_RELEASE_LOG(Loading, "continueNavigationInNewProcess: newProcessPID=%i, hasSuspendedPage=%i", newProcess->processIdentifier(), !!suspendedPage);
3704 LOG(Loading, "Continuing navigation %" PRIu64 " '%s' in a new web process", navigation.navigationID(), navigation.loggingString());
3705 RELEASE_ASSERT(!newProcess->isInProcessCache());
3706 ASSERT(shouldTreatAsContinuingLoad != ShouldTreatAsContinuingLoad::No);
3707
3708 if (m_provisionalPage) {
3709 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "continueNavigationInNewProcess: There is already a pending provisional load, cancelling it (provisonalNavigationID=%llu, navigationID=%llu)", m_provisionalPage->navigationID(), navigation.navigationID());
3710 if (m_provisionalPage->navigationID() != navigation.navigationID())
3711 m_provisionalPage->cancel();
3712 m_provisionalPage = nullptr;
3713 }
3714
3715 RefPtr websitePolicies = navigation.websitePolicies();
3716 bool isServerSideRedirect = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::YesAfterNavigationPolicyDecision && navigation.currentRequestIsRedirect();
3717 bool isProcessSwappingOnNavigationResponse = shouldTreatAsContinuingLoad == ShouldTreatAsContinuingLoad::YesAfterProvisionalLoadStarted;
3718 m_provisionalPage = makeUnique<ProvisionalPageProxy>(*this, WTFMove(newProcess), WTFMove(suspendedPage), navigation.navigationID(), isServerSideRedirect, navigation.currentRequest(), processSwapRequestedByClient, isProcessSwappingOnNavigationResponse, websitePolicies.get());
3719 auto continuation = [this, protectedThis = Ref { *this }, navigation = Ref { navigation }, shouldTreatAsContinuingLoad, websitePolicies = WTFMove(websitePolicies), existingNetworkResourceLoadIdentifierToResume]() mutable {
3720 if (auto* item = navigation->targetItem()) {
3721 LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data());
3722
3723 auto transaction = m_pageLoadState.transaction();
3724 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), item->url() });
3725
3726 m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies), shouldTreatAsContinuingLoad, existingNetworkResourceLoadIdentifierToResume);
3727 return;
3728 }
3729
3730 if (m_backForwardList->currentItem() && (navigation->lockBackForwardList() == LockBackForwardList::Yes || navigation->lockHistory() == LockHistory::Yes)) {
3731 // 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
3732 // it instead of creating a new one.
3733 m_provisionalPage->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()));
3734 }
3735
3736 std::optional<WebsitePoliciesData> websitePoliciesData;
3737 if (websitePolicies)
3738 websitePoliciesData = websitePolicies->data();
3739
3740 // FIXME: Work out timing of responding with the last policy delegate, etc
3741 ASSERT(!navigation->currentRequest().isEmpty());
3742 ASSERT(!existingNetworkResourceLoadIdentifierToResume || !navigation->substituteData());
3743 if (auto& substituteData = navigation->substituteData())
3744 m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), shouldTreatAsContinuingLoad, isNavigatingToAppBoundDomain(), WTFMove(websitePoliciesData), substituteData->sessionHistoryVisibility);
3745 else
3746 m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation->currentRequest() }, nullptr, shouldTreatAsContinuingLoad, isNavigatingToAppBoundDomain(), WTFMove(websitePoliciesData), existingNetworkResourceLoadIdentifierToResume);
3747 };
3748 if (m_inspectorController->shouldPauseLoading(*m_provisionalPage))
3749 m_inspectorController->setContinueLoadingCallback(*m_provisionalPage, WTFMove(continuation));
3750 else
3751 continuation();
3752}
3753
3754bool WebPageProxy::isPageOpenedByDOMShowingInitialEmptyDocument() const
3755{
3756 return openedByDOM() && !hasCommittedAnyProvisionalLoads();
3757}
3758
3759// MSVC gives a redeclaration error if noreturn is used on the definition and not the declaration, while
3760// Cocoa tests segfault if it is moved to the declaration site (even if we move the definition with it!).
3761#if !COMPILER(MSVC)
3762NO_RETURN_DUE_TO_ASSERT
3763#endif
3764void WebPageProxy::didFailToSuspendAfterProcessSwap()
3765{
3766 // Only the SuspendedPageProxy should be getting this call.
3767 ASSERT_NOT_REACHED();
3768}
3769
3770#if !COMPILER(MSVC)
3771NO_RETURN_DUE_TO_ASSERT
3772#endif
3773void WebPageProxy::didSuspendAfterProcessSwap()
3774{
3775 // Only the SuspendedPageProxy should be getting this call.
3776 ASSERT_NOT_REACHED();
3777}
3778
3779void WebPageProxy::setUserAgent(String&& userAgent)
3780{
3781 if (m_userAgent == userAgent)
3782 return;
3783 m_userAgent = WTFMove(userAgent);
3784
3785 // We update the service worker there at the moment to be sure we use values used by actual web pages.
3786 // FIXME: Refactor this when we have a better User-Agent story.
3787 process().processPool().updateRemoteWorkerUserAgent(m_userAgent);
3788
3789 if (!hasRunningProcess())
3790 return;
3791 send(Messages::WebPage::SetUserAgent(m_userAgent));
3792}
3793
3794void WebPageProxy::setApplicationNameForUserAgent(const String& applicationName)
3795{
3796 if (m_applicationNameForUserAgent == applicationName)
3797 return;
3798
3799 m_applicationNameForUserAgent = applicationName;
3800 if (!m_customUserAgent.isEmpty())
3801 return;
3802
3803 setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3804}
3805
3806void WebPageProxy::setCustomUserAgent(const String& customUserAgent)
3807{
3808 if (m_customUserAgent == customUserAgent)
3809 return;
3810
3811 m_customUserAgent = customUserAgent;
3812
3813 if (m_customUserAgent.isEmpty()) {
3814 setUserAgent(standardUserAgent(m_applicationNameForUserAgent));
3815 return;
3816 }
3817
3818 setUserAgent(String { m_customUserAgent });
3819}
3820
3821void WebPageProxy::resumeActiveDOMObjectsAndAnimations()
3822{
3823 if (!hasRunningProcess() || !m_areActiveDOMObjectsAndAnimationsSuspended)
3824 return;
3825
3826 m_areActiveDOMObjectsAndAnimationsSuspended = false;
3827
3828 send(Messages::WebPage::ResumeActiveDOMObjectsAndAnimations());
3829}
3830
3831void WebPageProxy::suspendActiveDOMObjectsAndAnimations()
3832{
3833 if (!hasRunningProcess() || m_areActiveDOMObjectsAndAnimationsSuspended)
3834 return;
3835
3836 m_areActiveDOMObjectsAndAnimationsSuspended = true;
3837
3838 send(Messages::WebPage::SuspendActiveDOMObjectsAndAnimations());
3839}
3840
3841void WebPageProxy::suspend(CompletionHandler<void(bool)>&& completionHandler)
3842{
3843 WEBPAGEPROXY_RELEASE_LOG(Loading, "suspend:");
3844 if (!hasRunningProcess() || m_isSuspended)
3845 return completionHandler(false);
3846
3847 m_isSuspended = true;
3848 sendWithAsyncReply(Messages::WebPage::Suspend(), WTFMove(completionHandler));
3849}
3850
3851void WebPageProxy::resume(CompletionHandler<void(bool)>&& completionHandler)
3852{
3853 WEBPAGEPROXY_RELEASE_LOG(Loading, "resume:");
3854
3855 if (!hasRunningProcess() || !m_isSuspended)
3856 return completionHandler(false);
3857
3858 m_isSuspended = false;
3859 sendWithAsyncReply(Messages::WebPage::Resume(), WTFMove(completionHandler));
3860}
3861
3862bool WebPageProxy::supportsTextEncoding() const
3863{
3864 // FIXME (118840): We should probably only support this for text documents, not all non-image documents.
3865 return m_mainFrame && !m_mainFrame->isDisplayingStandaloneImageDocument();
3866}
3867
3868void WebPageProxy::setCustomTextEncodingName(const String& encodingName)
3869{
3870 if (m_customTextEncodingName == encodingName)
3871 return;
3872 m_customTextEncodingName = encodingName;
3873
3874 if (!hasRunningProcess())
3875 return;
3876 send(Messages::WebPage::SetCustomTextEncodingName(encodingName));
3877}
3878
3879SessionState WebPageProxy::sessionState(WTF::Function<bool (WebBackForwardListItem&)>&& filter) const
3880{
3881 RELEASE_ASSERT(RunLoop::isMain());
3882 SessionState sessionState;
3883
3884 sessionState.backForwardListState = m_backForwardList->backForwardListState(WTFMove(filter));
3885
3886 String provisionalURLString = m_pageLoadState.pendingAPIRequestURL();
3887 if (provisionalURLString.isEmpty())
3888 provisionalURLString = m_pageLoadState.provisionalURL();
3889
3890 if (!provisionalURLString.isEmpty())
3891 sessionState.provisionalURL = URL { provisionalURLString };
3892
3893 sessionState.renderTreeSize = renderTreeSize();
3894 sessionState.isAppInitiated = m_lastNavigationWasAppInitiated;
3895 return sessionState;
3896}
3897
3898RefPtr<API::Navigation> WebPageProxy::restoreFromSessionState(SessionState sessionState, bool navigate)
3899{
3900 WEBPAGEPROXY_RELEASE_LOG(Loading, "restoreFromSessionState:");
3901
3902 m_lastNavigationWasAppInitiated = sessionState.isAppInitiated;
3903 m_sessionRestorationRenderTreeSize = 0;
3904 m_hitRenderTreeSizeThreshold = false;
3905
3906 bool hasBackForwardList = !!sessionState.backForwardListState.currentIndex;
3907
3908 if (hasBackForwardList) {
3909 m_sessionStateWasRestoredByAPIRequest = true;
3910
3911 m_backForwardList->restoreFromState(WTFMove(sessionState.backForwardListState));
3912 // If the process is not launched yet, the session will be restored when sending the WebPageCreationParameters;
3913 if (hasRunningProcess())
3914 send(Messages::WebPage::RestoreSession(m_backForwardList->itemStates()));
3915
3916 auto transaction = m_pageLoadState.transaction();
3917 m_pageLoadState.setCanGoBack(transaction, m_backForwardList->backItem());
3918 m_pageLoadState.setCanGoForward(transaction, m_backForwardList->forwardItem());
3919
3920 // The back / forward list was restored from a sessionState so we don't want to snapshot the current
3921 // page when navigating away. Suppress navigation snapshotting until the next load has committed
3922 suppressNextAutomaticNavigationSnapshot();
3923 }
3924
3925 // FIXME: Navigating should be separate from state restoration.
3926 if (navigate) {
3927 m_sessionRestorationRenderTreeSize = sessionState.renderTreeSize;
3928 if (!m_sessionRestorationRenderTreeSize)
3929 m_hitRenderTreeSizeThreshold = true; // If we didn't get data on renderTreeSize, just don't fire the milestone.
3930
3931 if (!sessionState.provisionalURL.isNull())
3932 return loadRequest(sessionState.provisionalURL);
3933
3934 if (hasBackForwardList) {
3935 if (WebBackForwardListItem* item = m_backForwardList->currentItem())
3936 return goToBackForwardItem(*item);
3937 }
3938 }
3939
3940 return nullptr;
3941}
3942
3943bool WebPageProxy::supportsTextZoom() const
3944{
3945 // FIXME (118840): This should also return false for standalone media and plug-in documents.
3946 if (!m_mainFrame || m_mainFrame->isDisplayingStandaloneImageDocument())
3947 return false;
3948
3949 return true;
3950}
3951
3952void WebPageProxy::setTextZoomFactor(double zoomFactor)
3953{
3954 if (m_textZoomFactor == zoomFactor)
3955 return;
3956
3957 m_textZoomFactor = zoomFactor;
3958
3959 if (!hasRunningProcess())
3960 return;
3961
3962 send(Messages::WebPage::SetTextZoomFactor(m_textZoomFactor));
3963}
3964
3965void WebPageProxy::setPageZoomFactor(double zoomFactor)
3966{
3967 if (m_pageZoomFactor == zoomFactor)
3968 return;
3969
3970 closeOverlayedViews();
3971
3972 m_pageZoomFactor = zoomFactor;
3973
3974 if (!hasRunningProcess())
3975 return;
3976
3977 send(Messages::WebPage::SetPageZoomFactor(m_pageZoomFactor));
3978}
3979
3980void WebPageProxy::setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor)
3981{
3982 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
3983 return;
3984
3985 closeOverlayedViews();
3986
3987 m_pageZoomFactor = pageZoomFactor;
3988 m_textZoomFactor = textZoomFactor;
3989
3990 if (!hasRunningProcess())
3991 return;
3992
3993 send(Messages::WebPage::SetPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor));
3994}
3995
3996double WebPageProxy::pageZoomFactor() const
3997{
3998 // Zoom factor for non-PDF pages persists across page loads. We maintain a separate member variable for PDF
3999 // zoom which ensures that we don't use the PDF zoom for a normal page.
4000 if (m_mainFramePluginHandlesPageScaleGesture)
4001 return m_pluginZoomFactor;
4002 return m_pageZoomFactor;
4003}
4004
4005double WebPageProxy::pageScaleFactor() const
4006{
4007 // PDF documents use zoom and scale factors to size themselves appropriately in the window. We store them
4008 // separately but decide which to return based on the main frame.
4009 if (m_mainFramePluginHandlesPageScaleGesture)
4010 return m_pluginScaleFactor;
4011 return m_pageScaleFactor;
4012}
4013
4014void WebPageProxy::scalePage(double scale, const IntPoint& origin)
4015{
4016 ASSERT(scale > 0);
4017
4018 m_pageScaleFactor = scale;
4019
4020 if (!hasRunningProcess())
4021 return;
4022
4023 send(Messages::WebPage::ScalePage(scale, origin));
4024}
4025
4026void WebPageProxy::scalePageInViewCoordinates(double scale, const IntPoint& centerInViewCoordinates)
4027{
4028 ASSERT(scale > 0);
4029
4030 m_pageScaleFactor = scale;
4031
4032 if (!hasRunningProcess())
4033 return;
4034
4035 send(Messages::WebPage::ScalePageInViewCoordinates(scale, centerInViewCoordinates));
4036}
4037
4038void WebPageProxy::scaleView(double scale)
4039{
4040 ASSERT(scale > 0);
4041
4042 m_viewScaleFactor = scale;
4043
4044 if (!hasRunningProcess())
4045 return;
4046
4047 send(Messages::WebPage::ScaleView(scale));
4048}
4049
4050void WebPageProxy::setIntrinsicDeviceScaleFactor(float scaleFactor)
4051{
4052 if (m_intrinsicDeviceScaleFactor == scaleFactor)
4053 return;
4054
4055 m_intrinsicDeviceScaleFactor = scaleFactor;
4056
4057 if (m_drawingArea)
4058 m_drawingArea->deviceScaleFactorDidChange();
4059}
4060
4061void WebPageProxy::windowScreenDidChange(PlatformDisplayID displayID, std::optional<unsigned> nominalFramesPerSecond)
4062{
4063#if HAVE(CVDISPLAYLINK)
4064 if (hasRunningProcess() && m_displayID && m_registeredForFullSpeedUpdates)
4065 process().processPool().setDisplayLinkForDisplayWantsFullSpeedUpdates(*m_process->connection(), *m_displayID, false);
4066
4067 m_registeredForFullSpeedUpdates = false;
4068#endif
4069
4070 m_displayID = displayID;
4071
4072 if (!hasRunningProcess())
4073 return;
4074
4075 send(Messages::EventDispatcher::PageScreenDidChange(m_webPageID, displayID, nominalFramesPerSecond));
4076 send(Messages::WebPage::WindowScreenDidChange(displayID, nominalFramesPerSecond));
4077#if HAVE(CVDISPLAYLINK)
4078 updateDisplayLinkFrequency();
4079#endif
4080}
4081
4082float WebPageProxy::deviceScaleFactor() const
4083{
4084 return m_customDeviceScaleFactor.value_or(m_intrinsicDeviceScaleFactor);
4085}
4086
4087void WebPageProxy::setCustomDeviceScaleFactor(float customScaleFactor)
4088{
4089 if (m_customDeviceScaleFactor && m_customDeviceScaleFactor.value() == customScaleFactor)
4090 return;
4091
4092 float oldScaleFactor = deviceScaleFactor();
4093
4094 // A value of 0 clears the customScaleFactor.
4095 if (customScaleFactor)
4096 m_customDeviceScaleFactor = customScaleFactor;
4097 else
4098 m_customDeviceScaleFactor = std::nullopt;
4099
4100 if (!hasRunningProcess())
4101 return;
4102
4103 if (deviceScaleFactor() != oldScaleFactor)
4104 m_drawingArea->deviceScaleFactorDidChange();
4105}
4106
4107void WebPageProxy::accessibilitySettingsDidChange()
4108{
4109 if (!hasRunningProcess())
4110 return;
4111
4112 // Also update screen properties which encodes invert colors.
4113 process().processPool().screenPropertiesStateChanged();
4114 send(Messages::WebPage::AccessibilitySettingsDidChange());
4115}
4116
4117void WebPageProxy::setUseFixedLayout(bool fixed)
4118{
4119 // This check is fine as the value is initialized in the web
4120 // process as part of the creation parameters.
4121 if (fixed == m_useFixedLayout)
4122 return;
4123
4124 m_useFixedLayout = fixed;
4125 if (!fixed)
4126 m_fixedLayoutSize = IntSize();
4127
4128 if (!hasRunningProcess())
4129 return;
4130
4131 send(Messages::WebPage::SetUseFixedLayout(fixed));
4132}
4133
4134void WebPageProxy::setFixedLayoutSize(const IntSize& size)
4135{
4136 if (size == m_fixedLayoutSize)
4137 return;
4138
4139 m_fixedLayoutSize = size;
4140
4141 if (!hasRunningProcess())
4142 return;
4143
4144 send(Messages::WebPage::SetFixedLayoutSize(size));
4145}
4146
4147void WebPageProxy::setDefaultUnobscuredSize(const FloatSize& size)
4148{
4149 if (size == m_defaultUnobscuredSize)
4150 return;
4151
4152 m_defaultUnobscuredSize = size;
4153
4154 if (!hasRunningProcess())
4155 return;
4156
4157 send(Messages::WebPage::SetDefaultUnobscuredSize(m_defaultUnobscuredSize));
4158}
4159
4160void WebPageProxy::setMinimumUnobscuredSize(const FloatSize& size)
4161{
4162 if (size == m_minimumUnobscuredSize)
4163 return;
4164
4165 m_minimumUnobscuredSize = size;
4166
4167 if (!hasRunningProcess())
4168 return;
4169
4170 send(Messages::WebPage::SetMinimumUnobscuredSize(m_minimumUnobscuredSize));
4171}
4172
4173void WebPageProxy::setMaximumUnobscuredSize(const FloatSize& size)
4174{
4175 if (size == m_maximumUnobscuredSize)
4176 return;
4177
4178 m_maximumUnobscuredSize = size;
4179
4180 if (!hasRunningProcess())
4181 return;
4182
4183 send(Messages::WebPage::SetMaximumUnobscuredSize(m_maximumUnobscuredSize));
4184}
4185
4186void WebPageProxy::setViewExposedRect(std::optional<WebCore::FloatRect> viewExposedRect)
4187{
4188 if (m_viewExposedRect == viewExposedRect)
4189 return;
4190
4191 m_viewExposedRect = viewExposedRect;
4192
4193#if PLATFORM(MAC)
4194 if (m_drawingArea)
4195 m_drawingArea->didChangeViewExposedRect();
4196#endif
4197}
4198
4199void WebPageProxy::setAlwaysShowsHorizontalScroller(bool alwaysShowsHorizontalScroller)
4200{
4201 if (alwaysShowsHorizontalScroller == m_alwaysShowsHorizontalScroller)
4202 return;
4203
4204 m_alwaysShowsHorizontalScroller = alwaysShowsHorizontalScroller;
4205
4206 if (!hasRunningProcess())
4207 return;
4208
4209 send(Messages::WebPage::SetAlwaysShowsHorizontalScroller(alwaysShowsHorizontalScroller));
4210}
4211
4212void WebPageProxy::setAlwaysShowsVerticalScroller(bool alwaysShowsVerticalScroller)
4213{
4214 if (alwaysShowsVerticalScroller == m_alwaysShowsVerticalScroller)
4215 return;
4216
4217 m_alwaysShowsVerticalScroller = alwaysShowsVerticalScroller;
4218
4219 if (!hasRunningProcess())
4220 return;
4221
4222 send(Messages::WebPage::SetAlwaysShowsVerticalScroller(alwaysShowsVerticalScroller));
4223}
4224
4225void WebPageProxy::listenForLayoutMilestones(OptionSet<WebCore::LayoutMilestone> milestones)
4226{
4227 if (milestones == m_observedLayoutMilestones)
4228 return;
4229
4230 m_observedLayoutMilestones = milestones;
4231
4232 if (!hasRunningProcess())
4233 return;
4234
4235 send(Messages::WebPage::ListenForLayoutMilestones(milestones));
4236}
4237
4238void WebPageProxy::setSuppressScrollbarAnimations(bool suppressAnimations)
4239{
4240 if (suppressAnimations == m_suppressScrollbarAnimations)
4241 return;
4242
4243 m_suppressScrollbarAnimations = suppressAnimations;
4244
4245 if (!hasRunningProcess())
4246 return;
4247
4248 send(Messages::WebPage::SetSuppressScrollbarAnimations(suppressAnimations));
4249}
4250
4251void WebPageProxy::setRubberBandsAtLeft(bool rubberBandsAtLeft)
4252{
4253 m_rubberBandableEdges.setLeft(rubberBandsAtLeft);
4254}
4255
4256void WebPageProxy::setRubberBandsAtRight(bool rubberBandsAtRight)
4257{
4258 m_rubberBandableEdges.setRight(rubberBandsAtRight);
4259}
4260
4261void WebPageProxy::setRubberBandsAtTop(bool rubberBandsAtTop)
4262{
4263 m_rubberBandableEdges.setTop(rubberBandsAtTop);
4264}
4265
4266void WebPageProxy::setRubberBandsAtBottom(bool rubberBandsAtBottom)
4267{
4268 m_rubberBandableEdges.setBottom(rubberBandsAtBottom);
4269}
4270
4271void WebPageProxy::setEnableVerticalRubberBanding(bool enableVerticalRubberBanding)
4272{
4273 if (enableVerticalRubberBanding == m_enableVerticalRubberBanding)
4274 return;
4275
4276 m_enableVerticalRubberBanding = enableVerticalRubberBanding;
4277
4278 if (!hasRunningProcess())
4279 return;
4280 send(Messages::WebPage::SetEnableVerticalRubberBanding(enableVerticalRubberBanding));
4281}
4282
4283bool WebPageProxy::verticalRubberBandingIsEnabled() const
4284{
4285 return m_enableVerticalRubberBanding;
4286}
4287
4288void WebPageProxy::setEnableHorizontalRubberBanding(bool enableHorizontalRubberBanding)
4289{
4290 if (enableHorizontalRubberBanding == m_enableHorizontalRubberBanding)
4291 return;
4292
4293 m_enableHorizontalRubberBanding = enableHorizontalRubberBanding;
4294
4295 if (!hasRunningProcess())
4296 return;
4297 send(Messages::WebPage::SetEnableHorizontalRubberBanding(enableHorizontalRubberBanding));
4298}
4299
4300bool WebPageProxy::horizontalRubberBandingIsEnabled() const
4301{
4302 return m_enableHorizontalRubberBanding;
4303}
4304
4305void WebPageProxy::setBackgroundExtendsBeyondPage(bool backgroundExtendsBeyondPage)
4306{
4307 if (backgroundExtendsBeyondPage == m_backgroundExtendsBeyondPage)
4308 return;
4309
4310 m_backgroundExtendsBeyondPage = backgroundExtendsBeyondPage;
4311
4312 if (!hasRunningProcess())
4313 return;
4314 send(Messages::WebPage::SetBackgroundExtendsBeyondPage(backgroundExtendsBeyondPage));
4315}
4316
4317bool WebPageProxy::backgroundExtendsBeyondPage() const
4318{
4319 return m_backgroundExtendsBeyondPage;
4320}
4321
4322void WebPageProxy::setPaginationMode(WebCore::Pagination::Mode mode)
4323{
4324 if (mode == m_paginationMode)
4325 return;
4326
4327 m_paginationMode = mode;
4328
4329 if (!hasRunningProcess())
4330 return;
4331 send(Messages::WebPage::SetPaginationMode(mode));
4332}
4333
4334void WebPageProxy::setPaginationBehavesLikeColumns(bool behavesLikeColumns)
4335{
4336 if (behavesLikeColumns == m_paginationBehavesLikeColumns)
4337 return;
4338
4339 m_paginationBehavesLikeColumns = behavesLikeColumns;
4340
4341 if (!hasRunningProcess())
4342 return;
4343 send(Messages::WebPage::SetPaginationBehavesLikeColumns(behavesLikeColumns));
4344}
4345
4346void WebPageProxy::setPageLength(double pageLength)
4347{
4348 if (pageLength == m_pageLength)
4349 return;
4350
4351 m_pageLength = pageLength;
4352
4353 if (!hasRunningProcess())
4354 return;
4355 send(Messages::WebPage::SetPageLength(pageLength));
4356}
4357
4358void WebPageProxy::setGapBetweenPages(double gap)
4359{
4360 if (gap == m_gapBetweenPages)
4361 return;
4362
4363 m_gapBetweenPages = gap;
4364
4365 if (!hasRunningProcess())
4366 return;
4367 send(Messages::WebPage::SetGapBetweenPages(gap));
4368}
4369
4370void WebPageProxy::setPaginationLineGridEnabled(bool lineGridEnabled)
4371{
4372 if (lineGridEnabled == m_paginationLineGridEnabled)
4373 return;
4374
4375 m_paginationLineGridEnabled = lineGridEnabled;
4376
4377 if (!hasRunningProcess())
4378 return;
4379 send(Messages::WebPage::SetPaginationLineGridEnabled(lineGridEnabled));
4380}
4381
4382void WebPageProxy::pageScaleFactorDidChange(double scaleFactor)
4383{
4384 m_pageScaleFactor = scaleFactor;
4385}
4386
4387void WebPageProxy::pluginScaleFactorDidChange(double pluginScaleFactor)
4388{
4389 m_pluginScaleFactor = pluginScaleFactor;
4390}
4391
4392void WebPageProxy::pluginZoomFactorDidChange(double pluginZoomFactor)
4393{
4394 m_pluginZoomFactor = pluginZoomFactor;
4395}
4396
4397void WebPageProxy::findStringMatches(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount)
4398{
4399 if (string.isEmpty()) {
4400 didFindStringMatches(string, Vector<Vector<WebCore::IntRect>> (), 0);
4401 return;
4402 }
4403
4404 send(Messages::WebPage::FindStringMatches(string, options, maxMatchCount));
4405}
4406
4407void WebPageProxy::findString(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount, CompletionHandler<void(bool)>&& callbackFunction)
4408{
4409 sendWithAsyncReply(Messages::WebPage::FindString(string, options, maxMatchCount), WTFMove(callbackFunction));
4410}
4411
4412void WebPageProxy::findRectsForStringMatches(const String& string, OptionSet<WebKit::FindOptions> options, unsigned maxMatchCount, CompletionHandler<void(Vector<WebCore::FloatRect>&&)>&& callbackFunction)
4413{
4414 sendWithAsyncReply(Messages::WebPage::FindRectsForStringMatches(string, options, maxMatchCount), WTFMove(callbackFunction));
4415}
4416
4417void WebPageProxy::findTextRangesForStringMatches(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount, CompletionHandler<void(Vector<WebFoundTextRange>&&)>&& callbackFunction)
4418{
4419 sendWithAsyncReply(Messages::WebPage::FindTextRangesForStringMatches(string, options, maxMatchCount), WTFMove(callbackFunction));
4420}
4421
4422void WebPageProxy::replaceFoundTextRangeWithString(const WebFoundTextRange& range, const String& string)
4423{
4424 send(Messages::WebPage::ReplaceFoundTextRangeWithString(range, string));
4425}
4426
4427void WebPageProxy::decorateTextRangeWithStyle(const WebFoundTextRange& range, FindDecorationStyle style)
4428{
4429 send(Messages::WebPage::DecorateTextRangeWithStyle(range, style));
4430}
4431
4432void WebPageProxy::scrollTextRangeToVisible(const WebFoundTextRange& range)
4433{
4434 send(Messages::WebPage::ScrollTextRangeToVisible(range));
4435}
4436
4437void WebPageProxy::clearAllDecoratedFoundText()
4438{
4439 send(Messages::WebPage::ClearAllDecoratedFoundText());
4440}
4441
4442void WebPageProxy::didBeginTextSearchOperation()
4443{
4444 send(Messages::WebPage::DidBeginTextSearchOperation());
4445}
4446
4447void WebPageProxy::didEndTextSearchOperation()
4448{
4449 send(Messages::WebPage::DidEndTextSearchOperation());
4450}
4451
4452void WebPageProxy::requestRectForFoundTextRange(const WebFoundTextRange& range, CompletionHandler<void(WebCore::FloatRect)>&& callbackFunction)
4453{
4454 sendWithAsyncReply(Messages::WebPage::RequestRectForFoundTextRange(range), WTFMove(callbackFunction));
4455}
4456
4457void WebPageProxy::getImageForFindMatch(int32_t matchIndex)
4458{
4459 send(Messages::WebPage::GetImageForFindMatch(matchIndex));
4460}
4461
4462void WebPageProxy::selectFindMatch(int32_t matchIndex)
4463{
4464 send(Messages::WebPage::SelectFindMatch(matchIndex));
4465}
4466
4467void WebPageProxy::indicateFindMatch(int32_t matchIndex)
4468{
4469 send(Messages::WebPage::IndicateFindMatch(matchIndex));
4470}
4471
4472void WebPageProxy::hideFindUI()
4473{
4474 send(Messages::WebPage::HideFindUI());
4475}
4476
4477void WebPageProxy::hideFindIndicator()
4478{
4479 send(Messages::WebPage::HideFindIndicator());
4480}
4481
4482void WebPageProxy::countStringMatches(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount)
4483{
4484 if (!hasRunningProcess())
4485 return;
4486
4487 send(Messages::WebPage::CountStringMatches(string, options, maxMatchCount));
4488}
4489
4490void WebPageProxy::replaceMatches(Vector<uint32_t>&& matchIndices, const String& replacementText, bool selectionOnly, CompletionHandler<void(uint64_t)>&& callback)
4491{
4492 sendWithAsyncReply(Messages::WebPage::ReplaceMatches(WTFMove(matchIndices), replacementText, selectionOnly), WTFMove(callback));
4493}
4494
4495void WebPageProxy::launchInitialProcessIfNecessary()
4496{
4497 if (process().isDummyProcessProxy())
4498 launchProcess({ }, ProcessLaunchReason::InitialProcess);
4499}
4500
4501void WebPageProxy::runJavaScriptInMainFrame(RunJavaScriptParameters&& parameters, CompletionHandler<void(Expected<RefPtr<API::SerializedScriptValue>, WebCore::ExceptionDetails>&&)>&& callbackFunction)
4502{
4503 runJavaScriptInFrameInScriptWorld(WTFMove(parameters), std::nullopt, API::ContentWorld::pageContentWorld(), WTFMove(callbackFunction));
4504}
4505
4506void WebPageProxy::runJavaScriptInFrameInScriptWorld(RunJavaScriptParameters&& parameters, std::optional<WebCore::FrameIdentifier> frameID, API::ContentWorld& world, CompletionHandler<void(Expected<RefPtr<API::SerializedScriptValue>, WebCore::ExceptionDetails>&&)>&& callbackFunction)
4507{
4508 // For backward-compatibility support running script in a WebView which has not done any loads yets.
4509 launchInitialProcessIfNecessary();
4510
4511 if (!hasRunningProcess())
4512 return callbackFunction({ nullptr });
4513
4514 ProcessThrottler::ActivityVariant activity;
4515#if PLATFORM(IOS_FAMILY)
4516 if (pageClient().canTakeForegroundAssertions())
4517 activity = m_process->throttler().foregroundActivity("WebPageProxy::runJavaScriptInFrameInScriptWorld"_s);
4518#endif
4519
4520 sendWithAsyncReply(Messages::WebPage::RunJavaScriptInFrameInScriptWorld(parameters, frameID, world.worldData()), [activity = WTFMove(activity), callbackFunction = WTFMove(callbackFunction)] (const IPC::DataReference& dataReference, std::optional<ExceptionDetails>&& details) mutable {
4521 if (details)
4522 return callbackFunction(makeUnexpected(WTFMove(*details)));
4523 if (dataReference.empty())
4524 return callbackFunction({ nullptr });
4525 callbackFunction({ API::SerializedScriptValue::createFromWireBytes(Vector(dataReference)).ptr() });
4526 });
4527}
4528
4529void WebPageProxy::getRenderTreeExternalRepresentation(CompletionHandler<void(const String&)>&& callback)
4530{
4531 sendWithAsyncReply(Messages::WebPage::GetRenderTreeExternalRepresentation(), WTFMove(callback));
4532}
4533
4534void WebPageProxy::getSourceForFrame(WebFrameProxy* frame, CompletionHandler<void(const String&)>&& callback)
4535{
4536 sendWithAsyncReply(Messages::WebPage::GetSourceForFrame(frame->frameID()), WTFMove(callback));
4537}
4538
4539void WebPageProxy::getContentsAsString(ContentAsStringIncludesChildFrames includesChildFrames, CompletionHandler<void(const String&)>&& callback)
4540{
4541 sendWithAsyncReply(Messages::WebPage::GetContentsAsString(includesChildFrames), WTFMove(callback));
4542}
4543
4544#if PLATFORM(COCOA)
4545void WebPageProxy::getContentsAsAttributedString(CompletionHandler<void(const WebCore::AttributedString&)>&& completionHandler)
4546{
4547 if (!hasRunningProcess()) {
4548 completionHandler({ });
4549 return;
4550 }
4551
4552 sendWithAsyncReply(Messages::WebPage::GetContentsAsAttributedString(), WTFMove(completionHandler));
4553}
4554#endif
4555
4556void WebPageProxy::getAllFrames(CompletionHandler<void(FrameTreeNodeData&&)>&& completionHandler)
4557{
4558 sendWithAsyncReply(Messages::WebPage::GetAllFrames(), WTFMove(completionHandler));
4559}
4560
4561void WebPageProxy::getBytecodeProfile(CompletionHandler<void(const String&)>&& callback)
4562{
4563 sendWithAsyncReply(Messages::WebPage::GetBytecodeProfile(), WTFMove(callback));
4564}
4565
4566void WebPageProxy::getSamplingProfilerOutput(CompletionHandler<void(const String&)>&& callback)
4567{
4568 sendWithAsyncReply(Messages::WebPage::GetSamplingProfilerOutput(), WTFMove(callback));
4569}
4570
4571template <typename T>
4572static CompletionHandler<void(T data)> toAPIDataCallbackT(CompletionHandler<void(API::Data*)>&& callback)
4573{
4574 return [callback = WTFMove(callback)] (T data) mutable {
4575 if (!data) {
4576 callback(nullptr);
4577 return;
4578 }
4579 callback(API::Data::create(data->data(), data->size()).ptr());
4580 };
4581}
4582
4583auto* toAPIDataCallback = toAPIDataCallbackT<const std::optional<IPC::SharedBufferReference>&>;
4584auto* toAPIDataSharedBufferCallback = toAPIDataCallbackT<RefPtr<WebCore::SharedBuffer>&&>;
4585
4586#if ENABLE(MHTML)
4587void WebPageProxy::getContentsAsMHTMLData(CompletionHandler<void(API::Data*)>&& callback)
4588{
4589 sendWithAsyncReply(Messages::WebPage::GetContentsAsMHTMLData(), toAPIDataCallback(WTFMove(callback)));
4590}
4591#endif
4592
4593void WebPageProxy::getSelectionOrContentsAsString(CompletionHandler<void(const String&)>&& callback)
4594{
4595 sendWithAsyncReply(Messages::WebPage::GetSelectionOrContentsAsString(), callback);
4596}
4597
4598void WebPageProxy::getSelectionAsWebArchiveData(CompletionHandler<void(API::Data*)>&& callback)
4599{
4600 sendWithAsyncReply(Messages::WebPage::GetSelectionAsWebArchiveData(), toAPIDataCallback(WTFMove(callback)));
4601}
4602
4603void WebPageProxy::getMainResourceDataOfFrame(WebFrameProxy* frame, CompletionHandler<void(API::Data*)>&& callback)
4604{
4605 if (!frame)
4606 return callback(nullptr);
4607 sendWithAsyncReply(Messages::WebPage::GetMainResourceDataOfFrame(frame->frameID()), toAPIDataCallback(WTFMove(callback)));
4608}
4609
4610void WebPageProxy::getResourceDataFromFrame(WebFrameProxy& frame, API::URL* resourceURL, CompletionHandler<void(API::Data*)>&& callback)
4611{
4612 sendWithAsyncReply(Messages::WebPage::GetResourceDataFromFrame(frame.frameID(), resourceURL->string()), toAPIDataCallback(WTFMove(callback)));
4613}
4614
4615void WebPageProxy::getWebArchiveOfFrame(WebFrameProxy* frame, CompletionHandler<void(API::Data*)>&& callback)
4616{
4617 if (!frame)
4618 return callback(nullptr);
4619 sendWithAsyncReply(Messages::WebPage::GetWebArchiveOfFrame(frame->frameID()), toAPIDataCallback(WTFMove(callback)));
4620}
4621
4622void WebPageProxy::getAccessibilityTreeData(CompletionHandler<void(API::Data*)>&& callback)
4623{
4624 sendWithAsyncReply(Messages::WebPage::GetAccessibilityTreeData(), toAPIDataCallback(WTFMove(callback)));
4625}
4626
4627void WebPageProxy::forceRepaint(CompletionHandler<void()>&& callback)
4628{
4629 if (!hasRunningProcess())
4630 return callback();
4631
4632 m_drawingArea->waitForBackingStoreUpdateOnNextPaint();
4633
4634 sendWithAsyncReply(Messages::WebPage::ForceRepaint(), [weakThis = WeakPtr { *this }, callback = WTFMove(callback)] () mutable {
4635 if (weakThis) {
4636 weakThis->callAfterNextPresentationUpdate([callback = WTFMove(callback)] (auto) mutable {
4637 callback();
4638 });
4639 } else
4640 callback();
4641 });
4642}
4643
4644static OptionSet<IPC::SendOption> printingSendOptions(bool isPerformingDOMPrintOperation)
4645{
4646 if (isPerformingDOMPrintOperation)
4647 return IPC::SendOption::DispatchMessageEvenWhenWaitingForUnboundedSyncReply;
4648
4649 return { };
4650}
4651
4652void WebPageProxy::preferencesDidChange()
4653{
4654 if (!hasRunningProcess())
4655 return;
4656
4657 updateThrottleState();
4658 updateHiddenPageThrottlingAutoIncreases();
4659
4660 pageClient().preferencesDidChange();
4661
4662 // FIXME: It probably makes more sense to send individual preference changes.
4663 // However, WebKitTestRunner depends on getting a preference change notification
4664 // even if nothing changed in UI process, so that overrides get removed.
4665
4666 // Preferences need to be updated during synchronous printing to make "print backgrounds" preference work when toggled from a print dialog checkbox.
4667 send(Messages::WebPage::PreferencesDidChange(preferencesStore()), printingSendOptions(m_isPerformingDOMPrintOperation));
4668}
4669
4670void WebPageProxy::didCreateMainFrame(FrameIdentifier frameID)
4671{
4672 // The DecidePolicyForNavigationActionSync IPC is synchronous and may therefore get processed before the DidCreateMainFrame one.
4673 // When this happens, decidePolicyForNavigationActionSync() calls didCreateMainFrame() and we need to ignore the DidCreateMainFrame
4674 // IPC when it later gets processed.
4675 if (m_mainFrame && m_mainFrame->frameID() == frameID)
4676 return;
4677
4678 PageClientProtector protector(pageClient());
4679
4680 MESSAGE_CHECK(m_process, !m_mainFrame);
4681 MESSAGE_CHECK(m_process, m_process->canCreateFrame(frameID));
4682
4683 m_mainFrame = WebFrameProxy::create(*this, frameID);
4684
4685#if ENABLE(SERVICE_WORKER)
4686 if (m_serviceWorkerOpenWindowCompletionCallback)
4687 m_mainFrame->setNavigationCallback(WTFMove(m_serviceWorkerOpenWindowCompletionCallback));
4688#endif
4689
4690 // Add the frame to the process wide map.
4691 m_process->frameCreated(frameID, *m_mainFrame);
4692}
4693
4694void WebPageProxy::didCreateSubframe(FrameIdentifier frameID)
4695{
4696 PageClientProtector protector(pageClient());
4697
4698 MESSAGE_CHECK(m_process, m_mainFrame);
4699
4700 // The DecidePolicyForNavigationActionSync IPC is synchronous and may therefore get processed before the DidCreateSubframe one.
4701 // When this happens, decidePolicyForNavigationActionSync() calls didCreateSubframe() and we need to ignore the DidCreateSubframe
4702 // IPC when it later gets processed.
4703 if (m_process->webFrame(frameID))
4704 return;
4705
4706 MESSAGE_CHECK(m_process, m_process->canCreateFrame(frameID));
4707
4708 auto subFrame = WebFrameProxy::create(*this, frameID);
4709
4710 // Add the frame to the process wide map.
4711 m_process->frameCreated(frameID, subFrame.get());
4712}
4713
4714void WebPageProxy::didCreateWindow(FrameIdentifier frameID, GlobalWindowIdentifier&& windowIdentifier)
4715{
4716}
4717
4718double WebPageProxy::estimatedProgress() const
4719{
4720 return m_pageLoadState.estimatedProgress();
4721}
4722
4723void WebPageProxy::didStartProgress()
4724{
4725 ASSERT(!m_isClosed);
4726
4727 PageClientProtector protector(pageClient());
4728
4729 auto transaction = m_pageLoadState.transaction();
4730 m_pageLoadState.didStartProgress(transaction);
4731
4732 m_pageLoadState.commitChanges();
4733}
4734
4735void WebPageProxy::didChangeProgress(double value)
4736{
4737 PageClientProtector protector(pageClient());
4738
4739 auto transaction = m_pageLoadState.transaction();
4740 m_pageLoadState.didChangeProgress(transaction, value);
4741
4742 m_pageLoadState.commitChanges();
4743}
4744
4745void WebPageProxy::didFinishProgress()
4746{
4747 PageClientProtector protector(pageClient());
4748
4749 auto transaction = m_pageLoadState.transaction();
4750 m_pageLoadState.didFinishProgress(transaction);
4751
4752 m_pageLoadState.commitChanges();
4753}
4754
4755void WebPageProxy::setNetworkRequestsInProgress(bool networkRequestsInProgress)
4756{
4757 auto transaction = m_pageLoadState.transaction();
4758 m_pageLoadState.setNetworkRequestsInProgress(transaction, networkRequestsInProgress);
4759}
4760
4761void WebPageProxy::preconnectTo(const URL& url, const String& userAgent)
4762{
4763 if (!m_websiteDataStore->configuration().allowsServerPreconnect())
4764 return;
4765
4766 auto storedCredentialsPolicy = m_canUseCredentialStorage ? WebCore::StoredCredentialsPolicy::Use : WebCore::StoredCredentialsPolicy::DoNotUse;
4767
4768 websiteDataStore().networkProcess().preconnectTo(sessionID(), identifier(), webPageID(), url, userAgent, storedCredentialsPolicy, isNavigatingToAppBoundDomain(), m_lastNavigationWasAppInitiated ? LastNavigationWasAppInitiated::Yes : LastNavigationWasAppInitiated::No);
4769}
4770
4771void WebPageProxy::setCanUseCredentialStorage(bool canUseCredentialStorage)
4772{
4773 m_canUseCredentialStorage = canUseCredentialStorage;
4774 send(Messages::WebPage::SetCanUseCredentialStorage(canUseCredentialStorage));
4775}
4776
4777void WebPageProxy::didDestroyNavigation(uint64_t navigationID)
4778{
4779 MESSAGE_CHECK(m_process, WebNavigationState::NavigationMap::isValidKey(navigationID));
4780
4781 PageClientProtector protector(pageClient());
4782
4783 // On process-swap, the previous process tries to destroy the navigation but the provisional process is actually taking over the navigation.
4784 if (m_provisionalPage && m_provisionalPage->navigationID() == navigationID)
4785 return;
4786
4787 m_navigationState->didDestroyNavigation(navigationID);
4788}
4789
4790void WebPageProxy::didStartProvisionalLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, URL&& url, URL&& unreachableURL, const UserData& userData)
4791{
4792 didStartProvisionalLoadForFrameShared(m_process.copyRef(), frameID, WTFMove(frameInfo), WTFMove(request), navigationID, WTFMove(url), WTFMove(unreachableURL), userData);
4793}
4794
4795void WebPageProxy::didStartProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& process, FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, URL&& url, URL&& unreachableURL, const UserData& userData)
4796{
4797 PageClientProtector protector(pageClient());
4798
4799 RefPtr frame = process->webFrame(frameID);
4800 MESSAGE_CHECK(process, frame);
4801 MESSAGE_CHECK_URL(process, url);
4802
4803 // If the page starts a new main frame provisional load, then cancel any pending one in a provisional process.
4804 if (frame->isMainFrame() && m_provisionalPage && m_provisionalPage->mainFrame() != frame) {
4805 m_provisionalPage->cancel();
4806 m_provisionalPage = nullptr;
4807 }
4808
4809 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
4810 RefPtr<API::Navigation> navigation;
4811 if (frame->isMainFrame() && navigationID)
4812 navigation = navigationState().navigation(navigationID);
4813
4814 LOG(Loading, "WebPageProxy %" PRIu64 " in process pid %i didStartProvisionalLoadForFrame to frameID %" PRIu64 ", navigationID %" PRIu64 ", url %s", m_identifier.toUInt64(), process->processIdentifier(), frameID.toUInt64(), navigationID, url.string().utf8().data());
4815 WEBPAGEPROXY_RELEASE_LOG(Loading, "didStartProvisionalLoadForFrame: frameID=%" PRIu64 ", isMainFrame=%d", frameID.toUInt64(), frame->isMainFrame());
4816
4817 auto transaction = m_pageLoadState.transaction();
4818 m_pageLoadState.clearPendingAPIRequest(transaction);
4819
4820 if (frame->isMainFrame()) {
4821 process->didStartProvisionalLoadForMainFrame(url);
4822 reportPageLoadResult(ResourceError { ResourceError::Type::Cancellation });
4823 m_pageLoadStart = MonotonicTime::now();
4824 m_pageLoadState.didStartProvisionalLoad(transaction, url.string(), unreachableURL.string());
4825 pageClient().didStartProvisionalLoadForMainFrame();
4826 closeOverlayedViews();
4827 }
4828
4829 frame->setUnreachableURL(unreachableURL);
4830 frame->didStartProvisionalLoad(url);
4831
4832 m_pageLoadState.commitChanges();
4833 if (m_loaderClient)
4834 m_loaderClient->didStartProvisionalLoadForFrame(*this, *frame, navigation.get(), process->transformHandlesToObjects(userData.object()).get());
4835 else {
4836 if (frameInfo.isMainFrame)
4837 m_navigationClient->didStartProvisionalNavigation(*this, request, navigation.get(), process->transformHandlesToObjects(userData.object()).get());
4838 m_navigationClient->didStartProvisionalLoadForFrame(*this, WTFMove(request), WTFMove(frameInfo));
4839 }
4840
4841#if ENABLE(WEB_AUTHN)
4842 m_websiteDataStore->authenticatorManager().cancelRequest(m_webPageID, frameID);
4843#endif
4844}
4845
4846void WebPageProxy::didExplicitOpenForFrame(FrameIdentifier frameID, URL&& url, String&& mimeType)
4847{
4848 auto* frame = m_process->webFrame(frameID);
4849 MESSAGE_CHECK(m_process, frame);
4850
4851 if (!checkURLReceivedFromCurrentOrPreviousWebProcess(m_process, url)) {
4852 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "Ignoring WebPageProxy::DidExplicitOpenForFrame() IPC from the WebContent process because the file URL is outside the sandbox");
4853 return;
4854 }
4855
4856 auto transaction = m_pageLoadState.transaction();
4857
4858 if (frame->isMainFrame())
4859 m_pageLoadState.didExplicitOpen(transaction, url.string());
4860
4861 frame->didExplicitOpen(WTFMove(url), WTFMove(mimeType));
4862
4863 m_hasCommittedAnyProvisionalLoads = true;
4864 m_process->didCommitProvisionalLoad();
4865
4866 m_pageLoadState.commitChanges();
4867}
4868
4869void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame(FrameIdentifier frameID, uint64_t navigationID, ResourceRequest&& request, const UserData& userData)
4870{
4871 didReceiveServerRedirectForProvisionalLoadForFrameShared(m_process.copyRef(), frameID, navigationID, WTFMove(request), userData);
4872}
4873
4874void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& process, FrameIdentifier frameID, uint64_t navigationID, ResourceRequest&& request, const UserData& userData)
4875{
4876 LOG(Loading, "WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame to frameID %" PRIu64 ", navigationID %" PRIu64 ", url %s", frameID.toUInt64(), navigationID, request.url().string().utf8().data());
4877
4878 PageClientProtector protector(pageClient());
4879
4880 WebFrameProxy* frame = process->webFrame(frameID);
4881 MESSAGE_CHECK(process, frame);
4882 MESSAGE_CHECK_URL(process, request.url());
4883
4884 WEBPAGEPROXY_RELEASE_LOG(Loading, "didReceiveServerRedirectForProvisionalLoadForFrame: frameID=%" PRIu64 ", isMainFrame=%d", frameID.toUInt64(), frame->isMainFrame());
4885
4886 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
4887 RefPtr<API::Navigation> navigation = navigationID ? navigationState().navigation(navigationID) : nullptr;
4888 if (navigation)
4889 navigation->appendRedirectionURL(request.url());
4890
4891 auto transaction = m_pageLoadState.transaction();
4892
4893 if (frame->isMainFrame())
4894 m_pageLoadState.didReceiveServerRedirectForProvisionalLoad(transaction, request.url().string());
4895
4896 frame->didReceiveServerRedirectForProvisionalLoad(request.url());
4897
4898 m_pageLoadState.commitChanges();
4899 if (m_loaderClient)
4900 m_loaderClient->didReceiveServerRedirectForProvisionalLoadForFrame(*this, *frame, frame->isMainFrame() ? navigation.get() : nullptr, process->transformHandlesToObjects(userData.object()).get());
4901 else if (frame->isMainFrame())
4902 m_navigationClient->didReceiveServerRedirectForProvisionalNavigation(*this, navigation.get(), process->transformHandlesToObjects(userData.object()).get());
4903}
4904
4905void WebPageProxy::willPerformClientRedirectForFrame(FrameIdentifier frameID, const String& url, double delay, WebCore::LockBackForwardList)
4906{
4907 PageClientProtector protector(pageClient());
4908
4909 WebFrameProxy* frame = m_process->webFrame(frameID);
4910 MESSAGE_CHECK(m_process, frame);
4911
4912 WEBPAGEPROXY_RELEASE_LOG(Loading, "willPerformClientRedirectForFrame: frameID=%" PRIu64 ", isMainFrame=%d", frameID.toUInt64(), frame->isMainFrame());
4913
4914 if (frame->isMainFrame())
4915 m_navigationClient->willPerformClientRedirect(*this, url, delay);
4916}
4917
4918void WebPageProxy::didCancelClientRedirectForFrame(FrameIdentifier frameID)
4919{
4920 PageClientProtector protector(pageClient());
4921
4922 WebFrameProxy* frame = m_process->webFrame(frameID);
4923 MESSAGE_CHECK(m_process, frame);
4924
4925 WEBPAGEPROXY_RELEASE_LOG(Loading, "didCancelClientRedirectForFrame: frameID=%" PRIu64 ", isMainFrame=%d", frameID.toUInt64(), frame->isMainFrame());
4926
4927 if (frame->isMainFrame())
4928 m_navigationClient->didCancelClientRedirect(*this);
4929}
4930
4931void WebPageProxy::didChangeProvisionalURLForFrame(FrameIdentifier frameID, uint64_t navigationID, URL&& url)
4932{
4933 didChangeProvisionalURLForFrameShared(m_process.copyRef(), frameID, navigationID, WTFMove(url));
4934}
4935
4936void WebPageProxy::didChangeProvisionalURLForFrameShared(Ref<WebProcessProxy>&& process, FrameIdentifier frameID, uint64_t, URL&& url)
4937{
4938 PageClientProtector protector(pageClient());
4939
4940 WebFrameProxy* frame = process->webFrame(frameID);
4941 MESSAGE_CHECK(process, frame);
4942 MESSAGE_CHECK(process, frame->frameLoadState().state() == FrameLoadState::State::Provisional);
4943 MESSAGE_CHECK_URL(process, url);
4944
4945 auto transaction = m_pageLoadState.transaction();
4946
4947 // Internally, we handle this the same way we handle a server redirect. There are no client callbacks
4948 // for this, but if this is the main frame, clients may observe a change to the page's URL.
4949 if (frame->isMainFrame())
4950 m_pageLoadState.didReceiveServerRedirectForProvisionalLoad(transaction, url.string());
4951
4952 frame->didReceiveServerRedirectForProvisionalLoad(url);
4953}
4954
4955void WebPageProxy::didFailProvisionalLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, WebCore::ResourceRequest&& request, uint64_t navigationID, const String& provisionalURL, const ResourceError& error, WillContinueLoading willContinueLoading, const UserData& userData)
4956{
4957 WebFrameProxy* frame = m_process->webFrame(frameID);
4958 MESSAGE_CHECK(m_process, frame);
4959
4960 if (m_provisionalPage && frame->isMainFrame()) {
4961 // The load did not fail, it is merely happening in a new provisional process.
4962 return;
4963 }
4964
4965 didFailProvisionalLoadForFrameShared(m_process.copyRef(), *frame, WTFMove(frameInfo), WTFMove(request), navigationID, provisionalURL, error, willContinueLoading, userData);
4966}
4967
4968void WebPageProxy::didFailProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& process, WebFrameProxy& frame, FrameInfoData&& frameInfo, WebCore::ResourceRequest&& request, uint64_t navigationID, const String& provisionalURL, const ResourceError& error, WillContinueLoading willContinueLoading, const UserData& userData)
4969{
4970 LOG(Loading, "(Loading) WebPageProxy %" PRIu64 " in web process pid %i didFailProvisionalLoadForFrame to provisionalURL %s", m_identifier.toUInt64(), process->processIdentifier(), provisionalURL.utf8().data());
4971 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "didFailProvisionalLoadForFrame: frameID=%" PRIu64 ", isMainFrame=%d, domain=%s, code=%d, isMainFrame=%d", frame.frameID().toUInt64(), frame.isMainFrame(), error.domain().utf8().data(), error.errorCode(), frame.isMainFrame());
4972
4973 PageClientProtector protector(pageClient());
4974
4975 if (m_controlledByAutomation) {
4976 if (auto* automationSession = process->processPool().automationSession())
4977 automationSession->navigationOccurredForFrame(frame);
4978 }
4979
4980 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
4981 RefPtr<API::Navigation> navigation;
4982 if (frame.isMainFrame() && navigationID)
4983 navigation = navigationState().takeNavigation(navigationID);
4984
4985 auto transaction = m_pageLoadState.transaction();
4986
4987 if (frame.isMainFrame()) {
4988 reportPageLoadResult(error);
4989 m_pageLoadState.didFailProvisionalLoad(transaction);
4990 pageClient().didFailProvisionalLoadForMainFrame();
4991 if (navigation)
4992 navigation->setClientNavigationActivity(nullptr);
4993
4994 callLoadCompletionHandlersIfNecessary(false);
4995 }
4996
4997 frame.didFailProvisionalLoad();
4998
4999 m_pageLoadState.commitChanges();
5000
5001 ASSERT(!m_failingProvisionalLoadURL);
5002 m_failingProvisionalLoadURL = provisionalURL;
5003
5004 if (m_loaderClient)
5005 m_loaderClient->didFailProvisionalLoadWithErrorForFrame(*this, frame, navigation.get(), error, process->transformHandlesToObjects(userData.object()).get());
5006 else {
5007 m_navigationClient->didFailProvisionalNavigationWithError(*this, FrameInfoData { frameInfo }, navigation.get(), error, process->transformHandlesToObjects(userData.object()).get());
5008 m_navigationClient->didFailProvisionalLoadWithErrorForFrame(*this, WTFMove(request), error, WTFMove(frameInfo));
5009 }
5010
5011 m_failingProvisionalLoadURL = { };
5012
5013 // If the provisional page's load fails then we destroy the provisional page.
5014 if (m_provisionalPage && m_provisionalPage->mainFrame() == &frame && willContinueLoading == WillContinueLoading::No)
5015 m_provisionalPage = nullptr;
5016}
5017
5018#if ENABLE(SERVICE_WORKER)
5019void WebPageProxy::didFinishServiceWorkerPageRegistration(bool success)
5020{
5021 ASSERT(m_isServiceWorkerPage);
5022 ASSERT(m_serviceWorkerLaunchCompletionHandler);
5023
5024 if (m_serviceWorkerLaunchCompletionHandler)
5025 m_serviceWorkerLaunchCompletionHandler(success);
5026}
5027#endif
5028
5029void WebPageProxy::callLoadCompletionHandlersIfNecessary(bool success)
5030{
5031#if ENABLE(SERVICE_WORKER)
5032 if (m_isServiceWorkerPage && m_serviceWorkerLaunchCompletionHandler && !success)
5033 m_serviceWorkerLaunchCompletionHandler(false);
5034
5035 if (m_serviceWorkerOpenWindowCompletionCallback)
5036 m_serviceWorkerOpenWindowCompletionCallback(success ? webPageID() : std::optional<WebCore::PageIdentifier> { });
5037#endif
5038}
5039
5040#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
5041static OptionSet<CrossSiteNavigationDataTransfer::Flag> checkIfNavigationContainsDataTransfer(const SecurityOriginData requesterOrigin, const ResourceRequest& currentRequest)
5042{
5043 OptionSet<CrossSiteNavigationDataTransfer::Flag> navigationDataTransfer;
5044 if (requesterOrigin.securityOrigin()->isUnique())
5045 return navigationDataTransfer;
5046
5047 auto currentURL = currentRequest.url();
5048 if (!currentURL.query().isEmpty() || !currentURL.fragmentIdentifier().isEmpty())
5049 navigationDataTransfer.add(CrossSiteNavigationDataTransfer::Flag::DestinationLinkDecoration);
5050
5051 URL referrerURL { currentRequest.httpReferrer() };
5052 if (!referrerURL.query().isEmpty() || !referrerURL.fragmentIdentifier().isEmpty())
5053 navigationDataTransfer.add(CrossSiteNavigationDataTransfer::Flag::ReferrerLinkDecoration);
5054
5055 return navigationDataTransfer;
5056}
5057#endif
5058
5059void WebPageProxy::didCommitLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, WebCore::FrameLoadType frameLoadType, const WebCore::CertificateInfo& certificateInfo, bool usedLegacyTLS, bool containsPluginDocument, std::optional<HasInsecureContent> hasInsecureContent, WebCore::MouseEventPolicy mouseEventPolicy, const UserData& userData)
5060{
5061 LOG(Loading, "(Loading) WebPageProxy %" PRIu64 " didCommitLoadForFrame in navigation %" PRIu64, m_identifier.toUInt64(), navigationID);
5062 LOG(BackForward, "(Back/Forward) After load commit, back/forward list is now:%s", m_backForwardList->loggingString());
5063
5064 PageClientProtector protector(pageClient());
5065
5066 WebFrameProxy* frame = m_process->webFrame(frameID);
5067 MESSAGE_CHECK(m_process, frame);
5068
5069 WEBPAGEPROXY_RELEASE_LOG(Loading, "didCommitLoadForFrame: frameID=%" PRIu64 ", isMainFrame=%d", frameID.toUInt64(), frame->isMainFrame());
5070
5071 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
5072 RefPtr<API::Navigation> navigation;
5073 if (frame->isMainFrame() && navigationID && (navigation = navigationState().navigation(navigationID))) {
5074#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
5075 auto requesterOrigin = navigation->lastNavigationAction().requesterOrigin;
5076 auto currentRequest = navigation->currentRequest();
5077 auto navigationDataTransfer = checkIfNavigationContainsDataTransfer(requesterOrigin, currentRequest);
5078 if (!navigationDataTransfer.isEmpty()) {
5079 RegistrableDomain currentDomain { currentRequest.url() };
5080 URL requesterURL { requesterOrigin.toString() };
5081 if (!currentDomain.matches(requesterURL))
5082 m_websiteDataStore->networkProcess().didCommitCrossSiteLoadWithDataTransfer(m_websiteDataStore->sessionID(), RegistrableDomain { requesterURL }, currentDomain, navigationDataTransfer, m_identifier, m_webPageID);
5083 }
5084#endif
5085 }
5086
5087 m_hasCommittedAnyProvisionalLoads = true;
5088 m_process->didCommitProvisionalLoad();
5089
5090 if (frame->isMainFrame()) {
5091 m_hasUpdatedRenderingAfterDidCommitLoad = false;
5092#if PLATFORM(IOS_FAMILY)
5093 m_firstLayerTreeTransactionIdAfterDidCommitLoad = downcast<RemoteLayerTreeDrawingAreaProxy>(*drawingArea()).nextLayerTreeTransactionID();
5094#endif
5095 }
5096
5097 auto transaction = m_pageLoadState.transaction();
5098 Ref<WebCertificateInfo> webCertificateInfo = WebCertificateInfo::create(certificateInfo);
5099 bool markPageInsecure = hasInsecureContent ? hasInsecureContent.value() == HasInsecureContent::Yes : certificateInfo.containsNonRootSHA1SignedCertificate();
5100
5101 if (frame->isMainFrame()) {
5102 m_pageLoadState.didCommitLoad(transaction, webCertificateInfo, markPageInsecure, usedLegacyTLS);
5103 m_shouldSuppressNextAutomaticNavigationSnapshot = false;
5104 } else if (markPageInsecure)
5105 m_pageLoadState.didDisplayOrRunInsecureContent(transaction);
5106
5107#if USE(APPKIT)
5108 // FIXME (bug 59111): didCommitLoadForFrame comes too late when restoring a page from b/f cache, making us disable secure event mode in password fields.
5109 // FIXME: A load going on in one frame shouldn't affect text editing in other frames on the page.
5110 pageClient().resetSecureInputState();
5111#endif
5112
5113 frame->didCommitLoad(mimeType, webCertificateInfo, containsPluginDocument);
5114
5115 if (frame->isMainFrame()) {
5116 std::optional<WebCore::PrivateClickMeasurement> privateClickMeasurement;
5117 if (m_privateClickMeasurement)
5118 privateClickMeasurement = m_privateClickMeasurement->pcm;
5119 else if (navigation && navigation->privateClickMeasurement())
5120 privateClickMeasurement = navigation->privateClickMeasurement();
5121 if (privateClickMeasurement) {
5122 if (privateClickMeasurement->destinationSite().matches(frame->url()) || privateClickMeasurement->isSKAdNetworkAttribution())
5123 websiteDataStore().networkProcess().send(Messages::NetworkProcess::StorePrivateClickMeasurement(m_websiteDataStore->sessionID(), *privateClickMeasurement), 0);
5124 }
5125 }
5126 m_privateClickMeasurement.reset();
5127
5128 if (frame->isMainFrame()) {
5129 m_mainFrameHasCustomContentProvider = frameHasCustomContentProvider;
5130
5131 if (m_mainFrameHasCustomContentProvider) {
5132 // Always assume that the main frame is pinned here, since the custom representation view will handle
5133 // any wheel events and dispatch them to the WKView when necessary.
5134 m_mainFramePinnedState = { true, true, true, true };
5135 m_uiClient->pinnedStateDidChange(*this);
5136 }
5137 pageClient().didCommitLoadForMainFrame(mimeType, frameHasCustomContentProvider);
5138 }
5139
5140 // Even if WebPage has the default pageScaleFactor (and therefore doesn't reset it),
5141 // WebPageProxy's cache of the value can get out of sync (e.g. in the case where a
5142 // plugin is handling page scaling itself) so we should reset it to the default
5143 // for standard main frame loads.
5144 if (frame->isMainFrame()) {
5145 m_pageScaleFactor = 1;
5146 m_pluginScaleFactor = 1;
5147 m_mainFramePluginHandlesPageScaleGesture = false;
5148#if ENABLE(POINTER_LOCK)
5149 requestPointerUnlock();
5150#endif
5151 pageClient().setMouseEventPolicy(mouseEventPolicy);
5152#if ENABLE(UI_PROCESS_PDF_HUD)
5153 pageClient().removeAllPDFHUDs();
5154#endif
5155 }
5156
5157 m_pageLoadState.commitChanges();
5158 if (m_loaderClient)
5159 m_loaderClient->didCommitLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
5160 else {
5161 if (frameInfo.isMainFrame)
5162 m_navigationClient->didCommitNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
5163 m_navigationClient->didCommitLoadForFrame(*this, WTFMove(request), WTFMove(frameInfo));
5164 }
5165 if (frame->isMainFrame()) {
5166#if ENABLE(ATTACHMENT_ELEMENT)
5167 invalidateAllAttachments();
5168#endif
5169#if ENABLE(REMOTE_INSPECTOR)
5170 remoteInspectorInformationDidChange();
5171#endif
5172#if USE(APPKIT)
5173 closeSharedPreviewPanelIfNecessary();
5174#endif
5175 }
5176
5177#if ENABLE(MEDIA_SESSION_COORDINATOR) && HAVE(GROUP_ACTIVITIES)
5178 if (frame->isMainFrame() && m_preferences->mediaSessionCoordinatorEnabled())
5179 GroupActivitiesSessionNotifier::sharedNotifier().webPageURLChanged(*this);
5180#endif
5181}
5182
5183void WebPageProxy::didFinishDocumentLoadForFrame(FrameIdentifier frameID, uint64_t navigationID, const UserData& userData)
5184{
5185 PageClientProtector protector(pageClient());
5186
5187 WebFrameProxy* frame = m_process->webFrame(frameID);
5188 MESSAGE_CHECK(m_process, frame);
5189
5190 WEBPAGEPROXY_RELEASE_LOG(Loading, "didFinishDocumentLoadForFrame: frameID=%" PRIu64 ", isMainFrame=%d", frameID.toUInt64(), frame->isMainFrame());
5191
5192 if (m_controlledByAutomation) {
5193 if (auto* automationSession = process().processPool().automationSession())
5194 automationSession->documentLoadedForFrame(*frame);
5195 }
5196
5197 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
5198 RefPtr<API::Navigation> navigation;
5199 if (frame->isMainFrame() && navigationID)
5200 navigation = navigationState().navigation(navigationID);
5201
5202 if (frame->isMainFrame()) {
5203 m_navigationClient->didFinishDocumentLoad(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
5204#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
5205 m_didFinishDocumentLoadForMainFrameTimestamp = MonotonicTime::now();
5206#endif
5207 }
5208}
5209
5210void WebPageProxy::didFinishLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, const UserData& userData)
5211{
5212 LOG(Loading, "WebPageProxy::didFinishLoadForFrame - WebPageProxy %p with navigationID %" PRIu64 " didFinishLoad", this, navigationID);
5213
5214 PageClientProtector protector(pageClient());
5215
5216 WebFrameProxy* frame = m_process->webFrame(frameID);
5217 MESSAGE_CHECK(m_process, frame);
5218
5219 WEBPAGEPROXY_RELEASE_LOG(Loading, "didFinishLoadForFrame: frameID=%" PRIu64 ", isMainFrame=%d", frameID.toUInt64(), frame->isMainFrame());
5220
5221 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
5222 RefPtr<API::Navigation> navigation;
5223 if (frame->isMainFrame() && navigationID && navigationState().hasNavigation(navigationID))
5224 navigation = navigationState().navigation(navigationID);
5225
5226 bool isMainFrame = frame->isMainFrame();
5227 if (!isMainFrame || !navigationID || navigation) {
5228 auto transaction = m_pageLoadState.transaction();
5229
5230 if (isMainFrame)
5231 m_pageLoadState.didFinishLoad(transaction);
5232
5233 if (m_controlledByAutomation) {
5234 if (auto* automationSession = process().processPool().automationSession())
5235 automationSession->navigationOccurredForFrame(*frame);
5236 }
5237
5238 frame->didFinishLoad();
5239
5240 m_pageLoadState.commitChanges();
5241 }
5242
5243 if (m_loaderClient)
5244 m_loaderClient->didFinishLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
5245 else {
5246 if (frameInfo.isMainFrame)
5247 m_navigationClient->didFinishNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
5248 m_navigationClient->didFinishLoadForFrame(*this, WTFMove(request), WTFMove(frameInfo));
5249 }
5250
5251 if (isMainFrame) {
5252 reportPageLoadResult();
5253 pageClient().didFinishNavigation(navigation.get());
5254
5255 if (navigation)
5256 navigation->setClientNavigationActivity(nullptr);
5257
5258 resetRecentCrashCountSoon();
5259
5260 notifyProcessPoolToPrewarm();
5261
5262 callLoadCompletionHandlersIfNecessary(true);
5263 }
5264
5265 m_isLoadingAlternateHTMLStringForFailingProvisionalLoad = false;
5266}
5267
5268void WebPageProxy::didFailLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, const ResourceError& error, const UserData& userData)
5269{
5270 PageClientProtector protector(pageClient());
5271
5272 WebFrameProxy* frame = m_process->webFrame(frameID);
5273 MESSAGE_CHECK(m_process, frame);
5274
5275 WEBPAGEPROXY_RELEASE_LOG_ERROR(Loading, "didFailLoadForFrame: frameID=%" PRIu64 ", isMainFrame=%d, domain=%s, code=%d", frameID.toUInt64(), frame->isMainFrame(), error.domain().utf8().data(), error.errorCode());
5276
5277 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
5278 RefPtr<API::Navigation> navigation;
5279 if (frame->isMainFrame() && navigationID)
5280 navigation = navigationState().navigation(navigationID);
5281
5282 auto transaction = m_pageLoadState.transaction();
5283
5284 bool isMainFrame = frame->isMainFrame();
5285
5286 if (isMainFrame)
5287 m_pageLoadState.didFailLoad(transaction);
5288
5289 if (m_controlledByAutomation) {
5290 if (auto* automationSession = process().processPool().automationSession())
5291 automationSession->navigationOccurredForFrame(*frame);
5292 }
5293
5294 frame->didFailLoad();
5295
5296 m_pageLoadState.commitChanges();
5297 if (m_loaderClient)
5298 m_loaderClient->didFailLoadWithErrorForFrame(*this, *frame, navigation.get(), error, m_process->transformHandlesToObjects(userData.object()).get());
5299 else {
5300 if (frameInfo.isMainFrame)
5301 m_navigationClient->didFailNavigationWithError(*this, frameInfo, navigation.get(), error, m_process->transformHandlesToObjects(userData.object()).get());
5302 m_navigationClient->didFailLoadWithErrorForFrame(*this, WTFMove(request), error, WTFMove(frameInfo));
5303 }
5304
5305 if (isMainFrame) {
5306 reportPageLoadResult(error);
5307 pageClient().didFailNavigation(navigation.get());
5308 if (navigation)
5309 navigation->setClientNavigationActivity(nullptr);
5310
5311 callLoadCompletionHandlersIfNecessary(false);
5312 }
5313}
5314
5315void WebPageProxy::didSameDocumentNavigationForFrame(FrameIdentifier frameID, uint64_t navigationID, uint32_t opaqueSameDocumentNavigationType, URL&& url, const UserData& userData)
5316{
5317 PageClientProtector protector(pageClient());
5318
5319 WebFrameProxy* frame = m_process->webFrame(frameID);
5320 MESSAGE_CHECK(m_process, frame);
5321 MESSAGE_CHECK_URL(m_process, url);
5322
5323 WEBPAGEPROXY_RELEASE_LOG(Loading, "didSameDocumentNavigationForFrame: frameID=%" PRIu64 ", isMainFrame=%d", frameID.toUInt64(), frame->isMainFrame());
5324
5325 // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the back/forward cache.
5326 RefPtr<API::Navigation> navigation;
5327 if (frame->isMainFrame() && navigationID)
5328 navigation = navigationState().navigation(navigationID);
5329
5330 auto transaction = m_pageLoadState.transaction();
5331
5332 bool isMainFrame = frame->isMainFrame();
5333 if (isMainFrame)
5334 m_pageLoadState.didSameDocumentNavigation(transaction, url.string());
5335
5336 if (m_controlledByAutomation) {
5337 if (auto* automationSession = process().processPool().automationSession())
5338 automationSession->navigationOccurredForFrame(*frame);
5339 }
5340
5341 m_pageLoadState.clearPendingAPIRequest(transaction);
5342 frame->didSameDocumentNavigation(url);
5343
5344 m_pageLoadState.commitChanges();
5345
5346 SameDocumentNavigationType navigationType = static_cast<SameDocumentNavigationType>(opaqueSameDocumentNavigationType);
5347 if (isMainFrame)
5348 m_navigationClient->didSameDocumentNavigation(*this, navigation.get(), navigationType, m_process->transformHandlesToObjects(userData.object()).get());
5349
5350 if (isMainFrame)
5351 pageClient().didSameDocumentNavigationForMainFrame(navigationType);
5352}
5353
5354void WebPageProxy::didChangeMainDocument(FrameIdentifier frameID)
5355{
5356#if ENABLE(MEDIA_STREAM)
5357 if (m_userMediaPermissionRequestManager) {
5358 m_userMediaPermissionRequestManager->resetAccess(frameID);
5359
5360#if ENABLE(GPU_PROCESS)
5361 if (auto* gpuProcess = m_process->processPool().gpuProcess()) {
5362 if (auto* frame = m_process->webFrame(frameID))
5363 gpuProcess->updateCaptureOrigin(SecurityOriginData::fromURL(frame->url()), m_process->coreProcessIdentifier());
5364 }
5365#endif
5366 }
5367
5368#else
5369 UNUSED_PARAM(frameID);
5370#endif
5371
5372 m_isQuotaIncreaseDenied = false;
5373
5374 m_speechRecognitionPermissionManager = nullptr;
5375}
5376
5377void WebPageProxy::viewIsBecomingVisible()
5378{
5379 WEBPAGEPROXY_RELEASE_LOG(ViewState, "viewIsBecomingVisible:");
5380 m_process->markProcessAsRecentlyUsed();
5381#if ENABLE(MEDIA_STREAM)
5382 if (m_userMediaPermissionRequestManager)
5383 m_userMediaPermissionRequestManager->viewIsBecomingVisible();
5384#endif
5385}
5386
5387void WebPageProxy::didReceiveTitleForFrame(FrameIdentifier frameID, const String& title, const UserData& userData)
5388{
5389 PageClientProtector protector(pageClient());
5390
5391 WebFrameProxy* frame = m_process->webFrame(frameID);
5392 MESSAGE_CHECK(m_process, frame);
5393
5394 auto transaction = m_pageLoadState.transaction();
5395
5396 if (frame->isMainFrame())
5397 m_pageLoadState.setTitle(transaction, title);
5398
5399 frame->didChangeTitle(title);
5400
5401 m_pageLoadState.commitChanges();
5402
5403#if ENABLE(REMOTE_INSPECTOR)
5404 if (frame->isMainFrame())
5405 remoteInspectorInformationDidChange();
5406#endif
5407}
5408
5409void WebPageProxy::didFirstLayoutForFrame(FrameIdentifier, const UserData& userData)
5410{
5411}
5412
5413void WebPageProxy::didFirstVisuallyNonEmptyLayoutForFrame(FrameIdentifier frameID, const UserData& userData)
5414{
5415 PageClientProtector protector(pageClient());
5416
5417 WebFrameProxy* frame = m_process->webFrame(frameID);
5418 MESSAGE_CHECK(m_process, frame);
5419
5420 if (m_loaderClient)
5421 m_loaderClient->didFirstVisuallyNonEmptyLayoutForFrame(*this, *frame, m_process->transformHandlesToObjects(userData.object()).get());
5422
5423 if (frame->isMainFrame())
5424 pageClient().didFirstVisuallyNonEmptyLayoutForMainFrame();
5425}
5426
5427void WebPageProxy::didLayoutForCustomContentProvider()
5428{
5429 didReachLayoutMilestone({ DidFirstLayout, DidFirstVisuallyNonEmptyLayout, DidHitRelevantRepaintedObjectsAreaThreshold });
5430}
5431
5432void WebPageProxy::didReachLayoutMilestone(OptionSet<WebCore::LayoutMilestone> layoutMilestones)
5433{
5434 PageClientProtector protector(pageClient());
5435
5436 if (layoutMilestones.contains(DidFirstVisuallyNonEmptyLayout))
5437 pageClient().clearSafeBrowsingWarningIfForMainFrameNavigation();
5438
5439 if (m_loaderClient)
5440 m_loaderClient->didReachLayoutMilestone(*this, layoutMilestones);
5441 m_navigationClient->renderingProgressDidChange(*this, layoutMilestones);
5442}
5443
5444void WebPageProxy::didDisplayInsecureContentForFrame(FrameIdentifier frameID, const UserData& userData)
5445{
5446 PageClientProtector protector(pageClient());
5447
5448 WebFrameProxy* frame = m_process->webFrame(frameID);
5449 MESSAGE_CHECK(m_process, frame);
5450
5451 auto transaction = m_pageLoadState.transaction();
5452 m_pageLoadState.didDisplayOrRunInsecureContent(transaction);
5453 m_pageLoadState.commitChanges();
5454
5455 m_navigationClient->didDisplayInsecureContent(*this, m_process->transformHandlesToObjects(userData.object()).get());
5456}
5457
5458void WebPageProxy::didRunInsecureContentForFrame(FrameIdentifier frameID, const UserData& userData)
5459{
5460 PageClientProtector protector(pageClient());
5461
5462 WebFrameProxy* frame = m_process->webFrame(frameID);
5463 MESSAGE_CHECK(m_process, frame);
5464
5465 auto transaction = m_pageLoadState.transaction();
5466 m_pageLoadState.didDisplayOrRunInsecureContent(transaction);
5467 m_pageLoadState.commitChanges();
5468
5469 m_navigationClient->didRunInsecureContent(*this, m_process->transformHandlesToObjects(userData.object()).get());
5470}
5471
5472void WebPageProxy::didDetectXSSForFrame(FrameIdentifier, const UserData&)
5473{
5474}
5475
5476void WebPageProxy::mainFramePluginHandlesPageScaleGestureDidChange(bool mainFramePluginHandlesPageScaleGesture)
5477{
5478 m_mainFramePluginHandlesPageScaleGesture = mainFramePluginHandlesPageScaleGesture;
5479}
5480
5481#if !PLATFORM(COCOA)
5482void WebPageProxy::beginSafeBrowsingCheck(const URL&, bool, WebFramePolicyListenerProxy& listener)
5483{
5484 listener.didReceiveSafeBrowsingResults({ });
5485}
5486#endif
5487
5488void WebPageProxy::decidePolicyForNavigationActionAsync(FrameIdentifier frameID, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier, uint64_t navigationID,
5489 NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfo, std::optional<WebPageProxyIdentifier> originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request,
5490 IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData& userData, uint64_t listenerID)
5491{
5492 decidePolicyForNavigationActionAsyncShared(m_process.copyRef(), m_webPageID, frameID, WTFMove(frameInfo), identifier, navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, listenerID);
5493}
5494
5495void WebPageProxy::decidePolicyForNavigationActionAsyncShared(Ref<WebProcessProxy>&& process, PageIdentifier webPageID, FrameIdentifier frameID, FrameInfoData&& frameInfo,
5496 WebCore::PolicyCheckIdentifier identifier, uint64_t navigationID, NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfo, std::optional<WebPageProxyIdentifier> originatingPageID,
5497 const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse,
5498 const UserData& userData, uint64_t listenerID)
5499{
5500 auto* frame = process->webFrame(frameID);
5501 MESSAGE_CHECK(process, frame);
5502
5503 auto sender = PolicyDecisionSender::create(identifier, [webPageID, frameID, listenerID, process] (const auto& policyDecision) {
5504 process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, policyDecision
5505#if !ENABLE(CONTENT_FILTERING_IN_NETWORKING_PROCESS)
5506 , createNetworkExtensionsSandboxExtensions(process)
5507#endif
5508 ), webPageID);
5509 });
5510
5511 decidePolicyForNavigationAction(process.copyRef(), webPageID, *frame, WTFMove(frameInfo), navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID,
5512 originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, WTFMove(sender));
5513}
5514
5515#if PLATFORM(COCOA)
5516// https://html.spec.whatwg.org/#hand-off-to-external-software
5517static bool frameSandboxAllowsOpeningExternalCustomProtocols(SandboxFlags sandboxFlags, bool hasUserGesture)
5518{
5519 if (!(sandboxFlags & SandboxPopups) || !(sandboxFlags & SandboxTopNavigation) || !(sandboxFlags & SandboxTopNavigationToCustomProtocols))
5520 return true;
5521
5522 return !(sandboxFlags & SandboxTopNavigationByUserActivation) && hasUserGesture;
5523}
5524#endif
5525
5526void WebPageProxy::decidePolicyForNavigationAction(Ref<WebProcessProxy>&& process, PageIdentifier webPageID, WebFrameProxy& frame, FrameInfoData&& frameInfo, uint64_t navigationID,
5527 NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfoData, std::optional<WebPageProxyIdentifier> originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request,
5528 IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData& userData, Ref<PolicyDecisionSender>&& sender)
5529{
5530 WEBPAGEPROXY_RELEASE_LOG(Loading, "decidePolicyForNavigationAction: frameID=%llu, isMainFrame=%d, navigationID=%llu", frame.frameID().toUInt64(), frame.isMainFrame(), navigationID);
5531
5532 LOG(Loading, "WebPageProxy::decidePolicyForNavigationAction - Original URL %s, current target URL %s", originalRequest.url().string().utf8().data(), request.url().string().utf8().data());
5533
5534 PageClientProtector protector(pageClient());
5535
5536 // Make the request whole again as we do not normally encode the request's body when sending it over IPC, for performance reasons.
5537 request.setHTTPBody(requestBody.takeData());
5538
5539 auto transaction = m_pageLoadState.transaction();
5540
5541 bool fromAPI = request.url() == m_pageLoadState.pendingAPIRequestURL();
5542 if (navigationID && !fromAPI)
5543 m_pageLoadState.clearPendingAPIRequest(transaction);
5544
5545 if (!checkURLReceivedFromCurrentOrPreviousWebProcess(process, request.url())) {
5546 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "Ignoring request to load this main resource because it is outside the sandbox");
5547 sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), PolicyAction::Ignore, 0, std::nullopt, std::nullopt });
5548 return;
5549 }
5550
5551 MESSAGE_CHECK_URL(process, originalRequest.url());
5552
5553 RefPtr<API::Navigation> navigation;
5554 if (navigationID)
5555 navigation = m_navigationState->navigation(navigationID);
5556
5557 // When process-swapping on a redirect, the navigationActionData / originatingFrameInfoData provided by the fresh new WebProcess are inaccurate since
5558 // 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
5559 // policy decision.
5560 if (navigationActionData.isRedirect && navigation) {
5561 navigationActionData = navigation->lastNavigationAction();
5562 navigationActionData.isRedirect = true;
5563 originatingFrameInfoData = navigation->originatingFrameInfo();
5564 frameInfo.securityOrigin = navigation->destinationFrameSecurityOrigin();
5565 }
5566
5567 if (!navigation) {
5568 if (auto targetBackForwardItemIdentifier = navigationActionData.targetBackForwardItemIdentifier) {
5569 if (auto* item = m_backForwardList->itemForID(*targetBackForwardItemIdentifier)) {
5570 auto* fromItem = navigationActionData.sourceBackForwardItemIdentifier ? m_backForwardList->itemForID(*navigationActionData.sourceBackForwardItemIdentifier) : nullptr;
5571 if (!fromItem)
5572 fromItem = m_backForwardList->currentItem();
5573 navigation = m_navigationState->createBackForwardNavigation(*item, fromItem, FrameLoadType::IndexedBackForward);
5574 }
5575 }
5576 if (!navigation)
5577 navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem());
5578 }
5579
5580 navigationID = navigation->navigationID();
5581
5582 // Make sure the provisional page always has the latest navigationID.
5583 if (m_provisionalPage && &m_provisionalPage->process() == process.ptr())
5584 m_provisionalPage->setNavigationID(navigationID);
5585
5586 navigation->setCurrentRequest(ResourceRequest(request), process->coreProcessIdentifier());
5587 navigation->setLastNavigationAction(navigationActionData);
5588 navigation->setOriginatingFrameInfo(originatingFrameInfoData);
5589 navigation->setDestinationFrameSecurityOrigin(frameInfo.securityOrigin);
5590
5591 API::Navigation* mainFrameNavigation = frame.isMainFrame() ? navigation.get() : nullptr;
5592 WebFrameProxy* originatingFrame = originatingFrameInfoData.frameID ? process->webFrame(*originatingFrameInfoData.frameID) : nullptr;
5593 auto destinationFrameInfo = API::FrameInfo::create(FrameInfoData { frameInfo }, this);
5594 RefPtr<API::FrameInfo> sourceFrameInfo;
5595 if (!fromAPI && originatingFrame == &frame)
5596 sourceFrameInfo = destinationFrameInfo.copyRef();
5597 else if (!fromAPI) {
5598 auto* originatingPage = originatingPageID ? process->webPage(*originatingPageID) : nullptr;
5599 sourceFrameInfo = API::FrameInfo::create(WTFMove(originatingFrameInfoData), originatingPage);
5600 }
5601
5602 bool shouldOpenAppLinks = !m_shouldSuppressAppLinksInNextNavigationPolicyDecision
5603 && destinationFrameInfo->isMainFrame()
5604 && (m_mainFrame && m_mainFrame->url().host() != request.url().host())
5605 && navigationActionData.navigationType != WebCore::NavigationType::BackForward;
5606
5607 auto userInitiatedActivity = process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
5608 auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), sourceFrameInfo.get(), destinationFrameInfo.ptr(), std::nullopt, ResourceRequest(request), originalRequest.url(), shouldOpenAppLinks, WTFMove(userInitiatedActivity), mainFrameNavigation);
5609
5610#if ENABLE(CONTENT_FILTERING)
5611 if (frame.didHandleContentFilterUnblockNavigation(request)) {
5612 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "Ignoring request to load this main resource because it was handled by content filter");
5613 return receivedPolicyDecision(PolicyAction::Ignore, m_navigationState->navigation(navigationID), nullptr, WTFMove(navigationAction), WTFMove(sender));
5614 }
5615#endif
5616
5617 // Other ports do not implement WebPage::platformCanHandleRequest().
5618#if PLATFORM(COCOA)
5619 // Sandboxed iframes should be allowed to open external apps via custom protocols unless explicitely allowed (https://html.spec.whatwg.org/#hand-off-to-external-software).
5620 bool canHandleRequest = navigationActionData.canHandleRequest || m_urlSchemeHandlersByScheme.contains<StringViewHashTranslator>(request.url().protocol());
5621 if (!canHandleRequest && !destinationFrameInfo->isMainFrame() && !frameSandboxAllowsOpeningExternalCustomProtocols(navigationActionData.effectiveSandboxFlags, !!navigationActionData.userGestureTokenIdentifier)) {
5622 if (!sourceFrameInfo || !m_preferences->needsSiteSpecificQuirks() || !Quirks::shouldAllowNavigationToCustomProtocolWithoutUserGesture(request.url().protocol(), sourceFrameInfo->securityOrigin())) {
5623 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "Ignoring request to load this main resource because it has a custom protocol and comes from a sandboxed iframe");
5624 process->send(Messages::WebPage::AddConsoleMessage(frame.frameID(), MessageSource::Security, MessageLevel::Error, "Ignoring request to load this main resource because it has a custom protocol and comes from a sandboxed iframe"_s, std::nullopt), webPageID);
5625 return receivedPolicyDecision(PolicyAction::Ignore, m_navigationState->navigation(navigationID), nullptr, WTFMove(navigationAction), WTFMove(sender));
5626 }
5627 process->send(Messages::WebPage::AddConsoleMessage(frame.frameID(), MessageSource::Security, MessageLevel::Warning, "In the future, requests to navigate to a URL with custom protocol from a sandboxed iframe will be ignored"_s, std::nullopt), webPageID);
5628 }
5629#endif
5630
5631 ShouldExpectSafeBrowsingResult shouldExpectSafeBrowsingResult = ShouldExpectSafeBrowsingResult::Yes;
5632 if (!m_preferences->safeBrowsingEnabled())
5633 shouldExpectSafeBrowsingResult = ShouldExpectSafeBrowsingResult::No;
5634
5635 ShouldExpectAppBoundDomainResult shouldExpectAppBoundDomainResult = ShouldExpectAppBoundDomainResult::No;
5636#if ENABLE(APP_BOUND_DOMAINS)
5637 shouldExpectAppBoundDomainResult = ShouldExpectAppBoundDomainResult::Yes;
5638#endif
5639
5640 Ref listener = frame.setUpPolicyListenerProxy([this, protectedThis = Ref { *this }, frame = Ref { frame }, sender = WTFMove(sender), navigation, navigationAction, frameInfo, userDataObject = process->transformHandlesToObjects(userData.object()).get()] (PolicyAction policyAction, API::WebsitePolicies* policies, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning, std::optional<NavigatingToAppBoundDomain> isAppBoundDomain) mutable {
5641 WEBPAGEPROXY_RELEASE_LOG(Loading, "decidePolicyForNavigationAction: listener called: frameID=%llu, isMainFrame=%d, navigationID=%llu, policyAction=%u, safeBrowsingWarning=%d, isAppBoundDomain=%d", frame->frameID().toUInt64(), frame->isMainFrame(), navigation ? navigation->navigationID() : 0, (unsigned)policyAction, !!safeBrowsingWarning, !!isAppBoundDomain);
5642
5643 navigation->setWebsitePolicies(WTFMove(policies));
5644 auto completionHandler = [this, protectedThis, frame, frameInfo, sender = WTFMove(sender), navigation, navigationAction = WTFMove(navigationAction), processSwapRequestedByClient] (PolicyAction policyAction) mutable {
5645 if (frame->isMainFrame()) {
5646 if (!navigation->websitePolicies()) {
5647 if (auto* defaultPolicies = m_configuration->defaultWebsitePolicies())
5648 navigation->setWebsitePolicies(defaultPolicies->copy());
5649 }
5650 if (auto* policies = navigation->websitePolicies())
5651 navigation->setEffectiveContentMode(effectiveContentModeAfterAdjustingPolicies(*policies, navigation->currentRequest()));
5652 }
5653 receivedNavigationPolicyDecision(policyAction, navigation.get(), WTFMove(navigationAction), processSwapRequestedByClient, frame, frameInfo, WTFMove(sender));
5654 };
5655
5656#if ENABLE(APP_BOUND_DOMAINS)
5657 if (policyAction != PolicyAction::Ignore) {
5658 if (!setIsNavigatingToAppBoundDomainAndCheckIfPermitted(frame->isMainFrame(), navigation->currentRequest().url(), isAppBoundDomain)) {
5659 auto error = errorForUnpermittedAppBoundDomainNavigation(navigation->currentRequest().url());
5660 m_navigationClient->didFailProvisionalNavigationWithError(*this, FrameInfoData { frameInfo }, navigation.get(), error, userDataObject);
5661 WEBPAGEPROXY_RELEASE_LOG_ERROR(Loading, "Ignoring request to load this main resource because it is attempting to navigate away from an app-bound domain or navigate after using restricted APIs");
5662 completionHandler(PolicyAction::Ignore);
5663 return;
5664 }
5665 if (frame->isMainFrame())
5666 m_isTopFrameNavigatingToAppBoundDomain = m_isNavigatingToAppBoundDomain;
5667 }
5668#endif
5669
5670 if (!m_pageClient)
5671 return completionHandler(policyAction);
5672
5673 m_pageClient->clearSafeBrowsingWarning();
5674
5675 if (safeBrowsingWarning) {
5676 if (frame->isMainFrame() && safeBrowsingWarning->url().isValid()) {
5677 auto transaction = m_pageLoadState.transaction();
5678 m_pageLoadState.setPendingAPIRequest(transaction, { navigation->navigationID(), safeBrowsingWarning->url().string() });
5679 m_pageLoadState.commitChanges();
5680 }
5681
5682 auto transaction = m_pageLoadState.transaction();
5683 m_pageLoadState.setTitleFromSafeBrowsingWarning(transaction, safeBrowsingWarning->title());
5684
5685 m_pageClient->showSafeBrowsingWarning(*safeBrowsingWarning, [this, protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler), policyAction] (auto&& result) mutable {
5686
5687 auto transaction = m_pageLoadState.transaction();
5688 m_pageLoadState.setTitleFromSafeBrowsingWarning(transaction, { });
5689
5690 switchOn(result, [&] (const URL& url) {
5691 completionHandler(PolicyAction::Ignore);
5692 loadRequest({ url });
5693 }, [&] (ContinueUnsafeLoad continueUnsafeLoad) {
5694 switch (continueUnsafeLoad) {
5695 case ContinueUnsafeLoad::No:
5696 if (!hasCommittedAnyProvisionalLoads())
5697 m_uiClient->close(protectedThis.ptr());
5698 completionHandler(PolicyAction::Ignore);
5699 break;
5700 case ContinueUnsafeLoad::Yes:
5701 completionHandler(policyAction);
5702 break;
5703 }
5704 });
5705 });
5706 m_uiClient->didShowSafeBrowsingWarning();
5707 return;
5708 }
5709 completionHandler(policyAction);
5710
5711 }, shouldExpectSafeBrowsingResult, shouldExpectAppBoundDomainResult);
5712 if (shouldExpectSafeBrowsingResult == ShouldExpectSafeBrowsingResult::Yes)
5713 beginSafeBrowsingCheck(request.url(), frame.isMainFrame(), listener);
5714#if ENABLE(APP_BOUND_DOMAINS)
5715 bool shouldSendSecurityOriginData = !frame.isMainFrame() && shouldTreatURLProtocolAsAppBound(request.url(), websiteDataStore().configuration().enableInAppBrowserPrivacyForTesting());
5716 auto host = shouldSendSecurityOriginData ? frameInfo.securityOrigin.host : request.url().host();
5717 auto protocol = shouldSendSecurityOriginData ? frameInfo.securityOrigin.protocol : request.url().protocol();
5718 m_websiteDataStore->beginAppBoundDomainCheck(host.toString(), protocol.toString(), listener);
5719#endif
5720
5721#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
5722 auto wasPotentiallyInitiatedByUser = navigation->isLoadedWithNavigationShared() || userInitiatedActivity;
5723 if (!sessionID().isEphemeral())
5724 logFrameNavigation(frame, URL { m_pageLoadState.url() }, request, redirectResponse.url(), wasPotentiallyInitiatedByUser);
5725#endif
5726
5727 if (m_policyClient)
5728 m_policyClient->decidePolicyForNavigationAction(*this, &frame, WTFMove(navigationAction), originatingFrame, originalRequest, WTFMove(request), WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
5729 else {
5730#if HAVE(APP_SSO)
5731 if (m_shouldSuppressSOAuthorizationInNextNavigationPolicyDecision || !m_preferences->isExtensibleSSOEnabled())
5732 navigationAction->unsetShouldPerformSOAuthorization();
5733#endif
5734
5735 m_navigationClient->decidePolicyForNavigationAction(*this, WTFMove(navigationAction), WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
5736 }
5737
5738 m_shouldSuppressAppLinksInNextNavigationPolicyDecision = false;
5739
5740#if HAVE(APP_SSO)
5741 m_shouldSuppressSOAuthorizationInNextNavigationPolicyDecision = false;
5742#endif
5743}
5744
5745WebPageProxy* WebPageProxy::nonEphemeralWebPageProxy()
5746{
5747 auto processPools = WebProcessPool::allProcessPools();
5748 if (processPools.isEmpty())
5749 return nullptr;
5750
5751 for (auto& webProcess : processPools[0]->processes()) {
5752 for (auto& page : webProcess->pages()) {
5753 if (page->sessionID().isEphemeral())
5754 continue;
5755 return page;
5756 }
5757 }
5758 return nullptr;
5759}
5760
5761#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
5762void WebPageProxy::logFrameNavigation(const WebFrameProxy& frame, const URL& pageURL, const WebCore::ResourceRequest& request, const URL& redirectURL, bool wasPotentiallyInitiatedByUser)
5763{
5764 ASSERT(RunLoop::isMain());
5765
5766 auto sourceURL = redirectURL;
5767 bool isRedirect = !redirectURL.isNull();
5768 if (!isRedirect) {
5769 sourceURL = frame.url();
5770 if (sourceURL.isNull())
5771 sourceURL = pageURL;
5772 }
5773
5774 auto& targetURL = request.url();
5775
5776 if (!targetURL.isValid() || !pageURL.isValid())
5777 return;
5778
5779 auto targetHost = targetURL.host();
5780 auto mainFrameHost = pageURL.host();
5781
5782 if (targetHost.isEmpty() || mainFrameHost.isEmpty() || targetHost == sourceURL.host())
5783 return;
5784
5785 websiteDataStore().networkProcess().send(Messages::NetworkProcess::LogFrameNavigation(m_websiteDataStore->sessionID(), RegistrableDomain { targetURL }, RegistrableDomain { pageURL }, RegistrableDomain { sourceURL }, isRedirect, frame.isMainFrame(), MonotonicTime::now() - m_didFinishDocumentLoadForMainFrameTimestamp, wasPotentiallyInitiatedByUser), 0);
5786}
5787#endif
5788
5789void WebPageProxy::decidePolicyForNavigationActionSync(FrameIdentifier frameID, bool isMainFrame, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier,
5790 uint64_t navigationID, NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfo, std::optional<WebPageProxyIdentifier> originatingPageID,
5791 const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse,
5792 const UserData& userData, Messages::WebPageProxy::DecidePolicyForNavigationActionSync::DelayedReply&& reply)
5793{
5794 auto* frame = m_process->webFrame(frameID);
5795 if (!frame) {
5796 // This synchronous IPC message was processed before the asynchronous DidCreateMainFrame / DidCreateSubframe one so we do not know about this frameID yet.
5797 if (isMainFrame)
5798 didCreateMainFrame(frameID);
5799 else
5800 didCreateSubframe(frameID);
5801 }
5802
5803 decidePolicyForNavigationActionSyncShared(m_process.copyRef(), m_webPageID, frameID, isMainFrame, WTFMove(frameInfo), identifier, navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, WTFMove(reply));
5804}
5805
5806void WebPageProxy::decidePolicyForNavigationActionSyncShared(Ref<WebProcessProxy>&& process, PageIdentifier webPageID, FrameIdentifier frameID, bool isMainFrame, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier, uint64_t navigationID, NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfo, std::optional<WebPageProxyIdentifier> originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData& userData, Messages::WebPageProxy::DecidePolicyForNavigationActionSync::DelayedReply&& reply)
5807{
5808 auto sender = PolicyDecisionSender::create(identifier, WTFMove(reply));
5809
5810 auto* frame = process->webFrame(frameID);
5811 MESSAGE_CHECK(process, frame);
5812
5813 decidePolicyForNavigationAction(WTFMove(process), webPageID, *frame, WTFMove(frameInfo), navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, sender.copyRef());
5814
5815 // If the client did not respond synchronously, proceed with the load.
5816 sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), PolicyAction::Use, navigationID, std::nullopt, std::nullopt });
5817}
5818
5819void WebPageProxy::decidePolicyForNewWindowAction(FrameIdentifier frameID, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier, NavigationActionData&& navigationActionData, ResourceRequest&& request, const String& frameName, uint64_t listenerID, const UserData& userData)
5820{
5821 PageClientProtector protector(pageClient());
5822
5823 WebFrameProxy* frame = m_process->webFrame(frameID);
5824 MESSAGE_CHECK(m_process, frame);
5825 MESSAGE_CHECK_URL(m_process, request.url());
5826
5827 RefPtr<API::FrameInfo> sourceFrameInfo;
5828 if (frame)
5829 sourceFrameInfo = API::FrameInfo::create(WTFMove(frameInfo), this);
5830
5831 auto userInitiatedActivity = m_process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
5832 bool shouldOpenAppLinks = m_mainFrame && m_mainFrame->url().host() != request.url().host();
5833 auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), sourceFrameInfo.get(), nullptr, frameName, ResourceRequest(request), URL { }, shouldOpenAppLinks, WTFMove(userInitiatedActivity));
5834
5835 Ref listener = frame->setUpPolicyListenerProxy([this, protectedThis = Ref { *this }, identifier, listenerID, frameID, navigationAction] (PolicyAction policyAction, API::WebsitePolicies*, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain) mutable {
5836 // FIXME: Assert the API::WebsitePolicies* is nullptr here once clients of WKFramePolicyListenerUseWithPolicies go away.
5837 RELEASE_ASSERT(processSwapRequestedByClient == ProcessSwapRequestedByClient::No);
5838 ASSERT_UNUSED(safeBrowsingWarning, !safeBrowsingWarning);
5839
5840 auto sender = PolicyDecisionSender::create(identifier, [this, protectedThis = WTFMove(protectedThis), frameID, listenerID] (const auto& policyDecision) {
5841 send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, policyDecision
5842#if !ENABLE(CONTENT_FILTERING_IN_NETWORKING_PROCESS)
5843 , createNetworkExtensionsSandboxExtensions(m_process)
5844#endif
5845 ));
5846 });
5847
5848 receivedPolicyDecision(policyAction, nullptr, nullptr, WTFMove(navigationAction), WTFMove(sender));
5849 }, ShouldExpectSafeBrowsingResult::No, ShouldExpectAppBoundDomainResult::No);
5850
5851 if (m_policyClient)
5852 m_policyClient->decidePolicyForNewWindowAction(*this, *frame, navigationAction.get(), request, frameName, WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get());
5853 else
5854 m_navigationClient->decidePolicyForNavigationAction(*this, navigationAction.get(), WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get());
5855}
5856
5857void WebPageProxy::decidePolicyForResponse(FrameIdentifier frameID, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier,
5858 uint64_t navigationID, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, const String& downloadAttribute,
5859 bool wasAllowedByInjectedBundle, uint64_t listenerID, const UserData& userData)
5860{
5861 decidePolicyForResponseShared(m_process.copyRef(), m_webPageID, frameID, WTFMove(frameInfo), identifier, navigationID, response, request, canShowMIMEType, downloadAttribute, wasAllowedByInjectedBundle, listenerID, userData);
5862}
5863
5864void WebPageProxy::decidePolicyForResponseShared(Ref<WebProcessProxy>&& process, PageIdentifier webPageID, FrameIdentifier frameID, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier, uint64_t navigationID, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, const String& downloadAttribute, bool wasAllowedByInjectedBundle, uint64_t listenerID, const UserData& userData)
5865{
5866 PageClientProtector protector(pageClient());
5867
5868 m_decidePolicyForResponseRequest = request;
5869
5870 WebFrameProxy* frame = process->webFrame(frameID);
5871 MESSAGE_CHECK(process, frame);
5872 MESSAGE_CHECK_URL(process, request.url());
5873 MESSAGE_CHECK_URL(process, response.url());
5874 RefPtr<API::Navigation> navigation = navigationID ? m_navigationState->navigation(navigationID) : nullptr;
5875 auto navigationResponse = API::NavigationResponse::create(API::FrameInfo::create(WTFMove(frameInfo), this).get(), request, response, canShowMIMEType, downloadAttribute);
5876
5877 Ref listener = frame->setUpPolicyListenerProxy([this, protectedThis = Ref { *this }, webPageID, frameID, identifier, listenerID, navigation = WTFMove(navigation),
5878 process, navigationResponse] (PolicyAction policyAction, API::WebsitePolicies*, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain) mutable {
5879 // FIXME: Assert the API::WebsitePolicies* is nullptr here once clients of WKFramePolicyListenerUseWithPolicies go away.
5880 RELEASE_ASSERT(processSwapRequestedByClient == ProcessSwapRequestedByClient::No);
5881 ASSERT_UNUSED(safeBrowsingWarning, !safeBrowsingWarning);
5882
5883 auto sender = PolicyDecisionSender::create(identifier, [webPageID, frameID, listenerID, process] (const auto& policyDecision) {
5884 process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, policyDecision
5885#if !ENABLE(CONTENT_FILTERING_IN_NETWORKING_PROCESS)
5886 , createNetworkExtensionsSandboxExtensions(process)
5887#endif
5888 ), webPageID);
5889 });
5890#if USE(QUICK_LOOK)
5891 if (process->captivePortalMode() == WebProcessProxy::CaptivePortalMode::Enabled && (MIMETypeRegistry::isPDFOrPostScriptMIMEType(navigationResponse->response().mimeType()) || PreviewConverter::supportsMIMEType(navigationResponse->response().mimeType())))
5892 policyAction = PolicyAction::Download;
5893#endif
5894 receivedPolicyDecision(policyAction, navigation.get(), nullptr, WTFMove(navigationResponse), WTFMove(sender));
5895 }, ShouldExpectSafeBrowsingResult::No, ShouldExpectAppBoundDomainResult::No);
5896
5897 if (wasAllowedByInjectedBundle) {
5898 listener->use();
5899 return;
5900 }
5901
5902 if (m_policyClient)
5903 m_policyClient->decidePolicyForResponse(*this, *frame, response, request, canShowMIMEType, WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
5904 else
5905 m_navigationClient->decidePolicyForNavigationResponse(*this, WTFMove(navigationResponse), WTFMove(listener), process->transformHandlesToObjects(userData.object()).get());
5906}
5907
5908void WebPageProxy::triggerBrowsingContextGroupSwitchForNavigation(uint64_t navigationID, BrowsingContextGroupSwitchDecision browsingContextGroupSwitchDecision, const RegistrableDomain& responseDomain, NetworkResourceLoadIdentifier existingNetworkResourceLoadIdentifierToResume, CompletionHandler<void(bool success)>&& completionHandler)
5909{
5910 ASSERT(browsingContextGroupSwitchDecision != BrowsingContextGroupSwitchDecision::StayInGroup);
5911 RefPtr<API::Navigation> navigation = navigationID ? m_navigationState->navigation(navigationID) : nullptr;
5912 WEBPAGEPROXY_RELEASE_LOG(ProcessSwapping, "triggerBrowsingContextGroupSwitchForNavigation: Process-swapping due to Cross-Origin-Opener-Policy, newProcessIsCrossOriginIsolated=%d, navigation=%p existingNetworkResourceLoadIdentifierToResume=%" PRIu64, browsingContextGroupSwitchDecision == BrowsingContextGroupSwitchDecision::NewIsolatedGroup, navigation.get(), existingNetworkResourceLoadIdentifierToResume.toUInt64());
5913 if (!navigation)
5914 return completionHandler(false);
5915
5916 RefPtr<WebProcessProxy> processForNavigation;
5917 if (browsingContextGroupSwitchDecision == BrowsingContextGroupSwitchDecision::NewIsolatedGroup)
5918 processForNavigation = m_process->processPool().createNewWebProcess(&websiteDataStore(), m_process->captivePortalMode(), WebProcessProxy::IsPrewarmed::No, CrossOriginMode::Isolated);
5919 else
5920 processForNavigation = m_process->processPool().processForRegistrableDomain(websiteDataStore(), responseDomain, m_process->captivePortalMode());
5921
5922 // Tell committed process to stop loading since we're going to do the provisional load in a provisional page now.
5923 if (!m_provisionalPage)
5924 send(Messages::WebPage::StopLoadingDueToProcessSwap());
5925 continueNavigationInNewProcess(*navigation, nullptr, processForNavigation.releaseNonNull(), ProcessSwapRequestedByClient::No, ShouldTreatAsContinuingLoad::YesAfterProvisionalLoadStarted, existingNetworkResourceLoadIdentifierToResume);
5926 completionHandler(true);
5927}
5928
5929void WebPageProxy::unableToImplementPolicy(FrameIdentifier frameID, const ResourceError& error, const UserData& userData)
5930{
5931 PageClientProtector protector(pageClient());
5932
5933 WebFrameProxy* frame = m_process->webFrame(frameID);
5934 MESSAGE_CHECK(m_process, frame);
5935
5936 if (!m_policyClient)
5937 return;
5938 m_policyClient->unableToImplementPolicy(*this, *frame, error, m_process->transformHandlesToObjects(userData.object()).get());
5939}
5940
5941// FormClient
5942
5943void WebPageProxy::willSubmitForm(FrameIdentifier frameID, FrameIdentifier sourceFrameID, const Vector<std::pair<String, String>>& textFieldValues, FormSubmitListenerIdentifier listenerID, const UserData& userData)
5944{
5945 WebFrameProxy* frame = m_process->webFrame(frameID);
5946 MESSAGE_CHECK(m_process, frame);
5947
5948 WebFrameProxy* sourceFrame = m_process->webFrame(sourceFrameID);
5949 MESSAGE_CHECK(m_process, sourceFrame);
5950
5951 for (auto& pair : textFieldValues)
5952 MESSAGE_CHECK(m_process, API::Dictionary::MapType::isValidKey(pair.first));
5953
5954 m_formClient->willSubmitForm(*this, *frame, *sourceFrame, textFieldValues, m_process->transformHandlesToObjects(userData.object()).get(), [this, protectedThis = Ref { *this }, frameID, listenerID]() {
5955 send(Messages::WebPage::ContinueWillSubmitForm(frameID, listenerID));
5956 });
5957}
5958
5959#if ENABLE(CONTENT_EXTENSIONS)
5960void WebPageProxy::contentRuleListNotification(URL&& url, ContentRuleListResults&& results)
5961{
5962 m_navigationClient->contentRuleListNotification(*this, WTFMove(url), WTFMove(results));
5963}
5964#endif
5965
5966void WebPageProxy::didNavigateWithNavigationData(const WebNavigationDataStore& store, FrameIdentifier frameID)
5967{
5968 didNavigateWithNavigationDataShared(m_process.copyRef(), store, frameID);
5969}
5970
5971void WebPageProxy::didNavigateWithNavigationDataShared(Ref<WebProcessProxy>&& process, const WebNavigationDataStore& store, FrameIdentifier frameID)
5972{
5973 WEBPAGEPROXY_RELEASE_LOG(Loading, "didNavigateWithNavigationDataShared:");
5974
5975 PageClientProtector protector(pageClient());
5976
5977 WebFrameProxy* frame = process->webFrame(frameID);
5978 MESSAGE_CHECK(process, frame);
5979 MESSAGE_CHECK(process, frame->page() == this);
5980
5981 if (frame->isMainFrame())
5982 m_historyClient->didNavigateWithNavigationData(*this, store);
5983 process->processPool().historyClient().didNavigateWithNavigationData(process->processPool(), *this, store, *frame);
5984}
5985
5986void WebPageProxy::didPerformClientRedirect(const String& sourceURLString, const String& destinationURLString, FrameIdentifier frameID)
5987{
5988 didPerformClientRedirectShared(m_process.copyRef(), sourceURLString, destinationURLString, frameID);
5989}
5990
5991void WebPageProxy::didPerformClientRedirectShared(Ref<WebProcessProxy>&& process, const String& sourceURLString, const String& destinationURLString, FrameIdentifier frameID)
5992{
5993 PageClientProtector protector(pageClient());
5994
5995 if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
5996 return;
5997
5998 WebFrameProxy* frame = process->webFrame(frameID);
5999 MESSAGE_CHECK(process, frame);
6000 MESSAGE_CHECK(process, frame->page() == this);
6001 MESSAGE_CHECK_URL(process, sourceURLString);
6002 MESSAGE_CHECK_URL(process, destinationURLString);
6003
6004 WEBPAGEPROXY_RELEASE_LOG(Loading, "didPerformClientRedirectShared: frameID=%" PRIu64 ", isMainFrame=%d", frameID.toUInt64(), frame->isMainFrame());
6005
6006 if (frame->isMainFrame()) {
6007 m_historyClient->didPerformClientRedirect(*this, sourceURLString, destinationURLString);
6008 m_navigationClient->didPerformClientRedirect(*this, sourceURLString, destinationURLString);
6009 }
6010 process->processPool().historyClient().didPerformClientRedirect(process->processPool(), *this, sourceURLString, destinationURLString, *frame);
6011}
6012
6013void WebPageProxy::didPerformServerRedirect(const String& sourceURLString, const String& destinationURLString, FrameIdentifier frameID)
6014{
6015 didPerformServerRedirectShared(m_process.copyRef(), sourceURLString, destinationURLString, frameID);
6016}
6017
6018void WebPageProxy::didPerformServerRedirectShared(Ref<WebProcessProxy>&& process, const String& sourceURLString, const String& destinationURLString, FrameIdentifier frameID)
6019{
6020 WEBPAGEPROXY_RELEASE_LOG(Loading, "didPerformServerRedirect:");
6021
6022 PageClientProtector protector(pageClient());
6023
6024 if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
6025 return;
6026
6027 WebFrameProxy* frame = process->webFrame(frameID);
6028 MESSAGE_CHECK(process, frame);
6029 MESSAGE_CHECK(process, frame->page() == this);
6030
6031 MESSAGE_CHECK_URL(process, sourceURLString);
6032 MESSAGE_CHECK_URL(process, destinationURLString);
6033
6034 if (frame->isMainFrame())
6035 m_historyClient->didPerformServerRedirect(*this, sourceURLString, destinationURLString);
6036 process->processPool().historyClient().didPerformServerRedirect(process->processPool(), *this, sourceURLString, destinationURLString, *frame);
6037}
6038
6039void WebPageProxy::didUpdateHistoryTitle(const String& title, const String& url, FrameIdentifier frameID)
6040{
6041 PageClientProtector protector(pageClient());
6042
6043 WebFrameProxy* frame = m_process->webFrame(frameID);
6044 MESSAGE_CHECK(m_process, frame);
6045 MESSAGE_CHECK(m_process, frame->page() == this);
6046
6047 MESSAGE_CHECK_URL(m_process, url);
6048
6049 if (frame->isMainFrame())
6050 m_historyClient->didUpdateHistoryTitle(*this, title, url);
6051 process().processPool().historyClient().didUpdateHistoryTitle(process().processPool(), *this, title, url, *frame);
6052}
6053
6054// UIClient
6055
6056using NewPageCallback = CompletionHandler<void(RefPtr<WebPageProxy>&&)>;
6057using UIClientCallback = Function<void(Ref<API::NavigationAction>&&, NewPageCallback&&)>;
6058static void trySOAuthorization(Ref<API::NavigationAction>&& navigationAction, WebPageProxy& page, NewPageCallback&& newPageCallback, UIClientCallback&& uiClientCallback)
6059{
6060#if HAVE(APP_SSO)
6061 if (page.preferences().isExtensibleSSOEnabled()) {
6062 page.websiteDataStore().soAuthorizationCoordinator(page).tryAuthorize(WTFMove(navigationAction), page, WTFMove(newPageCallback), WTFMove(uiClientCallback));
6063 return;
6064 }
6065#endif
6066 uiClientCallback(WTFMove(navigationAction), WTFMove(newPageCallback));
6067}
6068
6069void WebPageProxy::createNewPage(FrameInfoData&& originatingFrameInfoData, WebPageProxyIdentifier originatingPageID, ResourceRequest&& request, WindowFeatures&& windowFeatures, NavigationActionData&& navigationActionData, Messages::WebPageProxy::CreateNewPage::DelayedReply&& reply)
6070{
6071 MESSAGE_CHECK(m_process, originatingFrameInfoData.frameID);
6072 MESSAGE_CHECK(m_process, m_process->webFrame(*originatingFrameInfoData.frameID));
6073
6074 auto* originatingPage = m_process->webPage(originatingPageID);
6075 auto originatingFrameInfo = API::FrameInfo::create(WTFMove(originatingFrameInfoData), originatingPage);
6076 auto mainFrameURL = m_mainFrame ? m_mainFrame->url() : URL();
6077
6078 std::optional<bool> openerAppInitiatedState;
6079 if (originatingPage)
6080 openerAppInitiatedState = originatingPage->lastNavigationWasAppInitiated();
6081
6082 auto completionHandler = [this, protectedThis = Ref { *this }, mainFrameURL, request, reply = WTFMove(reply), privateClickMeasurement = navigationActionData.privateClickMeasurement, openerAppInitiatedState = WTFMove(openerAppInitiatedState)] (RefPtr<WebPageProxy> newPage) mutable {
6083 if (!newPage) {
6084 reply(std::nullopt, std::nullopt);
6085 return;
6086 }
6087
6088 newPage->setOpenedByDOM();
6089
6090 if (openerAppInitiatedState)
6091 newPage->m_lastNavigationWasAppInitiated = *openerAppInitiatedState;
6092
6093 reply(newPage->webPageID(), newPage->creationParameters(m_process, *newPage->drawingArea()));
6094
6095 newPage->m_shouldSuppressAppLinksInNextNavigationPolicyDecision = mainFrameURL.host() == request.url().host();
6096
6097 if (privateClickMeasurement)
6098 newPage->m_privateClickMeasurement = {{ WTFMove(*privateClickMeasurement), { }, { }}};
6099#if HAVE(APP_SSO)
6100 newPage->m_shouldSuppressSOAuthorizationInNextNavigationPolicyDecision = true;
6101#endif
6102 };
6103
6104 RefPtr<API::UserInitiatedAction> userInitiatedActivity;
6105
6106#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
6107 // WebKit cancels the original gesture to open the BBC radio player so
6108 // we can call the Storage Access API first. When we re-initiate the open,
6109 // we should make sure the client knows that this was user initiated so it
6110 // does not block the popup.
6111 if (request.url().string() == Quirks::staticRadioPlayerURLString())
6112 userInitiatedActivity = API::UserInitiatedAction::create();
6113 else
6114#endif
6115 userInitiatedActivity = m_process->userInitiatedActivity(navigationActionData.userGestureTokenIdentifier);
6116
6117 bool shouldOpenAppLinks = originatingFrameInfo->request().url().host() != request.url().host();
6118 auto navigationAction = API::NavigationAction::create(WTFMove(navigationActionData), originatingFrameInfo.ptr(), nullptr, std::nullopt, WTFMove(request), URL(), shouldOpenAppLinks, WTFMove(userInitiatedActivity));
6119
6120 trySOAuthorization(WTFMove(navigationAction), *this, WTFMove(completionHandler), [this, protectedThis = Ref { *this }, windowFeatures = WTFMove(windowFeatures)] (Ref<API::NavigationAction>&& navigationAction, CompletionHandler<void(RefPtr<WebPageProxy>&&)>&& completionHandler) mutable {
6121 m_uiClient->createNewPage(*this, WTFMove(windowFeatures), WTFMove(navigationAction), WTFMove(completionHandler));
6122 });
6123}
6124
6125void WebPageProxy::showPage()
6126{
6127 m_uiClient->showPage(this);
6128}
6129
6130void WebPageProxy::exitFullscreenImmediately()
6131{
6132#if ENABLE(FULLSCREEN_API)
6133 if (fullScreenManager())
6134 fullScreenManager()->close();
6135#endif
6136
6137#if ENABLE(VIDEO_PRESENTATION_MODE)
6138 if (videoFullscreenManager())
6139 videoFullscreenManager()->requestHideAndExitFullscreen();
6140#endif
6141}
6142
6143void WebPageProxy::fullscreenMayReturnToInline()
6144{
6145 m_uiClient->fullscreenMayReturnToInline(this);
6146}
6147
6148#if ENABLE(VIDEO_PRESENTATION_MODE)
6149
6150void WebPageProxy::didEnterFullscreen(PlaybackSessionContextIdentifier identifier)
6151{
6152 m_uiClient->didEnterFullscreen(this);
6153
6154 m_currentFullscreenVideoSessionIdentifier = identifier;
6155 updateFullscreenVideoTextRecognition();
6156}
6157
6158void WebPageProxy::didExitFullscreen(PlaybackSessionContextIdentifier identifier)
6159{
6160 m_uiClient->didExitFullscreen(this);
6161
6162 if (m_currentFullscreenVideoSessionIdentifier == identifier) {
6163 m_currentFullscreenVideoSessionIdentifier = std::nullopt;
6164 updateFullscreenVideoTextRecognition();
6165 }
6166}
6167
6168#else
6169
6170void WebPageProxy::didEnterFullscreen()
6171{
6172 m_uiClient->didEnterFullscreen(this);
6173}
6174
6175void WebPageProxy::didExitFullscreen()
6176{
6177 m_uiClient->didExitFullscreen(this);
6178}
6179
6180#endif
6181
6182void WebPageProxy::closePage()
6183{
6184 if (isClosed())
6185 return;
6186
6187 WEBPAGEPROXY_RELEASE_LOG(Process, "closePage:");
6188 pageClient().clearAllEditCommands();
6189 m_uiClient->close(this);
6190}
6191
6192void WebPageProxy::runModalJavaScriptDialog(RefPtr<WebFrameProxy>&& frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void(WebPageProxy&, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&&)>&& runDialogCallback)
6193{
6194 pageClient().runModalJavaScriptDialog([weakThis = WeakPtr { *this }, frameInfo = WTFMove(frameInfo), frame = WTFMove(frame), message, runDialogCallback = WTFMove(runDialogCallback)]() mutable {
6195 RefPtr protectedThis { weakThis.get() };
6196 if (!protectedThis)
6197 return;
6198
6199 protectedThis->m_isRunningModalJavaScriptDialog = true;
6200 runDialogCallback(*protectedThis, frame.get(), WTFMove(frameInfo), message, [weakThis = WTFMove(weakThis)]() mutable {
6201 if (RefPtr protectedThis = weakThis.get())
6202 protectedThis->m_isRunningModalJavaScriptDialog = false;
6203 });
6204 });
6205}
6206
6207void WebPageProxy::runJavaScriptAlert(FrameIdentifier frameID, FrameInfoData&& frameInfo, const String& message, Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply&& reply)
6208{
6209 RefPtr frame = m_process->webFrame(frameID);
6210 MESSAGE_CHECK(m_process, frame);
6211
6212 exitFullscreenImmediately();
6213
6214 // Since runJavaScriptAlert() can spin a nested run loop we need to turn off the responsiveness timer.
6215 m_process->stopResponsivenessTimer();
6216
6217 if (m_controlledByAutomation) {
6218 if (auto* automationSession = process().processPool().automationSession())
6219 automationSession->willShowJavaScriptDialog(*this);
6220 }
6221
6222 runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&& completion) mutable {
6223 page.m_uiClient->runJavaScriptAlert(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)]() mutable {
6224 reply();
6225 completion();
6226 });
6227 });
6228}
6229
6230void WebPageProxy::runJavaScriptConfirm(FrameIdentifier frameID, FrameInfoData&& frameInfo, const String& message, Messages::WebPageProxy::RunJavaScriptConfirm::DelayedReply&& reply)
6231{
6232 RefPtr frame = m_process->webFrame(frameID);
6233 MESSAGE_CHECK(m_process, frame);
6234
6235 exitFullscreenImmediately();
6236
6237 // Since runJavaScriptConfirm() can spin a nested run loop we need to turn off the responsiveness timer.
6238 m_process->stopResponsivenessTimer();
6239
6240 if (m_controlledByAutomation) {
6241 if (auto* automationSession = process().processPool().automationSession())
6242 automationSession->willShowJavaScriptDialog(*this);
6243 }
6244
6245 runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&& completion) mutable {
6246 page.m_uiClient->runJavaScriptConfirm(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](bool result) mutable {
6247 reply(result);
6248 completion();
6249 });
6250 });
6251}
6252
6253void WebPageProxy::runJavaScriptPrompt(FrameIdentifier frameID, FrameInfoData&& frameInfo, const String& message, const String& defaultValue, Messages::WebPageProxy::RunJavaScriptPrompt::DelayedReply&& reply)
6254{
6255 RefPtr frame = m_process->webFrame(frameID);
6256 MESSAGE_CHECK(m_process, frame);
6257
6258 exitFullscreenImmediately();
6259
6260 // Since runJavaScriptPrompt() can spin a nested run loop we need to turn off the responsiveness timer.
6261 m_process->stopResponsivenessTimer();
6262
6263 if (m_controlledByAutomation) {
6264 if (auto* automationSession = process().processPool().automationSession())
6265 automationSession->willShowJavaScriptDialog(*this);
6266 }
6267
6268 runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply), defaultValue](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&& completion) mutable {
6269 page.m_uiClient->runJavaScriptPrompt(page, message, defaultValue, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](auto& result) mutable {
6270 reply(result);
6271 completion();
6272 });
6273 });
6274}
6275
6276void WebPageProxy::setStatusText(const String& text)
6277{
6278 m_uiClient->setStatusText(this, text);
6279}
6280
6281void WebPageProxy::mouseDidMoveOverElement(WebHitTestResultData&& hitTestResultData, uint32_t opaqueModifiers, UserData&& userData)
6282{
6283 m_lastMouseMoveHitTestResult = API::HitTestResult::create(hitTestResultData);
6284 auto modifiers = OptionSet<WebEvent::Modifier>::fromRaw(opaqueModifiers);
6285 m_uiClient->mouseDidMoveOverElement(*this, hitTestResultData, modifiers, m_process->transformHandlesToObjects(userData.object()).get());
6286 setToolTip(hitTestResultData.toolTipText);
6287}
6288
6289#if ENABLE(WEBGL)
6290void WebPageProxy::webGLPolicyForURL(URL&& url, Messages::WebPageProxy::WebGLPolicyForURL::DelayedReply&& reply)
6291{
6292 m_navigationClient->webGLLoadPolicy(*this, url, WTFMove(reply));
6293}
6294
6295void WebPageProxy::resolveWebGLPolicyForURL(URL&& url, Messages::WebPageProxy::ResolveWebGLPolicyForURL::DelayedReply&& reply)
6296{
6297 m_navigationClient->resolveWebGLLoadPolicy(*this, url, WTFMove(reply));
6298}
6299#endif // ENABLE(WEBGL)
6300
6301void WebPageProxy::setToolbarsAreVisible(bool toolbarsAreVisible)
6302{
6303 m_uiClient->setToolbarsAreVisible(*this, toolbarsAreVisible);
6304}
6305
6306void WebPageProxy::getToolbarsAreVisible(Messages::WebPageProxy::GetToolbarsAreVisible::DelayedReply&& reply)
6307{
6308 m_uiClient->toolbarsAreVisible(*this, WTFMove(reply));
6309}
6310
6311void WebPageProxy::setMenuBarIsVisible(bool menuBarIsVisible)
6312{
6313 m_uiClient->setMenuBarIsVisible(*this, menuBarIsVisible);
6314}
6315
6316void WebPageProxy::getMenuBarIsVisible(Messages::WebPageProxy::GetMenuBarIsVisible::DelayedReply&& reply)
6317{
6318 m_uiClient->menuBarIsVisible(*this, WTFMove(reply));
6319}
6320
6321void WebPageProxy::setStatusBarIsVisible(bool statusBarIsVisible)
6322{
6323 m_uiClient->setStatusBarIsVisible(*this, statusBarIsVisible);
6324}
6325
6326void WebPageProxy::getStatusBarIsVisible(Messages::WebPageProxy::GetStatusBarIsVisible::DelayedReply&& reply)
6327{
6328 m_uiClient->statusBarIsVisible(*this, WTFMove(reply));
6329}
6330
6331void WebPageProxy::setIsResizable(bool isResizable)
6332{
6333 m_uiClient->setIsResizable(*this, isResizable);
6334}
6335
6336void WebPageProxy::setWindowFrame(const FloatRect& newWindowFrame)
6337{
6338 m_uiClient->setWindowFrame(*this, pageClient().convertToDeviceSpace(newWindowFrame));
6339}
6340
6341void WebPageProxy::getWindowFrame(Messages::WebPageProxy::GetWindowFrame::DelayedReply&& reply)
6342{
6343 m_uiClient->windowFrame(*this, [this, protectedThis = Ref { *this }, reply = WTFMove(reply)] (FloatRect frame) mutable {
6344 reply(pageClient().convertToUserSpace(frame));
6345 });
6346}
6347
6348void WebPageProxy::getWindowFrameWithCallback(Function<void(FloatRect)>&& completionHandler)
6349{
6350 m_uiClient->windowFrame(*this, [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)] (FloatRect frame) {
6351 completionHandler(pageClient().convertToUserSpace(frame));
6352 });
6353}
6354
6355void WebPageProxy::screenToRootView(const IntPoint& screenPoint, Messages::WebPageProxy::ScreenToRootView::DelayedReply&& reply)
6356{
6357 reply(pageClient().screenToRootView(screenPoint));
6358}
6359
6360void WebPageProxy::rootViewToScreen(const IntRect& viewRect, Messages::WebPageProxy::RootViewToScreen::DelayedReply&& reply)
6361{
6362 reply(pageClient().rootViewToScreen(viewRect));
6363}
6364
6365IntRect WebPageProxy::syncRootViewToScreen(const IntRect& viewRect)
6366{
6367 return pageClient().rootViewToScreen(viewRect);
6368}
6369
6370void WebPageProxy::accessibilityScreenToRootView(const IntPoint& screenPoint, CompletionHandler<void(IntPoint)>&& completionHandler)
6371{
6372 completionHandler(pageClient().accessibilityScreenToRootView(screenPoint));
6373}
6374
6375void WebPageProxy::rootViewToAccessibilityScreen(const IntRect& viewRect, CompletionHandler<void(IntRect)>&& completionHandler)
6376{
6377 completionHandler(pageClient().rootViewToAccessibilityScreen(viewRect));
6378}
6379
6380void WebPageProxy::runBeforeUnloadConfirmPanel(FrameIdentifier frameID, FrameInfoData&& frameInfo, const String& message, Messages::WebPageProxy::RunBeforeUnloadConfirmPanel::DelayedReply&& reply)
6381{
6382 WebFrameProxy* frame = m_process->webFrame(frameID);
6383 MESSAGE_CHECK(m_process, frame);
6384
6385 // Per §18 User Prompts in the WebDriver spec, "User prompts that are spawned from beforeunload
6386 // event handlers, are dismissed implicitly upon navigation or close window, regardless of the
6387 // defined user prompt handler." So, always allow the unload to proceed if the page is being automated.
6388 if (m_controlledByAutomation) {
6389 if (!!process().processPool().automationSession()) {
6390 reply(true);
6391 return;
6392 }
6393 }
6394
6395 // Since runBeforeUnloadConfirmPanel() can spin a nested run loop we need to turn off the responsiveness timer and the tryClose timer.
6396 m_process->stopResponsivenessTimer();
6397 bool shouldResumeTimerAfterPrompt = m_tryCloseTimeoutTimer.isActive();
6398 m_tryCloseTimeoutTimer.stop();
6399 m_uiClient->runBeforeUnloadConfirmPanel(*this, message, frame, WTFMove(frameInfo),
6400 [this, weakThis = WeakPtr { *this }, completionHandler = WTFMove(reply), shouldResumeTimerAfterPrompt](bool shouldClose) mutable {
6401 if (weakThis && shouldResumeTimerAfterPrompt)
6402 m_tryCloseTimeoutTimer.startOneShot(tryCloseTimeoutDelay);
6403 completionHandler(shouldClose);
6404 });
6405}
6406
6407void WebPageProxy::didChangeViewportProperties(const ViewportAttributes& attr)
6408{
6409 pageClient().didChangeViewportProperties(attr);
6410}
6411
6412void WebPageProxy::pageDidScroll(const WebCore::IntPoint& scrollPosition)
6413{
6414 m_uiClient->pageDidScroll(this);
6415
6416 pageClient().pageDidScroll(scrollPosition);
6417
6418#if PLATFORM(IOS_FAMILY)
6419 // Do not hide the validation message if the scrolling was caused by the keyboard showing up.
6420 if (m_isKeyboardAnimatingIn)
6421 return;
6422#endif
6423
6424#if !PLATFORM(IOS_FAMILY)
6425 closeOverlayedViews();
6426#endif
6427}
6428
6429void WebPageProxy::setHasActiveAnimatedScrolls(bool isRunning)
6430{
6431 m_hasActiveAnimatedScroll = isRunning;
6432#if HAVE(CVDISPLAYLINK)
6433 updateDisplayLinkFrequency();
6434#endif
6435}
6436
6437void WebPageProxy::runOpenPanel(FrameIdentifier frameID, FrameInfoData&& frameInfo, const FileChooserSettings& settings)
6438{
6439 if (m_openPanelResultListener) {
6440 m_openPanelResultListener->invalidate();
6441 m_openPanelResultListener = nullptr;
6442 }
6443
6444 WebFrameProxy* frame = m_process->webFrame(frameID);
6445 MESSAGE_CHECK(m_process, frame);
6446
6447 Ref<API::OpenPanelParameters> parameters = API::OpenPanelParameters::create(settings);
6448 m_openPanelResultListener = WebOpenPanelResultListenerProxy::create(this);
6449
6450 if (m_controlledByAutomation) {
6451 if (auto* automationSession = process().processPool().automationSession())
6452 automationSession->handleRunOpenPanel(*this, *frame, parameters.get(), *m_openPanelResultListener);
6453
6454 // Don't show a file chooser, since automation will be unable to interact with it.
6455 return;
6456 }
6457
6458 // Since runOpenPanel() can spin a nested run loop we need to turn off the responsiveness timer.
6459 m_process->stopResponsivenessTimer();
6460
6461 const auto frameInfoForPageClient = frameInfo;
6462
6463 if (!m_uiClient->runOpenPanel(*this, frame, WTFMove(frameInfo), parameters.ptr(), m_openPanelResultListener.get())) {
6464 if (!pageClient().handleRunOpenPanel(this, frame, frameInfoForPageClient, parameters.ptr(), m_openPanelResultListener.get()))
6465 didCancelForOpenPanel();
6466 }
6467}
6468
6469void WebPageProxy::showShareSheet(const ShareDataWithParsedURL& shareData, CompletionHandler<void(bool)>&& completionHandler)
6470{
6471 MESSAGE_CHECK(m_process, !shareData.url || shareData.url->protocolIsInHTTPFamily() || shareData.url->protocolIsData());
6472 MESSAGE_CHECK(m_process, shareData.files.isEmpty() || m_preferences->webShareFileAPIEnabled());
6473 pageClient().showShareSheet(shareData, WTFMove(completionHandler));
6474}
6475
6476void WebPageProxy::showContactPicker(const WebCore::ContactsRequestData& requestData, CompletionHandler<void(std::optional<Vector<WebCore::ContactInfo>>&&)>&& completionHandler)
6477{
6478 MESSAGE_CHECK(m_process, m_preferences->contactPickerAPIEnabled());
6479 pageClient().showContactPicker(requestData, WTFMove(completionHandler));
6480}
6481
6482void WebPageProxy::printFrame(FrameIdentifier frameID, const String& title, const WebCore::FloatSize& pdfFirstPageSize, CompletionHandler<void()>&& completionHandler)
6483{
6484 ASSERT(!m_isPerformingDOMPrintOperation);
6485 m_isPerformingDOMPrintOperation = true;
6486
6487 WebFrameProxy* frame = m_process->webFrame(frameID);
6488 MESSAGE_CHECK(m_process, frame);
6489
6490 frame->didChangeTitle(title);
6491
6492 m_uiClient->printFrame(*this, *frame, pdfFirstPageSize, [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)] () mutable {
6493 endPrinting(); // Send a message synchronously while m_isPerformingDOMPrintOperation is still true.
6494 m_isPerformingDOMPrintOperation = false;
6495 completionHandler();
6496 });
6497}
6498
6499void WebPageProxy::setMediaVolume(float volume)
6500{
6501 if (volume == m_mediaVolume)
6502 return;
6503
6504 m_mediaVolume = volume;
6505
6506 if (!hasRunningProcess())
6507 return;
6508
6509 send(Messages::WebPage::SetMediaVolume(volume));
6510}
6511
6512void WebPageProxy::setMuted(WebCore::MediaProducerMutedStateFlags state, CompletionHandler<void()>&& completionHandler)
6513{
6514 if (!isAllowedToChangeMuteState())
6515 state.add(WebCore::MediaProducer::MediaStreamCaptureIsMuted);
6516
6517 m_mutedState = state;
6518
6519 if (!hasRunningProcess())
6520 return completionHandler();
6521
6522#if ENABLE(MEDIA_STREAM)
6523 bool hasMutedCaptureStreams = m_mediaState.containsAny(WebCore::MediaProducer::MutedCaptureMask);
6524 if (hasMutedCaptureStreams && !(state.containsAny(WebCore::MediaProducer::MediaStreamCaptureIsMuted)))
6525 WebProcessProxy::muteCaptureInPagesExcept(m_webPageID);
6526#endif
6527
6528 m_process->pageMutedStateChanged(m_webPageID, state);
6529
6530 sendWithAsyncReply(Messages::WebPage::SetMuted(state), WTFMove(completionHandler));
6531 activityStateDidChange({ ActivityState::IsAudible, ActivityState::IsCapturingMedia });
6532}
6533
6534void WebPageProxy::setMediaCaptureEnabled(bool enabled)
6535{
6536 m_mediaCaptureEnabled = enabled;
6537
6538 if (!hasRunningProcess())
6539 return;
6540
6541#if ENABLE(MEDIA_STREAM)
6542 UserMediaProcessManager::singleton().setCaptureEnabled(enabled);
6543#endif
6544}
6545
6546void WebPageProxy::stopMediaCapture(MediaProducerMediaCaptureKind kind, CompletionHandler<void()>&& completionHandler)
6547{
6548 if (!hasRunningProcess())
6549 return completionHandler();
6550
6551#if ENABLE(MEDIA_STREAM)
6552 if (m_userMediaPermissionRequestManager)
6553 m_userMediaPermissionRequestManager->resetAccess();
6554 sendWithAsyncReply(Messages::WebPage::StopMediaCapture(kind), WTFMove(completionHandler));
6555#endif
6556}
6557
6558void WebPageProxy::requestMediaPlaybackState(CompletionHandler<void(MediaPlaybackState)>&& completionHandler)
6559{
6560 if (!hasRunningProcess()) {
6561 completionHandler({ });
6562 return;
6563 }
6564
6565 sendWithAsyncReply(Messages::WebPage::RequestMediaPlaybackState(), WTFMove(completionHandler));
6566}
6567
6568void WebPageProxy::pauseAllMediaPlayback(CompletionHandler<void()>&& completionHandler)
6569{
6570 if (!hasRunningProcess()) {
6571 completionHandler();
6572 return;
6573 }
6574
6575 sendWithAsyncReply(Messages::WebPage::PauseAllMediaPlayback(), WTFMove(completionHandler));
6576}
6577
6578void WebPageProxy::suspendAllMediaPlayback(CompletionHandler<void()>&& completionHandler)
6579{
6580 m_suspendMediaPlaybackCounter++;
6581 if (m_mediaPlaybackIsSuspended) {
6582 completionHandler();
6583 return;
6584 }
6585 m_mediaPlaybackIsSuspended = true;
6586
6587 if (!hasRunningProcess()) {
6588 completionHandler();
6589 return;
6590 }
6591
6592 sendWithAsyncReply(Messages::WebPage::SuspendAllMediaPlayback(), WTFMove(completionHandler));
6593}
6594
6595void WebPageProxy::resumeAllMediaPlayback(CompletionHandler<void()>&& completionHandler)
6596{
6597 if (m_suspendMediaPlaybackCounter > 0)
6598 m_suspendMediaPlaybackCounter--;
6599
6600 if (!m_mediaPlaybackIsSuspended || m_suspendMediaPlaybackCounter) {
6601 completionHandler();
6602 return;
6603 }
6604 m_mediaPlaybackIsSuspended = false;
6605
6606 if (!hasRunningProcess()) {
6607 completionHandler();
6608 return;
6609 }
6610
6611 sendWithAsyncReply(Messages::WebPage::ResumeAllMediaPlayback(), WTFMove(completionHandler));
6612}
6613
6614void WebPageProxy::setMayStartMediaWhenInWindow(bool mayStartMedia)
6615{
6616 if (mayStartMedia == m_mayStartMediaWhenInWindow)
6617 return;
6618
6619 m_mayStartMediaWhenInWindow = mayStartMedia;
6620
6621 if (!hasRunningProcess())
6622 return;
6623
6624 send(Messages::WebPage::SetMayStartMediaWhenInWindow(mayStartMedia));
6625}
6626
6627void WebPageProxy::handleDownloadRequest(DownloadProxy& download)
6628{
6629 pageClient().handleDownloadRequest(download);
6630}
6631
6632void WebPageProxy::resumeDownload(const API::Data& resumeData, const String& path, CompletionHandler<void(DownloadProxy*)>&& completionHandler)
6633{
6634 auto& download = process().processPool().resumeDownload(websiteDataStore(), this, resumeData, path, CallDownloadDidStart::Yes);
6635 download.setDestinationFilename(path);
6636 download.setDidStartCallback(WTFMove(completionHandler));
6637}
6638
6639void WebPageProxy::downloadRequest(WebCore::ResourceRequest&& request, CompletionHandler<void(DownloadProxy*)>&& completionHandler)
6640{
6641 auto& download = process().processPool().download(websiteDataStore(), this, request, { });
6642 download.setDidStartCallback(WTFMove(completionHandler));
6643}
6644
6645void WebPageProxy::dataTaskWithRequest(WebCore::ResourceRequest&& request, CompletionHandler<void(API::DataTask&)>&& completionHandler)
6646{
6647 websiteDataStore().networkProcess().dataTaskWithRequest(*this, sessionID(), WTFMove(request), WTFMove(completionHandler));
6648}
6649
6650void WebPageProxy::didChangeContentSize(const IntSize& size)
6651{
6652 pageClient().didChangeContentSize(size);
6653}
6654
6655void WebPageProxy::didChangeIntrinsicContentSize(const IntSize& intrinsicContentSize)
6656{
6657#if USE(APPKIT)
6658 pageClient().intrinsicContentSizeDidChange(intrinsicContentSize);
6659#endif
6660}
6661
6662#if ENABLE(INPUT_TYPE_COLOR)
6663void WebPageProxy::showColorPicker(const WebCore::Color& initialColor, const IntRect& elementRect, Vector<WebCore::Color>&& suggestions)
6664{
6665 m_colorPicker = pageClient().createColorPicker(this, initialColor, elementRect, WTFMove(suggestions));
6666 m_colorPicker->showColorPicker(initialColor);
6667}
6668
6669void WebPageProxy::setColorPickerColor(const WebCore::Color& color)
6670{
6671 if (m_colorPicker)
6672 m_colorPicker->setSelectedColor(color);
6673}
6674
6675void WebPageProxy::endColorPicker()
6676{
6677 if (auto colorPicker = std::exchange(m_colorPicker, nullptr))
6678 colorPicker->endPicker();
6679}
6680
6681void WebPageProxy::didChooseColor(const WebCore::Color& color)
6682{
6683 if (!hasRunningProcess())
6684 return;
6685
6686 send(Messages::WebPage::DidChooseColor(color));
6687}
6688
6689void WebPageProxy::didEndColorPicker()
6690{
6691 if (std::exchange(m_colorPicker, nullptr)) {
6692 if (!hasRunningProcess())
6693 return;
6694
6695 send(Messages::WebPage::DidEndColorPicker());
6696 }
6697
6698}
6699#endif
6700
6701#if ENABLE(DATALIST_ELEMENT)
6702
6703void WebPageProxy::showDataListSuggestions(WebCore::DataListSuggestionInformation&& info)
6704{
6705 if (!m_dataListSuggestionsDropdown)
6706 m_dataListSuggestionsDropdown = pageClient().createDataListSuggestionsDropdown(*this);
6707
6708 m_dataListSuggestionsDropdown->show(WTFMove(info));
6709}
6710
6711void WebPageProxy::handleKeydownInDataList(const String& key)
6712{
6713 if (!m_dataListSuggestionsDropdown)
6714 return;
6715
6716 m_dataListSuggestionsDropdown->handleKeydownWithIdentifier(key);
6717}
6718
6719void WebPageProxy::endDataListSuggestions()
6720{
6721 if (m_dataListSuggestionsDropdown)
6722 m_dataListSuggestionsDropdown->close();
6723}
6724
6725void WebPageProxy::didCloseSuggestions()
6726{
6727 if (!m_dataListSuggestionsDropdown)
6728 return;
6729
6730 m_dataListSuggestionsDropdown = nullptr;
6731 send(Messages::WebPage::DidCloseSuggestions());
6732}
6733
6734void WebPageProxy::didSelectOption(const String& selectedOption)
6735{
6736 if (!hasRunningProcess())
6737 return;
6738
6739 send(Messages::WebPage::DidSelectDataListOption(selectedOption));
6740}
6741
6742#endif
6743
6744#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
6745
6746void WebPageProxy::showDateTimePicker(WebCore::DateTimeChooserParameters&& params)
6747{
6748 if (!m_dateTimePicker)
6749 m_dateTimePicker = pageClient().createDateTimePicker(*this);
6750
6751 m_dateTimePicker->showDateTimePicker(WTFMove(params));
6752}
6753
6754void WebPageProxy::endDateTimePicker()
6755{
6756 if (!m_dateTimePicker)
6757 return;
6758
6759 m_dateTimePicker->endPicker();
6760}
6761
6762void WebPageProxy::didChooseDate(StringView date)
6763{
6764 if (!hasRunningProcess())
6765 return;
6766
6767 send(Messages::WebPage::DidChooseDate(date.toString()));
6768}
6769
6770void WebPageProxy::didEndDateTimePicker()
6771{
6772 m_dateTimePicker = nullptr;
6773 if (!hasRunningProcess())
6774 return;
6775
6776 send(Messages::WebPage::DidEndDateTimePicker());
6777}
6778
6779#endif
6780
6781WebInspectorUIProxy* WebPageProxy::inspector() const
6782{
6783 if (isClosed())
6784 return nullptr;
6785 return m_inspector.get();
6786}
6787
6788void WebPageProxy::resourceLoadDidSendRequest(ResourceLoadInfo&& loadInfo, WebCore::ResourceRequest&& request)
6789{
6790 if (m_resourceLoadClient)
6791 m_resourceLoadClient->didSendRequest(WTFMove(loadInfo), WTFMove(request));
6792}
6793
6794void WebPageProxy::resourceLoadDidPerformHTTPRedirection(ResourceLoadInfo&& loadInfo, WebCore::ResourceResponse&& response, WebCore::ResourceRequest&& request)
6795{
6796 if (m_resourceLoadClient)
6797 m_resourceLoadClient->didPerformHTTPRedirection(WTFMove(loadInfo), WTFMove(response), WTFMove(request));
6798}
6799
6800void WebPageProxy::resourceLoadDidReceiveChallenge(ResourceLoadInfo&& loadInfo, WebCore::AuthenticationChallenge&& challenge)
6801{
6802 if (m_resourceLoadClient)
6803 m_resourceLoadClient->didReceiveChallenge(WTFMove(loadInfo), WTFMove(challenge));
6804}
6805
6806void WebPageProxy::resourceLoadDidReceiveResponse(ResourceLoadInfo&& loadInfo, WebCore::ResourceResponse&& response)
6807{
6808 if (m_resourceLoadClient)
6809 m_resourceLoadClient->didReceiveResponse(WTFMove(loadInfo), WTFMove(response));
6810}
6811
6812void WebPageProxy::resourceLoadDidCompleteWithError(ResourceLoadInfo&& loadInfo, WebCore::ResourceResponse&& response, WebCore::ResourceError&& error)
6813{
6814 if (m_resourceLoadClient)
6815 m_resourceLoadClient->didCompleteWithError(WTFMove(loadInfo), WTFMove(response), WTFMove(error));
6816}
6817
6818#if ENABLE(FULLSCREEN_API)
6819WebFullScreenManagerProxy* WebPageProxy::fullScreenManager()
6820{
6821 return m_fullScreenManager.get();
6822}
6823
6824void WebPageProxy::setFullscreenClient(std::unique_ptr<API::FullscreenClient>&& client)
6825{
6826 if (!client) {
6827 m_fullscreenClient = makeUnique<API::FullscreenClient>();
6828 return;
6829 }
6830
6831 m_fullscreenClient = WTFMove(client);
6832}
6833#endif
6834
6835#if ENABLE(VIDEO_PRESENTATION_MODE)
6836PlaybackSessionManagerProxy* WebPageProxy::playbackSessionManager()
6837{
6838 return m_playbackSessionManager.get();
6839}
6840
6841VideoFullscreenManagerProxy* WebPageProxy::videoFullscreenManager()
6842{
6843 return m_videoFullscreenManager.get();
6844}
6845
6846void WebPageProxy::setMockVideoPresentationModeEnabled(bool enabled)
6847{
6848 m_mockVideoPresentationModeEnabled = enabled;
6849 if (m_videoFullscreenManager)
6850 m_videoFullscreenManager->setMockVideoPresentationModeEnabled(enabled);
6851}
6852#endif
6853
6854#if PLATFORM(IOS_FAMILY)
6855bool WebPageProxy::allowsMediaDocumentInlinePlayback() const
6856{
6857 return m_allowsMediaDocumentInlinePlayback;
6858}
6859
6860void WebPageProxy::setAllowsMediaDocumentInlinePlayback(bool allows)
6861{
6862 if (m_allowsMediaDocumentInlinePlayback == allows)
6863 return;
6864 m_allowsMediaDocumentInlinePlayback = allows;
6865
6866 send(Messages::WebPage::SetAllowsMediaDocumentInlinePlayback(allows));
6867}
6868#endif
6869
6870void WebPageProxy::setHasHadSelectionChangesFromUserInteraction(bool hasHadUserSelectionChanges)
6871{
6872 m_hasHadSelectionChangesFromUserInteraction = hasHadUserSelectionChanges;
6873}
6874
6875#if HAVE(TOUCH_BAR)
6876
6877void WebPageProxy::setIsTouchBarUpdateSupressedForHiddenContentEditable(bool ignoreTouchBarUpdate)
6878{
6879 m_isTouchBarUpdateSupressedForHiddenContentEditable = ignoreTouchBarUpdate;
6880}
6881
6882void WebPageProxy::setIsNeverRichlyEditableForTouchBar(bool isNeverRichlyEditable)
6883{
6884 m_isNeverRichlyEditableForTouchBar = isNeverRichlyEditable;
6885}
6886
6887#endif
6888
6889void WebPageProxy::requestDOMPasteAccess(WebCore::DOMPasteAccessCategory pasteAccessCategory, const WebCore::IntRect& elementRect, const String& originIdentifier, CompletionHandler<void(WebCore::DOMPasteAccessResponse)>&& completionHandler)
6890{
6891 m_pageClient->requestDOMPasteAccess(pasteAccessCategory, elementRect, originIdentifier, WTFMove(completionHandler));
6892}
6893
6894// BackForwardList
6895
6896void WebPageProxy::backForwardAddItem(BackForwardListItemState&& itemState)
6897{
6898 auto item = WebBackForwardListItem::create(WTFMove(itemState), identifier());
6899 item->setResourceDirectoryURL(currentResourceDirectoryURL());
6900 m_backForwardList->addItem(WTFMove(item));
6901}
6902
6903void WebPageProxy::backForwardGoToItem(const BackForwardItemIdentifier& itemID, CompletionHandler<void(const WebBackForwardListCounts&)>&& completionHandler)
6904{
6905 // 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
6906 // value. Since the load is really going on in a new provisional process, we want to ignore such requests from the committed process.
6907 // Any real new load in the committed process would have cleared m_provisionalPage.
6908 if (m_provisionalPage)
6909 return completionHandler(m_backForwardList->counts());
6910
6911 backForwardGoToItemShared(m_process.copyRef(), itemID, WTFMove(completionHandler));
6912}
6913
6914void WebPageProxy::backForwardGoToItemShared(Ref<WebProcessProxy>&& process, const BackForwardItemIdentifier& itemID, CompletionHandler<void(const WebBackForwardListCounts&)>&& completionHandler)
6915{
6916 MESSAGE_CHECK_COMPLETION(m_process, !WebKit::isInspectorPage(*this), completionHandler(m_backForwardList->counts()));
6917
6918 auto* item = m_backForwardList->itemForID(itemID);
6919 if (!item)
6920 return completionHandler(m_backForwardList->counts());
6921
6922 m_backForwardList->goToItem(*item);
6923 completionHandler(m_backForwardList->counts());
6924}
6925
6926void WebPageProxy::backForwardItemAtIndex(int32_t index, CompletionHandler<void(std::optional<BackForwardItemIdentifier>&&)>&& completionHandler)
6927{
6928 if (auto* item = m_backForwardList->itemAtIndex(index))
6929 completionHandler(item->itemID());
6930 else
6931 completionHandler(std::nullopt);
6932}
6933
6934void WebPageProxy::backForwardListCounts(Messages::WebPageProxy::BackForwardListCountsDelayedReply&& completionHandler)
6935{
6936 completionHandler(m_backForwardList->counts());
6937}
6938
6939void WebPageProxy::compositionWasCanceled()
6940{
6941#if PLATFORM(COCOA)
6942 pageClient().notifyInputContextAboutDiscardedComposition();
6943#endif
6944}
6945
6946// Undo management
6947
6948void WebPageProxy::registerEditCommandForUndo(WebUndoStepID commandID, const String& label)
6949{
6950 registerEditCommand(WebEditCommandProxy::create(commandID, label, *this), UndoOrRedo::Undo);
6951}
6952
6953void WebPageProxy::registerInsertionUndoGrouping()
6954{
6955#if USE(INSERTION_UNDO_GROUPING)
6956 pageClient().registerInsertionUndoGrouping();
6957#endif
6958}
6959
6960void WebPageProxy::canUndoRedo(UndoOrRedo action, CompletionHandler<void(bool)>&& completionHandler)
6961{
6962 completionHandler(pageClient().canUndoRedo(action));
6963}
6964
6965void WebPageProxy::executeUndoRedo(UndoOrRedo action, CompletionHandler<void()>&& completionHandler)
6966{
6967 pageClient().executeUndoRedo(action);
6968 completionHandler();
6969}
6970
6971void WebPageProxy::clearAllEditCommands()
6972{
6973 pageClient().clearAllEditCommands();
6974}
6975
6976void WebPageProxy::didCountStringMatches(const String& string, uint32_t matchCount)
6977{
6978 m_findClient->didCountStringMatches(this, string, matchCount);
6979}
6980
6981void WebPageProxy::didGetImageForFindMatch(const ImageBufferBackend::Parameters& parameters, ShareableBitmap::Handle contentImageHandle, uint32_t matchIndex)
6982{
6983 auto image = WebImage::create(parameters, WTFMove(contentImageHandle));
6984 if (!image) {
6985 ASSERT_NOT_REACHED();
6986 return;
6987 }
6988 m_findMatchesClient->didGetImageForMatchResult(this, image.get(), matchIndex);
6989}
6990
6991void WebPageProxy::setTextIndicator(const TextIndicatorData& indicatorData, uint64_t lifetime)
6992{
6993 // FIXME: Make TextIndicatorWindow a platform-independent presentational thing ("TextIndicatorPresentation"?).
6994#if PLATFORM(COCOA)
6995 pageClient().setTextIndicator(TextIndicator::create(indicatorData), static_cast<WebCore::TextIndicatorLifetime>(lifetime));
6996#else
6997 ASSERT_NOT_REACHED();
6998#endif
6999}
7000
7001void WebPageProxy::clearTextIndicator()
7002{
7003#if PLATFORM(COCOA)
7004 pageClient().clearTextIndicator(WebCore::TextIndicatorDismissalAnimation::FadeOut);
7005#else
7006 ASSERT_NOT_REACHED();
7007#endif
7008}
7009
7010void WebPageProxy::setTextIndicatorAnimationProgress(float progress)
7011{
7012#if PLATFORM(COCOA)
7013 pageClient().setTextIndicatorAnimationProgress(progress);
7014#else
7015 ASSERT_NOT_REACHED();
7016#endif
7017}
7018
7019void WebPageProxy::didFindString(const String& string, const Vector<WebCore::IntRect>& matchRects, uint32_t matchCount, int32_t matchIndex, bool didWrapAround)
7020{
7021 m_findClient->didFindString(this, string, matchRects, matchCount, matchIndex, didWrapAround);
7022}
7023
7024void WebPageProxy::didFindStringMatches(const String& string, const Vector<Vector<WebCore::IntRect>>& matchRects, int32_t firstIndexAfterSelection)
7025{
7026 m_findMatchesClient->didFindStringMatches(this, string, matchRects, firstIndexAfterSelection);
7027}
7028
7029void WebPageProxy::didFailToFindString(const String& string)
7030{
7031 m_findClient->didFailToFindString(this, string);
7032}
7033
7034bool WebPageProxy::sendMessage(UniqueRef<IPC::Encoder>&& encoder, OptionSet<IPC::SendOption> sendOptions, std::optional<std::pair<CompletionHandler<void(IPC::Decoder*)>, uint64_t>>&& asyncReplyInfo)
7035{
7036 return m_process->sendMessage(WTFMove(encoder), sendOptions, WTFMove(asyncReplyInfo));
7037}
7038
7039IPC::Connection* WebPageProxy::messageSenderConnection() const
7040{
7041 return m_process->hasConnection() ? m_process->connection() : nullptr;
7042}
7043
7044uint64_t WebPageProxy::messageSenderDestinationID() const
7045{
7046 return m_webPageID.toUInt64();
7047}
7048
7049void WebPageProxy::valueChangedForPopupMenu(WebPopupMenuProxy*, int32_t newSelectedIndex)
7050{
7051 send(Messages::WebPage::DidChangeSelectedIndexForActivePopupMenu(newSelectedIndex));
7052}
7053
7054void WebPageProxy::setTextFromItemForPopupMenu(WebPopupMenuProxy*, int32_t index)
7055{
7056 send(Messages::WebPage::SetTextForActivePopupMenu(index));
7057}
7058
7059bool WebPageProxy::isProcessingKeyboardEvents() const
7060{
7061 return !m_keyEventQueue.isEmpty();
7062}
7063
7064bool WebPageProxy::isProcessingMouseEvents() const
7065{
7066 return !m_mouseEventQueue.isEmpty();
7067}
7068
7069bool WebPageProxy::isProcessingWheelEvents() const
7070{
7071 return m_wheelEventCoalescer && m_wheelEventCoalescer->hasEventsBeingProcessed();
7072}
7073
7074NativeWebMouseEvent* WebPageProxy::currentlyProcessedMouseDownEvent()
7075{
7076 // <https://bugs.webkit.org/show_bug.cgi?id=57904> We need to keep track of the mouse down event in the case where we
7077 // display a popup menu for select elements. When the user changes the selected item, we fake a mouseup event by
7078 // using this stored mousedown event and changing the event type. This trickery happens when WebProcess handles
7079 // a mousedown event that runs the default handler for HTMLSelectElement, so the triggering mousedown must be the first event.
7080
7081 if (m_mouseEventQueue.isEmpty())
7082 return nullptr;
7083
7084 auto& event = m_mouseEventQueue.first();
7085 if (event.type() != WebEvent::Type::MouseDown)
7086 return nullptr;
7087
7088 return &event;
7089}
7090
7091void WebPageProxy::postMessageToInjectedBundle(const String& messageName, API::Object* messageBody)
7092{
7093 if (!hasRunningProcess()) {
7094 m_pendingInjectedBundleMessages.append(InjectedBundleMessage { messageName, messageBody });
7095 return;
7096 }
7097
7098 send(Messages::WebPage::PostInjectedBundleMessage(messageName, UserData(process().transformObjectsToHandles(messageBody).get())));
7099}
7100
7101#if PLATFORM(GTK)
7102void WebPageProxy::failedToShowPopupMenu()
7103{
7104 send(Messages::WebPage::FailedToShowPopupMenu());
7105}
7106#endif
7107
7108void WebPageProxy::showPopupMenu(const IntRect& rect, uint64_t textDirection, const Vector<WebPopupItem>& items, int32_t selectedIndex, const PlatformPopupMenuData& data)
7109{
7110 MESSAGE_CHECK(m_process, selectedIndex == -1 || static_cast<uint32_t>(selectedIndex) < items.size());
7111
7112 if (m_activePopupMenu) {
7113 m_activePopupMenu->hidePopupMenu();
7114 m_activePopupMenu->invalidate();
7115 m_activePopupMenu = nullptr;
7116 }
7117
7118 // If the page is controlled by automation, entering a nested run loop while the menu is open
7119 // can hang the page / WebDriver test. Since <option> elements are selected via a different
7120 // code path anyway, just don't show the native popup menu.
7121 if (auto* automationSession = process().processPool().automationSession()) {
7122 if (m_controlledByAutomation && automationSession->isSimulatingUserInteraction())
7123 return;
7124 }
7125
7126 m_activePopupMenu = pageClient().createPopupMenuProxy(*this);
7127
7128 if (!m_activePopupMenu)
7129 return;
7130
7131 // Since showPopupMenu() can spin a nested run loop we need to turn off the responsiveness timer.
7132 m_process->stopResponsivenessTimer();
7133
7134 // Showing a popup menu runs a nested runloop, which can handle messages that cause |this| to get closed.
7135 Ref<WebPageProxy> protect(*this);
7136 m_activePopupMenu->showPopupMenu(rect, static_cast<TextDirection>(textDirection), m_pageScaleFactor, items, data, selectedIndex);
7137}
7138
7139void WebPageProxy::hidePopupMenu()
7140{
7141 if (!m_activePopupMenu)
7142 return;
7143
7144 m_activePopupMenu->hidePopupMenu();
7145 m_activePopupMenu->invalidate();
7146 m_activePopupMenu = nullptr;
7147}
7148
7149#if ENABLE(CONTEXT_MENUS)
7150void WebPageProxy::showContextMenu(ContextMenuContextData&& contextMenuContextData, const UserData& userData)
7151{
7152 // Showing a context menu runs a nested runloop, which can handle messages that cause |this| to get closed.
7153 Ref<WebPageProxy> protect(*this);
7154
7155 // If the page is controlled by automation, entering a nested run loop while the menu is open
7156 // can hang the page / WebDriver test. Pretend to show and immediately dismiss the context menu.
7157 if (auto* automationSession = process().processPool().automationSession()) {
7158 if (m_controlledByAutomation && automationSession->isSimulatingUserInteraction()) {
7159 send(Messages::WebPage::DidShowContextMenu());
7160 return;
7161 }
7162 }
7163
7164 // Discard any enqueued mouse events that have been delivered to the UIProcess whilst the WebProcess is still processing the
7165 // MouseDown event that triggered this ShowContextMenu message. This can happen if we take too long to enter the nested runloop.
7166 discardQueuedMouseEvents();
7167
7168 m_activeContextMenuContextData = contextMenuContextData;
7169
7170 m_activeContextMenu = pageClient().createContextMenuProxy(*this, WTFMove(contextMenuContextData), userData);
7171
7172 m_activeContextMenu->show();
7173}
7174
7175void WebPageProxy::didShowContextMenu()
7176{
7177 // Don't send `Messages::WebPage::DidShowContextMenu` as that should've already been eagerly
7178 // sent when requesting the context menu to show, regardless of the result of that request.
7179
7180 pageClient().didShowContextMenu();
7181}
7182
7183void WebPageProxy::didDismissContextMenu()
7184{
7185 send(Messages::WebPage::DidDismissContextMenu());
7186
7187 pageClient().didDismissContextMenu();
7188}
7189
7190void WebPageProxy::contextMenuItemSelected(const WebContextMenuItemData& item)
7191{
7192 // Application custom items don't need to round-trip through to WebCore in the WebProcess.
7193 if (item.action() >= ContextMenuItemBaseApplicationTag) {
7194 m_contextMenuClient->customContextMenuItemSelected(*this, item);
7195 return;
7196 }
7197
7198 struct DownloadInfo {
7199 String url;
7200 String suggestedFilename;
7201 };
7202 std::optional<DownloadInfo> downloadInfo;
7203
7204 ASSERT(m_activeContextMenuContextData.webHitTestResultData());
7205
7206 auto hitTestData = m_activeContextMenuContextData.webHitTestResultData().value();
7207
7208 switch (item.action()) {
7209#if PLATFORM(COCOA)
7210 case ContextMenuItemTagSmartCopyPaste:
7211 setSmartInsertDeleteEnabled(!isSmartInsertDeleteEnabled());
7212 return;
7213
7214 case ContextMenuItemTagSmartQuotes:
7215 TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled);
7216 m_process->updateTextCheckerState();
7217 return;
7218
7219 case ContextMenuItemTagSmartDashes:
7220 TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled);
7221 m_process->updateTextCheckerState();
7222 return;
7223
7224 case ContextMenuItemTagSmartLinks:
7225 TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled);
7226 m_process->updateTextCheckerState();
7227 return;
7228
7229 case ContextMenuItemTagTextReplacement:
7230 TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled);
7231 m_process->updateTextCheckerState();
7232 return;
7233
7234 case ContextMenuItemTagCorrectSpellingAutomatically:
7235 TextChecker::setAutomaticSpellingCorrectionEnabled(!TextChecker::state().isAutomaticSpellingCorrectionEnabled);
7236 m_process->updateTextCheckerState();
7237 return;
7238
7239 case ContextMenuItemTagShowSubstitutions:
7240 TextChecker::toggleSubstitutionsPanelIsShowing();
7241 return;
7242#endif
7243
7244 case ContextMenuItemTagDownloadImageToDisk:
7245 downloadInfo = { { hitTestData.absoluteImageURL, { } } };
7246 break;
7247
7248 case ContextMenuItemTagDownloadLinkToDisk: {
7249 downloadInfo = { { hitTestData.absoluteLinkURL, hitTestData.linkSuggestedFilename } };
7250 break;
7251 }
7252
7253 case ContextMenuItemTagDownloadMediaToDisk:
7254 downloadInfo = { { hitTestData.absoluteMediaURL, { } } };
7255 break;
7256
7257 case ContextMenuItemTagCheckSpellingWhileTyping:
7258 TextChecker::setContinuousSpellCheckingEnabled(!TextChecker::state().isContinuousSpellCheckingEnabled);
7259 m_process->updateTextCheckerState();
7260 return;
7261
7262 case ContextMenuItemTagCheckGrammarWithSpelling:
7263 TextChecker::setGrammarCheckingEnabled(!TextChecker::state().isGrammarCheckingEnabled);
7264 m_process->updateTextCheckerState();
7265 return;
7266
7267 case ContextMenuItemTagShowSpellingPanel:
7268 if (!TextChecker::spellingUIIsShowing())
7269 advanceToNextMisspelling(true);
7270 TextChecker::toggleSpellingUIIsShowing();
7271 return;
7272
7273 case ContextMenuItemTagAddHighlightToNewQuickNote:
7274#if ENABLE(APP_HIGHLIGHTS)
7275 createAppHighlightInSelectedRange(CreateNewGroupForHighlight::Yes, HighlightRequestOriginatedInApp::No);
7276#endif
7277 return;
7278
7279 case ContextMenuItemTagAddHighlightToCurrentQuickNote:
7280#if ENABLE(APP_HIGHLIGHTS)
7281 createAppHighlightInSelectedRange(CreateNewGroupForHighlight::No, HighlightRequestOriginatedInApp::No);
7282#endif
7283 return;
7284
7285 case ContextMenuItemTagLearnSpelling:
7286 case ContextMenuItemTagIgnoreSpelling:
7287 ++m_pendingLearnOrIgnoreWordMessageCount;
7288 break;
7289
7290 case ContextMenuItemTagLookUpImage:
7291#if ENABLE(IMAGE_ANALYSIS)
7292 handleContextMenuLookUpImage();
7293#endif
7294 return;
7295
7296 case ContextMenuItemTagCopySubject:
7297#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
7298 handleContextMenuCopySubject(hitTestData.sourceImageMIMEType);
7299#endif
7300 return;
7301
7302 default:
7303 break;
7304 }
7305
7306 if (downloadInfo) {
7307 auto& download = m_process->processPool().download(m_websiteDataStore, this, URL { downloadInfo->url }, downloadInfo->suggestedFilename);
7308 download.setDidStartCallback([this, weakThis = WeakPtr { *this }] (auto* download) {
7309 if (!weakThis || !download)
7310 return;
7311 m_navigationClient->contextMenuDidCreateDownload(*this, *download);
7312 });
7313 }
7314
7315 platformDidSelectItemFromActiveContextMenu(item);
7316
7317 send(Messages::WebPage::DidSelectItemFromActiveContextMenu(item));
7318}
7319
7320void WebPageProxy::handleContextMenuKeyEvent()
7321{
7322 send(Messages::WebPage::ContextMenuForKeyEvent());
7323}
7324#endif // ENABLE(CONTEXT_MENUS)
7325
7326#if PLATFORM(IOS_FAMILY)
7327void WebPageProxy::didChooseFilesForOpenPanelWithDisplayStringAndIcon(const Vector<String>& fileURLs, const String& displayString, const API::Data* iconData)
7328{
7329 if (!hasRunningProcess())
7330 return;
7331
7332#if ENABLE(SANDBOX_EXTENSIONS)
7333 auto sandboxExtensionHandles = SandboxExtension::createReadOnlyHandlesForFiles("WebPageProxy::didChooseFilesForOpenPanelWithDisplayStringAndIcon"_s, fileURLs);
7334 send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(WTFMove(sandboxExtensionHandles)));
7335#endif
7336
7337 SandboxExtension::Handle frontboardServicesSandboxExtension, iconServicesSandboxExtension;
7338 auto auditToken = m_process->auditToken();
7339#if HAVE(FRONTBOARD_SYSTEM_APP_SERVICES)
7340 if (auto handle = SandboxExtension::createHandleForMachLookup("com.apple.frontboard.systemappservices"_s, auditToken, SandboxExtension::MachBootstrapOptions::EnableMachBootstrap))
7341 frontboardServicesSandboxExtension = WTFMove(*handle);
7342#endif
7343 if (auto handle = SandboxExtension::createHandleForMachLookup("com.apple.iconservices"_s, auditToken, SandboxExtension::MachBootstrapOptions::EnableMachBootstrap))
7344 iconServicesSandboxExtension = WTFMove(*handle);
7345
7346 send(Messages::WebPage::DidChooseFilesForOpenPanelWithDisplayStringAndIcon(fileURLs, displayString, iconData ? iconData->dataReference() : IPC::DataReference(), frontboardServicesSandboxExtension, iconServicesSandboxExtension));
7347
7348 m_openPanelResultListener->invalidate();
7349 m_openPanelResultListener = nullptr;
7350}
7351#endif
7352
7353bool WebPageProxy::didChooseFilesForOpenPanelWithImageTranscoding(const Vector<String>& fileURLs, const Vector<String>& allowedMIMETypes)
7354{
7355#if PLATFORM(MAC)
7356 auto transcodingMIMEType = WebCore::MIMETypeRegistry::preferredImageMIMETypeForEncoding(allowedMIMETypes, { });
7357 if (transcodingMIMEType.isNull())
7358 return false;
7359
7360 auto transcodingURLs = findImagesForTranscoding(fileURLs, allowedMIMETypes);
7361 if (transcodingURLs.isEmpty())
7362 return false;
7363
7364 auto transcodingUTI = WebCore::UTIFromMIMEType(transcodingMIMEType);
7365 auto transcodingExtension = WebCore::MIMETypeRegistry::preferredExtensionForMIMEType(transcodingMIMEType);
7366
7367 sharedImageTranscodingQueue().dispatch([this, protectedThis = Ref { *this }, fileURLs = crossThreadCopy(fileURLs), transcodingURLs = crossThreadCopy(WTFMove(transcodingURLs)), transcodingUTI = WTFMove(transcodingUTI).isolatedCopy(), transcodingExtension = WTFMove(transcodingExtension).isolatedCopy()]() mutable {
7368 ASSERT(!RunLoop::isMain());
7369
7370 auto transcodedURLs = transcodeImages(transcodingURLs, transcodingUTI, transcodingExtension);
7371 ASSERT(transcodingURLs.size() == transcodedURLs.size());
7372
7373 RunLoop::main().dispatch([this, protectedThis = WTFMove(protectedThis), fileURLs = crossThreadCopy(WTFMove(fileURLs)), transcodedURLs = crossThreadCopy(WTFMove(transcodedURLs))]() {
7374#if ENABLE(SANDBOX_EXTENSIONS)
7375 Vector<String> sandboxExtensionFiles;
7376 for (size_t i = 0, size = fileURLs.size(); i < size; ++i)
7377 sandboxExtensionFiles.append(!transcodedURLs[i].isNull() ? transcodedURLs[i] : fileURLs[i]);
7378 auto sandboxExtensionHandles = SandboxExtension::createReadOnlyHandlesForFiles("WebPageProxy::didChooseFilesForOpenPanel"_s, sandboxExtensionFiles);
7379 send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(WTFMove(sandboxExtensionHandles)));
7380#endif
7381 send(Messages::WebPage::DidChooseFilesForOpenPanel(fileURLs, transcodedURLs));
7382 });
7383 });
7384
7385 return true;
7386#else
7387 UNUSED_PARAM(fileURLs);
7388 UNUSED_PARAM(allowedMIMETypes);
7389 return false;
7390#endif
7391}
7392
7393void WebPageProxy::didChooseFilesForOpenPanel(const Vector<String>& fileURLs, const Vector<String>& allowedMIMETypes)
7394{
7395 if (!hasRunningProcess())
7396 return;
7397
7398 if (!didChooseFilesForOpenPanelWithImageTranscoding(fileURLs, allowedMIMETypes)) {
7399#if ENABLE(SANDBOX_EXTENSIONS)
7400 auto sandboxExtensionHandles = SandboxExtension::createReadOnlyHandlesForFiles("WebPageProxy::didChooseFilesForOpenPanel"_s, fileURLs);
7401 send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(WTFMove(sandboxExtensionHandles)));
7402#endif
7403 send(Messages::WebPage::DidChooseFilesForOpenPanel(fileURLs, { }));
7404 }
7405
7406 m_openPanelResultListener->invalidate();
7407 m_openPanelResultListener = nullptr;
7408}
7409
7410void WebPageProxy::didCancelForOpenPanel()
7411{
7412 if (!hasRunningProcess())
7413 return;
7414
7415 send(Messages::WebPage::DidCancelForOpenPanel());
7416
7417 m_openPanelResultListener->invalidate();
7418 m_openPanelResultListener = nullptr;
7419}
7420
7421void WebPageProxy::advanceToNextMisspelling(bool startBeforeSelection)
7422{
7423 send(Messages::WebPage::AdvanceToNextMisspelling(startBeforeSelection));
7424}
7425
7426void WebPageProxy::changeSpellingToWord(const String& word)
7427{
7428 if (word.isEmpty())
7429 return;
7430
7431 send(Messages::WebPage::ChangeSpellingToWord(word));
7432}
7433
7434void WebPageProxy::registerEditCommand(Ref<WebEditCommandProxy>&& commandProxy, UndoOrRedo undoOrRedo)
7435{
7436 MESSAGE_CHECK(m_process, commandProxy->commandID());
7437 pageClient().registerEditCommand(WTFMove(commandProxy), undoOrRedo);
7438}
7439
7440void WebPageProxy::addEditCommand(WebEditCommandProxy& command)
7441{
7442 m_editCommandSet.add(&command);
7443}
7444
7445void WebPageProxy::removeEditCommand(WebEditCommandProxy& command)
7446{
7447 m_editCommandSet.remove(&command);
7448
7449 if (!hasRunningProcess())
7450 return;
7451 send(Messages::WebPage::DidRemoveEditCommand(command.commandID()));
7452}
7453
7454bool WebPageProxy::canUndo()
7455{
7456 return pageClient().canUndoRedo(UndoOrRedo::Undo);
7457}
7458
7459bool WebPageProxy::canRedo()
7460{
7461 return pageClient().canUndoRedo(UndoOrRedo::Redo);
7462}
7463
7464SpellDocumentTag WebPageProxy::spellDocumentTag()
7465{
7466 if (!m_spellDocumentTag)
7467 m_spellDocumentTag = TextChecker::uniqueSpellDocumentTag(this);
7468 return m_spellDocumentTag.value();
7469}
7470
7471#if USE(UNIFIED_TEXT_CHECKING)
7472void WebPageProxy::checkTextOfParagraph(const String& text, OptionSet<TextCheckingType> checkingTypes, int32_t insertionPoint, CompletionHandler<void(Vector<WebCore::TextCheckingResult>&&)>&& completionHandler)
7473{
7474 completionHandler(TextChecker::checkTextOfParagraph(spellDocumentTag(), text, insertionPoint, checkingTypes, m_initialCapitalizationEnabled));
7475}
7476#endif
7477
7478void WebPageProxy::checkSpellingOfString(const String& text, CompletionHandler<void(int32_t misspellingLocation, int32_t misspellingLength)>&& completionHandler)
7479{
7480 int32_t misspellingLocation = 0;
7481 int32_t misspellingLength = 0;
7482 TextChecker::checkSpellingOfString(spellDocumentTag(), text, misspellingLocation, misspellingLength);
7483 completionHandler(misspellingLocation, misspellingLength);
7484}
7485
7486void WebPageProxy::checkGrammarOfString(const String& text, CompletionHandler<void(Vector<WebCore::GrammarDetail>&&, int32_t badGrammarLocation, int32_t badGrammarLength)>&& completionHandler)
7487{
7488 Vector<GrammarDetail> grammarDetails;
7489 int32_t badGrammarLocation = 0;
7490 int32_t badGrammarLength = 0;
7491 TextChecker::checkGrammarOfString(spellDocumentTag(), text, grammarDetails, badGrammarLocation, badGrammarLength);
7492 completionHandler(WTFMove(grammarDetails), badGrammarLocation, badGrammarLength);
7493}
7494
7495void WebPageProxy::spellingUIIsShowing(CompletionHandler<void(bool)>&& completionHandler)
7496{
7497 completionHandler(TextChecker::spellingUIIsShowing());
7498}
7499
7500void WebPageProxy::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
7501{
7502 TextChecker::updateSpellingUIWithMisspelledWord(spellDocumentTag(), misspelledWord);
7503}
7504
7505void WebPageProxy::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
7506{
7507 TextChecker::updateSpellingUIWithGrammarString(spellDocumentTag(), badGrammarPhrase, grammarDetail);
7508}
7509
7510void WebPageProxy::getGuessesForWord(const String& word, const String& context, int32_t insertionPoint, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
7511{
7512 Vector<String> guesses;
7513 TextChecker::getGuessesForWord(spellDocumentTag(), word, context, insertionPoint, guesses, m_initialCapitalizationEnabled);
7514 completionHandler(WTFMove(guesses));
7515}
7516
7517void WebPageProxy::learnWord(const String& word)
7518{
7519 MESSAGE_CHECK(m_process, m_pendingLearnOrIgnoreWordMessageCount);
7520 --m_pendingLearnOrIgnoreWordMessageCount;
7521
7522 TextChecker::learnWord(spellDocumentTag(), word);
7523}
7524
7525void WebPageProxy::ignoreWord(const String& word)
7526{
7527 MESSAGE_CHECK(m_process, m_pendingLearnOrIgnoreWordMessageCount);
7528 --m_pendingLearnOrIgnoreWordMessageCount;
7529
7530 TextChecker::ignoreWord(spellDocumentTag(), word);
7531}
7532
7533void WebPageProxy::requestCheckingOfString(TextCheckerRequestID requestID, const TextCheckingRequestData& request, int32_t insertionPoint)
7534{
7535 TextChecker::requestCheckingOfString(TextCheckerCompletion::create(requestID, request, this), insertionPoint);
7536}
7537
7538void WebPageProxy::didFinishCheckingText(TextCheckerRequestID requestID, const Vector<WebCore::TextCheckingResult>& result)
7539{
7540 send(Messages::WebPage::DidFinishCheckingText(requestID, result));
7541}
7542
7543void WebPageProxy::didCancelCheckingText(TextCheckerRequestID requestID)
7544{
7545 send(Messages::WebPage::DidCancelCheckingText(requestID));
7546}
7547
7548void WebPageProxy::focusFromServiceWorker(CompletionHandler<void()>&& callback)
7549{
7550 if (!m_uiClient->focusFromServiceWorker(*this)) {
7551 callback();
7552 return;
7553 }
7554
7555#if PLATFORM(COCOA)
7556 makeFirstResponder();
7557#endif
7558
7559 if (m_activityState.contains(ActivityState::IsVisible)) {
7560 callback();
7561 return;
7562 }
7563 installActivityStateChangeCompletionHandler(WTFMove(callback));
7564}
7565
7566// Other
7567
7568void WebPageProxy::setFocus(bool focused)
7569{
7570 if (focused)
7571 m_uiClient->focus(this);
7572 else
7573 m_uiClient->unfocus(this);
7574}
7575
7576void WebPageProxy::takeFocus(uint8_t direction)
7577{
7578 if (m_uiClient->takeFocus(this, (static_cast<FocusDirection>(direction) == FocusDirection::Forward) ? kWKFocusDirectionForward : kWKFocusDirectionBackward))
7579 return;
7580
7581 pageClient().takeFocus(static_cast<FocusDirection>(direction));
7582}
7583
7584void WebPageProxy::setToolTip(const String& toolTip)
7585{
7586 if (m_toolTip == toolTip)
7587 return;
7588
7589 String oldToolTip = m_toolTip;
7590 m_toolTip = toolTip;
7591 pageClient().toolTipChanged(oldToolTip, m_toolTip);
7592}
7593
7594void WebPageProxy::setCursor(const WebCore::Cursor& cursor)
7595{
7596 pageClient().setCursor(cursor);
7597}
7598
7599void WebPageProxy::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
7600{
7601 pageClient().setCursorHiddenUntilMouseMoves(hiddenUntilMouseMoves);
7602}
7603
7604void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled)
7605{
7606 WebEvent::Type type = static_cast<WebEvent::Type>(opaqueType);
7607
7608 switch (type) {
7609 case WebEvent::NoType:
7610 case WebEvent::MouseMove:
7611 case WebEvent::Wheel:
7612 break;
7613
7614 case WebEvent::MouseDown:
7615 case WebEvent::MouseUp:
7616 case WebEvent::MouseForceChanged:
7617 case WebEvent::MouseForceDown:
7618 case WebEvent::MouseForceUp:
7619 case WebEvent::KeyDown:
7620 case WebEvent::KeyUp:
7621 case WebEvent::RawKeyDown:
7622 case WebEvent::Char:
7623#if ENABLE(TOUCH_EVENTS)
7624 case WebEvent::TouchStart:
7625 case WebEvent::TouchMove:
7626 case WebEvent::TouchEnd:
7627 case WebEvent::TouchCancel:
7628#endif
7629#if ENABLE(MAC_GESTURE_EVENTS)
7630 case WebEvent::GestureStart:
7631 case WebEvent::GestureChange:
7632 case WebEvent::GestureEnd:
7633#endif
7634 m_process->stopResponsivenessTimer();
7635 break;
7636 }
7637
7638 switch (type) {
7639 case WebEvent::NoType:
7640 break;
7641 case WebEvent::MouseForceChanged:
7642 case WebEvent::MouseForceDown:
7643 case WebEvent::MouseForceUp:
7644 case WebEvent::MouseMove:
7645 case WebEvent::MouseDown:
7646 case WebEvent::MouseUp: {
7647 LOG(MouseHandling, "WebPageProxy::didReceiveEvent: %s (queue size %zu)", webMouseEventTypeString(type), m_mouseEventQueue.size());
7648
7649 // Retire the last sent event now that WebProcess is done handling it.
7650 MESSAGE_CHECK(m_process, !m_mouseEventQueue.isEmpty());
7651 auto event = m_mouseEventQueue.takeFirst();
7652 MESSAGE_CHECK(m_process, type == event.type());
7653
7654 if (!m_mouseEventQueue.isEmpty()) {
7655 LOG(MouseHandling, " UIProcess: handling a queued mouse event from didReceiveEvent");
7656 processNextQueuedMouseEvent();
7657 } else {
7658 if (auto* automationSession = process().processPool().automationSession())
7659 automationSession->mouseEventsFlushedForPage(*this);
7660 didFinishProcessingAllPendingMouseEvents();
7661 }
7662 break;
7663 }
7664
7665 case WebEvent::Wheel: {
7666 MESSAGE_CHECK(m_process, wheelEventCoalescer().hasEventsBeingProcessed());
7667 auto oldestProcessedEvent = wheelEventCoalescer().takeOldestEventBeingProcessed();
7668
7669 // FIXME: Dispatch additional events to the didNotHandleWheelEvent client function.
7670 if (!handled) {
7671 m_uiClient->didNotHandleWheelEvent(this, oldestProcessedEvent);
7672 pageClient().wheelEventWasNotHandledByWebCore(oldestProcessedEvent);
7673 }
7674
7675 if (auto eventToSend = wheelEventCoalescer().nextEventToDispatch())
7676 sendWheelEvent(*eventToSend);
7677 else if (auto* automationSession = process().processPool().automationSession())
7678 automationSession->wheelEventsFlushedForPage(*this);
7679 break;
7680 }
7681
7682 case WebEvent::KeyDown:
7683 case WebEvent::KeyUp:
7684 case WebEvent::RawKeyDown:
7685 case WebEvent::Char: {
7686 LOG(KeyHandling, "WebPageProxy::didReceiveEvent: %s (queue empty %d)", webKeyboardEventTypeString(type), m_keyEventQueue.isEmpty());
7687
7688 MESSAGE_CHECK(m_process, !m_keyEventQueue.isEmpty());
7689 auto event = m_keyEventQueue.takeFirst();
7690 MESSAGE_CHECK(m_process, type == event.type());
7691
7692#if PLATFORM(WIN)
7693 if (!handled && type == WebEvent::RawKeyDown)
7694 dispatchPendingCharEvents(event);
7695#endif
7696
7697 bool canProcessMoreKeyEvents = !m_keyEventQueue.isEmpty();
7698 if (canProcessMoreKeyEvents) {
7699 LOG(KeyHandling, " UI process: sent keyEvent from didReceiveEvent");
7700 send(Messages::WebPage::KeyEvent(m_keyEventQueue.first()));
7701 }
7702
7703 // The call to doneWithKeyEvent may close this WebPage.
7704 // Protect against this being destroyed.
7705 Ref<WebPageProxy> protect(*this);
7706
7707 pageClient().doneWithKeyEvent(event, handled);
7708 if (!handled)
7709 m_uiClient->didNotHandleKeyEvent(this, event);
7710
7711 // Notify the session after -[NSApp sendEvent:] has a crack at turning the event into an action.
7712 if (!canProcessMoreKeyEvents) {
7713 if (auto* automationSession = process().processPool().automationSession())
7714 automationSession->keyboardEventsFlushedForPage(*this);
7715 }
7716 break;
7717 }
7718#if ENABLE(MAC_GESTURE_EVENTS)
7719 case WebEvent::GestureStart:
7720 case WebEvent::GestureChange:
7721 case WebEvent::GestureEnd: {
7722 MESSAGE_CHECK(m_process, !m_gestureEventQueue.isEmpty());
7723 auto event = m_gestureEventQueue.takeFirst();
7724 MESSAGE_CHECK(m_process, type == event.type());
7725
7726 if (!handled)
7727 pageClient().gestureEventWasNotHandledByWebCore(event);
7728 break;
7729 }
7730#endif
7731#if ENABLE(IOS_TOUCH_EVENTS)
7732 case WebEvent::TouchStart:
7733 case WebEvent::TouchMove:
7734 case WebEvent::TouchEnd:
7735 case WebEvent::TouchCancel:
7736 break;
7737#elif ENABLE(TOUCH_EVENTS)
7738 case WebEvent::TouchStart:
7739 case WebEvent::TouchMove:
7740 case WebEvent::TouchEnd:
7741 case WebEvent::TouchCancel: {
7742 MESSAGE_CHECK(m_process, !m_touchEventQueue.isEmpty());
7743 auto queuedEvents = m_touchEventQueue.takeFirst();
7744 MESSAGE_CHECK(m_process, type == queuedEvents.forwardedEvent.type());
7745
7746 pageClient().doneWithTouchEvent(queuedEvents.forwardedEvent, handled);
7747 for (size_t i = 0; i < queuedEvents.deferredTouchEvents.size(); ++i) {
7748 bool isEventHandled = false;
7749 pageClient().doneWithTouchEvent(queuedEvents.deferredTouchEvents.at(i), isEventHandled);
7750 }
7751 break;
7752 }
7753#endif
7754 }
7755}
7756
7757void WebPageProxy::editorStateChanged(const EditorState& editorState, CompletionHandler<void()>&& completionHandler)
7758{
7759 if (updateEditorState(editorState))
7760 dispatchDidUpdateEditorState();
7761
7762 completionHandler();
7763}
7764
7765bool WebPageProxy::updateEditorState(const EditorState& newEditorState)
7766{
7767 if (newEditorState.identifier < m_editorState.identifier)
7768 return false;
7769
7770 auto oldEditorState = std::exchange(m_editorState, newEditorState);
7771 didUpdateEditorState(oldEditorState, newEditorState);
7772 return true;
7773}
7774
7775#if !PLATFORM(IOS_FAMILY)
7776
7777void WebPageProxy::dispatchDidUpdateEditorState()
7778{
7779}
7780
7781#endif
7782
7783inline API::DiagnosticLoggingClient* WebPageProxy::effectiveDiagnosticLoggingClient(ShouldSample shouldSample)
7784{
7785 // Diagnostic logging is disabled for ephemeral sessions for privacy reasons.
7786 if (sessionID().isEphemeral())
7787 return nullptr;
7788
7789 return DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample) ? diagnosticLoggingClient() : nullptr;
7790}
7791
7792void WebPageProxy::logDiagnosticMessage(const String& message, const String& description, WebCore::ShouldSample shouldSample)
7793{
7794 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
7795 if (!effectiveClient)
7796 return;
7797
7798 effectiveClient->logDiagnosticMessage(this, message, description);
7799}
7800
7801void WebPageProxy::logDiagnosticMessageFromWebProcess(const String& message, const String& description, WebCore::ShouldSample shouldSample)
7802{
7803 MESSAGE_CHECK(m_process, message.isAllASCII());
7804
7805 logDiagnosticMessage(message, description, shouldSample);
7806}
7807
7808void WebPageProxy::logDiagnosticMessageWithResult(const String& message, const String& description, uint32_t result, WebCore::ShouldSample shouldSample)
7809{
7810 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
7811 if (!effectiveClient)
7812 return;
7813
7814 effectiveClient->logDiagnosticMessageWithResult(this, message, description, static_cast<WebCore::DiagnosticLoggingResultType>(result));
7815}
7816
7817void WebPageProxy::logDiagnosticMessageWithResultFromWebProcess(const String& message, const String& description, uint32_t result, WebCore::ShouldSample shouldSample)
7818{
7819 MESSAGE_CHECK(m_process, message.isAllASCII());
7820
7821 logDiagnosticMessageWithResult(message, description, result, shouldSample);
7822}
7823
7824void WebPageProxy::logDiagnosticMessageWithValue(const String& message, const String& description, double value, unsigned significantFigures, ShouldSample shouldSample)
7825{
7826 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
7827 if (!effectiveClient)
7828 return;
7829
7830 effectiveClient->logDiagnosticMessageWithValue(this, message, description, String::numberToStringFixedPrecision(value, significantFigures));
7831}
7832
7833void WebPageProxy::logDiagnosticMessageWithValueFromWebProcess(const String& message, const String& description, double value, unsigned significantFigures, ShouldSample shouldSample)
7834{
7835 MESSAGE_CHECK(m_process, message.isAllASCII());
7836
7837 logDiagnosticMessageWithValue(message, description, value, significantFigures, shouldSample);
7838}
7839
7840void WebPageProxy::logDiagnosticMessageWithEnhancedPrivacy(const String& message, const String& description, ShouldSample shouldSample)
7841{
7842 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
7843 if (!effectiveClient)
7844 return;
7845
7846 effectiveClient->logDiagnosticMessageWithEnhancedPrivacy(this, message, description);
7847}
7848
7849void WebPageProxy::logDiagnosticMessageWithEnhancedPrivacyFromWebProcess(const String& message, const String& description, WebCore::ShouldSample shouldSample)
7850{
7851 MESSAGE_CHECK(m_process, message.isAllASCII());
7852
7853 logDiagnosticMessageWithEnhancedPrivacy(message, description, shouldSample);
7854}
7855
7856void WebPageProxy::logDiagnosticMessageWithValueDictionary(const String& message, const String& description, const WebCore::DiagnosticLoggingClient::ValueDictionary& valueDictionary, WebCore::ShouldSample shouldSample)
7857{
7858 auto* effectiveClient = effectiveDiagnosticLoggingClient(shouldSample);
7859 if (!effectiveClient)
7860 return;
7861
7862 auto apiDictionary = API::Dictionary::create();
7863
7864 for (auto& keyValuePair : valueDictionary) {
7865 apiDictionary->add(keyValuePair.key, WTF::switchOn(keyValuePair.value,
7866 [](const String& value) -> Ref<Object> { return API::String::create(value); },
7867 [](uint64_t value) -> Ref<Object> { return API::UInt64::create(value); },
7868 [](int64_t value) -> Ref<Object> { return API::Int64::create(value); },
7869 [](bool value) -> Ref<Object> { return API::Boolean::create(value); },
7870 [](double value) -> Ref<Object> { return API::Double::create(value); }
7871 ));
7872 }
7873
7874 effectiveClient->logDiagnosticMessageWithValueDictionary(this, message, description, WTFMove(apiDictionary));
7875}
7876
7877void WebPageProxy::logDiagnosticMessageWithValueDictionaryFromWebProcess(const String& message, const String& description, const WebCore::DiagnosticLoggingClient::ValueDictionary& valueDictionary, WebCore::ShouldSample shouldSample)
7878{
7879 MESSAGE_CHECK(m_process, message.isAllASCII());
7880
7881 logDiagnosticMessageWithValueDictionary(message, description, valueDictionary, shouldSample);
7882}
7883
7884void WebPageProxy::logDiagnosticMessageWithDomain(const String& message, WebCore::DiagnosticLoggingDomain domain)
7885{
7886 auto* effectiveClient = effectiveDiagnosticLoggingClient(ShouldSample::No);
7887 if (!effectiveClient)
7888 return;
7889
7890 effectiveClient->logDiagnosticMessageWithDomain(this, message, domain);
7891}
7892
7893void WebPageProxy::logDiagnosticMessageWithDomainFromWebProcess(const String& message, WebCore::DiagnosticLoggingDomain domain)
7894{
7895 MESSAGE_CHECK(m_process, message.isAllASCII());
7896
7897 logDiagnosticMessageWithDomain(message, domain);
7898}
7899
7900void WebPageProxy::logScrollingEvent(uint32_t eventType, MonotonicTime timestamp, uint64_t data)
7901{
7902 PerformanceLoggingClient::ScrollingEvent event = static_cast<PerformanceLoggingClient::ScrollingEvent>(eventType);
7903
7904 switch (event) {
7905 case PerformanceLoggingClient::ScrollingEvent::LoggingEnabled:
7906 WTFLogAlways("SCROLLING: ScrollingPerformanceTestingEnabled\n");
7907 break;
7908 case PerformanceLoggingClient::ScrollingEvent::ExposedTilelessArea:
7909 WTFLogAlways("SCROLLING: Exposed tileless area. Time: %f Unfilled Pixels: %llu\n", timestamp.secondsSinceEpoch().value(), (unsigned long long)data);
7910 break;
7911 case PerformanceLoggingClient::ScrollingEvent::FilledTile:
7912 WTFLogAlways("SCROLLING: Filled visible fresh tile. Time: %f Unfilled Pixels: %llu\n", timestamp.secondsSinceEpoch().value(), (unsigned long long)data);
7913 break;
7914 case PerformanceLoggingClient::ScrollingEvent::SwitchedScrollingMode:
7915 if (data)
7916 WTFLogAlways("SCROLLING: Switching to main-thread scrolling mode. Time: %f Reason(s): %s\n", timestamp.secondsSinceEpoch().value(), PerformanceLoggingClient::synchronousScrollingReasonsAsString(OptionSet<SynchronousScrollingReason>::fromRaw(data)).utf8().data());
7917 else
7918 WTFLogAlways("SCROLLING: Switching to threaded scrolling mode. Time: %f\n", timestamp.secondsSinceEpoch().value());
7919 break;
7920 }
7921}
7922
7923void WebPageProxy::focusedFrameChanged(const std::optional<FrameIdentifier>& frameID)
7924{
7925 if (!frameID) {
7926 m_focusedFrame = nullptr;
7927 return;
7928 }
7929
7930 WebFrameProxy* frame = m_process->webFrame(*frameID);
7931 MESSAGE_CHECK(m_process, frame);
7932
7933 m_focusedFrame = frame;
7934}
7935
7936void WebPageProxy::processDidBecomeUnresponsive()
7937{
7938 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "processDidBecomeUnresponsive:");
7939
7940 if (!hasRunningProcess())
7941 return;
7942
7943 updateBackingStoreDiscardableState();
7944
7945 m_navigationClient->processDidBecomeUnresponsive(*this);
7946}
7947
7948void WebPageProxy::processDidBecomeResponsive()
7949{
7950 WEBPAGEPROXY_RELEASE_LOG(Process, "processDidBecomeResponsive:");
7951
7952 if (!hasRunningProcess())
7953 return;
7954
7955 updateBackingStoreDiscardableState();
7956
7957 m_navigationClient->processDidBecomeResponsive(*this);
7958}
7959
7960void WebPageProxy::willChangeProcessIsResponsive()
7961{
7962 m_pageLoadState.willChangeProcessIsResponsive();
7963}
7964
7965void WebPageProxy::didChangeProcessIsResponsive()
7966{
7967 m_pageLoadState.didChangeProcessIsResponsive();
7968}
7969
7970String WebPageProxy::currentURL() const
7971{
7972 String url = m_pageLoadState.activeURL();
7973 if (url.isEmpty() && m_backForwardList->currentItem())
7974 url = m_backForwardList->currentItem()->url();
7975 return url;
7976}
7977
7978URL WebPageProxy::currentResourceDirectoryURL() const
7979{
7980 auto resourceDirectoryURL = m_pageLoadState.resourceDirectoryURL();
7981 if (!resourceDirectoryURL.isEmpty())
7982 return resourceDirectoryURL;
7983 if (auto* item = m_backForwardList->currentItem())
7984 return item->resourceDirectoryURL();
7985 return { };
7986}
7987
7988void WebPageProxy::resetStateAfterProcessTermination(ProcessTerminationReason reason)
7989{
7990 if (reason != ProcessTerminationReason::NavigationSwap)
7991 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "processDidTerminate: (pid %d), reason=%{public}s", processIdentifier(), processTerminationReasonToString(reason));
7992
7993 ASSERT(m_hasRunningProcess);
7994
7995#if PLATFORM(IOS_FAMILY)
7996 if (m_process->isUnderMemoryPressure()) {
7997 String domain = WebCore::topPrivatelyControlledDomain(URL({ }, currentURL()).host().toString());
7998 if (!domain.isEmpty())
7999 logDiagnosticMessageWithEnhancedPrivacy(WebCore::DiagnosticLoggingKeys::domainCausingJetsamKey(), domain, WebCore::ShouldSample::No);
8000 }
8001#endif
8002
8003 resetStateAfterProcessExited(reason);
8004 stopAllURLSchemeTasks(m_process.ptr());
8005#if ENABLE(UI_PROCESS_PDF_HUD)
8006 pageClient().removeAllPDFHUDs();
8007#endif
8008
8009 // For bringup of process swapping, NavigationSwap termination will not go out to clients.
8010 // If it does *during* process swapping, and the client triggers a reload, that causes bizarre WebKit re-entry.
8011 // FIXME: This might have to change
8012 if (reason != ProcessTerminationReason::NavigationSwap)
8013 navigationState().clearAllNavigations();
8014
8015 if (m_controlledByAutomation) {
8016 if (auto* automationSession = process().processPool().automationSession())
8017 automationSession->terminate();
8018 }
8019}
8020
8021void WebPageProxy::provisionalProcessDidTerminate()
8022{
8023 ASSERT(m_provisionalPage);
8024 m_provisionalPage = nullptr;
8025}
8026
8027static bool shouldReloadAfterProcessTermination(ProcessTerminationReason reason)
8028{
8029 switch (reason) {
8030 case ProcessTerminationReason::ExceededMemoryLimit:
8031 case ProcessTerminationReason::ExceededCPULimit:
8032 case ProcessTerminationReason::RequestedByNetworkProcess:
8033 case ProcessTerminationReason::RequestedByGPUProcess:
8034 case ProcessTerminationReason::Crash:
8035 case ProcessTerminationReason::Unresponsive:
8036 return true;
8037 case ProcessTerminationReason::ExceededProcessCountLimit:
8038 case ProcessTerminationReason::NavigationSwap:
8039 case ProcessTerminationReason::IdleExit:
8040 case ProcessTerminationReason::RequestedByClient:
8041 break;
8042 }
8043 return false;
8044}
8045
8046void WebPageProxy::dispatchProcessDidTerminate(ProcessTerminationReason reason)
8047{
8048 WEBPAGEPROXY_RELEASE_LOG_ERROR(Loading, "dispatchProcessDidTerminate: reason=%{public}s", processTerminationReasonToString(reason));
8049
8050 bool handledByClient = false;
8051 if (m_loaderClient)
8052 handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this);
8053 else
8054 handledByClient = m_navigationClient->processDidTerminate(*this, reason);
8055
8056 if (!handledByClient && shouldReloadAfterProcessTermination(reason)) {
8057 // We delay the view reload until it becomes visible.
8058 if (isViewVisible())
8059 tryReloadAfterProcessTermination();
8060 else {
8061 WEBPAGEPROXY_RELEASE_LOG_ERROR(Loading, "dispatchProcessDidTerminate: Not eagerly reloading the view because it is not currently visible");
8062 m_shouldReloadDueToCrashWhenVisible = true;
8063 }
8064 }
8065}
8066
8067void WebPageProxy::tryReloadAfterProcessTermination()
8068{
8069 m_resetRecentCrashCountTimer.stop();
8070
8071 if (++m_recentCrashCount > maximumWebProcessRelaunchAttempts) {
8072 WEBPAGEPROXY_RELEASE_LOG_ERROR(Process, "tryReloadAfterProcessTermination: process crashed and the client did not handle it, not reloading the page because we reached the maximum number of attempts");
8073 m_recentCrashCount = 0;
8074 return;
8075 }
8076 WEBPAGEPROXY_RELEASE_LOG(Process, "tryReloadAfterProcessTermination: process crashed and the client did not handle it, reloading the page");
8077 reload(ReloadOption::ExpiredOnly);
8078}
8079
8080void WebPageProxy::resetRecentCrashCountSoon()
8081{
8082 m_resetRecentCrashCountTimer.startOneShot(resetRecentCrashCountDelay);
8083}
8084
8085void WebPageProxy::resetRecentCrashCount()
8086{
8087 m_recentCrashCount = 0;
8088}
8089
8090void WebPageProxy::stopAllURLSchemeTasks(WebProcessProxy* process)
8091{
8092 for (auto& handler : copyToVectorOf<Ref<WebURLSchemeHandler>>(m_urlSchemeHandlersByScheme.values()))
8093 handler->stopAllTasksForPage(*this, process);
8094}
8095
8096void WebPageProxy::resetState(ResetStateReason resetStateReason)
8097{
8098 m_mainFrame = nullptr;
8099 m_focusedFrame = nullptr;
8100 m_suspendedPageKeptToPreventFlashing = nullptr;
8101 m_lastSuspendedPage = nullptr;
8102
8103#if PLATFORM(COCOA)
8104 m_scrollingPerformanceData = nullptr;
8105#endif
8106
8107 if (m_drawingArea) {
8108#if PLATFORM(COCOA)
8109 if (resetStateReason == ResetStateReason::NavigationSwap && is<RemoteLayerTreeDrawingAreaProxy>(*m_drawingArea)) {
8110 // Keep layers around in frozen state to avoid flashing during process swaps.
8111 m_frozenRemoteLayerTreeHost = downcast<RemoteLayerTreeDrawingAreaProxy>(*m_drawingArea).detachRemoteLayerTreeHost();
8112 }
8113#endif
8114 m_drawingArea = nullptr;
8115 }
8116 closeOverlayedViews();
8117
8118 m_inspector->reset();
8119
8120#if ENABLE(FULLSCREEN_API)
8121 if (m_fullScreenManager) {
8122 m_fullScreenManager->close();
8123 m_fullScreenManager = nullptr;
8124 }
8125#endif
8126
8127#if ENABLE(MEDIA_USAGE)
8128 if (m_mediaUsageManager)
8129 m_mediaUsageManager->reset();
8130#endif
8131
8132#if HAVE(VISIBILITY_PROPAGATION_VIEW)
8133 if (resetStateReason != ResetStateReason::NavigationSwap)
8134 m_contextIDForVisibilityPropagationInWebProcess = 0;
8135#endif
8136
8137 if (resetStateReason != ResetStateReason::NavigationSwap)
8138 callLoadCompletionHandlersIfNecessary(false);
8139
8140 if (m_openPanelResultListener) {
8141 m_openPanelResultListener->invalidate();
8142 m_openPanelResultListener = nullptr;
8143 }
8144
8145#if ENABLE(TOUCH_EVENTS)
8146 m_touchAndPointerEventTracking.reset();
8147#endif
8148
8149#if ENABLE(GEOLOCATION)
8150 m_geolocationPermissionRequestManager.invalidateRequests();
8151#endif
8152
8153 setToolTip({ });
8154
8155 m_mainFrameHasHorizontalScrollbar = false;
8156 m_mainFrameHasVerticalScrollbar = false;
8157
8158 m_mainFramePinnedState = { true, true, true, true };
8159
8160 m_visibleScrollerThumbRect = IntRect();
8161
8162#if ENABLE(VIDEO_PRESENTATION_MODE)
8163 if (m_playbackSessionManager) {
8164 m_playbackSessionManager->invalidate();
8165 m_playbackSessionManager = nullptr;
8166 }
8167 if (m_videoFullscreenManager) {
8168 m_videoFullscreenManager->invalidate();
8169 m_videoFullscreenManager = nullptr;
8170 }
8171#endif
8172
8173#if PLATFORM(IOS_FAMILY)
8174 m_firstLayerTreeTransactionIdAfterDidCommitLoad = { };
8175 m_lastVisibleContentRectUpdate = { };
8176 m_hasNetworkRequestsOnSuspended = false;
8177 m_isKeyboardAnimatingIn = false;
8178 m_isScrollingOrZooming = false;
8179 m_lastObservedStateWasBackground = false;
8180#endif
8181
8182#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
8183 pageClient().mediaSessionManager().removeAllPlaybackTargetPickerClients(*this);
8184#endif
8185
8186#if ENABLE(APPLE_PAY)
8187 m_paymentCoordinator = nullptr;
8188#endif
8189
8190#if USE(SYSTEM_PREVIEW)
8191 m_systemPreviewController = nullptr;
8192#endif
8193
8194#if ENABLE(ARKIT_INLINE_PREVIEW)
8195 m_modelElementController = nullptr;
8196#endif
8197
8198#if ENABLE(WEB_AUTHN)
8199 m_credentialsMessenger = nullptr;
8200#endif
8201
8202#if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION)
8203 m_webDeviceOrientationUpdateProviderProxy = nullptr;
8204#endif
8205
8206 for (auto& editCommand : std::exchange(m_editCommandSet, { }))
8207 editCommand->invalidate();
8208
8209 m_activePopupMenu = nullptr;
8210
8211 updatePlayingMediaDidChange(MediaProducer::IsNotPlaying);
8212#if ENABLE(MEDIA_STREAM)
8213 m_userMediaPermissionRequestManager = nullptr;
8214#endif
8215
8216#if ENABLE(POINTER_LOCK)
8217 requestPointerUnlock();
8218#endif
8219
8220#if ENABLE(SPEECH_SYNTHESIS)
8221 resetSpeechSynthesizer();
8222#endif
8223
8224#if ENABLE(WEB_AUTHN)
8225 m_websiteDataStore->authenticatorManager().cancelRequest(m_webPageID, std::nullopt);
8226#endif
8227
8228 m_speechRecognitionPermissionManager = nullptr;
8229
8230#if ENABLE(WEBXR) && !USE(OPENXR)
8231 if (m_xrSystem) {
8232 m_xrSystem->invalidate();
8233 m_xrSystem = nullptr;
8234 }
8235#endif
8236
8237#if ENABLE(MOMENTUM_EVENT_DISPATCHER)
8238 m_lastSentScrollingAccelerationCurve = std::nullopt;
8239#endif
8240}
8241
8242void WebPageProxy::resetStateAfterProcessExited(ProcessTerminationReason terminationReason)
8243{
8244 if (!hasRunningProcess())
8245 return;
8246
8247 PageClientProtector protector(pageClient());
8248
8249#if ASSERT_ENABLED
8250 // FIXME: It's weird that resetStateAfterProcessExited() is called even though the process is launching.
8251 if (terminationReason != ProcessTerminationReason::NavigationSwap)
8252 ASSERT(m_process->state() == WebProcessProxy::State::Launching || m_process->state() == WebProcessProxy::State::Terminated);
8253#endif
8254
8255#if PLATFORM(IOS_FAMILY)
8256 m_waitingForPostLayoutEditorStateUpdateAfterFocusingElement = false;
8257 m_isVisibleActivity = nullptr;
8258 m_isAudibleActivity = nullptr;
8259 m_isCapturingActivity = nullptr;
8260 m_openingAppLinkActivity = nullptr;
8261#endif
8262
8263 m_pageIsUserObservableCount = nullptr;
8264 m_visiblePageToken = nullptr;
8265
8266 m_hasRunningProcess = false;
8267 m_areActiveDOMObjectsAndAnimationsSuspended = false;
8268#if ENABLE(SERVICE_WORKER)
8269 m_isServiceWorkerPage = false;
8270#endif
8271
8272 m_userScriptsNotified = false;
8273 m_hasActiveAnimatedScroll = false;
8274 m_registeredForFullSpeedUpdates = false;
8275
8276 m_editorState = EditorState();
8277 m_cachedFontAttributesAtSelectionStart.reset();
8278
8279 if (terminationReason != ProcessTerminationReason::NavigationSwap)
8280 m_provisionalPage = nullptr;
8281
8282 if (terminationReason == ProcessTerminationReason::NavigationSwap)
8283 pageClient().processWillSwap();
8284 else
8285 pageClient().processDidExit();
8286
8287 pageClient().clearAllEditCommands();
8288
8289#if PLATFORM(COCOA)
8290 WebPasteboardProxy::singleton().revokeAccess(m_process.get());
8291#endif
8292
8293 auto resetStateReason = terminationReason == ProcessTerminationReason::NavigationSwap ? ResetStateReason::NavigationSwap : ResetStateReason::WebProcessExited;
8294 resetState(resetStateReason);
8295
8296 m_pendingLearnOrIgnoreWordMessageCount = 0;
8297
8298 // Can't expect DidReceiveEvent notifications from a crashed web process.
8299 m_mouseEventQueue.clear();
8300 m_keyEventQueue.clear();
8301 if (m_wheelEventCoalescer)
8302 m_wheelEventCoalescer->clear();
8303
8304#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
8305 m_touchEventQueue.clear();
8306#endif
8307
8308#if ENABLE(ATTACHMENT_ELEMENT)
8309 invalidateAllAttachments();
8310#endif
8311
8312#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
8313 if (m_scrollingCoordinatorProxy)
8314 m_scrollingCoordinatorProxy->resetStateAfterProcessExited();
8315#endif
8316
8317 if (terminationReason != ProcessTerminationReason::NavigationSwap) {
8318 PageLoadState::Transaction transaction = m_pageLoadState.transaction();
8319 m_pageLoadState.reset(transaction);
8320 }
8321
8322 updatePlayingMediaDidChange(MediaProducer::IsNotPlaying);
8323
8324#if ENABLE(VIDEO_PRESENTATION_MODE)
8325 m_fullscreenVideoTextRecognitionTimer.stop();
8326 m_currentFullscreenVideoSessionIdentifier = std::nullopt;
8327#endif
8328
8329 // FIXME: <rdar://problem/38676604> In case of process swaps, the old process should gracefully suspend instead of terminating.
8330 m_process->processTerminated();
8331}
8332
8333#if PLATFORM(COCOA)
8334
8335static Span<const ASCIILiteral> gpuIOKitClasses()
8336{
8337 static constexpr std::array services {
8338#if PLATFORM(IOS_FAMILY)
8339 "AGXDeviceUserClient"_s,
8340 "IOGPU"_s,
8341 "IOSurfaceRootUserClient"_s,
8342#endif
8343#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
8344 "AGPMClient"_s,
8345 "AppleGraphicsControlClient"_s,
8346 "AppleGraphicsPolicyClient"_s,
8347 "AppleIntelMEUserClient"_s,
8348 "AppleMGPUPowerControlClient"_s,
8349 "AppleSNBFBUserClient"_s,
8350 "AppleUpstreamUserClient"_s,
8351 "AudioAUUC"_s,
8352 "IOAccelerationUserClient"_s,
8353 "IOAccelerator"_s,
8354 "IOAudioControlUserClient"_s,
8355 "IOAudioEngineUserClient"_s,
8356 "IOSurfaceRootUserClient"_s,
8357#endif
8358 // FIXME: Is this also needed in PLATFORM(MACCATALYST)?
8359#if PLATFORM(MAC) && CPU(ARM64)
8360 "IOMobileFramebufferUserClient"_s,
8361#endif
8362#if (PLATFORM(MAC) && CPU(ARM64)) || PLATFORM(IOS_FAMILY)
8363 "IOSurfaceAcceleratorClient"_s,
8364#endif
8365 };
8366 return services;
8367}
8368
8369static Span<const ASCIILiteral> gpuMachServices()
8370{
8371 static constexpr std::array services {
8372 "com.apple.MTLCompilerService"_s,
8373#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
8374 "com.apple.cvmsServ"_s,
8375#endif
8376 };
8377 return services;
8378}
8379
8380#endif // PLATFORM(COCOA)
8381
8382WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& process, DrawingAreaProxy& drawingArea, RefPtr<API::WebsitePolicies>&& websitePolicies)
8383{
8384 WebPageCreationParameters parameters;
8385
8386 parameters.processDisplayName = configuration().processDisplayName();
8387
8388 parameters.viewSize = pageClient().viewSize();
8389 parameters.activityState = m_activityState;
8390 parameters.drawingAreaType = drawingArea.type();
8391 parameters.drawingAreaIdentifier = drawingArea.identifier();
8392 parameters.webPageProxyIdentifier = m_identifier;
8393 parameters.store = preferencesStore();
8394 parameters.pageGroupData = m_pageGroup->data();
8395 parameters.isEditable = m_isEditable;
8396 parameters.underlayColor = m_underlayColor;
8397 parameters.useFixedLayout = m_useFixedLayout;
8398 parameters.fixedLayoutSize = m_fixedLayoutSize;
8399 parameters.defaultUnobscuredSize = m_defaultUnobscuredSize;
8400 parameters.minimumUnobscuredSize = m_minimumUnobscuredSize;
8401 parameters.maximumUnobscuredSize = m_maximumUnobscuredSize;
8402 parameters.viewExposedRect = m_viewExposedRect;
8403 parameters.alwaysShowsHorizontalScroller = m_alwaysShowsHorizontalScroller;
8404 parameters.alwaysShowsVerticalScroller = m_alwaysShowsVerticalScroller;
8405 parameters.suppressScrollbarAnimations = m_suppressScrollbarAnimations;
8406 parameters.paginationMode = m_paginationMode;
8407 parameters.paginationBehavesLikeColumns = m_paginationBehavesLikeColumns;
8408 parameters.pageLength = m_pageLength;
8409 parameters.gapBetweenPages = m_gapBetweenPages;
8410 parameters.paginationLineGridEnabled = m_paginationLineGridEnabled;
8411 parameters.userAgent = userAgent();
8412 parameters.itemStatesWereRestoredByAPIRequest = m_sessionStateWasRestoredByAPIRequest;
8413 parameters.itemStates = m_backForwardList->itemStates();
8414 parameters.visitedLinkTableID = m_visitedLinkStore->identifier();
8415 parameters.canRunBeforeUnloadConfirmPanel = m_uiClient->canRunBeforeUnloadConfirmPanel();
8416 parameters.canRunModal = m_canRunModal;
8417 parameters.deviceScaleFactor = deviceScaleFactor();
8418 parameters.viewScaleFactor = m_viewScaleFactor;
8419 parameters.textZoomFactor = m_textZoomFactor;
8420 parameters.pageZoomFactor = m_pageZoomFactor;
8421 parameters.topContentInset = m_topContentInset;
8422 parameters.mediaVolume = m_mediaVolume;
8423 parameters.muted = m_mutedState;
8424 parameters.openedByDOM = m_openedByDOM;
8425 parameters.mayStartMediaWhenInWindow = m_mayStartMediaWhenInWindow;
8426 parameters.mediaPlaybackIsSuspended = m_mediaPlaybackIsSuspended;
8427 parameters.minimumSizeForAutoLayout = m_minimumSizeForAutoLayout;
8428 parameters.sizeToContentAutoSizeMaximumSize = m_sizeToContentAutoSizeMaximumSize;
8429 parameters.autoSizingShouldExpandToViewHeight = m_autoSizingShouldExpandToViewHeight;
8430 parameters.viewportSizeForCSSViewportUnits = m_viewportSizeForCSSViewportUnits;
8431 parameters.scrollPinningBehavior = m_scrollPinningBehavior;
8432 if (m_scrollbarOverlayStyle)
8433 parameters.scrollbarOverlayStyle = m_scrollbarOverlayStyle.value();
8434 else
8435 parameters.scrollbarOverlayStyle = std::nullopt;
8436 parameters.backgroundExtendsBeyondPage = m_backgroundExtendsBeyondPage;
8437 parameters.layerHostingMode = m_layerHostingMode;
8438 parameters.controlledByAutomation = m_controlledByAutomation;
8439 parameters.useDarkAppearance = useDarkAppearance();
8440 parameters.useElevatedUserInterfaceLevel = useElevatedUserInterfaceLevel();
8441#if PLATFORM(MAC)
8442 parameters.colorSpace = pageClient().colorSpace();
8443 parameters.useSystemAppearance = m_useSystemAppearance;
8444#endif
8445
8446#if ENABLE(META_VIEWPORT)
8447 parameters.ignoresViewportScaleLimits = m_forceAlwaysUserScalable;
8448 parameters.viewportConfigurationViewLayoutSize = m_viewportConfigurationViewLayoutSize;
8449 parameters.viewportConfigurationLayoutSizeScaleFactor = m_viewportConfigurationLayoutSizeScaleFactor;
8450 parameters.viewportConfigurationMinimumEffectiveDeviceWidth = m_viewportConfigurationMinimumEffectiveDeviceWidth;
8451 parameters.overrideViewportArguments = m_overrideViewportArguments;
8452#endif
8453
8454#if PLATFORM(IOS_FAMILY)
8455 parameters.screenSize = screenSize();
8456 parameters.availableScreenSize = availableScreenSize();
8457 parameters.overrideScreenSize = overrideScreenSize();
8458 parameters.textAutosizingWidth = textAutosizingWidth();
8459 parameters.mimeTypesWithCustomContentProviders = pageClient().mimeTypesWithCustomContentProviders();
8460 parameters.deviceOrientation = m_deviceOrientation;
8461 parameters.keyboardIsAttached = isInHardwareKeyboardMode();
8462 parameters.canShowWhileLocked = m_configuration->canShowWhileLocked();
8463#endif
8464
8465#if PLATFORM(COCOA)
8466 parameters.smartInsertDeleteEnabled = m_isSmartInsertDeleteEnabled;
8467 parameters.additionalSupportedImageTypes = m_configuration->additionalSupportedImageTypes();
8468
8469 if (!preferences().useGPUProcessForMediaEnabled()
8470 || (!preferences().captureVideoInGPUProcessEnabled() && !preferences().captureVideoInUIProcessEnabled())
8471 || (!preferences().captureAudioInGPUProcessEnabled() && !preferences().captureAudioInUIProcessEnabled())
8472 || !preferences().webRTCPlatformCodecsInGPUProcessEnabled()
8473 || !preferences().useGPUProcessForCanvasRenderingEnabled()
8474 || !preferences().useGPUProcessForWebGLEnabled()) {
8475 parameters.gpuIOKitExtensionHandles = SandboxExtension::createHandlesForIOKitClassExtensions(gpuIOKitClasses(), std::nullopt);
8476 parameters.gpuMachExtensionHandles = SandboxExtension::createHandlesForMachLookup(gpuMachServices(), std::nullopt);
8477 }
8478#endif
8479#if HAVE(STATIC_FONT_REGISTRY)
8480 if (preferences().shouldAllowUserInstalledFonts())
8481 parameters.fontMachExtensionHandle = process.fontdMachExtensionHandle(SandboxExtension::MachBootstrapOptions::DoNotEnableMachBootstrap);
8482#endif
8483#if HAVE(APP_ACCENT_COLORS)
8484 parameters.accentColor = pageClient().accentColor();
8485#endif
8486 parameters.shouldScaleViewToFitDocument = m_shouldScaleViewToFitDocument;
8487 parameters.userInterfaceLayoutDirection = pageClient().userInterfaceLayoutDirection();
8488 parameters.observedLayoutMilestones = m_observedLayoutMilestones;
8489 parameters.overrideContentSecurityPolicy = m_overrideContentSecurityPolicy;
8490 parameters.contentSecurityPolicyModeForExtension = m_configuration->contentSecurityPolicyModeForExtension();
8491 parameters.cpuLimit = m_cpuLimit;
8492
8493#if USE(WPE_RENDERER)
8494 parameters.hostFileDescriptor = pageClient().hostFileDescriptor();
8495#endif
8496
8497#if PLATFORM(WIN)
8498 parameters.nativeWindowHandle = reinterpret_cast<uint64_t>(viewWidget());
8499#endif
8500#if USE(GRAPHICS_LAYER_WC)
8501 parameters.usesOffscreenRendering = pageClient().usesOffscreenRendering();
8502#endif
8503
8504 for (auto& iterator : m_urlSchemeHandlersByScheme)
8505 parameters.urlSchemeHandlers.set(iterator.key, iterator.value->identifier());
8506 parameters.urlSchemesWithLegacyCustomProtocolHandlers = WebProcessPool::urlSchemesWithCustomProtocolHandlers();
8507
8508#if ENABLE(WEB_RTC)
8509 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8510 parameters.iceCandidateFilteringEnabled = m_preferences->iceCandidateFilteringEnabled();
8511#if USE(LIBWEBRTC)
8512 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8513 parameters.enumeratingAllNetworkInterfacesEnabled = m_preferences->enumeratingAllNetworkInterfacesEnabled();
8514#endif
8515#endif
8516
8517#if ENABLE(APPLICATION_MANIFEST)
8518 parameters.applicationManifest = m_configuration->applicationManifest() ? std::optional<WebCore::ApplicationManifest>(m_configuration->applicationManifest()->applicationManifest()) : std::nullopt;
8519#endif
8520
8521 parameters.needsFontAttributes = m_needsFontAttributes;
8522 parameters.backgroundColor = m_backgroundColor;
8523
8524 parameters.overriddenMediaType = m_overriddenMediaType;
8525 parameters.corsDisablingPatterns = corsDisablingPatterns();
8526 parameters.userScriptsShouldWaitUntilNotification = m_configuration->userScriptsShouldWaitUntilNotification();
8527 parameters.allowedNetworkHosts = m_configuration->allowedNetworkHosts();
8528 parameters.loadsSubresources = m_configuration->loadsSubresources();
8529 parameters.crossOriginAccessControlCheckEnabled = m_configuration->crossOriginAccessControlCheckEnabled();
8530 parameters.hasResourceLoadClient = !!m_resourceLoadClient;
8531
8532 std::reference_wrapper<WebUserContentControllerProxy> userContentController(m_userContentController.get());
8533 if (auto* userContentControllerFromWebsitePolicies = websitePolicies ? websitePolicies->userContentController() : nullptr)
8534 userContentController = *userContentControllerFromWebsitePolicies;
8535 process.addWebUserContentControllerProxy(userContentController);
8536 parameters.userContentControllerParameters = userContentController.get().parameters();
8537
8538 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8539 parameters.shouldCaptureAudioInUIProcess = preferences().captureAudioInUIProcessEnabled();
8540 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8541 parameters.shouldCaptureAudioInGPUProcess = preferences().captureAudioInGPUProcessEnabled();
8542 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8543 parameters.shouldCaptureVideoInUIProcess = preferences().captureVideoInUIProcessEnabled();
8544 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8545 parameters.shouldCaptureVideoInGPUProcess = preferences().captureVideoInGPUProcessEnabled();
8546 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8547 parameters.shouldRenderCanvasInGPUProcess = preferences().useGPUProcessForCanvasRenderingEnabled();
8548 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8549 parameters.shouldRenderDOMInGPUProcess = preferences().useGPUProcessForDOMRenderingEnabled();
8550 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8551 parameters.shouldPlayMediaInGPUProcess = preferences().useGPUProcessForMediaEnabled();
8552#if ENABLE(WEBGL)
8553 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8554 parameters.shouldRenderWebGLInGPUProcess = preferences().useGPUProcessForWebGLEnabled();
8555#endif
8556
8557 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8558 parameters.shouldEnableVP9Decoder = preferences().vp9DecoderEnabled();
8559#if ENABLE(VP9) && PLATFORM(COCOA)
8560 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8561 parameters.shouldEnableVP8Decoder = preferences().vp8DecoderEnabled();
8562 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8563 parameters.shouldEnableVP9SWDecoder = preferences().vp9DecoderEnabled() && (!WebCore::systemHasBattery() || preferences().vp9SWDecoderEnabledOnBattery());
8564#endif
8565 parameters.shouldCaptureDisplayInUIProcess = m_process->processPool().configuration().shouldCaptureDisplayInUIProcess();
8566 parameters.shouldCaptureDisplayInGPUProcess = preferences().useGPUProcessForDisplayCapture();
8567#if ENABLE(APP_BOUND_DOMAINS)
8568 parameters.limitsNavigationsToAppBoundDomains = m_limitsNavigationsToAppBoundDomains;
8569#endif
8570 parameters.lastNavigationWasAppInitiated = m_lastNavigationWasAppInitiated;
8571 parameters.shouldRelaxThirdPartyCookieBlocking = m_configuration->shouldRelaxThirdPartyCookieBlocking();
8572 parameters.canUseCredentialStorage = m_canUseCredentialStorage;
8573
8574 parameters.httpsUpgradeEnabled = preferences().upgradeKnownHostsToHTTPSEnabled() ? m_configuration->httpsUpgradeEnabled() : false;
8575
8576#if PLATFORM(IOS)
8577 // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
8578 parameters.allowsDeprecatedSynchronousXMLHttpRequestDuringUnload = allowsDeprecatedSynchronousXMLHttpRequestDuringUnload();
8579#endif
8580
8581#if ENABLE(APP_HIGHLIGHTS)
8582 parameters.appHighlightsVisible = appHighlightsVisibility() ? HighlightVisibility::Visible : HighlightVisibility::Hidden;
8583#endif
8584
8585#if HAVE(TOUCH_BAR)
8586 parameters.requiresUserActionForEditingControlsManager = m_configuration->requiresUserActionForEditingControlsManager();
8587#endif
8588
8589#if HAVE(UIKIT_RESIZABLE_WINDOWS)
8590 parameters.hasResizableWindows = pageClient().hasResizableWindows();
8591#endif
8592
8593 return parameters;
8594}
8595
8596void WebPageProxy::isJITEnabled(CompletionHandler<void(bool)>&& completionHandler)
8597{
8598 launchInitialProcessIfNecessary();
8599 sendWithAsyncReply(Messages::WebProcess::IsJITEnabled(), WTFMove(completionHandler), 0);
8600}
8601
8602void WebPageProxy::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
8603{
8604#if PLATFORM(MAC)
8605 ASSERT(m_drawingArea->type() == DrawingAreaType::TiledCoreAnimation);
8606#endif
8607 pageClient().enterAcceleratedCompositingMode(layerTreeContext);
8608}
8609
8610void WebPageProxy::didFirstLayerFlush(const LayerTreeContext& layerTreeContext)
8611{
8612#if PLATFORM(MAC)
8613 ASSERT(m_drawingArea->type() == DrawingAreaType::TiledCoreAnimation);
8614#endif
8615 pageClient().didFirstLayerFlush(layerTreeContext);
8616
8617 if (m_lastSuspendedPage)
8618 m_lastSuspendedPage->pageDidFirstLayerFlush();
8619 m_suspendedPageKeptToPreventFlashing = nullptr;
8620}
8621
8622void WebPageProxy::exitAcceleratedCompositingMode()
8623{
8624 pageClient().exitAcceleratedCompositingMode();
8625}
8626
8627void WebPageProxy::updateAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
8628{
8629 pageClient().updateAcceleratedCompositingMode(layerTreeContext);
8630}
8631
8632void WebPageProxy::backForwardClear()
8633{
8634 m_backForwardList->clear();
8635}
8636
8637#if ENABLE(GAMEPAD)
8638
8639void WebPageProxy::gamepadActivity(const Vector<GamepadData>& gamepadDatas, EventMakesGamepadsVisible eventVisibility)
8640{
8641 send(Messages::WebPage::GamepadActivity(gamepadDatas, eventVisibility));
8642}
8643
8644#endif
8645
8646void WebPageProxy::didReceiveAuthenticationChallengeProxy(Ref<AuthenticationChallengeProxy>&& authenticationChallenge, NegotiatedLegacyTLS negotiatedLegacyTLS)
8647{
8648 if (negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes) {
8649 m_navigationClient->shouldAllowLegacyTLS(*this, authenticationChallenge.get(), [this, protectedThis = Ref { *this }, authenticationChallenge] (bool shouldAllowLegacyTLS) {
8650 if (shouldAllowLegacyTLS)
8651 m_navigationClient->didReceiveAuthenticationChallenge(*this, authenticationChallenge.get());
8652 else
8653 authenticationChallenge->listener().completeChallenge(AuthenticationChallengeDisposition::Cancel);
8654 });
8655 return;
8656 }
8657 m_navigationClient->didReceiveAuthenticationChallenge(*this, authenticationChallenge.get());
8658}
8659
8660void WebPageProxy::negotiatedLegacyTLS()
8661{
8662 auto transaction = m_pageLoadState.transaction();
8663 m_pageLoadState.negotiatedLegacyTLS(transaction);
8664}
8665
8666void WebPageProxy::didNegotiateModernTLS(const URL& url)
8667{
8668 m_navigationClient->didNegotiateModernTLS(url);
8669}
8670
8671void WebPageProxy::exceededDatabaseQuota(FrameIdentifier 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)
8672{
8673 requestStorageSpace(frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, [reply = WTFMove(reply)](auto quota) mutable {
8674 reply(quota);
8675 });
8676}
8677
8678void WebPageProxy::requestStorageSpace(FrameIdentifier 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)
8679{
8680 WEBPAGEPROXY_RELEASE_LOG(Storage, "requestStorageSpace for frame %" PRIu64 ", current quota %" PRIu64 " current usage %" PRIu64 " expected usage %" PRIu64, frameID.toUInt64(), currentQuota, currentDatabaseUsage, expectedUsage);
8681
8682 StorageRequests::singleton().processOrAppend([this, protectedThis = Ref { *this }, pageURL = currentURL(), frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, completionHandler = WTFMove(completionHandler)]() mutable {
8683 this->makeStorageSpaceRequest(frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, [this, protectedThis = WTFMove(protectedThis), frameID, pageURL = WTFMove(pageURL), completionHandler = WTFMove(completionHandler), currentQuota](auto quota) mutable {
8684
8685 WEBPAGEPROXY_RELEASE_LOG(Storage, "requestStorageSpace response for frame %" PRIu64 ", quota %" PRIu64, frameID.toUInt64(), quota);
8686 UNUSED_VARIABLE(frameID);
8687
8688 if (quota <= currentQuota && this->currentURL() == pageURL) {
8689 WEBPAGEPROXY_RELEASE_LOG(Storage, "storage space increase denied");
8690 m_isQuotaIncreaseDenied = true;
8691 }
8692 completionHandler(quota);
8693 StorageRequests::singleton().processNextIfAny();
8694 });
8695 });
8696}
8697
8698void WebPageProxy::makeStorageSpaceRequest(FrameIdentifier 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)
8699{
8700 if (m_isQuotaIncreaseDenied) {
8701 completionHandler(currentQuota);
8702 return;
8703 }
8704
8705 WebFrameProxy* frame = m_process->webFrame(frameID);
8706 MESSAGE_CHECK(m_process, frame);
8707
8708 auto originData = SecurityOriginData::fromDatabaseIdentifier(originIdentifier);
8709 if (originData != SecurityOriginData::fromURL(URL { currentURL() })) {
8710 completionHandler(currentQuota);
8711 return;
8712 }
8713
8714 auto origin = API::SecurityOrigin::create(originData->securityOrigin());
8715 m_uiClient->exceededDatabaseQuota(this, frame, origin.ptr(), databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, WTFMove(completionHandler));
8716}
8717
8718void WebPageProxy::reachedApplicationCacheOriginQuota(const String& originIdentifier, uint64_t currentQuota, uint64_t totalBytesNeeded, Messages::WebPageProxy::ReachedApplicationCacheOriginQuota::DelayedReply&& reply)
8719{
8720 auto securityOriginData = SecurityOriginData::fromDatabaseIdentifier(originIdentifier);
8721 MESSAGE_CHECK(m_process, securityOriginData);
8722
8723 Ref<SecurityOrigin> securityOrigin = securityOriginData->securityOrigin();
8724 m_uiClient->reachedApplicationCacheOriginQuota(this, securityOrigin.get(), currentQuota, totalBytesNeeded, WTFMove(reply));
8725}
8726
8727void WebPageProxy::requestGeolocationPermissionForFrame(GeolocationIdentifier geolocationID, FrameInfoData&& frameInfo)
8728{
8729 MESSAGE_CHECK(m_process, frameInfo.frameID);
8730 auto* frame = m_process->webFrame(*frameInfo.frameID);
8731 MESSAGE_CHECK(m_process, frame);
8732
8733 auto request = m_geolocationPermissionRequestManager.createRequest(geolocationID);
8734 Function<void(bool)> completionHandler = [request = WTFMove(request)](bool allowed) {
8735 if (allowed)
8736 request->allow();
8737 else
8738 request->deny();
8739 };
8740
8741 // FIXME: Once iOS migrates to the new WKUIDelegate SPI, clean this up
8742 // and make it one UIClient call that calls the completionHandler with false
8743 // if there is no delegate instead of returning the completionHandler
8744 // for other code paths to try.
8745 m_uiClient->decidePolicyForGeolocationPermissionRequest(*this, *frame, frameInfo, completionHandler);
8746#if PLATFORM(IOS_FAMILY)
8747 if (completionHandler)
8748 pageClient().decidePolicyForGeolocationPermissionRequest(*frame, frameInfo, completionHandler);
8749#endif
8750 if (completionHandler)
8751 completionHandler(false);
8752}
8753
8754void WebPageProxy::revokeGeolocationAuthorizationToken(const String& authorizationToken)
8755{
8756 m_geolocationPermissionRequestManager.revokeAuthorizationToken(authorizationToken);
8757}
8758
8759void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const PermissionDescriptor& descriptor, CompletionHandler<void(std::optional<PermissionState>, bool shouldCache)>&& completionHandler)
8760{
8761 bool canAPISucceed = true;
8762 bool shouldChangeDeniedToPrompt = true;
8763 bool shouldChangePromptToGrant = false;
8764 String name;
8765 if (descriptor.name == PermissionName::Camera) {
8766#if ENABLE(MEDIA_STREAM)
8767 name = "camera"_s;
8768 canAPISucceed = userMediaPermissionRequestManager().canVideoCaptureSucceed();
8769 shouldChangeDeniedToPrompt = userMediaPermissionRequestManager().shouldChangeDeniedToPromptForCamera(clientOrigin);
8770 shouldChangePromptToGrant = userMediaPermissionRequestManager().shouldChangePromptToGrantForCamera(clientOrigin);
8771#endif
8772 } else if (descriptor.name == PermissionName::Microphone) {
8773#if ENABLE(MEDIA_STREAM)
8774 name = "microphone"_s;
8775 canAPISucceed = userMediaPermissionRequestManager().canAudioCaptureSucceed();
8776 shouldChangeDeniedToPrompt = userMediaPermissionRequestManager().shouldChangeDeniedToPromptForMicrophone(clientOrigin);
8777 shouldChangePromptToGrant = userMediaPermissionRequestManager().shouldChangePromptToGrantForMicrophone(clientOrigin);
8778#endif
8779 } else if (descriptor.name == PermissionName::Geolocation) {
8780#if ENABLE(GEOLOCATION)
8781 name = "geolocation"_s;
8782#endif
8783 }
8784
8785 if (name.isNull()) {
8786 completionHandler({ }, false);
8787 return;
8788 }
8789
8790 if (!canAPISucceed) {
8791 completionHandler(shouldChangeDeniedToPrompt ? PermissionState::Prompt : PermissionState::Denied, false);
8792 return;
8793 }
8794
8795 auto origin = API::SecurityOrigin::create(clientOrigin.topOrigin);
8796 m_uiClient->queryPermission(name, origin, [clientOrigin, shouldChangeDeniedToPrompt, shouldChangePromptToGrant, completionHandler = WTFMove(completionHandler)](auto result) mutable {
8797 if (!result) {
8798 completionHandler({ }, false);
8799 return;
8800 }
8801 if (*result == PermissionState::Denied && shouldChangeDeniedToPrompt)
8802 result = PermissionState::Prompt;
8803 else if (*result == PermissionState::Prompt && shouldChangePromptToGrant)
8804 result = PermissionState::Granted;
8805 completionHandler(*result, false);
8806 });
8807}
8808
8809#if ENABLE(MEDIA_STREAM)
8810UserMediaPermissionRequestManagerProxy& WebPageProxy::userMediaPermissionRequestManager()
8811{
8812 if (m_userMediaPermissionRequestManager)
8813 return *m_userMediaPermissionRequestManager;
8814
8815 m_userMediaPermissionRequestManager = makeUnique<UserMediaPermissionRequestManagerProxy>(*this);
8816
8817 return *m_userMediaPermissionRequestManager;
8818}
8819
8820void WebPageProxy::setMockCaptureDevicesEnabledOverride(std::optional<bool> enabled)
8821{
8822 userMediaPermissionRequestManager().setMockCaptureDevicesEnabledOverride(enabled);
8823}
8824
8825void WebPageProxy::willStartCapture(const UserMediaPermissionRequestProxy& request, CompletionHandler<void()>&& callback)
8826{
8827#if ENABLE(GPU_PROCESS)
8828 if (!preferences().captureVideoInGPUProcessEnabled() && !preferences().captureAudioInGPUProcessEnabled())
8829 return callback();
8830
8831 auto& gpuProcess = process().processPool().ensureGPUProcess();
8832 gpuProcess.updateCaptureAccess(request.requiresAudioCapture(), request.requiresVideoCapture(), request.requiresDisplayCapture(), m_process->coreProcessIdentifier(), WTFMove(callback));
8833 gpuProcess.updateCaptureOrigin(request.topLevelDocumentSecurityOrigin().data(), m_process->coreProcessIdentifier());
8834#if PLATFORM(IOS_FAMILY)
8835 gpuProcess.setOrientationForMediaCapture(m_deviceOrientation);
8836#endif
8837#else
8838 callback();
8839#endif
8840}
8841
8842#endif
8843
8844void WebPageProxy::requestUserMediaPermissionForFrame(UserMediaRequestIdentifier userMediaID, FrameIdentifier frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginData, const WebCore::SecurityOriginData& topLevelDocumentOriginData, WebCore::MediaStreamRequest&& request)
8845{
8846#if ENABLE(MEDIA_STREAM)
8847 MESSAGE_CHECK(m_process, m_process->webFrame(frameID));
8848#if PLATFORM(MAC)
8849 CoreAudioCaptureDeviceManager::singleton().setFilterTapEnabledDevices(!preferences().captureAudioInGPUProcessEnabled());
8850#endif
8851 userMediaPermissionRequestManager().requestUserMediaPermissionForFrame(userMediaID, frameID, userMediaDocumentOriginData.securityOrigin(), topLevelDocumentOriginData.securityOrigin(), WTFMove(request));
8852#else
8853 UNUSED_PARAM(userMediaID);
8854 UNUSED_PARAM(frameID);
8855 UNUSED_PARAM(userMediaDocumentOriginData);
8856 UNUSED_PARAM(topLevelDocumentOriginData);
8857 UNUSED_PARAM(request);
8858#endif
8859}
8860
8861void WebPageProxy::enumerateMediaDevicesForFrame(FrameIdentifier frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginData, const WebCore::SecurityOriginData& topLevelDocumentOriginData, CompletionHandler<void(const Vector<CaptureDevice>&, const String&)>&& completionHandler)
8862{
8863#if ENABLE(MEDIA_STREAM)
8864 WebFrameProxy* frame = m_process->webFrame(frameID);
8865 MESSAGE_CHECK(m_process, frame);
8866
8867 userMediaPermissionRequestManager().enumerateMediaDevicesForFrame(frameID, userMediaDocumentOriginData.securityOrigin(), topLevelDocumentOriginData.securityOrigin(), WTFMove(completionHandler));
8868#else
8869 UNUSED_PARAM(frameID);
8870 UNUSED_PARAM(userMediaDocumentOriginData);
8871 UNUSED_PARAM(topLevelDocumentOriginData);
8872 UNUSED_PARAM(completionHandler);
8873#endif
8874}
8875
8876void WebPageProxy::syncIfMockDevicesEnabledChanged()
8877{
8878#if ENABLE(MEDIA_STREAM)
8879 userMediaPermissionRequestManager().syncWithWebCorePrefs();
8880#endif
8881}
8882
8883void WebPageProxy::beginMonitoringCaptureDevices()
8884{
8885#if ENABLE(MEDIA_STREAM)
8886 userMediaPermissionRequestManager().syncWithWebCorePrefs();
8887 UserMediaProcessManager::singleton().beginMonitoringCaptureDevices();
8888#endif
8889}
8890
8891void WebPageProxy::clearUserMediaState()
8892{
8893#if ENABLE(MEDIA_STREAM)
8894 if (m_userMediaPermissionRequestManager)
8895 m_userMediaPermissionRequestManager->clearCachedState();
8896#endif
8897}
8898
8899void WebPageProxy::requestMediaKeySystemPermissionForFrame(MediaKeySystemRequestIdentifier mediaKeySystemID, FrameIdentifier frameID, const WebCore::SecurityOriginData& topLevelDocumentOriginData, const String& keySystem)
8900{
8901#if ENABLE(ENCRYPTED_MEDIA)
8902 MESSAGE_CHECK(m_process, m_process->webFrame(frameID));
8903
8904 auto origin = API::SecurityOrigin::create(topLevelDocumentOriginData.securityOrigin());
8905 auto request = mediaKeySystemPermissionRequestManager().createRequestForFrame(mediaKeySystemID, frameID, topLevelDocumentOriginData.securityOrigin(), keySystem);
8906 m_uiClient->decidePolicyForMediaKeySystemPermissionRequest(*this, origin, keySystem, [request = WTFMove(request)](bool allowed) {
8907 if (allowed)
8908 request->allow();
8909 else
8910 request->deny();
8911 });
8912#else
8913 UNUSED_PARAM(mediaKeySystemID);
8914 UNUSED_PARAM(frameID);
8915 UNUSED_PARAM(topLevelDocumentOriginData);
8916 UNUSED_PARAM(keySystem);
8917#endif
8918}
8919
8920#if ENABLE(DEVICE_ORIENTATION)
8921void WebPageProxy::shouldAllowDeviceOrientationAndMotionAccess(FrameIdentifier frameID, FrameInfoData&& frameInfo, bool mayPrompt, CompletionHandler<void(DeviceOrientationOrMotionPermissionState)>&& completionHandler)
8922{
8923 WebFrameProxy* frame = m_process->webFrame(frameID);
8924 MESSAGE_CHECK(m_process, frame);
8925
8926 websiteDataStore().deviceOrientationAndMotionAccessController().shouldAllowAccess(*this, *frame, WTFMove(frameInfo), mayPrompt, WTFMove(completionHandler));
8927}
8928#endif
8929
8930
8931#if ENABLE(IMAGE_ANALYSIS)
8932
8933void WebPageProxy::requestTextRecognition(const URL& imageURL, const ShareableBitmap::Handle& imageData, const String& sourceLanguageIdentifier, const String& targetLanguageIdentifier, CompletionHandler<void(TextRecognitionResult&&)>&& completionHandler)
8934{
8935 pageClient().requestTextRecognition(imageURL, imageData, sourceLanguageIdentifier, targetLanguageIdentifier, WTFMove(completionHandler));
8936}
8937
8938void WebPageProxy::computeHasVisualSearchResults(const URL& imageURL, ShareableBitmap& imageBitmap, CompletionHandler<void(bool)>&& completion)
8939{
8940 pageClient().computeHasVisualSearchResults(imageURL, imageBitmap, WTFMove(completion));
8941}
8942
8943void WebPageProxy::updateWithTextRecognitionResult(TextRecognitionResult&& results, const ElementContext& context, const FloatPoint& location, CompletionHandler<void(TextRecognitionUpdateResult)>&& completionHandler)
8944{
8945 if (!hasRunningProcess()) {
8946 completionHandler(TextRecognitionUpdateResult::NoText);
8947 return;
8948 }
8949
8950 sendWithAsyncReply(Messages::WebPage::UpdateWithTextRecognitionResult(WTFMove(results), context, location), WTFMove(completionHandler));
8951}
8952
8953void WebPageProxy::startVisualTranslation(const String& sourceLanguageIdentifier, const String& targetLanguageIdentifier)
8954{
8955 if (hasRunningProcess())
8956 send(Messages::WebPage::StartVisualTranslation(sourceLanguageIdentifier, targetLanguageIdentifier));
8957}
8958
8959#endif // ENABLE(IMAGE_ANALYSIS)
8960
8961void WebPageProxy::requestImageBitmap(const ElementContext& elementContext, CompletionHandler<void(const ShareableBitmap::Handle&, const String&)>&& completion)
8962{
8963 if (!hasRunningProcess()) {
8964 completion({ }, { });
8965 return;
8966 }
8967
8968 sendWithAsyncReply(Messages::WebPage::RequestImageBitmap(elementContext), WTFMove(completion));
8969}
8970
8971#if ENABLE(ENCRYPTED_MEDIA)
8972MediaKeySystemPermissionRequestManagerProxy& WebPageProxy::mediaKeySystemPermissionRequestManager()
8973{
8974 if (m_mediaKeySystemPermissionRequestManager)
8975 return *m_mediaKeySystemPermissionRequestManager;
8976
8977 m_mediaKeySystemPermissionRequestManager = makeUnique<MediaKeySystemPermissionRequestManagerProxy>(*this);
8978 return *m_mediaKeySystemPermissionRequestManager;
8979}
8980#endif
8981
8982#if ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
8983
8984void WebPageProxy::showMediaControlsContextMenu(FloatRect&& targetFrame, Vector<MediaControlsContextMenuItem>&& items, CompletionHandler<void(MediaControlsContextMenuItem::ID)>&& completionHandler)
8985{
8986 pageClient().showMediaControlsContextMenu(WTFMove(targetFrame), WTFMove(items), WTFMove(completionHandler));
8987}
8988
8989#endif // ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
8990
8991
8992void WebPageProxy::requestNotificationPermission(const String& originString, CompletionHandler<void(bool allowed)>&& completionHandler)
8993{
8994 auto origin = API::SecurityOrigin::createFromString(originString);
8995 m_uiClient->decidePolicyForNotificationPermissionRequest(*this, origin.get(), WTFMove(completionHandler));
8996}
8997
8998void WebPageProxy::showNotification(IPC::Connection& connection, const WebCore::NotificationData& notificationData)
8999{
9000 m_process->processPool().supplement<WebNotificationManagerProxy>()->show(this, connection, notificationData);
9001}
9002
9003void WebPageProxy::cancelNotification(const UUID& notificationID)
9004{
9005 m_process->processPool().supplement<WebNotificationManagerProxy>()->cancel(this, notificationID);
9006}
9007
9008void WebPageProxy::clearNotifications(const Vector<UUID>& notificationIDs)
9009{
9010 m_process->processPool().supplement<WebNotificationManagerProxy>()->clearNotifications(this, notificationIDs);
9011}
9012
9013void WebPageProxy::didDestroyNotification(const UUID& notificationID)
9014{
9015 m_process->processPool().supplement<WebNotificationManagerProxy>()->didDestroyNotification(this, notificationID);
9016}
9017
9018float WebPageProxy::headerHeightForPrinting(WebFrameProxy& frame)
9019{
9020 if (frame.isDisplayingPDFDocument())
9021 return 0;
9022 return m_uiClient->headerHeight(*this, frame);
9023}
9024
9025float WebPageProxy::footerHeightForPrinting(WebFrameProxy& frame)
9026{
9027 if (frame.isDisplayingPDFDocument())
9028 return 0;
9029 return m_uiClient->footerHeight(*this, frame);
9030}
9031
9032void WebPageProxy::drawHeaderForPrinting(WebFrameProxy& frame, FloatRect&& rect)
9033{
9034 if (frame.isDisplayingPDFDocument())
9035 return;
9036 m_uiClient->drawHeader(*this, frame, WTFMove(rect));
9037}
9038
9039void WebPageProxy::drawFooterForPrinting(WebFrameProxy& frame, FloatRect&& rect)
9040{
9041 if (frame.isDisplayingPDFDocument())
9042 return;
9043 m_uiClient->drawFooter(*this, frame, WTFMove(rect));
9044}
9045
9046void WebPageProxy::runModal()
9047{
9048 // Since runModal() can (and probably will) spin a nested run loop we need to turn off the responsiveness timer.
9049 m_process->stopResponsivenessTimer();
9050
9051 // Our Connection's run loop might have more messages waiting to be handled after this RunModal message.
9052 // To make sure they are handled inside of the nested modal run loop we must first signal the Connection's
9053 // run loop so we're guaranteed that it has a chance to wake up.
9054 // See http://webkit.org/b/89590 for more discussion.
9055 m_process->connection()->wakeUpRunLoop();
9056
9057 m_uiClient->runModal(*this);
9058}
9059
9060void WebPageProxy::notifyScrollerThumbIsVisibleInRect(const IntRect& scrollerThumb)
9061{
9062 m_visibleScrollerThumbRect = scrollerThumb;
9063}
9064
9065void WebPageProxy::recommendedScrollbarStyleDidChange(int32_t newStyle)
9066{
9067#if USE(APPKIT)
9068 pageClient().recommendedScrollbarStyleDidChange(static_cast<WebCore::ScrollbarStyle>(newStyle));
9069#else
9070 UNUSED_PARAM(newStyle);
9071#endif
9072}
9073
9074void WebPageProxy::didChangeScrollbarsForMainFrame(bool hasHorizontalScrollbar, bool hasVerticalScrollbar)
9075{
9076 m_mainFrameHasHorizontalScrollbar = hasHorizontalScrollbar;
9077 m_mainFrameHasVerticalScrollbar = hasVerticalScrollbar;
9078}
9079
9080void WebPageProxy::didChangeScrollOffsetPinningForMainFrame(RectEdges<bool> pinnedState)
9081{
9082 pageClient().pinnedStateWillChange();
9083 m_mainFramePinnedState = pinnedState;
9084 pageClient().pinnedStateDidChange();
9085
9086 m_uiClient->pinnedStateDidChange(*this);
9087}
9088
9089void WebPageProxy::didChangePageCount(unsigned pageCount)
9090{
9091 m_pageCount = pageCount;
9092}
9093
9094void WebPageProxy::themeColorChanged(const Color& themeColor)
9095{
9096 if (m_themeColor == themeColor)
9097 return;
9098
9099 pageClient().themeColorWillChange();
9100 m_themeColor = themeColor;
9101 pageClient().themeColorDidChange();
9102}
9103
9104void WebPageProxy::pageExtendedBackgroundColorDidChange(const Color& newPageExtendedBackgroundColor)
9105{
9106 if (m_pageExtendedBackgroundColor == newPageExtendedBackgroundColor)
9107 return;
9108
9109 auto oldUnderPageBackgroundColor = underPageBackgroundColor();
9110 auto oldPageExtendedBackgroundColor = std::exchange(m_pageExtendedBackgroundColor, newPageExtendedBackgroundColor);
9111 bool changesUnderPageBackgroundColor = !equalIgnoringSemanticColor(oldUnderPageBackgroundColor, underPageBackgroundColor());
9112 m_pageExtendedBackgroundColor = WTFMove(oldPageExtendedBackgroundColor);
9113
9114 if (changesUnderPageBackgroundColor)
9115 pageClient().underPageBackgroundColorWillChange();
9116 pageClient().pageExtendedBackgroundColorWillChange();
9117
9118 m_pageExtendedBackgroundColor = newPageExtendedBackgroundColor;
9119
9120 if (changesUnderPageBackgroundColor)
9121 pageClient().underPageBackgroundColorDidChange();
9122 pageClient().pageExtendedBackgroundColorDidChange();
9123}
9124
9125void WebPageProxy::sampledPageTopColorChanged(const Color& sampledPageTopColor)
9126{
9127 if (m_sampledPageTopColor == sampledPageTopColor)
9128 return;
9129
9130 pageClient().sampledPageTopColorWillChange();
9131 m_sampledPageTopColor = sampledPageTopColor;
9132 pageClient().sampledPageTopColorDidChange();
9133}
9134
9135#if !PLATFORM(COCOA)
9136
9137Color WebPageProxy::platformUnderPageBackgroundColor() const
9138{
9139 return Color::transparentBlack;
9140}
9141
9142#endif // !PLATFORM(COCOA)
9143
9144bool WebPageProxy::willHandleHorizontalScrollEvents() const
9145{
9146 return !m_canShortCircuitHorizontalWheelEvents;
9147}
9148
9149void WebPageProxy::updateWebsitePolicies(WebsitePoliciesData&& websitePolicies)
9150{
9151 send(Messages::WebPage::UpdateWebsitePolicies(websitePolicies));
9152}
9153
9154void WebPageProxy::notifyUserScripts()
9155{
9156 m_userScriptsNotified = true;
9157 send(Messages::WebPage::NotifyUserScripts());
9158}
9159
9160bool WebPageProxy::userScriptsNeedNotification() const
9161{
9162 if (!m_configuration->userScriptsShouldWaitUntilNotification())
9163 return false;
9164 return !m_userScriptsNotified;
9165}
9166
9167void WebPageProxy::didFinishLoadingDataForCustomContentProvider(const String& suggestedFilename, const IPC::DataReference& dataReference)
9168{
9169 pageClient().didFinishLoadingDataForCustomContentProvider(ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), dataReference);
9170}
9171
9172void WebPageProxy::backForwardRemovedItem(const BackForwardItemIdentifier& itemID)
9173{
9174 send(Messages::WebPage::DidRemoveBackForwardItem(itemID));
9175}
9176
9177void WebPageProxy::setCanRunModal(bool canRunModal)
9178{
9179 // It's only possible to change the state for a WebPage which
9180 // already qualifies for running modal child web pages, otherwise
9181 // there's no other possibility than not allowing it.
9182 m_canRunModal = m_uiClient->canRunModal() && canRunModal;
9183
9184 if (!hasRunningProcess())
9185 return;
9186
9187 send(Messages::WebPage::SetCanRunModal(m_canRunModal));
9188}
9189
9190bool WebPageProxy::canRunModal()
9191{
9192 return hasRunningProcess() ? m_canRunModal : false;
9193}
9194
9195void WebPageProxy::beginPrinting(WebFrameProxy* frame, const PrintInfo& printInfo)
9196{
9197 if (m_isInPrintingMode)
9198 return;
9199
9200 m_isInPrintingMode = true;
9201 send(Messages::WebPage::BeginPrinting(frame->frameID(), printInfo), printingSendOptions(m_isPerformingDOMPrintOperation));
9202}
9203
9204void WebPageProxy::endPrinting()
9205{
9206 if (!m_isInPrintingMode)
9207 return;
9208
9209 m_isInPrintingMode = false;
9210 send(Messages::WebPage::EndPrinting(), printingSendOptions(m_isPerformingDOMPrintOperation));
9211}
9212
9213uint64_t WebPageProxy::computePagesForPrinting(FrameIdentifier frameID, const PrintInfo& printInfo, CompletionHandler<void(const Vector<WebCore::IntRect>&, double, const WebCore::FloatBoxExtent&)>&& callback)
9214{
9215 m_isInPrintingMode = true;
9216 return sendWithAsyncReply(Messages::WebPage::ComputePagesForPrinting(frameID, printInfo), WTFMove(callback), printingSendOptions(m_isPerformingDOMPrintOperation));
9217}
9218
9219#if PLATFORM(COCOA)
9220uint64_t WebPageProxy::drawRectToImage(WebFrameProxy* frame, const PrintInfo& printInfo, const IntRect& rect, const WebCore::IntSize& imageSize, CompletionHandler<void(const WebKit::ShareableBitmap::Handle&)>&& callback)
9221{
9222 return sendWithAsyncReply(Messages::WebPage::DrawRectToImage(frame->frameID(), printInfo, rect, imageSize), WTFMove(callback), printingSendOptions(m_isPerformingDOMPrintOperation));
9223}
9224
9225uint64_t WebPageProxy::drawPagesToPDF(WebFrameProxy* frame, const PrintInfo& printInfo, uint32_t first, uint32_t count, CompletionHandler<void(API::Data*)>&& callback)
9226{
9227 return sendWithAsyncReply(Messages::WebPage::DrawPagesToPDF(frame->frameID(), printInfo, first, count), toAPIDataSharedBufferCallback(WTFMove(callback)), printingSendOptions(m_isPerformingDOMPrintOperation));
9228}
9229#elif PLATFORM(GTK)
9230void WebPageProxy::drawPagesForPrinting(WebFrameProxy* frame, const PrintInfo& printInfo, CompletionHandler<void(API::Error*)>&& callback)
9231{
9232 auto callbackWrapper = [callback = WTFMove(callback)] (const WebCore::ResourceError& error) mutable {
9233 if (error.isNull())
9234 return callback(nullptr);
9235 callback(API::Error::create(error).ptr());
9236 };
9237 m_isInPrintingMode = true;
9238 sendWithAsyncReply(Messages::WebPage::DrawPagesForPrinting(frame->frameID(), printInfo), WTFMove(callbackWrapper), printingSendOptions(m_isPerformingDOMPrintOperation));
9239}
9240#endif
9241
9242#if PLATFORM(COCOA)
9243void WebPageProxy::drawToPDF(FrameIdentifier frameID, const std::optional<FloatRect>& rect, CompletionHandler<void(RefPtr<SharedBuffer>&&)>&& callback)
9244{
9245 if (!hasRunningProcess()) {
9246 callback({ });
9247 return;
9248 }
9249 sendWithAsyncReply(Messages::WebPage::DrawToPDF(frameID, rect), WTFMove(callback));
9250}
9251#endif // PLATFORM(COCOA)
9252
9253void WebPageProxy::getPDFFirstPageSize(WebCore::FrameIdentifier frameID, CompletionHandler<void(WebCore::FloatSize)>&& completionHandler)
9254{
9255 sendWithAsyncReply(Messages::WebPage::GetPDFFirstPageSize(frameID), WTFMove(completionHandler));
9256}
9257
9258void WebPageProxy::updateBackingStoreDiscardableState()
9259{
9260 ASSERT(hasRunningProcess());
9261
9262 if (!m_drawingArea)
9263 return;
9264
9265 bool isDiscardable;
9266
9267 if (!m_process->isResponsive())
9268 isDiscardable = false;
9269 else
9270 isDiscardable = !pageClient().isViewWindowActive() || !isViewVisible();
9271
9272 m_drawingArea->setBackingStoreIsDiscardable(isDiscardable);
9273}
9274
9275void WebPageProxy::saveDataToFileInDownloadsFolder(String&& suggestedFilename, String&& mimeType, URL&& originatingURLString, API::Data& data)
9276{
9277 m_uiClient->saveDataToFileInDownloadsFolder(this, ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), mimeType, originatingURLString, data);
9278}
9279
9280void WebPageProxy::savePDFToFileInDownloadsFolder(String&& suggestedFilename, URL&& originatingURL, const IPC::DataReference& dataReference)
9281{
9282 String sanitizedFilename = ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename);
9283 if (!sanitizedFilename.endsWithIgnoringASCIICase(".pdf"_s))
9284 return;
9285
9286 saveDataToFileInDownloadsFolder(WTFMove(sanitizedFilename), "application/pdf"_s, WTFMove(originatingURL),
9287 API::Data::create(dataReference.data(), dataReference.size()).get());
9288}
9289
9290void WebPageProxy::setMinimumSizeForAutoLayout(const IntSize& size)
9291{
9292 if (m_minimumSizeForAutoLayout == size)
9293 return;
9294
9295 m_minimumSizeForAutoLayout = size;
9296
9297 if (!hasRunningProcess())
9298 return;
9299
9300 send(Messages::WebPage::SetMinimumSizeForAutoLayout(size));
9301 m_drawingArea->minimumSizeForAutoLayoutDidChange();
9302
9303#if USE(APPKIT)
9304 if (m_minimumSizeForAutoLayout.width() <= 0)
9305 didChangeIntrinsicContentSize(IntSize(-1, -1));
9306#endif
9307}
9308
9309void WebPageProxy::setSizeToContentAutoSizeMaximumSize(const IntSize& size)
9310{
9311 if (m_sizeToContentAutoSizeMaximumSize == size)
9312 return;
9313
9314 m_sizeToContentAutoSizeMaximumSize = size;
9315
9316 if (!hasRunningProcess())
9317 return;
9318
9319 send(Messages::WebPage::SetSizeToContentAutoSizeMaximumSize(size));
9320 m_drawingArea->sizeToContentAutoSizeMaximumSizeDidChange();
9321
9322#if USE(APPKIT)
9323 if (m_sizeToContentAutoSizeMaximumSize.width() <= 0)
9324 didChangeIntrinsicContentSize(IntSize(-1, -1));
9325#endif
9326}
9327
9328void WebPageProxy::setAutoSizingShouldExpandToViewHeight(bool shouldExpand)
9329{
9330 if (m_autoSizingShouldExpandToViewHeight == shouldExpand)
9331 return;
9332
9333 m_autoSizingShouldExpandToViewHeight = shouldExpand;
9334
9335 if (!hasRunningProcess())
9336 return;
9337
9338 send(Messages::WebPage::SetAutoSizingShouldExpandToViewHeight(shouldExpand));
9339}
9340
9341void WebPageProxy::setViewportSizeForCSSViewportUnits(const FloatSize& viewportSize)
9342{
9343 if (m_viewportSizeForCSSViewportUnits && *m_viewportSizeForCSSViewportUnits == viewportSize)
9344 return;
9345
9346 m_viewportSizeForCSSViewportUnits = viewportSize;
9347
9348 if (!hasRunningProcess())
9349 return;
9350
9351 send(Messages::WebPage::SetViewportSizeForCSSViewportUnits(viewportSize));
9352}
9353
9354#if USE(AUTOMATIC_TEXT_REPLACEMENT)
9355
9356void WebPageProxy::toggleSmartInsertDelete()
9357{
9358 if (TextChecker::isTestingMode())
9359 TextChecker::setSmartInsertDeleteEnabled(!TextChecker::isSmartInsertDeleteEnabled());
9360}
9361
9362void WebPageProxy::toggleAutomaticQuoteSubstitution()
9363{
9364 if (TextChecker::isTestingMode())
9365 TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled);
9366}
9367
9368void WebPageProxy::toggleAutomaticLinkDetection()
9369{
9370 if (TextChecker::isTestingMode())
9371 TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled);
9372}
9373
9374void WebPageProxy::toggleAutomaticDashSubstitution()
9375{
9376 if (TextChecker::isTestingMode())
9377 TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled);
9378}
9379
9380void WebPageProxy::toggleAutomaticTextReplacement()
9381{
9382 if (TextChecker::isTestingMode())
9383 TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled);
9384}
9385
9386#endif
9387
9388#if USE(DICTATION_ALTERNATIVES)
9389
9390void WebPageProxy::showDictationAlternativeUI(const WebCore::FloatRect& boundingBoxOfDictatedText, WebCore::DictationContext dictationContext)
9391{
9392 pageClient().showDictationAlternativeUI(boundingBoxOfDictatedText, dictationContext);
9393}
9394
9395void WebPageProxy::removeDictationAlternatives(WebCore::DictationContext dictationContext)
9396{
9397 pageClient().removeDictationAlternatives(dictationContext);
9398}
9399
9400void WebPageProxy::dictationAlternatives(WebCore::DictationContext dictationContext, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
9401{
9402 completionHandler(pageClient().dictationAlternatives(dictationContext));
9403}
9404
9405#endif
9406
9407#if PLATFORM(MAC)
9408
9409void WebPageProxy::substitutionsPanelIsShowing(CompletionHandler<void(bool)>&& completionHandler)
9410{
9411 completionHandler(TextChecker::substitutionsPanelIsShowing());
9412}
9413
9414void WebPageProxy::showCorrectionPanel(int32_t panelType, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings)
9415{
9416 // FIXME: Make AlternativeTextType an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
9417 pageClient().showCorrectionPanel((AlternativeTextType)panelType, boundingBoxOfReplacedString, replacedString, replacementString, alternativeReplacementStrings);
9418}
9419
9420void WebPageProxy::dismissCorrectionPanel(int32_t reason)
9421{
9422 // FIXME: Make ReasonForDismissingAlternativeText an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
9423 pageClient().dismissCorrectionPanel((ReasonForDismissingAlternativeText)reason);
9424}
9425
9426void WebPageProxy::dismissCorrectionPanelSoon(int32_t reason, CompletionHandler<void(String)>&& completionHandler)
9427{
9428 // FIXME: Make ReasonForDismissingAlternativeText an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
9429 completionHandler(pageClient().dismissCorrectionPanelSoon((ReasonForDismissingAlternativeText)reason));
9430}
9431
9432void WebPageProxy::recordAutocorrectionResponse(int32_t response, const String& replacedString, const String& replacementString)
9433{
9434 // FIXME: Make AutocorrectionResponse an enum class with EnumTraits and serialize it instead of casting to/from an int32_t.
9435 pageClient().recordAutocorrectionResponse(static_cast<AutocorrectionResponse>(response), replacedString, replacementString);
9436}
9437
9438void WebPageProxy::handleAlternativeTextUIResult(const String& result)
9439{
9440 if (!isClosed())
9441 send(Messages::WebPage::HandleAlternativeTextUIResult(result));
9442}
9443
9444void WebPageProxy::setEditableElementIsFocused(bool editableElementIsFocused)
9445{
9446 pageClient().setEditableElementIsFocused(editableElementIsFocused);
9447}
9448
9449#endif // PLATFORM(MAC)
9450
9451#if PLATFORM(COCOA) || PLATFORM(GTK)
9452RefPtr<ViewSnapshot> WebPageProxy::takeViewSnapshot(std::optional<WebCore::IntRect>&& clipRect)
9453{
9454 return pageClient().takeViewSnapshot(WTFMove(clipRect));
9455}
9456#endif
9457
9458#if PLATFORM(GTK) || PLATFORM(WPE)
9459void WebPageProxy::cancelComposition(const String& compositionString)
9460{
9461 if (!hasRunningProcess())
9462 return;
9463
9464 // Remove any pending composition key event.
9465 if (m_keyEventQueue.size() > 1) {
9466 auto event = m_keyEventQueue.takeFirst();
9467 m_keyEventQueue.removeAllMatching([](const auto& event) {
9468 return event.handledByInputMethod();
9469 });
9470 m_keyEventQueue.prepend(WTFMove(event));
9471 }
9472 send(Messages::WebPage::CancelComposition(compositionString));
9473}
9474
9475void WebPageProxy::deleteSurrounding(int64_t offset, unsigned characterCount)
9476{
9477 if (!hasRunningProcess())
9478 return;
9479
9480 send(Messages::WebPage::DeleteSurrounding(offset, characterCount));
9481}
9482#endif // PLATFORM(GTK) || PLATFORM(WPE)
9483
9484void WebPageProxy::setScrollPinningBehavior(ScrollPinningBehavior pinning)
9485{
9486 if (m_scrollPinningBehavior == pinning)
9487 return;
9488
9489 m_scrollPinningBehavior = pinning;
9490
9491 if (hasRunningProcess())
9492 send(Messages::WebPage::SetScrollPinningBehavior(pinning));
9493}
9494
9495void WebPageProxy::setOverlayScrollbarStyle(std::optional<WebCore::ScrollbarOverlayStyle> scrollbarStyle)
9496{
9497 if (!m_scrollbarOverlayStyle && !scrollbarStyle)
9498 return;
9499
9500 if ((m_scrollbarOverlayStyle && scrollbarStyle) && m_scrollbarOverlayStyle.value() == scrollbarStyle.value())
9501 return;
9502
9503 m_scrollbarOverlayStyle = scrollbarStyle;
9504
9505 std::optional<uint32_t> scrollbarStyleForMessage;
9506 if (scrollbarStyle)
9507 scrollbarStyleForMessage = static_cast<ScrollbarOverlayStyle>(scrollbarStyle.value());
9508
9509 if (hasRunningProcess())
9510 send(Messages::WebPage::SetScrollbarOverlayStyle(scrollbarStyleForMessage), m_webPageID);
9511}
9512
9513#if ENABLE(WEB_CRYPTO)
9514void WebPageProxy::wrapCryptoKey(const Vector<uint8_t>& key, CompletionHandler<void(bool, Vector<uint8_t>&&)>&& completionHandler)
9515{
9516 PageClientProtector protector(pageClient());
9517
9518 Vector<uint8_t> masterKey;
9519
9520 if (auto keyData = m_navigationClient->webCryptoMasterKey(*this))
9521 masterKey = Vector(keyData->dataReference());
9522
9523 Vector<uint8_t> wrappedKey;
9524 bool succeeded = wrapSerializedCryptoKey(masterKey, key, wrappedKey);
9525 completionHandler(succeeded, WTFMove(wrappedKey));
9526}
9527
9528void WebPageProxy::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, CompletionHandler<void(bool, Vector<uint8_t>&&)>&& completionHandler)
9529{
9530 PageClientProtector protector(pageClient());
9531
9532 Vector<uint8_t> masterKey;
9533
9534 if (auto keyData = m_navigationClient->webCryptoMasterKey(*this))
9535 masterKey = Vector(keyData->dataReference());
9536
9537 Vector<uint8_t> key;
9538 bool succeeded = unwrapSerializedCryptoKey(masterKey, wrappedKey, key);
9539 completionHandler(succeeded, WTFMove(key));
9540}
9541#endif
9542
9543void WebPageProxy::signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challengeString, const URL& url, CompletionHandler<void(String)>&& completionHandler)
9544{
9545 PageClientProtector protector(pageClient());
9546
9547 if (auto apiString = m_navigationClient->signedPublicKeyAndChallengeString(*this, keySizeIndex, API::String::create(challengeString), url))
9548 return completionHandler(apiString->string());
9549
9550 completionHandler({ });
9551}
9552
9553void WebPageProxy::addMIMETypeWithCustomContentProvider(const String& mimeType)
9554{
9555 send(Messages::WebPage::AddMIMETypeWithCustomContentProvider(mimeType));
9556}
9557
9558void WebPageProxy::changeFontAttributes(WebCore::FontAttributeChanges&& changes)
9559{
9560 if (!hasRunningProcess())
9561 return;
9562
9563 send(Messages::WebPage::ChangeFontAttributes(WTFMove(changes)));
9564}
9565
9566void WebPageProxy::changeFont(WebCore::FontChanges&& changes)
9567{
9568 if (!hasRunningProcess())
9569 return;
9570
9571 send(Messages::WebPage::ChangeFont(WTFMove(changes)));
9572}
9573
9574// FIXME: Move these functions to WebPageProxyCocoa.mm.
9575#if PLATFORM(COCOA)
9576
9577void WebPageProxy::setTextAsync(const String& text)
9578{
9579 if (hasRunningProcess())
9580 send(Messages::WebPage::SetTextAsync(text));
9581}
9582
9583void WebPageProxy::insertTextAsync(const String& text, const EditingRange& replacementRange, InsertTextOptions&& options)
9584{
9585 if (!hasRunningProcess())
9586 return;
9587
9588 send(Messages::WebPage::InsertTextAsync(text, replacementRange, WTFMove(options)));
9589}
9590
9591void WebPageProxy::hasMarkedText(CompletionHandler<void(bool)>&& callback)
9592{
9593 if (!hasRunningProcess()) {
9594 callback(false);
9595 return;
9596 }
9597 sendWithAsyncReply(Messages::WebPage::HasMarkedText(), WTFMove(callback));
9598}
9599
9600void WebPageProxy::getMarkedRangeAsync(CompletionHandler<void(const EditingRange&)>&& callbackFunction)
9601{
9602 if (!hasRunningProcess()) {
9603 callbackFunction(EditingRange());
9604 return;
9605 }
9606
9607 sendWithAsyncReply(Messages::WebPage::GetMarkedRangeAsync(), WTFMove(callbackFunction));
9608}
9609
9610void WebPageProxy::getSelectedRangeAsync(CompletionHandler<void(const EditingRange&)>&& callbackFunction)
9611{
9612 if (!hasRunningProcess()) {
9613 callbackFunction(EditingRange());
9614 return;
9615 }
9616
9617 sendWithAsyncReply(Messages::WebPage::GetSelectedRangeAsync(), WTFMove(callbackFunction));
9618}
9619
9620void WebPageProxy::characterIndexForPointAsync(const WebCore::IntPoint& point, CompletionHandler<void(uint64_t)>&& callbackFunction)
9621{
9622 sendWithAsyncReply(Messages::WebPage::CharacterIndexForPointAsync(point), WTFMove(callbackFunction));
9623}
9624
9625void WebPageProxy::firstRectForCharacterRangeAsync(const EditingRange& range, CompletionHandler<void(const WebCore::IntRect&, const EditingRange&)>&& callbackFunction)
9626{
9627 if (!hasRunningProcess())
9628 return callbackFunction({ }, { });
9629
9630 sendWithAsyncReply(Messages::WebPage::FirstRectForCharacterRangeAsync(range), WTFMove(callbackFunction));
9631}
9632
9633void WebPageProxy::setCompositionAsync(const String& text, const Vector<CompositionUnderline>& underlines, const Vector<CompositionHighlight>& highlights, const EditingRange& selectionRange, const EditingRange& replacementRange)
9634{
9635 if (!hasRunningProcess()) {
9636 // If this fails, we should call -discardMarkedText on input context to notify the input method.
9637 // This will happen naturally later, as part of reloading the page.
9638 return;
9639 }
9640
9641 send(Messages::WebPage::SetCompositionAsync(text, underlines, highlights, selectionRange, replacementRange));
9642}
9643
9644void WebPageProxy::confirmCompositionAsync()
9645{
9646 if (!hasRunningProcess())
9647 return;
9648
9649 send(Messages::WebPage::ConfirmCompositionAsync());
9650}
9651
9652void WebPageProxy::setScrollPerformanceDataCollectionEnabled(bool enabled)
9653{
9654 if (enabled == m_scrollPerformanceDataCollectionEnabled)
9655 return;
9656
9657 m_scrollPerformanceDataCollectionEnabled = enabled;
9658
9659 if (m_scrollPerformanceDataCollectionEnabled && !m_scrollingPerformanceData)
9660 m_scrollingPerformanceData = makeUnique<RemoteLayerTreeScrollingPerformanceData>(downcast<RemoteLayerTreeDrawingAreaProxy>(*m_drawingArea));
9661 else if (!m_scrollPerformanceDataCollectionEnabled)
9662 m_scrollingPerformanceData = nullptr;
9663}
9664#endif
9665
9666void WebPageProxy::takeSnapshot(IntRect rect, IntSize bitmapSize, SnapshotOptions options, CompletionHandler<void(const ShareableBitmap::Handle&)>&& callback)
9667{
9668 sendWithAsyncReply(Messages::WebPage::TakeSnapshot(rect, bitmapSize, options), WTFMove(callback));
9669}
9670
9671void WebPageProxy::navigationGestureDidBegin()
9672{
9673 PageClientProtector protector(pageClient());
9674
9675 m_isShowingNavigationGestureSnapshot = true;
9676 pageClient().navigationGestureDidBegin();
9677
9678 m_navigationClient->didBeginNavigationGesture(*this);
9679}
9680
9681void WebPageProxy::navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem& item)
9682{
9683 PageClientProtector protector(pageClient());
9684 if (willNavigate) {
9685 m_isLayerTreeFrozenDueToSwipeAnimation = true;
9686 send(Messages::WebPage::FreezeLayerTreeDueToSwipeAnimation());
9687 }
9688
9689 pageClient().navigationGestureWillEnd(willNavigate, item);
9690
9691 m_navigationClient->willEndNavigationGesture(*this, willNavigate, item);
9692}
9693
9694void WebPageProxy::navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem& item)
9695{
9696 PageClientProtector protector(pageClient());
9697
9698 pageClient().navigationGestureDidEnd(willNavigate, item);
9699
9700 m_navigationClient->didEndNavigationGesture(*this, willNavigate, item);
9701
9702 if (m_isLayerTreeFrozenDueToSwipeAnimation) {
9703 m_isLayerTreeFrozenDueToSwipeAnimation = false;
9704 send(Messages::WebPage::UnfreezeLayerTreeDueToSwipeAnimation());
9705
9706 if (m_provisionalPage)
9707 m_provisionalPage->unfreezeLayerTreeDueToSwipeAnimation();
9708 }
9709}
9710
9711void WebPageProxy::navigationGestureDidEnd()
9712{
9713 PageClientProtector protector(pageClient());
9714
9715 pageClient().navigationGestureDidEnd();
9716}
9717
9718void WebPageProxy::willRecordNavigationSnapshot(WebBackForwardListItem& item)
9719{
9720 PageClientProtector protector(pageClient());
9721
9722 pageClient().willRecordNavigationSnapshot(item);
9723}
9724
9725void WebPageProxy::navigationGestureSnapshotWasRemoved()
9726{
9727 m_isShowingNavigationGestureSnapshot = false;
9728
9729 // The ViewGestureController may call this method on a WebPageProxy whose view has been destroyed. In such case,
9730 // we need to return early as the pageClient will not be valid below.
9731 if (m_isClosed)
9732 return;
9733
9734 pageClient().didRemoveNavigationGestureSnapshot();
9735
9736 m_navigationClient->didRemoveNavigationGestureSnapshot(*this);
9737}
9738
9739void WebPageProxy::isPlayingMediaDidChange(MediaProducerMediaStateFlags newState)
9740{
9741#if PLATFORM(IOS_FAMILY)
9742 if (!m_process->throttler().shouldBeRunnable())
9743 return;
9744#endif
9745
9746 if (!m_isClosed)
9747 updatePlayingMediaDidChange(newState, CanDelayNotification::Yes);
9748}
9749
9750void WebPageProxy::updatePlayingMediaDidChange(MediaProducerMediaStateFlags newState, CanDelayNotification canDelayNotification)
9751{
9752#if ENABLE(MEDIA_STREAM)
9753 auto updateMediaCaptureStateImmediatelyIfNeeded = [&] {
9754 if (canDelayNotification == CanDelayNotification::No && m_updateReportedMediaCaptureStateTimer.isActive()) {
9755 m_updateReportedMediaCaptureStateTimer.stop();
9756 updateReportedMediaCaptureState();
9757 }
9758 };
9759#endif
9760
9761 if (newState == m_mediaState) {
9762#if ENABLE(MEDIA_STREAM)
9763 updateMediaCaptureStateImmediatelyIfNeeded();
9764#endif
9765 return;
9766 }
9767
9768#if PLATFORM(MACCATALYST)
9769 // When the page starts playing media for the first time, make sure we register with
9770 // the EndowmentStateTracker to get notifications when the application is no longer
9771 // user-facing, so that we can appropriately suspend all media playback.
9772 if (!m_isListeningForUserFacingStateChangeNotification) {
9773 EndowmentStateTracker::singleton().addClient(*this);
9774 m_isListeningForUserFacingStateChangeNotification = true;
9775 }
9776#endif
9777
9778#if ENABLE(MEDIA_STREAM)
9779 WebCore::MediaProducerMediaStateFlags oldMediaCaptureState = m_mediaState & WebCore::MediaProducer::MediaCaptureMask;
9780 WebCore::MediaProducerMediaStateFlags newMediaCaptureState = newState & WebCore::MediaProducer::MediaCaptureMask;
9781#endif
9782
9783 MediaProducerMediaStateFlags playingMediaMask { MediaProducerMediaState::IsPlayingAudio, MediaProducerMediaState::IsPlayingVideo };
9784 MediaProducerMediaStateFlags oldState = m_mediaState;
9785
9786 bool playingAudioChanges = (oldState.contains(MediaProducerMediaState::IsPlayingAudio)) != (newState.contains(MediaProducerMediaState::IsPlayingAudio));
9787 if (playingAudioChanges)
9788 pageClient().isPlayingAudioWillChange();
9789 m_mediaState = newState;
9790 if (playingAudioChanges)
9791 pageClient().isPlayingAudioDidChange();
9792
9793#if ENABLE(MEDIA_STREAM)
9794 if (oldMediaCaptureState != newMediaCaptureState) {
9795 updateReportedMediaCaptureState();
9796
9797 ASSERT(m_userMediaPermissionRequestManager);
9798 if (m_userMediaPermissionRequestManager)
9799 m_userMediaPermissionRequestManager->captureStateChanged(oldMediaCaptureState, newMediaCaptureState);
9800 }
9801 updateMediaCaptureStateImmediatelyIfNeeded();
9802#endif
9803
9804 activityStateDidChange({ ActivityState::IsAudible, ActivityState::IsCapturingMedia });
9805
9806 playingMediaMask.add(WebCore::MediaProducer::MediaCaptureMask);
9807 if ((oldState & playingMediaMask) != (m_mediaState & playingMediaMask))
9808 m_uiClient->isPlayingMediaDidChange(*this);
9809
9810 if ((oldState.containsAny(MediaProducerMediaState::HasAudioOrVideo)) != (m_mediaState.containsAny(MediaProducerMediaState::HasAudioOrVideo)))
9811 videoControlsManagerDidChange();
9812
9813 m_process->updateAudibleMediaAssertions();
9814}
9815
9816void WebPageProxy::updateReportedMediaCaptureState()
9817{
9818 auto activeCaptureState = m_mediaState & MediaProducer::MediaCaptureMask;
9819 if (m_reportedMediaCaptureState == activeCaptureState)
9820 return;
9821
9822 bool haveReportedCapture = m_reportedMediaCaptureState.containsAny(MediaProducer::MediaCaptureMask);
9823 bool willReportCapture = !activeCaptureState.isEmpty();
9824
9825 if (haveReportedCapture && !willReportCapture && m_updateReportedMediaCaptureStateTimer.isActive())
9826 return;
9827
9828 if (!haveReportedCapture && willReportCapture)
9829 m_updateReportedMediaCaptureStateTimer.startOneShot(m_mediaCaptureReportingDelay);
9830
9831 WEBPAGEPROXY_RELEASE_LOG(WebRTC, "updateReportedMediaCaptureState: from %d to %d", m_reportedMediaCaptureState.toRaw(), activeCaptureState.toRaw());
9832
9833 bool microphoneCaptureChanged = (m_reportedMediaCaptureState & MediaProducer::MicrophoneCaptureMask) != (activeCaptureState & MediaProducer::MicrophoneCaptureMask);
9834 bool cameraCaptureChanged = (m_reportedMediaCaptureState & MediaProducer::VideoCaptureMask) != (activeCaptureState & MediaProducer::VideoCaptureMask);
9835 bool displayCaptureChanged = (m_reportedMediaCaptureState & MediaProducer::DisplayCaptureMask) != (activeCaptureState & MediaProducer::DisplayCaptureMask);
9836 bool systemAudioCaptureChanged = (m_reportedMediaCaptureState & MediaProducer::SystemAudioCaptureMask) != (activeCaptureState & MediaProducer::SystemAudioCaptureMask);
9837
9838 auto reportedDisplayCaptureSurfaces = m_reportedMediaCaptureState & (MediaProducer::ScreenCaptureMask | MediaProducer::WindowCaptureMask);
9839 auto activeDisplayCaptureSurfaces = activeCaptureState & (MediaProducer::ScreenCaptureMask | MediaProducer::WindowCaptureMask);
9840 auto displayCaptureSurfacesChanged = reportedDisplayCaptureSurfaces != activeDisplayCaptureSurfaces;
9841
9842 if (microphoneCaptureChanged)
9843 pageClient().microphoneCaptureWillChange();
9844 if (cameraCaptureChanged)
9845 pageClient().cameraCaptureWillChange();
9846 if (displayCaptureChanged)
9847 pageClient().displayCaptureWillChange();
9848 if (displayCaptureSurfacesChanged)
9849 pageClient().displayCaptureSurfacesWillChange();
9850 if (systemAudioCaptureChanged)
9851 pageClient().systemAudioCaptureWillChange();
9852
9853 m_reportedMediaCaptureState = activeCaptureState;
9854 m_uiClient->mediaCaptureStateDidChange(m_mediaState);
9855
9856 if (microphoneCaptureChanged)
9857 pageClient().microphoneCaptureChanged();
9858 if (cameraCaptureChanged)
9859 pageClient().cameraCaptureChanged();
9860 if (displayCaptureChanged)
9861 pageClient().displayCaptureChanged();
9862 if (displayCaptureSurfacesChanged)
9863 pageClient().displayCaptureSurfacesChanged();
9864 if (systemAudioCaptureChanged)
9865 pageClient().systemAudioCaptureChanged();
9866}
9867
9868void WebPageProxy::videoControlsManagerDidChange()
9869{
9870 pageClient().videoControlsManagerDidChange();
9871}
9872
9873bool WebPageProxy::hasActiveVideoForControlsManager() const
9874{
9875#if ENABLE(VIDEO_PRESENTATION_MODE)
9876 return m_playbackSessionManager && m_playbackSessionManager->controlsManagerInterface();
9877#else
9878 return false;
9879#endif
9880}
9881
9882void WebPageProxy::requestControlledElementID() const
9883{
9884#if ENABLE(VIDEO_PRESENTATION_MODE)
9885 if (m_playbackSessionManager)
9886 m_playbackSessionManager->requestControlledElementID();
9887#endif
9888}
9889
9890void WebPageProxy::handleControlledElementIDResponse(const String& identifier) const
9891{
9892#if PLATFORM(MAC)
9893 pageClient().handleControlledElementIDResponse(identifier);
9894#endif
9895}
9896
9897bool WebPageProxy::isPlayingVideoInEnhancedFullscreen() const
9898{
9899#if ENABLE(VIDEO_PRESENTATION_MODE)
9900 return m_videoFullscreenManager && m_videoFullscreenManager->isPlayingVideoInEnhancedFullscreen();
9901#else
9902 return false;
9903#endif
9904}
9905
9906void WebPageProxy::handleAutoplayEvent(WebCore::AutoplayEvent event, OptionSet<AutoplayEventFlags> flags)
9907{
9908 m_uiClient->handleAutoplayEvent(*this, event, flags);
9909}
9910
9911#if PLATFORM(MAC)
9912void WebPageProxy::performImmediateActionHitTestAtLocation(FloatPoint point)
9913{
9914 send(Messages::WebPage::PerformImmediateActionHitTestAtLocation(point));
9915}
9916
9917void WebPageProxy::immediateActionDidUpdate()
9918{
9919 send(Messages::WebPage::ImmediateActionDidUpdate());
9920}
9921
9922void WebPageProxy::immediateActionDidCancel()
9923{
9924 send(Messages::WebPage::ImmediateActionDidCancel());
9925}
9926
9927void WebPageProxy::immediateActionDidComplete()
9928{
9929 send(Messages::WebPage::ImmediateActionDidComplete());
9930}
9931
9932void WebPageProxy::didPerformImmediateActionHitTest(const WebHitTestResultData& result, bool contentPreventsDefault, const UserData& userData)
9933{
9934 pageClient().didPerformImmediateActionHitTest(result, contentPreventsDefault, m_process->transformHandlesToObjects(userData.object()).get());
9935}
9936
9937NSObject *WebPageProxy::immediateActionAnimationControllerForHitTestResult(RefPtr<API::HitTestResult> hitTestResult, uint64_t type, RefPtr<API::Object> userData)
9938{
9939 return pageClient().immediateActionAnimationControllerForHitTestResult(hitTestResult, type, userData);
9940}
9941
9942void WebPageProxy::handleAcceptedCandidate(WebCore::TextCheckingResult acceptedCandidate)
9943{
9944 send(Messages::WebPage::HandleAcceptedCandidate(acceptedCandidate));
9945}
9946
9947void WebPageProxy::didHandleAcceptedCandidate()
9948{
9949 pageClient().didHandleAcceptedCandidate();
9950}
9951
9952void WebPageProxy::setUseSystemAppearance(bool useSystemAppearance)
9953{
9954 if (useSystemAppearance == m_useSystemAppearance)
9955 return;
9956
9957 m_useSystemAppearance = useSystemAppearance;
9958
9959 if (!hasRunningProcess())
9960 return;
9961
9962 send(Messages::WebPage::SetUseSystemAppearance(useSystemAppearance));
9963}
9964
9965void WebPageProxy::setHeaderBannerHeightForTesting(int height)
9966{
9967 send(Messages::WebPage::SetHeaderBannerHeightForTesting(height));
9968}
9969
9970void WebPageProxy::setFooterBannerHeightForTesting(int height)
9971{
9972 send(Messages::WebPage::SetFooterBannerHeightForTesting(height));
9973}
9974
9975void WebPageProxy::didEndMagnificationGesture()
9976{
9977 send(Messages::WebPage::DidEndMagnificationGesture());
9978}
9979
9980#endif
9981
9982void WebPageProxy::installActivityStateChangeCompletionHandler(CompletionHandler<void()>&& completionHandler)
9983{
9984 if (!hasRunningProcess()) {
9985 completionHandler();
9986 return;
9987 }
9988
9989 m_nextActivityStateChangeCallbacks.append(WTFMove(completionHandler));
9990}
9991
9992void WebPageProxy::imageOrMediaDocumentSizeChanged(const WebCore::IntSize& newSize)
9993{
9994 m_uiClient->imageOrMediaDocumentSizeChanged(newSize);
9995}
9996
9997void WebPageProxy::setShouldDispatchFakeMouseMoveEvents(bool shouldDispatchFakeMouseMoveEvents)
9998{
9999 send(Messages::WebPage::SetShouldDispatchFakeMouseMoveEvents(shouldDispatchFakeMouseMoveEvents));
10000}
10001
10002void WebPageProxy::handleAutoFillButtonClick(const UserData& userData)
10003{
10004 m_uiClient->didClickAutoFillButton(*this, m_process->transformHandlesToObjects(userData.object()).get());
10005}
10006
10007void WebPageProxy::didResignInputElementStrongPasswordAppearance(const UserData& userData)
10008{
10009 m_uiClient->didResignInputElementStrongPasswordAppearance(*this, m_process->transformHandlesToObjects(userData.object()).get());
10010}
10011
10012#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
10013void WebPageProxy::addPlaybackTargetPickerClient(PlaybackTargetClientContextIdentifier contextId)
10014{
10015 pageClient().mediaSessionManager().addPlaybackTargetPickerClient(*this, contextId);
10016}
10017
10018void WebPageProxy::removePlaybackTargetPickerClient(PlaybackTargetClientContextIdentifier contextId)
10019{
10020 pageClient().mediaSessionManager().removePlaybackTargetPickerClient(*this, contextId);
10021}
10022
10023void WebPageProxy::showPlaybackTargetPicker(PlaybackTargetClientContextIdentifier contextId, const WebCore::FloatRect& rect, bool hasVideo)
10024{
10025 pageClient().mediaSessionManager().showPlaybackTargetPicker(*this, contextId, pageClient().rootViewToScreen(IntRect(rect)), hasVideo, useDarkAppearance());
10026}
10027
10028void WebPageProxy::playbackTargetPickerClientStateDidChange(PlaybackTargetClientContextIdentifier contextId, WebCore::MediaProducerMediaStateFlags state)
10029{
10030 pageClient().mediaSessionManager().clientStateDidChange(*this, contextId, state);
10031}
10032
10033void WebPageProxy::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
10034{
10035 pageClient().mediaSessionManager().setMockMediaPlaybackTargetPickerEnabled(enabled);
10036}
10037
10038void WebPageProxy::setMockMediaPlaybackTargetPickerState(const String& name, WebCore::MediaPlaybackTargetContext::MockState state)
10039{
10040 pageClient().mediaSessionManager().setMockMediaPlaybackTargetPickerState(name, state);
10041}
10042
10043void WebPageProxy::mockMediaPlaybackTargetPickerDismissPopup()
10044{
10045 pageClient().mediaSessionManager().mockMediaPlaybackTargetPickerDismissPopup();
10046}
10047
10048void WebPageProxy::setPlaybackTarget(PlaybackTargetClientContextIdentifier contextId, Ref<MediaPlaybackTarget>&& target)
10049{
10050 if (!hasRunningProcess())
10051 return;
10052
10053 auto context = target->targetContext();
10054 ASSERT(context.type() != MediaPlaybackTargetContext::Type::SerializedAVOutputContext);
10055 if (preferences().useGPUProcessForMediaEnabled())
10056 context.serializeOutputContext();
10057
10058 send(Messages::WebPage::PlaybackTargetSelected(contextId, context));
10059}
10060
10061void WebPageProxy::externalOutputDeviceAvailableDidChange(PlaybackTargetClientContextIdentifier contextId, bool available)
10062{
10063 if (!hasRunningProcess())
10064 return;
10065
10066 send(Messages::WebPage::PlaybackTargetAvailabilityDidChange(contextId, available));
10067}
10068
10069void WebPageProxy::setShouldPlayToPlaybackTarget(PlaybackTargetClientContextIdentifier contextId, bool shouldPlay)
10070{
10071 if (!hasRunningProcess())
10072 return;
10073
10074 send(Messages::WebPage::SetShouldPlayToPlaybackTarget(contextId, shouldPlay));
10075}
10076
10077void WebPageProxy::playbackTargetPickerWasDismissed(PlaybackTargetClientContextIdentifier contextId)
10078{
10079 if (!hasRunningProcess())
10080 return;
10081
10082 send(Messages::WebPage::PlaybackTargetPickerWasDismissed(contextId));
10083}
10084#endif
10085
10086void WebPageProxy::didExceedInactiveMemoryLimitWhileActive()
10087{
10088 WEBPAGEPROXY_RELEASE_LOG_ERROR(PerformanceLogging, "didExceedInactiveMemoryLimitWhileActive");
10089 m_uiClient->didExceedBackgroundResourceLimitWhileInForeground(*this, kWKResourceLimitMemory);
10090}
10091
10092void WebPageProxy::didExceedBackgroundCPULimitWhileInForeground()
10093{
10094 WEBPAGEPROXY_RELEASE_LOG_ERROR(PerformanceLogging, "didExceedBackgroundCPULimitWhileInForeground");
10095 m_uiClient->didExceedBackgroundResourceLimitWhileInForeground(*this, kWKResourceLimitCPU);
10096}
10097
10098void WebPageProxy::didChangeBackgroundColor()
10099{
10100 pageClient().didChangeBackgroundColor();
10101}
10102
10103void WebPageProxy::clearWheelEventTestMonitor()
10104{
10105 if (!hasRunningProcess())
10106 return;
10107
10108 send(Messages::WebPage::ClearWheelEventTestMonitor());
10109}
10110
10111void WebPageProxy::callAfterNextPresentationUpdate(WTF::Function<void (CallbackBase::Error)>&& callback)
10112{
10113 if (!hasRunningProcess() || !m_drawingArea) {
10114 callback(CallbackBase::Error::OwnerWasInvalidated);
10115 return;
10116 }
10117
10118 m_drawingArea->dispatchAfterEnsuringDrawing(WTFMove(callback));
10119}
10120
10121void WebPageProxy::setShouldScaleViewToFitDocument(bool shouldScaleViewToFitDocument)
10122{
10123 if (m_shouldScaleViewToFitDocument == shouldScaleViewToFitDocument)
10124 return;
10125
10126 m_shouldScaleViewToFitDocument = shouldScaleViewToFitDocument;
10127
10128 if (!hasRunningProcess())
10129 return;
10130
10131 send(Messages::WebPage::SetShouldScaleViewToFitDocument(shouldScaleViewToFitDocument));
10132}
10133
10134void WebPageProxy::didRestoreScrollPosition()
10135{
10136 pageClient().didRestoreScrollPosition();
10137}
10138
10139void WebPageProxy::getLoadDecisionForIcon(const WebCore::LinkIcon& icon, CallbackID loadIdentifier)
10140{
10141 m_iconLoadingClient->getLoadDecisionForIcon(icon, [this, protectedThis = Ref { *this }, loadIdentifier] (CompletionHandler<void(API::Data*)>&& callback) {
10142 if (!hasRunningProcess()) {
10143 if (callback)
10144 callback(nullptr);
10145 return;
10146 }
10147
10148 if (!callback) {
10149 sendWithAsyncReply(Messages::WebPage::DidGetLoadDecisionForIcon(false, loadIdentifier), [](auto) { });
10150 return;
10151 }
10152 sendWithAsyncReply(Messages::WebPage::DidGetLoadDecisionForIcon(true, loadIdentifier), [callback = WTFMove(callback)](const IPC::SharedBufferReference& iconData) mutable {
10153 callback(API::Data::create(iconData.data(), iconData.size()).ptr());
10154 });
10155 });
10156}
10157
10158WebCore::UserInterfaceLayoutDirection WebPageProxy::userInterfaceLayoutDirection()
10159{
10160 return pageClient().userInterfaceLayoutDirection();
10161}
10162
10163void WebPageProxy::setUserInterfaceLayoutDirection(WebCore::UserInterfaceLayoutDirection userInterfaceLayoutDirection)
10164{
10165 if (!hasRunningProcess())
10166 return;
10167
10168 send(Messages::WebPage::SetUserInterfaceLayoutDirection(static_cast<uint32_t>(userInterfaceLayoutDirection)));
10169}
10170
10171void WebPageProxy::hideValidationMessage()
10172{
10173#if PLATFORM(COCOA) || PLATFORM(GTK)
10174 m_validationBubble = nullptr;
10175#endif
10176}
10177
10178// FIXME: Consolidate with dismissContentRelativeChildWindows
10179void WebPageProxy::closeOverlayedViews()
10180{
10181 hideValidationMessage();
10182
10183#if ENABLE(DATALIST_ELEMENT)
10184 endDataListSuggestions();
10185#endif
10186
10187#if ENABLE(INPUT_TYPE_COLOR)
10188 endColorPicker();
10189#endif
10190
10191#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
10192 endDateTimePicker();
10193#endif
10194}
10195
10196#if ENABLE(POINTER_LOCK)
10197void WebPageProxy::requestPointerLock()
10198{
10199 ASSERT(!m_isPointerLockPending);
10200 ASSERT(!m_isPointerLocked);
10201 m_isPointerLockPending = true;
10202
10203 if (!isViewVisible() || !(m_activityState & ActivityState::IsFocused)) {
10204 didDenyPointerLock();
10205 return;
10206 }
10207 m_uiClient->requestPointerLock(this);
10208}
10209
10210void WebPageProxy::didAllowPointerLock()
10211{
10212 ASSERT(m_isPointerLockPending && !m_isPointerLocked);
10213 m_isPointerLocked = true;
10214 m_isPointerLockPending = false;
10215#if PLATFORM(MAC)
10216 CGDisplayHideCursor(CGMainDisplayID());
10217 CGAssociateMouseAndMouseCursorPosition(false);
10218#endif
10219 send(Messages::WebPage::DidAcquirePointerLock());
10220}
10221
10222void WebPageProxy::didDenyPointerLock()
10223{
10224 ASSERT(m_isPointerLockPending && !m_isPointerLocked);
10225 m_isPointerLockPending = false;
10226 send(Messages::WebPage::DidNotAcquirePointerLock());
10227}
10228
10229void WebPageProxy::requestPointerUnlock()
10230{
10231 if (m_isPointerLocked) {
10232#if PLATFORM(MAC)
10233 CGAssociateMouseAndMouseCursorPosition(true);
10234 CGDisplayShowCursor(CGMainDisplayID());
10235#endif
10236 m_uiClient->didLosePointerLock(this);
10237 send(Messages::WebPage::DidLosePointerLock());
10238 }
10239
10240 if (m_isPointerLockPending) {
10241 m_uiClient->didLosePointerLock(this);
10242 send(Messages::WebPage::DidNotAcquirePointerLock());
10243 }
10244
10245 m_isPointerLocked = false;
10246 m_isPointerLockPending = false;
10247}
10248#endif
10249
10250void WebPageProxy::setURLSchemeHandlerForScheme(Ref<WebURLSchemeHandler>&& handler, const String& scheme)
10251{
10252 auto canonicalizedScheme = WTF::URLParser::maybeCanonicalizeScheme(scheme);
10253 ASSERT(canonicalizedScheme);
10254 ASSERT(!WTF::URLParser::isSpecialScheme(canonicalizedScheme.value()));
10255
10256 auto schemeResult = m_urlSchemeHandlersByScheme.add(canonicalizedScheme.value(), handler.get());
10257 ASSERT_UNUSED(schemeResult, schemeResult.isNewEntry);
10258
10259 auto handlerIdentifier = handler->identifier();
10260 auto handlerIdentifierResult = m_urlSchemeHandlersByIdentifier.add(handlerIdentifier, WTFMove(handler));
10261 ASSERT_UNUSED(handlerIdentifierResult, handlerIdentifierResult.isNewEntry);
10262
10263 send(Messages::WebPage::RegisterURLSchemeHandler(handlerIdentifier, canonicalizedScheme.value()));
10264}
10265
10266WebURLSchemeHandler* WebPageProxy::urlSchemeHandlerForScheme(const String& scheme)
10267{
10268 return scheme.isNull() ? nullptr : m_urlSchemeHandlersByScheme.get(scheme);
10269}
10270
10271void WebPageProxy::startURLSchemeTask(URLSchemeTaskParameters&& parameters)
10272{
10273 startURLSchemeTaskShared(m_process.copyRef(), m_webPageID, WTFMove(parameters));
10274}
10275
10276void WebPageProxy::startURLSchemeTaskShared(Ref<WebProcessProxy>&& process, PageIdentifier webPageID, URLSchemeTaskParameters&& parameters)
10277{
10278 MESSAGE_CHECK(m_process, decltype(m_urlSchemeHandlersByIdentifier)::isValidKey(parameters.handlerIdentifier));
10279 auto iterator = m_urlSchemeHandlersByIdentifier.find(parameters.handlerIdentifier);
10280 MESSAGE_CHECK(process, iterator != m_urlSchemeHandlersByIdentifier.end());
10281
10282 iterator->value->startTask(*this, process, webPageID, WTFMove(parameters), nullptr);
10283}
10284
10285void WebPageProxy::stopURLSchemeTask(WebURLSchemeHandlerIdentifier handlerIdentifier, WebCore::ResourceLoaderIdentifier taskIdentifier)
10286{
10287 MESSAGE_CHECK(m_process, decltype(m_urlSchemeHandlersByIdentifier)::isValidKey(handlerIdentifier));
10288 auto iterator = m_urlSchemeHandlersByIdentifier.find(handlerIdentifier);
10289 MESSAGE_CHECK(m_process, iterator != m_urlSchemeHandlersByIdentifier.end());
10290
10291 iterator->value->stopTask(*this, taskIdentifier);
10292}
10293
10294void WebPageProxy::loadSynchronousURLSchemeTask(URLSchemeTaskParameters&& parameters, Messages::WebPageProxy::LoadSynchronousURLSchemeTask::DelayedReply&& reply)
10295{
10296 MESSAGE_CHECK(m_process, decltype(m_urlSchemeHandlersByIdentifier)::isValidKey(parameters.handlerIdentifier));
10297 auto iterator = m_urlSchemeHandlersByIdentifier.find(parameters.handlerIdentifier);
10298 MESSAGE_CHECK(m_process, iterator != m_urlSchemeHandlersByIdentifier.end());
10299
10300 iterator->value->startTask(*this, m_process, m_webPageID, WTFMove(parameters), WTFMove(reply));
10301}
10302
10303#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
10304void WebPageProxy::requestStorageAccessConfirm(const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, FrameIdentifier frameID, CompletionHandler<void(bool)>&& completionHandler)
10305{
10306 m_uiClient->requestStorageAccessConfirm(*this, m_process->webFrame(frameID), subFrameDomain, topFrameDomain, WTFMove(completionHandler));
10307}
10308
10309void WebPageProxy::didCommitCrossSiteLoadWithDataTransferFromPrevalentResource()
10310{
10311 if (!hasRunningProcess())
10312 return;
10313
10314 send(Messages::WebPage::WasLoadedWithDataTransferFromPrevalentResource());
10315}
10316#endif
10317
10318bool WebPageProxy::useDarkAppearance() const
10319{
10320 return pageClient().effectiveAppearanceIsDark();
10321}
10322
10323bool WebPageProxy::useElevatedUserInterfaceLevel() const
10324{
10325 return pageClient().effectiveUserInterfaceLevelIsElevated();
10326}
10327
10328void WebPageProxy::effectiveAppearanceDidChange()
10329{
10330 if (!hasRunningProcess())
10331 return;
10332
10333 send(Messages::WebPage::EffectiveAppearanceDidChange(useDarkAppearance(), useElevatedUserInterfaceLevel()));
10334}
10335
10336#if HAVE(TOUCH_BAR)
10337void WebPageProxy::touchBarMenuDataChanged(const TouchBarMenuData& touchBarMenuData)
10338{
10339 m_touchBarMenuData = touchBarMenuData;
10340}
10341
10342void WebPageProxy::touchBarMenuItemDataAdded(const TouchBarMenuItemData& touchBarMenuItemData)
10343{
10344 m_touchBarMenuData.addMenuItem(touchBarMenuItemData);
10345}
10346
10347void WebPageProxy::touchBarMenuItemDataRemoved(const TouchBarMenuItemData& touchBarMenuItemData)
10348{
10349 m_touchBarMenuData.removeMenuItem(touchBarMenuItemData);
10350}
10351#endif
10352
10353#if HAVE(PASTEBOARD_DATA_OWNER)
10354
10355DataOwnerType WebPageProxy::dataOwnerForPasteboard(PasteboardAccessIntent intent) const
10356{
10357 return pageClient().dataOwnerForPasteboard(intent);
10358}
10359
10360#endif
10361
10362#if ENABLE(ATTACHMENT_ELEMENT)
10363
10364#if PLATFORM(IOS_FAMILY)
10365void WebPageProxy::writePromisedAttachmentToPasteboard(WebCore::PromisedAttachmentInfo&& info, const String& authorizationToken)
10366{
10367 MESSAGE_CHECK(m_process, isValidPerformActionOnElementAuthorizationToken(authorizationToken));
10368
10369 pageClient().writePromisedAttachmentToPasteboard(WTFMove(info));
10370}
10371#endif
10372
10373void WebPageProxy::requestAttachmentIcon(const String& identifier, const String& contentType, const String& fileName, const String& title, const FloatSize& requestedSize)
10374{
10375 FloatSize size = requestedSize;
10376 ShareableBitmap::Handle handle;
10377#if PLATFORM(MAC)
10378 auto attachment = attachmentForIdentifier(identifier);
10379 if (attachment && attachment->contentType() == "public.directory"_s) {
10380 updateIconForDirectory(attachment->fileWrapper(), attachment->identifier());
10381 return;
10382 }
10383#endif
10384
10385#if PLATFORM(COCOA)
10386 if (auto icon = iconForAttachment(fileName, contentType, title, size))
10387 icon->createHandle(handle);
10388#endif
10389 send(Messages::WebPage::UpdateAttachmentIcon(identifier, handle, size));
10390}
10391
10392RefPtr<API::Attachment> WebPageProxy::attachmentForIdentifier(const String& identifier) const
10393{
10394 if (identifier.isEmpty())
10395 return nullptr;
10396
10397 return m_attachmentIdentifierToAttachmentMap.get(identifier);
10398}
10399
10400void WebPageProxy::insertAttachment(Ref<API::Attachment>&& attachment, CompletionHandler<void()>&& callback)
10401{
10402 auto attachmentIdentifier = attachment->identifier();
10403 sendWithAsyncReply(Messages::WebPage::InsertAttachment(attachmentIdentifier, attachment->fileSizeForDisplay(), attachment->fileName(), attachment->contentType()), WTFMove(callback));
10404 m_attachmentIdentifierToAttachmentMap.set(attachmentIdentifier, WTFMove(attachment));
10405}
10406
10407void WebPageProxy::updateAttachmentAttributes(const API::Attachment& attachment, CompletionHandler<void()>&& callback)
10408{
10409#if HAVE(QUICKLOOK_THUMBNAILING)
10410 requestThumbnailWithFileWrapper(attachment.fileWrapper(), attachment.identifier());
10411#endif
10412
10413 sendWithAsyncReply(Messages::WebPage::UpdateAttachmentAttributes(attachment.identifier(), attachment.fileSizeForDisplay(), attachment.contentType(), attachment.fileName(), IPC::SharedBufferReference(attachment.enclosingImageData())), WTFMove(callback));
10414}
10415
10416#if HAVE(QUICKLOOK_THUMBNAILING)
10417void WebPageProxy::updateAttachmentThumbnail(const String& identifier, const RefPtr<ShareableBitmap>& bitmap)
10418{
10419 if (!hasRunningProcess())
10420 return;
10421
10422 ShareableBitmap::Handle handle;
10423 if (bitmap)
10424 bitmap->createHandle(handle);
10425
10426 send(Messages::WebPage::UpdateAttachmentThumbnail(identifier, handle));
10427}
10428#endif
10429
10430void WebPageProxy::registerAttachmentIdentifierFromData(const String& identifier, const String& contentType, const String& preferredFileName, const IPC::SharedBufferReference& data)
10431{
10432 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10433 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(identifier));
10434
10435 if (attachmentForIdentifier(identifier))
10436 return;
10437
10438 auto attachment = ensureAttachment(identifier);
10439 attachment->setContentType(contentType);
10440 m_attachmentIdentifierToAttachmentMap.set(identifier, attachment.copyRef());
10441
10442 platformRegisterAttachment(WTFMove(attachment), preferredFileName, data);
10443}
10444
10445void WebPageProxy::registerAttachmentIdentifierFromFilePath(const String& identifier, const String& contentType, const String& filePath)
10446{
10447 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10448 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(identifier));
10449
10450 if (attachmentForIdentifier(identifier))
10451 return;
10452
10453 auto attachment = ensureAttachment(identifier);
10454 attachment->setContentType(contentType);
10455 attachment->setFilePath(filePath);
10456 m_attachmentIdentifierToAttachmentMap.set(identifier, attachment.copyRef());
10457 platformRegisterAttachment(WTFMove(attachment), filePath);
10458#if HAVE(QUICKLOOK_THUMBNAILING)
10459 requestThumbnailWithPath(identifier, filePath);
10460#endif
10461}
10462
10463void WebPageProxy::registerAttachmentIdentifier(const String& identifier)
10464{
10465 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10466 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(identifier));
10467
10468 if (!attachmentForIdentifier(identifier))
10469 m_attachmentIdentifierToAttachmentMap.set(identifier, ensureAttachment(identifier));
10470}
10471
10472void WebPageProxy::registerAttachmentsFromSerializedData(Vector<WebCore::SerializedAttachmentData>&& data)
10473{
10474 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10475
10476 for (auto& serializedData : data) {
10477 auto identifier = WTFMove(serializedData.identifier);
10478 if (!attachmentForIdentifier(identifier)) {
10479 auto attachment = ensureAttachment(identifier);
10480 attachment->updateFromSerializedRepresentation(WTFMove(serializedData.data), WTFMove(serializedData.mimeType));
10481#if HAVE(QUICKLOOK_THUMBNAILING)
10482 requestThumbnailWithFileWrapper(attachment->fileWrapper(), identifier);
10483#endif
10484 }
10485 }
10486}
10487
10488void WebPageProxy::cloneAttachmentData(const String& fromIdentifier, const String& toIdentifier)
10489{
10490 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10491 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(fromIdentifier));
10492 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(toIdentifier));
10493
10494 auto newAttachment = ensureAttachment(toIdentifier);
10495 auto existingAttachment = attachmentForIdentifier(fromIdentifier);
10496 if (!existingAttachment) {
10497 ASSERT_NOT_REACHED();
10498 return;
10499 }
10500
10501 newAttachment->setContentType(existingAttachment->contentType());
10502 newAttachment->setFilePath(existingAttachment->filePath());
10503
10504 platformCloneAttachment(existingAttachment.releaseNonNull(), WTFMove(newAttachment));
10505}
10506
10507void WebPageProxy::invalidateAllAttachments()
10508{
10509 for (auto& attachment : m_attachmentIdentifierToAttachmentMap.values()) {
10510 if (attachment->insertionState() == API::Attachment::InsertionState::Inserted)
10511 didRemoveAttachment(attachment.get());
10512 attachment->invalidate();
10513 }
10514 m_attachmentIdentifierToAttachmentMap.clear();
10515}
10516
10517void WebPageProxy::serializedAttachmentDataForIdentifiers(const Vector<String>& identifiers, CompletionHandler<void(Vector<WebCore::SerializedAttachmentData>&&)>&& completionHandler)
10518{
10519 Vector<WebCore::SerializedAttachmentData> serializedData;
10520
10521 MESSAGE_CHECK_COMPLETION(m_process, m_preferences->attachmentElementEnabled(), completionHandler(WTFMove(serializedData)));
10522
10523 for (const auto& identifier : identifiers) {
10524 auto attachment = attachmentForIdentifier(identifier);
10525 if (!attachment)
10526 continue;
10527
10528 auto data = attachment->createSerializedRepresentation();
10529 if (!data)
10530 continue;
10531
10532 serializedData.append({ identifier, attachment->mimeType(), data.releaseNonNull() });
10533 }
10534 completionHandler(WTFMove(serializedData));
10535}
10536
10537void WebPageProxy::didInvalidateDataForAttachment(API::Attachment& attachment)
10538{
10539 pageClient().didInvalidateDataForAttachment(attachment);
10540}
10541
10542WebPageProxy::ShouldUpdateAttachmentAttributes WebPageProxy::willUpdateAttachmentAttributes(const API::Attachment& attachment)
10543{
10544 return ShouldUpdateAttachmentAttributes::Yes;
10545}
10546
10547#if !PLATFORM(COCOA)
10548
10549void WebPageProxy::platformRegisterAttachment(Ref<API::Attachment>&&, const String&, const IPC::SharedBufferReference&)
10550{
10551}
10552
10553void WebPageProxy::platformRegisterAttachment(Ref<API::Attachment>&&, const String&)
10554{
10555}
10556
10557void WebPageProxy::platformCloneAttachment(Ref<API::Attachment>&&, Ref<API::Attachment>&&)
10558{
10559}
10560
10561#endif
10562
10563void WebPageProxy::didInsertAttachmentWithIdentifier(const String& identifier, const String& source, bool hasEnclosingImage)
10564{
10565 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10566 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(identifier));
10567
10568 auto attachment = ensureAttachment(identifier);
10569 attachment->setHasEnclosingImage(hasEnclosingImage);
10570 attachment->setInsertionState(API::Attachment::InsertionState::Inserted);
10571 pageClient().didInsertAttachment(attachment.get(), source);
10572
10573 if (!attachment->isEmpty() && hasEnclosingImage)
10574 updateAttachmentAttributes(attachment.get(), [] { });
10575}
10576
10577void WebPageProxy::didRemoveAttachmentWithIdentifier(const String& identifier)
10578{
10579 MESSAGE_CHECK(m_process, m_preferences->attachmentElementEnabled());
10580 MESSAGE_CHECK(m_process, IdentifierToAttachmentMap::isValidKey(identifier));
10581
10582 if (auto attachment = attachmentForIdentifier(identifier))
10583 didRemoveAttachment(*attachment);
10584}
10585
10586void WebPageProxy::didRemoveAttachment(API::Attachment& attachment)
10587{
10588 attachment.setInsertionState(API::Attachment::InsertionState::NotInserted);
10589 pageClient().didRemoveAttachment(attachment);
10590}
10591
10592Ref<API::Attachment> WebPageProxy::ensureAttachment(const String& identifier)
10593{
10594 if (auto existingAttachment = attachmentForIdentifier(identifier))
10595 return *existingAttachment;
10596
10597 auto attachment = API::Attachment::create(identifier, *this);
10598 m_attachmentIdentifierToAttachmentMap.set(identifier, attachment.copyRef());
10599 return attachment;
10600}
10601
10602#endif // ENABLE(ATTACHMENT_ELEMENT)
10603
10604#if ENABLE(APPLICATION_MANIFEST)
10605void WebPageProxy::getApplicationManifest(CompletionHandler<void(const std::optional<WebCore::ApplicationManifest>&)>&& callback)
10606{
10607 sendWithAsyncReply(Messages::WebPage::GetApplicationManifest(), WTFMove(callback));
10608}
10609#endif
10610
10611#if ENABLE(APP_HIGHLIGHTS)
10612void WebPageProxy::storeAppHighlight(const WebCore::AppHighlight& highlight)
10613{
10614 MESSAGE_CHECK(m_process, !highlight.highlight->isEmpty());
10615
10616 pageClient().storeAppHighlight(highlight);
10617
10618}
10619#endif
10620
10621namespace {
10622enum class CompletionCondition {
10623 Cancellation,
10624 Error,
10625 Success,
10626 Timeout,
10627};
10628struct MessageType {
10629 CompletionCondition condition;
10630 Seconds seconds;
10631 String message;
10632};
10633}
10634
10635void WebPageProxy::reportPageLoadResult(const ResourceError& error)
10636{
10637 static const NeverDestroyed<Vector<MessageType>> messages(std::initializer_list<MessageType> {
10638 { CompletionCondition::Cancellation, 2_s, DiagnosticLoggingKeys::canceledLessThan2SecondsKey() },
10639 { CompletionCondition::Cancellation, 5_s, DiagnosticLoggingKeys::canceledLessThan5SecondsKey() },
10640 { CompletionCondition::Cancellation, 20_s, DiagnosticLoggingKeys::canceledLessThan20SecondsKey() },
10641 { CompletionCondition::Cancellation, Seconds::infinity(), DiagnosticLoggingKeys::canceledMoreThan20SecondsKey() },
10642
10643 { CompletionCondition::Error, 2_s, DiagnosticLoggingKeys::failedLessThan2SecondsKey() },
10644 { CompletionCondition::Error, 5_s, DiagnosticLoggingKeys::failedLessThan5SecondsKey() },
10645 { CompletionCondition::Error, 20_s, DiagnosticLoggingKeys::failedLessThan20SecondsKey() },
10646 { CompletionCondition::Error, Seconds::infinity(), DiagnosticLoggingKeys::failedMoreThan20SecondsKey() },
10647
10648 { CompletionCondition::Success, 2_s, DiagnosticLoggingKeys::succeededLessThan2SecondsKey() },
10649 { CompletionCondition::Success, 5_s, DiagnosticLoggingKeys::succeededLessThan5SecondsKey() },
10650 { CompletionCondition::Success, 20_s, DiagnosticLoggingKeys::succeededLessThan20SecondsKey() },
10651 { CompletionCondition::Success, Seconds::infinity(), DiagnosticLoggingKeys::succeededMoreThan20SecondsKey() },
10652
10653 { CompletionCondition::Timeout, Seconds::infinity(), DiagnosticLoggingKeys::timedOutKey() }
10654 });
10655
10656 if (!m_pageLoadStart)
10657 return;
10658
10659 auto pageLoadTime = MonotonicTime::now() - *m_pageLoadStart;
10660 m_pageLoadStart = std::nullopt;
10661
10662 CompletionCondition condition { CompletionCondition::Success };
10663 if (error.isCancellation())
10664 condition = CompletionCondition::Cancellation;
10665 else if (error.isTimeout())
10666 condition = CompletionCondition::Timeout;
10667 else if (!error.isNull() || error.errorCode())
10668 condition = CompletionCondition::Error;
10669
10670 for (auto& messageItem : messages.get()) {
10671 if (condition == messageItem.condition && pageLoadTime < messageItem.seconds) {
10672 logDiagnosticMessage(DiagnosticLoggingKeys::telemetryPageLoadKey(), messageItem.message, ShouldSample::No);
10673 logDiagnosticMessage(DiagnosticLoggingKeys::telemetryPageLoadKey(), DiagnosticLoggingKeys::occurredKey(), ShouldSample::No);
10674 break;
10675 }
10676 }
10677}
10678
10679void WebPageProxy::setDefersLoadingForTesting(bool defersLoading)
10680{
10681 send(Messages::WebPage::SetDefersLoading(defersLoading));
10682}
10683
10684void WebPageProxy::getIsViewVisible(bool& result)
10685{
10686 result = isViewVisible();
10687}
10688
10689void WebPageProxy::updateCurrentModifierState()
10690{
10691#if PLATFORM(COCOA)
10692 auto modifiers = PlatformKeyboardEvent::currentStateOfModifierKeys();
10693 send(Messages::WebPage::UpdateCurrentModifierState(modifiers));
10694#endif
10695}
10696
10697bool WebPageProxy::checkURLReceivedFromCurrentOrPreviousWebProcess(WebProcessProxy& process, const String& urlString)
10698{
10699 return checkURLReceivedFromCurrentOrPreviousWebProcess(process, URL { urlString });
10700}
10701
10702bool WebPageProxy::checkURLReceivedFromCurrentOrPreviousWebProcess(WebProcessProxy& process, const URL& url)
10703{
10704 if (!url.isLocalFile())
10705 return true;
10706
10707 if (m_mayHaveUniversalFileReadSandboxExtension)
10708 return true;
10709
10710 String path = url.fileSystemPath();
10711 auto startsWithURLPath = [&path](const String& visitedPath) {
10712 return path.startsWith(visitedPath);
10713 };
10714
10715 auto localPathsEnd = m_previouslyVisitedPaths.end();
10716 if (std::find_if(m_previouslyVisitedPaths.begin(), localPathsEnd, startsWithURLPath) != localPathsEnd)
10717 return true;
10718
10719 return process.checkURLReceivedFromWebProcess(url);
10720}
10721
10722void WebPageProxy::addPreviouslyVisitedPath(const String& path)
10723{
10724 m_previouslyVisitedPaths.add(path);
10725}
10726
10727void WebPageProxy::willAcquireUniversalFileReadSandboxExtension(WebProcessProxy& process)
10728{
10729 m_mayHaveUniversalFileReadSandboxExtension = true;
10730 process.willAcquireUniversalFileReadSandboxExtension();
10731}
10732
10733void WebPageProxy::simulateDeviceOrientationChange(double alpha, double beta, double gamma)
10734{
10735 send(Messages::WebPage::SimulateDeviceOrientationChange(alpha, beta, gamma));
10736}
10737
10738#if ENABLE(DATA_DETECTION)
10739
10740void WebPageProxy::detectDataInAllFrames(OptionSet<WebCore::DataDetectorType> types, CompletionHandler<void(const DataDetectionResult&)>&& completionHandler)
10741{
10742 if (!hasRunningProcess()) {
10743 completionHandler({ });
10744 return;
10745 }
10746 sendWithAsyncReply(Messages::WebPage::DetectDataInAllFrames(types), WTFMove(completionHandler));
10747}
10748
10749void WebPageProxy::removeDataDetectedLinks(CompletionHandler<void(const DataDetectionResult&)>&& completionHandler)
10750{
10751 if (!hasRunningProcess()) {
10752 completionHandler({ });
10753 return;
10754 }
10755 sendWithAsyncReply(Messages::WebPage::RemoveDataDetectedLinks(), WTFMove(completionHandler));
10756}
10757
10758#endif
10759
10760#if USE(SYSTEM_PREVIEW)
10761void WebPageProxy::systemPreviewActionTriggered(const WebCore::SystemPreviewInfo& previewInfo, const String& message)
10762{
10763 send(Messages::WebPage::SystemPreviewActionTriggered(previewInfo, message));
10764}
10765#endif
10766
10767void WebPageProxy::dumpPrivateClickMeasurement(CompletionHandler<void(const String&)>&& completionHandler)
10768{
10769 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::DumpPrivateClickMeasurement(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10770}
10771
10772void WebPageProxy::clearPrivateClickMeasurement(CompletionHandler<void()>&& completionHandler)
10773{
10774 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::ClearPrivateClickMeasurement(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10775}
10776
10777void WebPageProxy::setPrivateClickMeasurementOverrideTimerForTesting(bool value, CompletionHandler<void()>&& completionHandler)
10778{
10779 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPrivateClickMeasurementOverrideTimerForTesting(m_websiteDataStore->sessionID(), value), WTFMove(completionHandler));
10780}
10781
10782void WebPageProxy::markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&& completionHandler)
10783{
10784 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::MarkAttributedPrivateClickMeasurementsAsExpiredForTesting(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10785}
10786
10787void WebPageProxy::setPrivateClickMeasurementEphemeralMeasurementForTesting(bool value, CompletionHandler<void()>&& completionHandler)
10788{
10789 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPrivateClickMeasurementEphemeralMeasurementForTesting(m_websiteDataStore->sessionID(), value), WTFMove(completionHandler));
10790}
10791
10792void WebPageProxy::simulatePrivateClickMeasurementSessionRestart(CompletionHandler<void()>&& completionHandler)
10793{
10794 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SimulatePrivateClickMeasurementSessionRestart(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10795}
10796
10797void WebPageProxy::setPrivateClickMeasurementTokenPublicKeyURLForTesting(const URL& url, CompletionHandler<void()>&& completionHandler)
10798{
10799 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPrivateClickMeasurementTokenPublicKeyURLForTesting(m_websiteDataStore->sessionID(), url), WTFMove(completionHandler));
10800}
10801
10802void WebPageProxy::setPrivateClickMeasurementTokenSignatureURLForTesting(const URL& url, CompletionHandler<void()>&& completionHandler)
10803{
10804 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPrivateClickMeasurementTokenSignatureURLForTesting(m_websiteDataStore->sessionID(), url), WTFMove(completionHandler));
10805}
10806
10807void WebPageProxy::setPrivateClickMeasurementAttributionReportURLsForTesting(const URL& sourceURL, const URL& destinationURL, CompletionHandler<void()>&& completionHandler)
10808{
10809 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPrivateClickMeasurementAttributionReportURLsForTesting(m_websiteDataStore->sessionID(), sourceURL, destinationURL), WTFMove(completionHandler));
10810}
10811
10812void WebPageProxy::markPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&& completionHandler)
10813{
10814 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::MarkPrivateClickMeasurementsAsExpiredForTesting(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
10815}
10816
10817void WebPageProxy::setPCMFraudPreventionValuesForTesting(const String& unlinkableToken, const String& secretToken, const String& signature, const String& keyID, CompletionHandler<void()>&& completionHandler)
10818{
10819 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPCMFraudPreventionValuesForTesting(m_websiteDataStore->sessionID(), unlinkableToken, secretToken, signature, keyID), WTFMove(completionHandler));
10820}
10821
10822void WebPageProxy::setPrivateClickMeasurementAppBundleIDForTesting(const String& appBundleIDForTesting, CompletionHandler<void()>&& completionHandler)
10823{
10824 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SetPrivateClickMeasurementAppBundleIDForTesting(m_websiteDataStore->sessionID(), appBundleIDForTesting), WTFMove(completionHandler));
10825}
10826
10827#if ENABLE(SPEECH_SYNTHESIS)
10828
10829void WebPageProxy::resetSpeechSynthesizer()
10830{
10831 if (!m_speechSynthesisData)
10832 return;
10833
10834 auto& synthesisData = speechSynthesisData();
10835 synthesisData.speakingFinishedCompletionHandler = nullptr;
10836 synthesisData.speakingStartedCompletionHandler = nullptr;
10837 synthesisData.speakingPausedCompletionHandler = nullptr;
10838 synthesisData.speakingResumedCompletionHandler = nullptr;
10839 if (synthesisData.synthesizer)
10840 synthesisData.synthesizer->resetState();
10841}
10842
10843WebPageProxy::SpeechSynthesisData& WebPageProxy::speechSynthesisData()
10844{
10845 if (!m_speechSynthesisData)
10846 m_speechSynthesisData = SpeechSynthesisData { makeUnique<PlatformSpeechSynthesizer>(this), nullptr, nullptr, nullptr, nullptr, nullptr };
10847 return *m_speechSynthesisData;
10848}
10849
10850void WebPageProxy::speechSynthesisVoiceList(CompletionHandler<void(Vector<WebSpeechSynthesisVoice>&&)>&& completionHandler)
10851{
10852 auto result = speechSynthesisData().synthesizer->voiceList().map([](auto& voice) {
10853 return WebSpeechSynthesisVoice { voice->voiceURI(), voice->name(), voice->lang(), voice->localService(), voice->isDefault() };
10854 });
10855 completionHandler(WTFMove(result));
10856}
10857
10858void WebPageProxy::speechSynthesisSetFinishedCallback(CompletionHandler<void()>&& completionHandler)
10859{
10860 speechSynthesisData().speakingFinishedCompletionHandler = WTFMove(completionHandler);
10861}
10862
10863void 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)
10864{
10865 auto voice = WebCore::PlatformSpeechSynthesisVoice::create(voiceURI, voiceName, voiceLang, localService, defaultVoice);
10866 auto utterance = WebCore::PlatformSpeechSynthesisUtterance::create(*this);
10867 utterance->setText(text);
10868 utterance->setLang(lang);
10869 utterance->setVolume(volume);
10870 utterance->setRate(rate);
10871 utterance->setPitch(pitch);
10872 utterance->setVoice(&voice.get());
10873
10874 speechSynthesisData().speakingStartedCompletionHandler = WTFMove(completionHandler);
10875 speechSynthesisData().utterance = WTFMove(utterance);
10876 speechSynthesisData().synthesizer->speak(m_speechSynthesisData->utterance.get());
10877}
10878
10879void WebPageProxy::speechSynthesisCancel()
10880{
10881 speechSynthesisData().synthesizer->cancel();
10882}
10883
10884void WebPageProxy::speechSynthesisResetState()
10885{
10886 speechSynthesisData().synthesizer->resetState();
10887}
10888
10889void WebPageProxy::speechSynthesisPause(CompletionHandler<void()>&& completionHandler)
10890{
10891 speechSynthesisData().speakingPausedCompletionHandler = WTFMove(completionHandler);
10892 speechSynthesisData().synthesizer->pause();
10893}
10894
10895void WebPageProxy::speechSynthesisResume(CompletionHandler<void()>&& completionHandler)
10896{
10897 speechSynthesisData().speakingResumedCompletionHandler = WTFMove(completionHandler);
10898 speechSynthesisData().synthesizer->resume();
10899}
10900#endif // ENABLE(SPEECH_SYNTHESIS)
10901
10902#if !PLATFORM(IOS_FAMILY)
10903
10904WebContentMode WebPageProxy::effectiveContentModeAfterAdjustingPolicies(API::WebsitePolicies&, const WebCore::ResourceRequest&)
10905{
10906 return WebContentMode::Recommended;
10907}
10908
10909#endif // !PLATFORM(IOS_FAMILY)
10910
10911void WebPageProxy::addObserver(WebViewDidMoveToWindowObserver& observer)
10912{
10913 auto result = m_webViewDidMoveToWindowObservers.add(&observer, observer);
10914 ASSERT_UNUSED(result, result.isNewEntry);
10915}
10916
10917void WebPageProxy::removeObserver(WebViewDidMoveToWindowObserver& observer)
10918{
10919 auto result = m_webViewDidMoveToWindowObservers.remove(&observer);
10920 ASSERT_UNUSED(result, result);
10921}
10922
10923void WebPageProxy::webViewDidMoveToWindow()
10924{
10925 auto observersCopy = m_webViewDidMoveToWindowObservers;
10926 for (const auto& observer : observersCopy) {
10927 if (!observer.value)
10928 continue;
10929 observer.value->webViewDidMoveToWindow();
10930 }
10931
10932 auto newWindowKind = pageClient().windowKind();
10933 if (m_windowKind != newWindowKind) {
10934 m_windowKind = newWindowKind;
10935 if (m_drawingArea)
10936 m_drawingArea->windowKindDidChange();
10937 }
10938}
10939
10940void WebPageProxy::setCanShowPlaceholder(const WebCore::ElementContext& context, bool canShowPlaceholder)
10941{
10942 if (hasRunningProcess())
10943 send(Messages::WebPage::SetCanShowPlaceholder(context, canShowPlaceholder));
10944}
10945
10946Logger& WebPageProxy::logger()
10947{
10948 if (!m_logger) {
10949 m_logger = Logger::create(this);
10950 // FIXME: Does this really need to be disabled in ephemeral sessions?
10951 m_logger->setEnabled(this, !sessionID().isEphemeral());
10952 }
10953
10954 return *m_logger;
10955}
10956
10957void WebPageProxy::configureLoggingChannel(const String& channelName, WTFLogChannelState state, WTFLogLevel level)
10958{
10959#if !RELEASE_LOG_DISABLED
10960 auto* channel = getLogChannel(channelName);
10961 if (!channel)
10962 return;
10963
10964 channel->state = state;
10965 channel->level = level;
10966#else
10967 UNUSED_PARAM(channelName);
10968 UNUSED_PARAM(state);
10969 UNUSED_PARAM(level);
10970#endif
10971}
10972
10973#if HAVE(APP_SSO)
10974void WebPageProxy::decidePolicyForSOAuthorizationLoad(const String& extension, CompletionHandler<void(SOAuthorizationLoadPolicy)>&& completionHandler)
10975{
10976 m_navigationClient->decidePolicyForSOAuthorizationLoad(*this, SOAuthorizationLoadPolicy::Allow, extension, WTFMove(completionHandler));
10977}
10978#endif
10979
10980#if ENABLE(WEB_AUTHN)
10981void WebPageProxy::setMockWebAuthenticationConfiguration(MockWebAuthenticationConfiguration&& configuration)
10982{
10983 m_websiteDataStore->setMockWebAuthenticationConfiguration(WTFMove(configuration));
10984}
10985#endif
10986
10987void WebPageProxy::startTextManipulations(const Vector<WebCore::TextManipulationController::ExclusionRule>& exclusionRules,
10988 TextManipulationItemCallback&& callback, WTF::CompletionHandler<void()>&& completionHandler)
10989{
10990 if (!hasRunningProcess()) {
10991 completionHandler();
10992 return;
10993 }
10994 m_textManipulationItemCallback = WTFMove(callback);
10995 sendWithAsyncReply(Messages::WebPage::StartTextManipulations(exclusionRules), WTFMove(completionHandler));
10996}
10997
10998void WebPageProxy::didFindTextManipulationItems(const Vector<WebCore::TextManipulationController::ManipulationItem>& items)
10999{
11000 if (!m_textManipulationItemCallback)
11001 return;
11002 m_textManipulationItemCallback(items);
11003}
11004
11005void WebPageProxy::completeTextManipulation(const Vector<WebCore::TextManipulationController::ManipulationItem>& items,
11006 WTF::Function<void(bool allFailed, const Vector<WebCore::TextManipulationController::ManipulationFailure>&)>&& completionHandler)
11007{
11008 if (!hasRunningProcess()) {
11009 completionHandler(true, { });
11010 return;
11011 }
11012 sendWithAsyncReply(Messages::WebPage::CompleteTextManipulation(items), WTFMove(completionHandler));
11013}
11014
11015void WebPageProxy::setCORSDisablingPatterns(Vector<String>&& patterns)
11016{
11017 m_corsDisablingPatterns = WTFMove(patterns);
11018 send(Messages::WebPage::UpdateCORSDisablingPatterns(m_corsDisablingPatterns));
11019}
11020
11021void WebPageProxy::setOverriddenMediaType(const String& mediaType)
11022{
11023 m_overriddenMediaType = mediaType;
11024 send(Messages::WebPage::SetOverriddenMediaType(mediaType));
11025}
11026
11027void WebPageProxy::setIsTakingSnapshotsForApplicationSuspension(bool isTakingSnapshotsForApplicationSuspension)
11028{
11029 send(Messages::WebPage::SetIsTakingSnapshotsForApplicationSuspension(isTakingSnapshotsForApplicationSuspension));
11030}
11031
11032void WebPageProxy::setNeedsDOMWindowResizeEvent()
11033{
11034 send(Messages::WebPage::SetNeedsDOMWindowResizeEvent());
11035}
11036
11037void WebPageProxy::loadServiceWorker(const URL& url, CompletionHandler<void(bool success)>&& completionHandler)
11038{
11039#if ENABLE(SERVICE_WORKER)
11040 if (m_isClosed)
11041 return completionHandler(false);
11042
11043 WEBPAGEPROXY_RELEASE_LOG(Loading, "loadServiceWorker:");
11044
11045 if (m_serviceWorkerLaunchCompletionHandler)
11046 return completionHandler(false);
11047
11048 m_isServiceWorkerPage = true;
11049 m_serviceWorkerLaunchCompletionHandler = WTFMove(completionHandler);
11050
11051 CString html = makeString("<script>navigator.serviceWorker.register('", url.string().utf8().data(), "');</script>").utf8();
11052 loadData({ reinterpret_cast<const uint8_t*>(html.data()), html.length() }, "text/html"_s, "UTF-8"_s, url.protocolHostAndPort());
11053#else
11054 UNUSED_PARAM(url);
11055 completionHandler(false);
11056#endif
11057}
11058
11059#if !PLATFORM(IOS_FAMILY)
11060bool WebPageProxy::shouldForceForegroundPriorityForClientNavigation() const
11061{
11062 return false;
11063}
11064#endif
11065
11066void WebPageProxy::getProcessDisplayName(CompletionHandler<void(String&&)>&& completionHandler)
11067{
11068 sendWithAsyncReply(Messages::WebPage::GetProcessDisplayName(), WTFMove(completionHandler));
11069}
11070
11071void WebPageProxy::setOrientationForMediaCapture(uint64_t orientation)
11072{
11073#if ENABLE(MEDIA_STREAM)
11074#if PLATFORM(COCOA)
11075 if (auto* proxy = m_process->userMediaCaptureManagerProxy())
11076 proxy->setOrientation(orientation);
11077
11078 auto* gpuProcess = m_process->processPool().gpuProcess();
11079 if (gpuProcess && preferences().captureVideoInGPUProcessEnabled())
11080 gpuProcess->setOrientationForMediaCapture(orientation);
11081#elif USE(GSTREAMER)
11082 send(Messages::WebPage::SetOrientationForMediaCapture(orientation));
11083#endif
11084#endif
11085}
11086
11087#if ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
11088void WebPageProxy::setMockCaptureDevicesInterrupted(bool isCameraInterrupted, bool isMicrophoneInterrupted)
11089{
11090 send(Messages::WebPage::SetMockCaptureDevicesInterrupted(isCameraInterrupted, isMicrophoneInterrupted));
11091}
11092#endif
11093
11094#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
11095void WebPageProxy::getLoadedSubresourceDomains(CompletionHandler<void(Vector<RegistrableDomain>&&)>&& completionHandler)
11096{
11097 sendWithAsyncReply(Messages::WebPage::GetLoadedSubresourceDomains(), WTFMove(completionHandler));
11098}
11099
11100void WebPageProxy::clearLoadedSubresourceDomains()
11101{
11102 send(Messages::WebPage::ClearLoadedSubresourceDomains());
11103}
11104#endif
11105
11106#if ENABLE(GPU_PROCESS)
11107void WebPageProxy::gpuProcessDidFinishLaunching()
11108{
11109 pageClient().gpuProcessDidFinishLaunching();
11110}
11111
11112void WebPageProxy::gpuProcessExited(ProcessTerminationReason)
11113{
11114#if HAVE(VISIBILITY_PROPAGATION_VIEW)
11115 m_contextIDForVisibilityPropagationInGPUProcess = 0;
11116#endif
11117
11118 pageClient().gpuProcessDidExit();
11119
11120#if ENABLE(MEDIA_STREAM)
11121 bool activeAudioCapture = isCapturingAudio() && preferences().captureAudioInGPUProcessEnabled();
11122 bool activeVideoCapture = isCapturingVideo() && preferences().captureVideoInGPUProcessEnabled();
11123 bool activeDisplayCapture = false;
11124 if (activeAudioCapture || activeVideoCapture) {
11125 auto& gpuProcess = process().processPool().ensureGPUProcess();
11126 gpuProcess.updateCaptureAccess(activeAudioCapture, activeVideoCapture, activeDisplayCapture, m_process->coreProcessIdentifier(), [] { });
11127 }
11128#endif
11129}
11130#endif
11131
11132#if ENABLE(CONTEXT_MENUS) && !PLATFORM(MAC)
11133
11134void WebPageProxy::platformDidSelectItemFromActiveContextMenu(const WebContextMenuItemData&)
11135{
11136}
11137
11138#endif
11139
11140#if !PLATFORM(COCOA)
11141
11142void WebPageProxy::willPerformPasteCommand(DOMPasteAccessCategory)
11143{
11144}
11145
11146#endif
11147
11148void WebPageProxy::dispatchActivityStateUpdateForTesting()
11149{
11150 RunLoop::current().dispatch([protectedThis = Ref { *this }] {
11151 protectedThis->dispatchActivityStateChange();
11152 });
11153}
11154
11155void WebPageProxy::isLayerTreeFrozen(CompletionHandler<void(bool)>&& completionHandler)
11156{
11157 sendWithAsyncReply(Messages::WebPage::IsLayerTreeFrozen(), WTFMove(completionHandler));
11158}
11159
11160void WebPageProxy::requestSpeechRecognitionPermission(WebCore::SpeechRecognitionRequest& request, CompletionHandler<void(std::optional<SpeechRecognitionError>&&)>&& completionHandler)
11161{
11162 if (!m_speechRecognitionPermissionManager)
11163 m_speechRecognitionPermissionManager = makeUnique<SpeechRecognitionPermissionManager>(*this);
11164
11165 m_speechRecognitionPermissionManager->request(request, WTFMove(completionHandler));
11166}
11167
11168void WebPageProxy::requestSpeechRecognitionPermissionByDefaultAction(const WebCore::SecurityOriginData& origin, CompletionHandler<void(bool)>&& completionHandler)
11169{
11170 if (!m_speechRecognitionPermissionManager) {
11171 completionHandler(false);
11172 return;
11173 }
11174
11175 m_speechRecognitionPermissionManager->decideByDefaultAction(origin, WTFMove(completionHandler));
11176}
11177
11178void WebPageProxy::requestUserMediaPermissionForSpeechRecognition(FrameIdentifier frameIdentifier, const WebCore::SecurityOrigin& requestingOrigin, const WebCore::SecurityOrigin& topOrigin, CompletionHandler<void(bool)>&& completionHandler)
11179{
11180#if ENABLE(MEDIA_STREAM)
11181 auto captureDevice = SpeechRecognitionCaptureSource::findCaptureDevice();
11182 if (!captureDevice) {
11183 completionHandler(false);
11184 return;
11185 }
11186
11187 userMediaPermissionRequestManager().checkUserMediaPermissionForSpeechRecognition(frameIdentifier, requestingOrigin, topOrigin, *captureDevice, WTFMove(completionHandler));
11188#else
11189 completionHandler(false);
11190#endif
11191}
11192
11193void WebPageProxy::requestMediaKeySystemPermissionByDefaultAction(const WebCore::SecurityOriginData& origin, CompletionHandler<void(bool)>&& completionHandler)
11194{
11195 completionHandler(true);
11196}
11197
11198#if ENABLE(MEDIA_STREAM)
11199
11200WebCore::CaptureSourceOrError WebPageProxy::createRealtimeMediaSourceForSpeechRecognition()
11201{
11202 auto captureDevice = SpeechRecognitionCaptureSource::findCaptureDevice();
11203 if (!captureDevice)
11204 return CaptureSourceOrError { "No device is available for capture"_s };
11205
11206 if (preferences().captureAudioInGPUProcessEnabled())
11207 return CaptureSourceOrError { SpeechRecognitionRemoteRealtimeMediaSource::create(m_process->ensureSpeechRecognitionRemoteRealtimeMediaSourceManager(), *captureDevice, m_webPageID) };
11208
11209#if PLATFORM(IOS_FAMILY)
11210 return CaptureSourceOrError { SpeechRecognitionRemoteRealtimeMediaSource::create(m_process->ensureSpeechRecognitionRemoteRealtimeMediaSourceManager(), *captureDevice, m_webPageID) };
11211#else
11212 return SpeechRecognitionCaptureSource::createRealtimeMediaSource(*captureDevice, m_webPageID);
11213#endif
11214}
11215
11216#endif
11217
11218#if HAVE(SCREEN_CAPTURE_KIT)
11219void WebPageProxy::setIndexOfGetDisplayMediaDeviceSelectedForTesting(std::optional<unsigned> index)
11220{
11221 DisplayCaptureSessionManager::singleton().setIndexOfDeviceSelectedForTesting(index);
11222}
11223#endif
11224
11225#if ENABLE(ARKIT_INLINE_PREVIEW)
11226void WebPageProxy::modelElementGetCamera(ModelIdentifier modelIdentifier, CompletionHandler<void(Expected<WebCore::HTMLModelElementCamera, ResourceError>)>&& completionHandler)
11227{
11228 if (m_modelElementController)
11229 m_modelElementController->getCameraForModelElement(modelIdentifier, WTFMove(completionHandler));
11230}
11231
11232void WebPageProxy::modelElementSetCamera(ModelIdentifier modelIdentifier, WebCore::HTMLModelElementCamera camera, CompletionHandler<void(bool)>&& completionHandler)
11233{
11234 if (m_modelElementController)
11235 m_modelElementController->setCameraForModelElement(modelIdentifier, camera, WTFMove(completionHandler));
11236}
11237
11238void WebPageProxy::modelElementIsPlayingAnimation(ModelIdentifier modelIdentifier, CompletionHandler<void(Expected<bool, ResourceError>)>&& completionHandler)
11239{
11240 if (m_modelElementController)
11241 m_modelElementController->isPlayingAnimationForModelElement(modelIdentifier, WTFMove(completionHandler));
11242}
11243
11244void WebPageProxy::modelElementSetAnimationIsPlaying(ModelIdentifier modelIdentifier, bool isPlaying, CompletionHandler<void(bool)>&& completionHandler)
11245{
11246 if (m_modelElementController)
11247 m_modelElementController->setAnimationIsPlayingForModelElement(modelIdentifier, isPlaying, WTFMove(completionHandler));
11248}
11249
11250void WebPageProxy::modelElementIsLoopingAnimation(ModelIdentifier modelIdentifier, CompletionHandler<void(Expected<bool, ResourceError>)>&& completionHandler)
11251{
11252 if (m_modelElementController)
11253 m_modelElementController->isLoopingAnimationForModelElement(modelIdentifier, WTFMove(completionHandler));
11254}
11255
11256void WebPageProxy::modelElementSetIsLoopingAnimation(ModelIdentifier modelIdentifier, bool isLooping, CompletionHandler<void(bool)>&& completionHandler)
11257{
11258 if (m_modelElementController)
11259 m_modelElementController->setIsLoopingAnimationForModelElement(modelIdentifier, isLooping, WTFMove(completionHandler));
11260}
11261
11262void WebPageProxy::modelElementAnimationDuration(ModelIdentifier modelIdentifier, CompletionHandler<void(Expected<Seconds, WebCore::ResourceError>)>&& completionHandler)
11263{
11264 if (m_modelElementController)
11265 m_modelElementController->animationDurationForModelElement(modelIdentifier, WTFMove(completionHandler));
11266}
11267
11268void WebPageProxy::modelElementAnimationCurrentTime(ModelIdentifier modelIdentifier, CompletionHandler<void(Expected<Seconds, WebCore::ResourceError>)>&& completionHandler)
11269{
11270 if (m_modelElementController)
11271 m_modelElementController->animationCurrentTimeForModelElement(modelIdentifier, WTFMove(completionHandler));
11272}
11273
11274void WebPageProxy::modelElementSetAnimationCurrentTime(ModelIdentifier modelIdentifier, Seconds currentTime, CompletionHandler<void(bool)>&& completionHandler)
11275{
11276 if (m_modelElementController)
11277 m_modelElementController->setAnimationCurrentTimeForModelElement(modelIdentifier, currentTime, WTFMove(completionHandler));
11278}
11279
11280void WebPageProxy::modelElementHasAudio(ModelIdentifier modelIdentifier, CompletionHandler<void(Expected<bool, ResourceError>)>&& completionHandler)
11281{
11282 if (m_modelElementController)
11283 m_modelElementController->hasAudioForModelElement(modelIdentifier, WTFMove(completionHandler));
11284}
11285
11286void WebPageProxy::modelElementIsMuted(ModelIdentifier modelIdentifier, CompletionHandler<void(Expected<bool, ResourceError>)>&& completionHandler)
11287{
11288 if (m_modelElementController)
11289 m_modelElementController->isMutedForModelElement(modelIdentifier, WTFMove(completionHandler));
11290}
11291
11292void WebPageProxy::modelElementSetIsMuted(ModelIdentifier modelIdentifier, bool isMuted, CompletionHandler<void(bool)>&& completionHandler)
11293{
11294 if (m_modelElementController)
11295 m_modelElementController->setIsMutedForModelElement(modelIdentifier, isMuted, WTFMove(completionHandler));
11296}
11297#endif
11298
11299#if ENABLE(ARKIT_INLINE_PREVIEW_IOS)
11300void WebPageProxy::takeModelElementFullscreen(ModelIdentifier modelIdentifier)
11301{
11302 if (m_modelElementController)
11303 m_modelElementController->takeModelElementFullscreen(modelIdentifier, URL { currentURL() });
11304}
11305
11306void WebPageProxy::modelElementSetInteractionEnabled(ModelIdentifier modelIdentifier, bool isInteractionEnabled)
11307{
11308 if (m_modelElementController)
11309 m_modelElementController->setInteractionEnabledForModelElement(modelIdentifier, isInteractionEnabled);
11310}
11311
11312void WebPageProxy::modelInlinePreviewDidLoad(WebCore::GraphicsLayer::PlatformLayerID layerID)
11313{
11314 send(Messages::WebPage::ModelInlinePreviewDidLoad(layerID));
11315}
11316
11317void WebPageProxy::modelInlinePreviewDidFailToLoad(WebCore::GraphicsLayer::PlatformLayerID layerID, const WebCore::ResourceError& error)
11318{
11319 send(Messages::WebPage::ModelInlinePreviewDidFailToLoad(layerID, error));
11320}
11321
11322#endif
11323
11324#if ENABLE(ARKIT_INLINE_PREVIEW_MAC)
11325void WebPageProxy::modelElementCreateRemotePreview(const String& uuid, const FloatSize& size, CompletionHandler<void(Expected<std::pair<String, uint32_t>, ResourceError>)>&& completionHandler)
11326{
11327 if (m_modelElementController)
11328 m_modelElementController->modelElementCreateRemotePreview(uuid, size, WTFMove(completionHandler));
11329}
11330
11331void WebPageProxy::modelElementLoadRemotePreview(const String& uuid, const URL& url, CompletionHandler<void(std::optional<WebCore::ResourceError>&&)>&& completionHandler)
11332{
11333 if (m_modelElementController)
11334 m_modelElementController->modelElementLoadRemotePreview(uuid, url, WTFMove(completionHandler));
11335}
11336
11337void WebPageProxy::modelElementDestroyRemotePreview(const String& uuid)
11338{
11339 if (m_modelElementController)
11340 m_modelElementController->modelElementDestroyRemotePreview(uuid);
11341}
11342
11343void WebPageProxy::modelElementSizeDidChange(const String& uuid, WebCore::FloatSize size, CompletionHandler<void(Expected<MachSendRight, WebCore::ResourceError>)>&& completionHandler)
11344{
11345 if (m_modelElementController)
11346 m_modelElementController->modelElementSizeDidChange(uuid, size, WTFMove(completionHandler));
11347}
11348
11349void WebPageProxy::handleMouseDownForModelElement(const String& uuid, const WebCore::LayoutPoint& flippedLocationInElement, MonotonicTime timestamp)
11350{
11351 if (m_modelElementController)
11352 m_modelElementController->handleMouseDownForModelElement(uuid, flippedLocationInElement, timestamp);
11353}
11354
11355void WebPageProxy::handleMouseMoveForModelElement(const String& uuid, const WebCore::LayoutPoint& flippedLocationInElement, MonotonicTime timestamp)
11356{
11357 if (m_modelElementController)
11358 m_modelElementController->handleMouseMoveForModelElement(uuid, flippedLocationInElement, timestamp);
11359}
11360
11361void WebPageProxy::handleMouseUpForModelElement(const String& uuid, const WebCore::LayoutPoint& flippedLocationInElement, MonotonicTime timestamp)
11362{
11363 if (m_modelElementController)
11364 m_modelElementController->handleMouseUpForModelElement(uuid, flippedLocationInElement, timestamp);
11365}
11366
11367void WebPageProxy::modelInlinePreviewUUIDs(CompletionHandler<void(Vector<String>&&)>&& completionHandler)
11368{
11369 if (m_modelElementController)
11370 m_modelElementController->inlinePreviewUUIDs(WTFMove(completionHandler));
11371}
11372#endif
11373
11374#if !PLATFORM(COCOA) && !ENABLE(CONTENT_FILTERING_IN_NETWORKING_PROCESS)
11375Vector<SandboxExtension::Handle> WebPageProxy::createNetworkExtensionsSandboxExtensions(WebProcessProxy& process)
11376{
11377 return { };
11378}
11379
11380void WebPageProxy::classifyModalContainerControls(Vector<String>&&, CompletionHandler<void(Vector<ModalContainerControlType>&&)>&& completion)
11381{
11382 completion({ });
11383}
11384#endif
11385
11386#if ENABLE(MEDIA_SESSION_COORDINATOR)
11387void WebPageProxy::createMediaSessionCoordinator(Ref<MediaSessionCoordinatorProxyPrivate>&& privateCoordinator, CompletionHandler<void(bool)>&& completionHandler)
11388{
11389 sendWithAsyncReply(Messages::WebPage::CreateMediaSessionCoordinator(privateCoordinator->identifier()), [weakThis = WeakPtr { *this }, privateCoordinator = WTFMove(privateCoordinator), completionHandler = WTFMove(completionHandler)](bool success) mutable {
11390
11391 if (!weakThis || !success) {
11392 completionHandler(false);
11393 return;
11394 }
11395
11396 weakThis->m_mediaSessionCoordinatorProxy = RemoteMediaSessionCoordinatorProxy::create(*weakThis, WTFMove(privateCoordinator));
11397 completionHandler(true);
11398 });
11399}
11400#endif
11401
11402void WebPageProxy::requestScrollToRect(const FloatRect& targetRect, const FloatPoint& origin)
11403{
11404 pageClient().requestScrollToRect(targetRect, origin);
11405}
11406
11407void WebPageProxy::scrollToRect(const FloatRect& targetRect, const FloatPoint& origin)
11408{
11409 send(Messages::WebPage::ScrollToRect(targetRect, origin));
11410}
11411
11412bool WebPageProxy::shouldEnableCaptivePortalMode() const
11413{
11414 return m_configuration->captivePortalModeEnabled();
11415}
11416
11417#if PLATFORM(COCOA)
11418void WebPageProxy::appPrivacyReportTestingData(CompletionHandler<void(const AppPrivacyReportTestingData&)>&& completionHandler)
11419{
11420 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::AppPrivacyReportTestingData(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
11421}
11422
11423void WebPageProxy::clearAppPrivacyReportTestingData(CompletionHandler<void()>&& completionHandler)
11424{
11425 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::ClearAppPrivacyReportTestingData(m_websiteDataStore->sessionID()), WTFMove(completionHandler));
11426}
11427#endif
11428
11429void WebPageProxy::requestCookieConsent(CompletionHandler<void(CookieConsentDecisionResult)>&& completion)
11430{
11431 m_uiClient->requestCookieConsent(WTFMove(completion));
11432}
11433
11434void WebPageProxy::decidePolicyForModalContainer(OptionSet<ModalContainerControlType> types, CompletionHandler<void(ModalContainerDecision)>&& completion)
11435{
11436 m_uiClient->decidePolicyForModalContainer(types, WTFMove(completion));
11437}
11438
11439void WebPageProxy::beginTextRecognitionForVideoInElementFullScreen(MediaPlayerIdentifier identifier, FloatRect bounds)
11440{
11441 if (!pageClient().isTextRecognitionInFullscreenVideoEnabled())
11442 return;
11443
11444#if ENABLE(GPU_PROCESS)
11445 RefPtr gpuProcess = GPUProcessProxy::singletonIfCreated();
11446 if (!gpuProcess)
11447 return;
11448
11449 m_isPerformingTextRecognitionInElementFullScreen = true;
11450 gpuProcess->requestBitmapImageForCurrentTime(m_process->coreProcessIdentifier(), identifier, [weakThis = WeakPtr { *this }, bounds](auto& bitmapHandle) {
11451 RefPtr protectedThis = weakThis.get();
11452 if (!protectedThis || !protectedThis->m_isPerformingTextRecognitionInElementFullScreen)
11453 return;
11454
11455 protectedThis->pageClient().beginTextRecognitionForVideoInElementFullscreen(bitmapHandle, bounds);
11456 protectedThis->m_isPerformingTextRecognitionInElementFullScreen = false;
11457 });
11458#else
11459 UNUSED_PARAM(identifier);
11460 UNUSED_PARAM(bounds);
11461#endif
11462}
11463
11464void WebPageProxy::cancelTextRecognitionForVideoInElementFullScreen()
11465{
11466 if (!pageClient().isTextRecognitionInFullscreenVideoEnabled())
11467 return;
11468
11469 m_isPerformingTextRecognitionInElementFullScreen = false;
11470 pageClient().cancelTextRecognitionForVideoInElementFullscreen();
11471}
11472
11473#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
11474
11475void WebPageProxy::shouldAllowRemoveBackground(const ElementContext& context, CompletionHandler<void(bool)>&& completion)
11476{
11477 sendWithAsyncReply(Messages::WebPage::ShouldAllowRemoveBackground(context), WTFMove(completion));
11478}
11479
11480#endif
11481
11482#if HAVE(UIKIT_RESIZABLE_WINDOWS)
11483
11484void WebPageProxy::setIsWindowResizingEnabled(bool hasResizableWindows)
11485{
11486 send(Messages::WebPage::SetIsWindowResizingEnabled(hasResizableWindows));
11487}
11488
11489#endif
11490
11491} // namespace WebKit
11492
11493#undef WEBPAGEPROXY_RELEASE_LOG
11494#undef WEBPAGEPROXY_RELEASE_LOG_ERROR
11495#undef MESSAGE_CHECK_COMPLETION
11496#undef MESSAGE_CHECK_URL
11497#undef MESSAGE_CHECK
Note: See TracBrowser for help on using the repository browser.