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