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