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