1/*
2 * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Intel Corporation. All rights reserved.
4 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 * THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "config.h"
29#include "WebPage.h"
30
31#include "APIArray.h"
32#include "APIGeometry.h"
33#include "DataReference.h"
34#include "DragControllerAction.h"
35#include "DrawingArea.h"
36#include "DrawingAreaMessages.h"
37#include "EditorState.h"
38#include "EventDispatcher.h"
39#include "FindController.h"
40#include "FormDataReference.h"
41#include "GeolocationPermissionRequestManager.h"
42#include "InjectUserScriptImmediately.h"
43#include "InjectedBundle.h"
44#include "InjectedBundleScriptWorld.h"
45#include "LibWebRTCProvider.h"
46#include "LoadParameters.h"
47#include "Logging.h"
48#include "NetscapePlugin.h"
49#include "NetworkConnectionToWebProcessMessages.h"
50#include "NetworkProcessConnection.h"
51#include "NotificationPermissionRequestManager.h"
52#include "PageBanner.h"
53#include "PluginProcessAttributes.h"
54#include "PluginProxy.h"
55#include "PluginView.h"
56#include "PrintInfo.h"
57#include "RemoteWebInspectorUI.h"
58#include "RemoteWebInspectorUIMessages.h"
59#include "SessionState.h"
60#include "SessionStateConversion.h"
61#include "ShareSheetCallbackID.h"
62#include "ShareableBitmap.h"
63#include "SharedBufferDataReference.h"
64#include "UserMediaPermissionRequestManager.h"
65#include "ViewGestureGeometryCollector.h"
66#include "VisitedLinkTableController.h"
67#include "WKBundleAPICast.h"
68#include "WKRetainPtr.h"
69#include "WKSharedAPICast.h"
70#include "WebAlternativeTextClient.h"
71#include "WebBackForwardListItem.h"
72#include "WebBackForwardListProxy.h"
73#include "WebCacheStorageProvider.h"
74#include "WebChromeClient.h"
75#include "WebColorChooser.h"
76#include "WebContextMenu.h"
77#include "WebContextMenuClient.h"
78#include "WebCookieJar.h"
79#include "WebCoreArgumentCoders.h"
80#include "WebDataListSuggestionPicker.h"
81#include "WebDatabaseProvider.h"
82#include "WebDiagnosticLoggingClient.h"
83#include "WebDocumentLoader.h"
84#include "WebDragClient.h"
85#include "WebEditorClient.h"
86#include "WebEvent.h"
87#include "WebEventConversion.h"
88#include "WebEventFactory.h"
89#include "WebFrame.h"
90#include "WebFrameLoaderClient.h"
91#include "WebFullScreenManager.h"
92#include "WebFullScreenManagerMessages.h"
93#include "WebGamepadProvider.h"
94#include "WebGeolocationClient.h"
95#include "WebImage.h"
96#include "WebInspector.h"
97#include "WebInspectorClient.h"
98#include "WebInspectorMessages.h"
99#include "WebInspectorUI.h"
100#include "WebInspectorUIMessages.h"
101#include "WebMediaKeyStorageManager.h"
102#include "WebNotificationClient.h"
103#include "WebOpenPanelResultListener.h"
104#include "WebPageCreationParameters.h"
105#include "WebPageGroupProxy.h"
106#include "WebPageInspectorTargetController.h"
107#include "WebPageMessages.h"
108#include "WebPageOverlay.h"
109#include "WebPageProxyMessages.h"
110#include "WebPaymentCoordinator.h"
111#include "WebPerformanceLoggingClient.h"
112#include "WebPlugInClient.h"
113#include "WebPluginInfoProvider.h"
114#include "WebPopupMenu.h"
115#include "WebPreferencesDefinitions.h"
116#include "WebPreferencesKeys.h"
117#include "WebPreferencesStore.h"
118#include "WebProcess.h"
119#include "WebProcessPoolMessages.h"
120#include "WebProcessProxyMessages.h"
121#include "WebProgressTrackerClient.h"
122#include "WebSocketProvider.h"
123#include "WebSpeechSynthesisClient.h"
124#include "WebStorageNamespaceProvider.h"
125#include "WebURLSchemeHandlerProxy.h"
126#include "WebUndoStep.h"
127#include "WebUserContentController.h"
128#include "WebUserMediaClient.h"
129#include "WebValidationMessageClient.h"
130#include "WebsiteDataStoreParameters.h"
131#include <JavaScriptCore/APICast.h>
132#include <JavaScriptCore/JSCInlines.h>
133#include <JavaScriptCore/JSCJSValue.h>
134#include <JavaScriptCore/JSLock.h>
135#include <JavaScriptCore/ProfilerDatabase.h>
136#include <JavaScriptCore/SamplingProfiler.h>
137#include <WebCore/ApplicationCacheStorage.h>
138#include <WebCore/ArchiveResource.h>
139#include <WebCore/BackForwardController.h>
140#include <WebCore/Chrome.h>
141#include <WebCore/CommonVM.h>
142#include <WebCore/ContextMenuController.h>
143#include <WebCore/DOMPasteAccess.h>
144#include <WebCore/DataTransfer.h>
145#include <WebCore/DatabaseManager.h>
146#include <WebCore/DeprecatedGlobalSettings.h>
147#include <WebCore/DocumentFragment.h>
148#include <WebCore/DocumentLoader.h>
149#include <WebCore/DocumentMarkerController.h>
150#include <WebCore/DocumentStorageAccess.h>
151#include <WebCore/DragController.h>
152#include <WebCore/DragData.h>
153#include <WebCore/Editing.h>
154#include <WebCore/Editor.h>
155#include <WebCore/ElementIterator.h>
156#include <WebCore/EventHandler.h>
157#include <WebCore/EventNames.h>
158#include <WebCore/File.h>
159#include <WebCore/FocusController.h>
160#include <WebCore/FontAttributeChanges.h>
161#include <WebCore/FontAttributes.h>
162#include <WebCore/FormState.h>
163#include <WebCore/Frame.h>
164#include <WebCore/FrameLoadRequest.h>
165#include <WebCore/FrameLoaderTypes.h>
166#include <WebCore/FrameView.h>
167#include <WebCore/FullscreenManager.h>
168#include <WebCore/GraphicsContext3D.h>
169#include <WebCore/HTMLAttachmentElement.h>
170#include <WebCore/HTMLFormElement.h>
171#include <WebCore/HTMLImageElement.h>
172#include <WebCore/HTMLInputElement.h>
173#include <WebCore/HTMLMenuElement.h>
174#include <WebCore/HTMLMenuItemElement.h>
175#include <WebCore/HTMLOListElement.h>
176#include <WebCore/HTMLPlugInElement.h>
177#include <WebCore/HTMLPlugInImageElement.h>
178#include <WebCore/HTMLSelectElement.h>
179#include <WebCore/HTMLTextAreaElement.h>
180#include <WebCore/HTMLTextFormControlElement.h>
181#include <WebCore/HTMLUListElement.h>
182#include <WebCore/HistoryController.h>
183#include <WebCore/HistoryItem.h>
184#include <WebCore/HitTestResult.h>
185#include <WebCore/InspectorController.h>
186#include <WebCore/JSDOMExceptionHandling.h>
187#include <WebCore/JSDOMWindow.h>
188#include <WebCore/KeyboardEvent.h>
189#include <WebCore/LocalizedStrings.h>
190#include <WebCore/MIMETypeRegistry.h>
191#include <WebCore/MouseEvent.h>
192#include <WebCore/NotImplemented.h>
193#include <WebCore/Page.h>
194#include <WebCore/PageCache.h>
195#include <WebCore/PageConfiguration.h>
196#include <WebCore/PingLoader.h>
197#include <WebCore/PlatformKeyboardEvent.h>
198#include <WebCore/PlatformMediaSessionManager.h>
199#include <WebCore/PluginDocument.h>
200#include <WebCore/PointerCaptureController.h>
201#include <WebCore/PrintContext.h>
202#include <WebCore/PromisedAttachmentInfo.h>
203#include <WebCore/Quirks.h>
204#include <WebCore/Range.h>
205#include <WebCore/RegistrableDomain.h>
206#include <WebCore/RemoteDOMWindow.h>
207#include <WebCore/RemoteFrame.h>
208#include <WebCore/RenderLayer.h>
209#include <WebCore/RenderTheme.h>
210#include <WebCore/RenderTreeAsText.h>
211#include <WebCore/RenderView.h>
212#include <WebCore/ResourceLoadStatistics.h>
213#include <WebCore/ResourceRequest.h>
214#include <WebCore/ResourceResponse.h>
215#include <WebCore/RuntimeEnabledFeatures.h>
216#include <WebCore/SWClientConnection.h>
217#include <WebCore/SchemeRegistry.h>
218#include <WebCore/ScriptController.h>
219#include <WebCore/SerializedScriptValue.h>
220#include <WebCore/ServiceWorkerProvider.h>
221#include <WebCore/Settings.h>
222#include <WebCore/ShadowRoot.h>
223#include <WebCore/SharedBuffer.h>
224#include <WebCore/StyleProperties.h>
225#include <WebCore/SubframeLoader.h>
226#include <WebCore/SubstituteData.h>
227#include <WebCore/TextIterator.h>
228#include <WebCore/UserGestureIndicator.h>
229#include <WebCore/UserInputBridge.h>
230#include <WebCore/UserScript.h>
231#include <WebCore/UserStyleSheet.h>
232#include <WebCore/UserTypingGestureIndicator.h>
233#include <WebCore/VisiblePosition.h>
234#include <WebCore/VisibleUnits.h>
235#include <WebCore/WebGLStateTracker.h>
236#include <WebCore/WritingDirection.h>
237#include <WebCore/markup.h>
238#include <pal/SessionID.h>
239#include <wtf/ProcessID.h>
240#include <wtf/RunLoop.h>
241#include <wtf/SetForScope.h>
242#include <wtf/text/TextStream.h>
243
244#if ENABLE(DATA_DETECTION)
245#include "DataDetectionResult.h"
246#endif
247
248#if ENABLE(MHTML)
249#include <WebCore/MHTMLArchive.h>
250#endif
251
252#if ENABLE(POINTER_LOCK)
253#include <WebCore/PointerLockController.h>
254#endif
255
256#if PLATFORM(COCOA)
257#include "InsertTextOptions.h"
258#include "PDFPlugin.h"
259#include "PlaybackSessionManager.h"
260#include "RemoteLayerTreeTransaction.h"
261#include "RemoteObjectRegistry.h"
262#include "RemoteObjectRegistryMessages.h"
263#include "TextCheckingControllerProxy.h"
264#include "TouchBarMenuData.h"
265#include "TouchBarMenuItemData.h"
266#include "VideoFullscreenManager.h"
267#include "WKStringCF.h"
268#include <WebCore/LegacyWebArchive.h>
269#include <WebCore/UTIRegistry.h>
270#include <wtf/MachSendRight.h>
271#endif
272
273#if PLATFORM(GTK)
274#include "WebPrintOperationGtk.h"
275#include "WebSelectionData.h"
276#include <gtk/gtk.h>
277#endif
278
279#if PLATFORM(IOS_FAMILY)
280#include "InteractionInformationAtPosition.h"
281#include "InteractionInformationRequest.h"
282#include "RemoteLayerTreeDrawingArea.h"
283#include "WebAutocorrectionContext.h"
284#include <CoreGraphics/CoreGraphics.h>
285#include <WebCore/Icon.h>
286#include <pal/spi/cocoa/CoreTextSPI.h>
287#endif
288
289#if PLATFORM(MAC)
290#include <WebCore/LocalDefaultSystemAppearance.h>
291#include <pal/spi/cf/CFUtilitiesSPI.h>
292#endif
293
294#ifndef NDEBUG
295#include <wtf/RefCountedLeakCounter.h>
296#endif
297
298#if ENABLE(DATA_DETECTION)
299#include <WebCore/DataDetection.h>
300#endif
301
302#if ENABLE(VIDEO) && USE(GSTREAMER)
303#include <WebCore/MediaPlayerRequestInstallMissingPluginsCallback.h>
304#endif
305
306#if ENABLE(WEB_AUTHN)
307#include "WebAuthenticatorCoordinator.h"
308#include <WebCore/AuthenticatorCoordinator.h>
309#endif
310
311namespace WebKit {
312using namespace JSC;
313using namespace WebCore;
314
315static const Seconds pageScrollHysteresisDuration { 300_ms };
316static const Seconds initialLayerVolatilityTimerInterval { 20_ms };
317static const Seconds maximumLayerVolatilityTimerInterval { 2_s };
318
319#define RELEASE_LOG_IF_ALLOWED(...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Layers, __VA_ARGS__)
320#define RELEASE_LOG_ERROR_IF_ALLOWED(...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), Layers, __VA_ARGS__)
321
322class SendStopResponsivenessTimer {
323public:
324 ~SendStopResponsivenessTimer()
325 {
326 WebProcess::singleton().parentProcessConnection()->send(Messages::WebProcessProxy::StopResponsivenessTimer(), 0);
327 }
328};
329
330class DeferredPageDestructor {
331public:
332 static void createDeferredPageDestructor(std::unique_ptr<Page> page, WebPage* webPage)
333 {
334 new DeferredPageDestructor(WTFMove(page), webPage);
335 }
336
337private:
338 DeferredPageDestructor(std::unique_ptr<Page> page, WebPage* webPage)
339 : m_page(WTFMove(page))
340 , m_webPage(webPage)
341 {
342 tryDestruction();
343 }
344
345 void tryDestruction()
346 {
347 if (m_page->insideNestedRunLoop()) {
348 m_page->whenUnnested([this] { tryDestruction(); });
349 return;
350 }
351
352 m_page = nullptr;
353 m_webPage = nullptr;
354 delete this;
355 }
356
357 std::unique_ptr<Page> m_page;
358 RefPtr<WebPage> m_webPage;
359};
360
361DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageCounter, ("WebPage"));
362
363Ref<WebPage> WebPage::create(uint64_t pageID, WebPageCreationParameters&& parameters)
364{
365 Ref<WebPage> page = adoptRef(*new WebPage(pageID, WTFMove(parameters)));
366
367 if (WebProcess::singleton().injectedBundle())
368 WebProcess::singleton().injectedBundle()->didCreatePage(page.ptr());
369
370 return page;
371}
372
373WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters)
374 : m_pageID(pageID)
375 , m_viewSize(parameters.viewSize)
376 , m_alwaysShowsHorizontalScroller { parameters.alwaysShowsHorizontalScroller }
377 , m_alwaysShowsVerticalScroller { parameters.alwaysShowsVerticalScroller }
378#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
379 , m_determinePrimarySnapshottedPlugInTimer(RunLoop::main(), this, &WebPage::determinePrimarySnapshottedPlugInTimerFired)
380#endif
381 , m_layerHostingMode(parameters.layerHostingMode)
382#if ENABLE(PLATFORM_DRIVEN_TEXT_CHECKING)
383 , m_textCheckingControllerProxy(makeUniqueRef<TextCheckingControllerProxy>(*this))
384#endif
385#if PLATFORM(COCOA) || PLATFORM(GTK)
386 , m_viewGestureGeometryCollector(std::make_unique<ViewGestureGeometryCollector>(*this))
387#elif HAVE(ACCESSIBILITY) && PLATFORM(GTK)
388 , m_accessibilityObject(nullptr)
389#endif
390 , m_setCanStartMediaTimer(RunLoop::main(), this, &WebPage::setCanStartMediaTimerFired)
391#if ENABLE(CONTEXT_MENUS)
392 , m_contextMenuClient(std::make_unique<API::InjectedBundle::PageContextMenuClient>())
393#endif
394 , m_editorClient { std::make_unique<API::InjectedBundle::EditorClient>() }
395 , m_formClient(std::make_unique<API::InjectedBundle::FormClient>())
396 , m_loaderClient(std::make_unique<API::InjectedBundle::PageLoaderClient>())
397 , m_resourceLoadClient(std::make_unique<API::InjectedBundle::ResourceLoadClient>())
398 , m_uiClient(std::make_unique<API::InjectedBundle::PageUIClient>())
399 , m_findController(makeUniqueRef<FindController>(this))
400 , m_inspectorTargetController(std::make_unique<WebPageInspectorTargetController>(*this))
401 , m_userContentController(WebUserContentController::getOrCreate(parameters.userContentControllerID))
402#if ENABLE(GEOLOCATION)
403 , m_geolocationPermissionRequestManager(makeUniqueRef<GeolocationPermissionRequestManager>(*this))
404#endif
405#if ENABLE(MEDIA_STREAM)
406 , m_userMediaPermissionRequestManager { makeUniqueRef<UserMediaPermissionRequestManager>(*this) }
407#endif
408 , m_pageScrolledHysteresis([this](PAL::HysteresisState state) { if (state == PAL::HysteresisState::Stopped) pageStoppedScrolling(); }, pageScrollHysteresisDuration)
409 , m_canRunBeforeUnloadConfirmPanel(parameters.canRunBeforeUnloadConfirmPanel)
410 , m_canRunModal(parameters.canRunModal)
411#if PLATFORM(IOS_FAMILY)
412 , m_forceAlwaysUserScalable(parameters.ignoresViewportScaleLimits)
413 , m_screenSize(parameters.screenSize)
414 , m_availableScreenSize(parameters.availableScreenSize)
415 , m_overrideScreenSize(parameters.overrideScreenSize)
416 , m_deviceOrientation(parameters.deviceOrientation)
417 , m_keyboardIsAttached(parameters.keyboardIsAttached)
418 , m_canShowWhileLocked(parameters.canShowWhileLocked)
419#endif
420 , m_layerVolatilityTimer(*this, &WebPage::layerVolatilityTimerFired)
421 , m_activityState(parameters.activityState)
422 , m_userActivity("App nap disabled for page due to user activity")
423 , m_userInterfaceLayoutDirection(parameters.userInterfaceLayoutDirection)
424 , m_overrideContentSecurityPolicy { parameters.overrideContentSecurityPolicy }
425 , m_cpuLimit(parameters.cpuLimit)
426#if PLATFORM(WPE)
427 , m_hostFileDescriptor(WTFMove(parameters.hostFileDescriptor))
428#endif
429#if ENABLE(VIEWPORT_RESIZING)
430 , m_shrinkToFitContentTimer(*this, &WebPage::shrinkToFitContentTimerFired, 0_s)
431#endif
432{
433 ASSERT(m_pageID);
434
435 m_pageGroup = WebProcess::singleton().webPageGroup(parameters.pageGroupData);
436
437#if PLATFORM(IOS_FAMILY)
438 DeprecatedGlobalSettings::setShouldManageAudioSessionCategory(true);
439#endif
440
441 PageConfiguration pageConfiguration(
442 makeUniqueRef<WebEditorClient>(this),
443 WebSocketProvider::create(),
444 makeUniqueRef<WebKit::LibWebRTCProvider>(),
445 WebProcess::singleton().cacheStorageProvider(),
446 WebBackForwardListProxy::create(*this),
447 WebCookieJar::create()
448 );
449 pageConfiguration.chromeClient = new WebChromeClient(*this);
450#if ENABLE(CONTEXT_MENUS)
451 pageConfiguration.contextMenuClient = new WebContextMenuClient(this);
452#endif
453#if ENABLE(DRAG_SUPPORT)
454 pageConfiguration.dragClient = new WebDragClient(this);
455#endif
456 pageConfiguration.inspectorClient = new WebInspectorClient(this);
457#if USE(AUTOCORRECTION_PANEL)
458 pageConfiguration.alternativeTextClient = new WebAlternativeTextClient(this);
459#endif
460
461 pageConfiguration.plugInClient = new WebPlugInClient(*this);
462 pageConfiguration.loaderClientForMainFrame = new WebFrameLoaderClient;
463 pageConfiguration.progressTrackerClient = new WebProgressTrackerClient(*this);
464 pageConfiguration.diagnosticLoggingClient = std::make_unique<WebDiagnosticLoggingClient>(*this);
465 pageConfiguration.performanceLoggingClient = std::make_unique<WebPerformanceLoggingClient>(*this);
466
467 pageConfiguration.webGLStateTracker = std::make_unique<WebGLStateTracker>([this](bool isUsingHighPerformanceWebGL) {
468 send(Messages::WebPageProxy::SetIsUsingHighPerformanceWebGL(isUsingHighPerformanceWebGL));
469 });
470
471#if ENABLE(SPEECH_SYNTHESIS)
472 pageConfiguration.speechSynthesisClient = std::make_unique<WebSpeechSynthesisClient>(*this);
473#endif
474
475#if PLATFORM(COCOA)
476 pageConfiguration.validationMessageClient = std::make_unique<WebValidationMessageClient>(*this);
477#endif
478
479 pageConfiguration.applicationCacheStorage = &WebProcess::singleton().applicationCacheStorage();
480 pageConfiguration.databaseProvider = WebDatabaseProvider::getOrCreate(m_pageGroup->pageGroupID());
481 pageConfiguration.pluginInfoProvider = &WebPluginInfoProvider::singleton();
482 pageConfiguration.storageNamespaceProvider = WebStorageNamespaceProvider::getOrCreate(m_pageGroup->pageGroupID());
483 pageConfiguration.userContentProvider = m_userContentController.ptr();
484 pageConfiguration.visitedLinkStore = VisitedLinkTableController::getOrCreate(parameters.visitedLinkTableID);
485
486#if ENABLE(APPLE_PAY)
487 pageConfiguration.paymentCoordinatorClient = new WebPaymentCoordinator(*this);
488#endif
489
490#if ENABLE(WEB_AUTHN)
491 pageConfiguration.authenticatorCoordinatorClient = std::make_unique<WebAuthenticatorCoordinator>(*this);
492#endif
493
494#if ENABLE(APPLICATION_MANIFEST)
495 pageConfiguration.applicationManifest = parameters.applicationManifest;
496#endif
497
498 m_page = std::make_unique<Page>(WTFMove(pageConfiguration));
499
500 // Set the sessionID *before* updating the preferences as the privateBrowsingEnabled preferences may need to override it.
501 if (parameters.sessionID.isValid())
502 setSessionID(parameters.sessionID);
503
504 updatePreferences(parameters.store);
505
506 m_backgroundColor = parameters.backgroundColor;
507
508 m_drawingArea = DrawingArea::create(*this, parameters);
509 m_drawingArea->setPaintingEnabled(false);
510 m_drawingArea->setShouldScaleViewToFitDocument(parameters.shouldScaleViewToFitDocument);
511
512 if (parameters.isProcessSwap)
513 freezeLayerTree(LayerTreeFreezeReason::ProcessSwap);
514
515#if ENABLE(ASYNC_SCROLLING)
516 m_useAsyncScrolling = parameters.store.getBoolValueForKey(WebPreferencesKey::threadedScrollingEnabledKey());
517 if (!m_drawingArea->supportsAsyncScrolling())
518 m_useAsyncScrolling = false;
519 m_page->settings().setScrollingCoordinatorEnabled(m_useAsyncScrolling);
520#endif
521
522 m_mainFrame = WebFrame::createWithCoreMainFrame(this, &m_page->mainFrame());
523 m_drawingArea->updatePreferences(parameters.store);
524
525 setBackgroundExtendsBeyondPage(parameters.backgroundExtendsBeyondPage);
526 setPageAndTextZoomFactors(parameters.pageZoomFactor, parameters.textZoomFactor);
527
528#if ENABLE(GEOLOCATION)
529 WebCore::provideGeolocationTo(m_page.get(), *new WebGeolocationClient(*this));
530#endif
531#if ENABLE(NOTIFICATIONS)
532 WebCore::provideNotification(m_page.get(), new WebNotificationClient(this));
533#endif
534#if ENABLE(MEDIA_STREAM)
535 WebCore::provideUserMediaTo(m_page.get(), new WebUserMediaClient(*this));
536#endif
537
538 m_page->setControlledByAutomation(parameters.controlledByAutomation);
539
540 m_page->setCanStartMedia(false);
541 m_mayStartMediaWhenInWindow = parameters.mayStartMediaWhenInWindow;
542
543 m_page->setGroupName(m_pageGroup->identifier());
544 m_page->setDeviceScaleFactor(parameters.deviceScaleFactor);
545 m_page->setUserInterfaceLayoutDirection(m_userInterfaceLayoutDirection);
546#if PLATFORM(IOS_FAMILY)
547 m_page->setTextAutosizingWidth(parameters.textAutosizingWidth);
548 setOverrideViewportArguments(parameters.overrideViewportArguments);
549#endif
550
551 platformInitialize();
552
553 setUseFixedLayout(parameters.useFixedLayout);
554
555 setUnderlayColor(parameters.underlayColor);
556
557 setPaginationMode(parameters.paginationMode);
558 setPaginationBehavesLikeColumns(parameters.paginationBehavesLikeColumns);
559 setPageLength(parameters.pageLength);
560 setGapBetweenPages(parameters.gapBetweenPages);
561 setPaginationLineGridEnabled(parameters.paginationLineGridEnabled);
562
563 effectiveAppearanceDidChange(parameters.useDarkAppearance, parameters.useInactiveAppearance);
564
565 if (parameters.isEditable)
566 setEditable(true);
567
568#if PLATFORM(MAC)
569 setUseSystemAppearance(parameters.useSystemAppearance);
570#endif
571
572 // If the page is created off-screen, its visibilityState should be prerender.
573 m_page->setActivityState(m_activityState);
574 if (!isVisible())
575 m_page->setIsPrerender();
576
577 updateIsInWindow(true);
578
579 setViewLayoutSize(parameters.viewLayoutSize);
580 setAutoSizingShouldExpandToViewHeight(parameters.autoSizingShouldExpandToViewHeight);
581 setViewportSizeForCSSViewportUnits(parameters.viewportSizeForCSSViewportUnits);
582
583 setScrollPinningBehavior(parameters.scrollPinningBehavior);
584 if (parameters.scrollbarOverlayStyle)
585 m_scrollbarOverlayStyle = static_cast<ScrollbarOverlayStyle>(parameters.scrollbarOverlayStyle.value());
586 else
587 m_scrollbarOverlayStyle = Optional<ScrollbarOverlayStyle>();
588
589 setTopContentInset(parameters.topContentInset);
590
591 m_userAgent = parameters.userAgent;
592
593 if (!parameters.itemStates.isEmpty())
594 restoreSessionInternal(parameters.itemStates, WasRestoredByAPIRequest::No, WebBackForwardListProxy::OverwriteExistingItem::Yes);
595
596 m_drawingArea->setPaintingEnabled(true);
597
598 setMediaVolume(parameters.mediaVolume);
599
600 setMuted(parameters.muted);
601
602 // We use the DidFirstVisuallyNonEmptyLayout milestone to determine when to unfreeze the layer tree.
603 m_page->addLayoutMilestones({ DidFirstLayout, DidFirstVisuallyNonEmptyLayout });
604
605 auto& webProcess = WebProcess::singleton();
606 webProcess.addMessageReceiver(Messages::WebPage::messageReceiverName(), m_pageID, *this);
607
608 // FIXME: This should be done in the object constructors, and the objects themselves should be message receivers.
609 webProcess.addMessageReceiver(Messages::WebInspector::messageReceiverName(), m_pageID, *this);
610 webProcess.addMessageReceiver(Messages::WebInspectorUI::messageReceiverName(), m_pageID, *this);
611 webProcess.addMessageReceiver(Messages::RemoteWebInspectorUI::messageReceiverName(), m_pageID, *this);
612#if ENABLE(FULLSCREEN_API)
613 webProcess.addMessageReceiver(Messages::WebFullScreenManager::messageReceiverName(), m_pageID, *this);
614#endif
615
616#ifndef NDEBUG
617 webPageCounter.increment();
618#endif
619
620#if ENABLE(ASYNC_SCROLLING)
621 if (m_useAsyncScrolling)
622 webProcess.eventDispatcher().addScrollingTreeForPage(this);
623#endif
624
625 for (auto& mimeType : parameters.mimeTypesWithCustomContentProviders)
626 m_mimeTypesWithCustomContentProviders.add(mimeType);
627
628
629#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
630 if (WebMediaKeyStorageManager* manager = webProcess.supplement<WebMediaKeyStorageManager>())
631 m_page->settings().setMediaKeysStorageDirectory(manager->mediaKeyStorageDirectory());
632#endif
633 m_page->settings().setAppleMailPaginationQuirkEnabled(parameters.appleMailPaginationQuirkEnabled);
634
635 if (parameters.viewScaleFactor != 1)
636 scaleView(parameters.viewScaleFactor);
637
638 m_page->addLayoutMilestones(parameters.observedLayoutMilestones);
639
640#if PLATFORM(COCOA)
641 m_page->settings().setContentDispositionAttachmentSandboxEnabled(true);
642 setSmartInsertDeleteEnabled(parameters.smartInsertDeleteEnabled);
643 WebCore::setAdditionalSupportedImageTypes(parameters.additionalSupportedImageTypes);
644#endif
645
646#if ENABLE(SERVICE_WORKER)
647 if (parameters.hasRegisteredServiceWorkers)
648 ServiceWorkerProvider::singleton().setMayHaveRegisteredServiceWorkers();
649#endif
650
651 m_needsFontAttributes = parameters.needsFontAttributes;
652
653#if ENABLE(WEB_RTC)
654 if (!parameters.iceCandidateFilteringEnabled)
655 disableICECandidateFiltering();
656#if USE(LIBWEBRTC)
657 if (parameters.enumeratingAllNetworkInterfacesEnabled)
658 enableEnumeratingAllNetworkInterfaces();
659#endif
660#endif
661
662 for (const auto& iterator : parameters.urlSchemeHandlers)
663 registerURLSchemeHandler(iterator.value, iterator.key);
664
665 m_userContentController->addUserContentWorlds(parameters.userContentWorlds);
666 m_userContentController->addUserScripts(WTFMove(parameters.userScripts), InjectUserScriptImmediately::No);
667 m_userContentController->addUserStyleSheets(parameters.userStyleSheets);
668 m_userContentController->addUserScriptMessageHandlers(parameters.messageHandlers);
669#if ENABLE(CONTENT_EXTENSIONS)
670 m_userContentController->addContentRuleLists(WTFMove(parameters.contentRuleLists));
671#endif
672
673#if PLATFORM(IOS_FAMILY)
674 setViewportConfigurationViewLayoutSize(parameters.viewportConfigurationViewLayoutSize, parameters.viewportConfigurationLayoutSizeScaleFactor, parameters.viewportConfigurationMinimumEffectiveDeviceWidth);
675 setMaximumUnobscuredSize(parameters.maximumUnobscuredSize);
676#endif
677
678#if USE(AUDIO_SESSION)
679 PlatformMediaSessionManager::setShouldDeactivateAudioSession(true);
680#endif
681
682 updateThrottleState();
683}
684
685#if ENABLE(WEB_RTC)
686void WebPage::disableICECandidateFiltering()
687{
688 m_page->disableICECandidateFiltering();
689}
690
691void WebPage::enableICECandidateFiltering()
692{
693 m_page->enableICECandidateFiltering();
694}
695
696#if USE(LIBWEBRTC)
697void WebPage::disableEnumeratingAllNetworkInterfaces()
698{
699 m_page->libWebRTCProvider().disableEnumeratingAllNetworkInterfaces();
700}
701
702void WebPage::enableEnumeratingAllNetworkInterfaces()
703{
704 m_page->libWebRTCProvider().enableEnumeratingAllNetworkInterfaces();
705}
706#endif
707#endif
708
709void WebPage::stopAllMediaPlayback()
710{
711 m_page->stopAllMediaPlayback();
712}
713
714void WebPage::suspendAllMediaPlayback()
715{
716 m_page->suspendAllMediaPlayback();
717}
718
719void WebPage::resumeAllMediaPlayback()
720{
721 m_page->resumeAllMediaPlayback();
722}
723
724void WebPage::suspendAllMediaBuffering()
725{
726 m_page->suspendAllMediaBuffering();
727}
728
729void WebPage::resumeAllMediaBuffering()
730{
731 m_page->resumeAllMediaBuffering();
732}
733
734
735void WebPage::reinitializeWebPage(WebPageCreationParameters&& parameters)
736{
737 ASSERT(m_drawingArea);
738
739 setSize(parameters.viewSize);
740
741 // If the UIProcess created a new DrawingArea, then we need to do the same.
742 if (m_drawingArea->identifier() != parameters.drawingAreaIdentifier) {
743 auto oldDrawingArea = std::exchange(m_drawingArea, nullptr);
744 oldDrawingArea->removeMessageReceiverIfNeeded();
745
746 m_drawingArea = DrawingArea::create(*this, parameters);
747 m_drawingArea->setPaintingEnabled(false);
748 m_drawingArea->setShouldScaleViewToFitDocument(parameters.shouldScaleViewToFitDocument);
749 m_drawingArea->updatePreferences(parameters.store);
750 m_drawingArea->setPaintingEnabled(true);
751
752 m_drawingArea->adoptLayersFromDrawingArea(*oldDrawingArea);
753
754 unfreezeLayerTree(LayerTreeFreezeReason::PageSuspended);
755 }
756
757 setViewLayoutSize(parameters.viewLayoutSize);
758
759 if (m_activityState != parameters.activityState)
760 setActivityState(parameters.activityState, ActivityStateChangeAsynchronous, Vector<CallbackID>());
761 if (m_layerHostingMode != parameters.layerHostingMode)
762 setLayerHostingMode(parameters.layerHostingMode);
763
764 platformReinitialize();
765}
766
767void WebPage::updateThrottleState()
768{
769 bool isThrottleable = this->isThrottleable();
770
771 // The UserActivity prevents App Nap. So if we want to allow App Nap of the page, stop the activity.
772 // If the page should not be app nap'd, start it.
773 if (isThrottleable)
774 m_userActivity.stop();
775 else
776 m_userActivity.start();
777
778#if ENABLE(SERVICE_WORKER)
779 RunLoop::main().dispatch([isThrottleable, sessionID = sessionID()] {
780 if (auto* connection = ServiceWorkerProvider::singleton().existingServiceWorkerConnectionForSession(sessionID)) {
781 if (isThrottleable != connection->isThrottleable())
782 connection->updateThrottleState();
783 }
784 });
785#endif
786}
787
788bool WebPage::isThrottleable() const
789{
790 bool isActive = m_activityState.containsAny({ ActivityState::IsLoading, ActivityState::IsAudible, ActivityState::IsCapturingMedia, ActivityState::WindowIsActive });
791 bool isVisuallyIdle = m_activityState.contains(ActivityState::IsVisuallyIdle);
792
793 return m_isAppNapEnabled && !isActive && isVisuallyIdle;
794}
795
796WebPage::~WebPage()
797{
798 ASSERT(!m_page);
799
800 platformDetach();
801
802 m_sandboxExtensionTracker.invalidate();
803
804 for (auto* pluginView : m_pluginViews)
805 pluginView->webPageDestroyed();
806
807#if !PLATFORM(IOS_FAMILY)
808 if (m_headerBanner)
809 m_headerBanner->detachFromPage();
810 if (m_footerBanner)
811 m_footerBanner->detachFromPage();
812#endif // !PLATFORM(IOS_FAMILY)
813
814#ifndef NDEBUG
815 webPageCounter.decrement();
816#endif
817
818#if (PLATFORM(IOS_FAMILY) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
819 if (m_playbackSessionManager)
820 m_playbackSessionManager->invalidate();
821
822 if (m_videoFullscreenManager)
823 m_videoFullscreenManager->invalidate();
824#endif
825}
826
827IPC::Connection* WebPage::messageSenderConnection() const
828{
829 return WebProcess::singleton().parentProcessConnection();
830}
831
832uint64_t WebPage::messageSenderDestinationID() const
833{
834 return pageID();
835}
836
837#if ENABLE(CONTEXT_MENUS)
838void WebPage::setInjectedBundleContextMenuClient(std::unique_ptr<API::InjectedBundle::PageContextMenuClient>&& contextMenuClient)
839{
840 if (!contextMenuClient) {
841 m_contextMenuClient = std::make_unique<API::InjectedBundle::PageContextMenuClient>();
842 return;
843 }
844
845 m_contextMenuClient = WTFMove(contextMenuClient);
846}
847#endif
848
849void WebPage::setInjectedBundleEditorClient(std::unique_ptr<API::InjectedBundle::EditorClient>&& editorClient)
850{
851 if (!editorClient) {
852 m_editorClient = std::make_unique<API::InjectedBundle::EditorClient>();
853 return;
854 }
855
856 m_editorClient = WTFMove(editorClient);
857}
858
859void WebPage::setInjectedBundleFormClient(std::unique_ptr<API::InjectedBundle::FormClient>&& formClient)
860{
861 if (!formClient) {
862 m_formClient = std::make_unique<API::InjectedBundle::FormClient>();
863 return;
864 }
865
866 m_formClient = WTFMove(formClient);
867}
868
869void WebPage::setInjectedBundlePageLoaderClient(std::unique_ptr<API::InjectedBundle::PageLoaderClient>&& loaderClient)
870{
871 if (!loaderClient) {
872 m_loaderClient = std::make_unique<API::InjectedBundle::PageLoaderClient>();
873 return;
874 }
875
876 m_loaderClient = WTFMove(loaderClient);
877
878 // It would be nice to get rid of this code and transition all clients to using didLayout instead of
879 // didFirstLayoutInFrame and didFirstVisuallyNonEmptyLayoutInFrame. In the meantime, this is required
880 // for backwards compatibility.
881 if (auto milestones = m_loaderClient->layoutMilestones())
882 listenForLayoutMilestones(milestones);
883}
884
885void WebPage::initializeInjectedBundlePolicyClient(WKBundlePagePolicyClientBase* client)
886{
887 m_policyClient.initialize(client);
888}
889
890void WebPage::setInjectedBundleResourceLoadClient(std::unique_ptr<API::InjectedBundle::ResourceLoadClient>&& client)
891{
892 if (!m_resourceLoadClient)
893 m_resourceLoadClient = std::make_unique<API::InjectedBundle::ResourceLoadClient>();
894 else
895 m_resourceLoadClient = WTFMove(client);
896}
897
898void WebPage::setInjectedBundleUIClient(std::unique_ptr<API::InjectedBundle::PageUIClient>&& uiClient)
899{
900 if (!uiClient) {
901 m_uiClient = std::make_unique<API::InjectedBundle::PageUIClient>();
902 return;
903 }
904
905 m_uiClient = WTFMove(uiClient);
906}
907
908#if ENABLE(FULLSCREEN_API)
909void WebPage::initializeInjectedBundleFullScreenClient(WKBundlePageFullScreenClientBase* client)
910{
911 m_fullScreenClient.initialize(client);
912}
913#endif
914
915#if ENABLE(NETSCAPE_PLUGIN_API)
916
917constexpr int smallPluginDimensionThreshold = 5;
918
919static bool pluginIsSmall(WebCore::HTMLPlugInElement& pluginElement)
920{
921 auto* renderer = pluginElement.renderer();
922 if (!is<RenderEmbeddedObject>(*renderer))
923 return false;
924
925 auto& box = downcast<RenderBox>(*renderer);
926 return box.contentWidth() <= smallPluginDimensionThreshold && box.contentHeight() <= smallPluginDimensionThreshold;
927}
928
929RefPtr<Plugin> WebPage::createPlugin(WebFrame* frame, HTMLPlugInElement* pluginElement, const Plugin::Parameters& parameters, String& newMIMEType)
930{
931 String frameURLString = frame->coreFrame()->loader().documentLoader()->responseURL().string();
932 String pageURLString = m_page->mainFrame().loader().documentLoader()->responseURL().string();
933
934#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
935 HTMLPlugInImageElement& pluginImageElement = downcast<HTMLPlugInImageElement>(*pluginElement);
936 unsigned pluginArea = 0;
937 PluginProcessType processType = pluginElement->displayState() == HTMLPlugInElement::WaitingForSnapshot && !(plugInIsPrimarySize(pluginImageElement, pluginArea) && !plugInIntersectsSearchRect(pluginImageElement)) ? PluginProcessTypeSnapshot : PluginProcessTypeNormal;
938#else
939 PluginProcessType processType = pluginElement->displayState() == HTMLPlugInElement::WaitingForSnapshot ? PluginProcessTypeSnapshot : PluginProcessTypeNormal;
940#endif
941
942 bool allowOnlyApplicationPlugins = !frame->coreFrame()->loader().subframeLoader().allowPlugins();
943
944 uint64_t pluginProcessToken;
945 uint32_t pluginLoadPolicy;
946 String unavailabilityDescription;
947 bool isUnsupported;
948 if (!sendSync(Messages::WebPageProxy::FindPlugin(parameters.mimeType, static_cast<uint32_t>(processType), parameters.url.string(), frameURLString, pageURLString, allowOnlyApplicationPlugins), Messages::WebPageProxy::FindPlugin::Reply(pluginProcessToken, newMIMEType, pluginLoadPolicy, unavailabilityDescription, isUnsupported)))
949 return nullptr;
950
951 PluginModuleLoadPolicy loadPolicy = static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy);
952 bool isBlockedPlugin = (loadPolicy == PluginModuleBlockedForSecurity) || (loadPolicy == PluginModuleBlockedForCompatibility);
953
954 if (isUnsupported || isBlockedPlugin || !pluginProcessToken) {
955#if ENABLE(PDFKIT_PLUGIN)
956 String path = parameters.url.path();
957 if (shouldUsePDFPlugin() && (MIMETypeRegistry::isPDFOrPostScriptMIMEType(parameters.mimeType) || (parameters.mimeType.isEmpty() && (path.endsWithIgnoringASCIICase(".pdf") || path.endsWithIgnoringASCIICase(".ps")))))
958 return PDFPlugin::create(*frame);
959#endif
960 }
961
962 if (isUnsupported) {
963 pluginElement->setReplacement(RenderEmbeddedObject::UnsupportedPlugin, unavailabilityDescription);
964 return nullptr;
965 }
966
967 if (isBlockedPlugin) {
968 bool isReplacementObscured = pluginElement->setReplacement(RenderEmbeddedObject::InsecurePluginVersion, unavailabilityDescription);
969 send(Messages::WebPageProxy::DidBlockInsecurePluginVersion(parameters.mimeType, parameters.url.string(), frameURLString, pageURLString, isReplacementObscured));
970 return nullptr;
971 }
972
973 if (!pluginProcessToken)
974 return nullptr;
975
976 if (m_page->settings().blockingOfSmallPluginsEnabled() && pluginIsSmall(*pluginElement)) {
977 RELEASE_LOG(Plugins, "Blocking a plugin because it is too small");
978 pluginElement->setReplacement(RenderEmbeddedObject::PluginTooSmall, pluginTooSmallText());
979 return nullptr;
980 }
981
982 bool isRestartedProcess = (pluginElement->displayState() == HTMLPlugInElement::Restarting || pluginElement->displayState() == HTMLPlugInElement::RestartingWithPendingMouseClick);
983 return PluginProxy::create(pluginProcessToken, isRestartedProcess);
984}
985#endif // ENABLE(NETSCAPE_PLUGIN_API)
986
987#if ENABLE(WEBGL) && !PLATFORM(MAC)
988WebCore::WebGLLoadPolicy WebPage::webGLPolicyForURL(WebFrame*, const URL&)
989{
990 return WebGLAllowCreation;
991}
992
993WebCore::WebGLLoadPolicy WebPage::resolveWebGLPolicyForURL(WebFrame*, const URL&)
994{
995 return WebGLAllowCreation;
996}
997#endif
998
999EditorState WebPage::editorState(IncludePostLayoutDataHint shouldIncludePostLayoutData) const
1000{
1001 Frame& frame = m_page->focusController().focusedOrMainFrame();
1002
1003 EditorState result;
1004
1005 if (PluginView* pluginView = focusedPluginViewForFrame(frame)) {
1006 if (!pluginView->getSelectionString().isNull()) {
1007 result.selectionIsNone = false;
1008 result.selectionIsRange = true;
1009 result.isInPlugin = true;
1010 return result;
1011 }
1012 }
1013
1014 const VisibleSelection& selection = frame.selection().selection();
1015 const Editor& editor = frame.editor();
1016
1017 result.selectionIsNone = selection.isNone();
1018 result.selectionIsRange = selection.isRange();
1019 result.isContentEditable = selection.isContentEditable();
1020 result.isContentRichlyEditable = selection.isContentRichlyEditable();
1021 result.isInPasswordField = selection.isInPasswordField();
1022 result.hasComposition = editor.hasComposition();
1023 result.shouldIgnoreSelectionChanges = editor.ignoreSelectionChanges();
1024
1025 if (auto* document = frame.document())
1026 result.originIdentifierForPasteboard = document->originIdentifierForPasteboard();
1027
1028 bool canIncludePostLayoutData = frame.view() && !frame.view()->needsLayout();
1029 if (shouldIncludePostLayoutData == IncludePostLayoutDataHint::Yes && canIncludePostLayoutData) {
1030 auto& postLayoutData = result.postLayoutData();
1031 postLayoutData.canCut = editor.canCut();
1032 postLayoutData.canCopy = editor.canCopy();
1033 postLayoutData.canPaste = editor.canPaste();
1034
1035 if (m_needsFontAttributes)
1036 postLayoutData.fontAttributes = editor.fontAttributesAtSelectionStart();
1037
1038#if PLATFORM(COCOA)
1039 if (result.isContentEditable && !selection.isNone()) {
1040 if (auto editingStyle = EditingStyle::styleAtSelectionStart(selection)) {
1041 if (editingStyle->hasStyle(CSSPropertyFontWeight, "bold"))
1042 postLayoutData.typingAttributes |= AttributeBold;
1043
1044 if (editingStyle->hasStyle(CSSPropertyFontStyle, "italic") || editingStyle->hasStyle(CSSPropertyFontStyle, "oblique"))
1045 postLayoutData.typingAttributes |= AttributeItalics;
1046
1047 if (editingStyle->hasStyle(CSSPropertyWebkitTextDecorationsInEffect, "underline"))
1048 postLayoutData.typingAttributes |= AttributeUnderline;
1049
1050 if (auto* styleProperties = editingStyle->style()) {
1051 bool isLeftToRight = styleProperties->propertyAsValueID(CSSPropertyDirection) == CSSValueLtr;
1052 switch (styleProperties->propertyAsValueID(CSSPropertyTextAlign)) {
1053 case CSSValueRight:
1054 case CSSValueWebkitRight:
1055 postLayoutData.textAlignment = RightAlignment;
1056 break;
1057 case CSSValueLeft:
1058 case CSSValueWebkitLeft:
1059 postLayoutData.textAlignment = LeftAlignment;
1060 break;
1061 case CSSValueCenter:
1062 case CSSValueWebkitCenter:
1063 postLayoutData.textAlignment = CenterAlignment;
1064 break;
1065 case CSSValueJustify:
1066 postLayoutData.textAlignment = JustifiedAlignment;
1067 break;
1068 case CSSValueStart:
1069 postLayoutData.textAlignment = isLeftToRight ? LeftAlignment : RightAlignment;
1070 break;
1071 case CSSValueEnd:
1072 postLayoutData.textAlignment = isLeftToRight ? RightAlignment : LeftAlignment;
1073 break;
1074 default:
1075 break;
1076 }
1077 if (auto textColor = styleProperties->propertyAsColor(CSSPropertyColor))
1078 postLayoutData.textColor = *textColor;
1079 }
1080 }
1081
1082 if (auto* enclosingListElement = enclosingList(selection.start().containerNode())) {
1083 if (is<HTMLUListElement>(*enclosingListElement))
1084 postLayoutData.enclosingListType = UnorderedList;
1085 else if (is<HTMLOListElement>(*enclosingListElement))
1086 postLayoutData.enclosingListType = OrderedList;
1087 else
1088 ASSERT_NOT_REACHED();
1089 }
1090
1091 postLayoutData.baseWritingDirection = editor.baseWritingDirectionForSelectionStart();
1092 }
1093#endif
1094 }
1095
1096 platformEditorState(frame, result, shouldIncludePostLayoutData);
1097
1098 m_lastEditorStateWasContentEditable = result.isContentEditable ? EditorStateIsContentEditable::Yes : EditorStateIsContentEditable::No;
1099
1100 return result;
1101}
1102
1103void WebPage::changeFontAttributes(WebCore::FontAttributeChanges&& changes)
1104{
1105 auto& frame = m_page->focusController().focusedOrMainFrame();
1106 if (frame.selection().selection().isContentEditable())
1107 frame.editor().applyStyleToSelection(changes.createEditingStyle(), changes.editAction(), Editor::ColorFilterMode::InvertColor);
1108}
1109
1110void WebPage::changeFont(WebCore::FontChanges&& changes)
1111{
1112 auto& frame = m_page->focusController().focusedOrMainFrame();
1113 if (frame.selection().selection().isContentEditable())
1114 frame.editor().applyStyleToSelection(changes.createEditingStyle(), EditAction::SetFont, Editor::ColorFilterMode::InvertColor);
1115}
1116
1117void WebPage::executeEditCommandWithCallback(const String& commandName, const String& argument, CallbackID callbackID)
1118{
1119 executeEditCommand(commandName, argument);
1120 send(Messages::WebPageProxy::VoidCallback(callbackID));
1121}
1122
1123void WebPage::selectAll()
1124{
1125 executeEditingCommand("SelectAll"_s, { });
1126 platformDidSelectAll();
1127}
1128
1129bool WebPage::shouldDispatchSyntheticMouseEventsWhenModifyingSelection() const
1130{
1131 auto* document = m_page->mainFrame().document();
1132 return document && document->quirks().shouldDispatchSyntheticMouseEventsWhenModifyingSelection();
1133}
1134
1135#if !PLATFORM(IOS_FAMILY)
1136
1137void WebPage::platformDidSelectAll()
1138{
1139}
1140
1141#endif // !PLATFORM(IOS_FAMILY)
1142
1143void WebPage::updateEditorStateAfterLayoutIfEditabilityChanged()
1144{
1145 // FIXME: We should update EditorStateIsContentEditable to track whether the state is richly
1146 // editable or plainttext-only.
1147 if (m_lastEditorStateWasContentEditable == EditorStateIsContentEditable::Unset)
1148 return;
1149
1150 Frame& frame = m_page->focusController().focusedOrMainFrame();
1151 EditorStateIsContentEditable editorStateIsContentEditable = frame.selection().selection().isContentEditable() ? EditorStateIsContentEditable::Yes : EditorStateIsContentEditable::No;
1152 if (m_lastEditorStateWasContentEditable != editorStateIsContentEditable)
1153 scheduleFullEditorStateUpdate();
1154}
1155
1156static OptionSet<RenderAsTextFlag> toRenderAsTextFlags(unsigned options)
1157{
1158 OptionSet<RenderAsTextFlag> flags;
1159
1160 if (options & RenderTreeShowAllLayers)
1161 flags.add(RenderAsTextFlag::ShowAllLayers);
1162 if (options & RenderTreeShowLayerNesting)
1163 flags.add(RenderAsTextFlag::ShowLayerNesting);
1164 if (options & RenderTreeShowCompositedLayers)
1165 flags.add(RenderAsTextFlag::ShowCompositedLayers);
1166 if (options & RenderTreeShowOverflow)
1167 flags.add(RenderAsTextFlag::ShowOverflow);
1168 if (options & RenderTreeShowSVGGeometry)
1169 flags.add(RenderAsTextFlag::ShowSVGGeometry);
1170 if (options & RenderTreeShowLayerFragments)
1171 flags.add(RenderAsTextFlag::ShowLayerFragments);
1172
1173 return flags;
1174}
1175
1176String WebPage::renderTreeExternalRepresentation(unsigned options) const
1177{
1178 return externalRepresentation(m_mainFrame->coreFrame(), toRenderAsTextFlags(options));
1179}
1180
1181String WebPage::renderTreeExternalRepresentationForPrinting() const
1182{
1183 return externalRepresentation(m_mainFrame->coreFrame(), { RenderAsTextFlag::PrintingMode });
1184}
1185
1186uint64_t WebPage::renderTreeSize() const
1187{
1188 if (!m_page)
1189 return 0;
1190 return m_page->renderTreeSize();
1191}
1192
1193void WebPage::setTracksRepaints(bool trackRepaints)
1194{
1195 if (FrameView* view = mainFrameView())
1196 view->setTracksRepaints(trackRepaints);
1197}
1198
1199bool WebPage::isTrackingRepaints() const
1200{
1201 if (FrameView* view = mainFrameView())
1202 return view->isTrackingRepaints();
1203
1204 return false;
1205}
1206
1207void WebPage::resetTrackedRepaints()
1208{
1209 if (FrameView* view = mainFrameView())
1210 view->resetTrackedRepaints();
1211}
1212
1213Ref<API::Array> WebPage::trackedRepaintRects()
1214{
1215 FrameView* view = mainFrameView();
1216 if (!view)
1217 return API::Array::create();
1218
1219 Vector<RefPtr<API::Object>> repaintRects;
1220 repaintRects.reserveInitialCapacity(view->trackedRepaintRects().size());
1221
1222 for (const auto& repaintRect : view->trackedRepaintRects())
1223 repaintRects.uncheckedAppend(API::Rect::create(toAPI(repaintRect)));
1224
1225 return API::Array::create(WTFMove(repaintRects));
1226}
1227
1228PluginView* WebPage::focusedPluginViewForFrame(Frame& frame)
1229{
1230 if (!is<PluginDocument>(frame.document()))
1231 return nullptr;
1232
1233 auto& pluginDocument = downcast<PluginDocument>(*frame.document());
1234 if (pluginDocument.focusedElement() != pluginDocument.pluginElement())
1235 return nullptr;
1236
1237 return pluginViewForFrame(&frame);
1238}
1239
1240PluginView* WebPage::pluginViewForFrame(Frame* frame)
1241{
1242 if (!frame || !is<PluginDocument>(frame->document()))
1243 return nullptr;
1244
1245 auto& document = downcast<PluginDocument>(*frame->document());
1246 return static_cast<PluginView*>(document.pluginWidget());
1247}
1248
1249void WebPage::executeEditingCommand(const String& commandName, const String& argument)
1250{
1251 Frame& frame = m_page->focusController().focusedOrMainFrame();
1252
1253 if (PluginView* pluginView = focusedPluginViewForFrame(frame)) {
1254 pluginView->handleEditingCommand(commandName, argument);
1255 return;
1256 }
1257
1258 frame.editor().command(commandName).execute(argument);
1259}
1260
1261void WebPage::setEditable(bool editable)
1262{
1263 m_page->setEditable(editable);
1264 m_page->setTabKeyCyclesThroughElements(!editable);
1265 Frame& frame = m_page->focusController().focusedOrMainFrame();
1266 if (editable) {
1267 frame.editor().applyEditingStyleToBodyElement();
1268 // If the page is made editable and the selection is empty, set it to something.
1269 if (frame.selection().isNone())
1270 frame.selection().setSelectionFromNone();
1271 }
1272}
1273
1274void WebPage::increaseListLevel()
1275{
1276 m_page->focusController().focusedOrMainFrame().editor().increaseSelectionListLevel();
1277}
1278
1279void WebPage::decreaseListLevel()
1280{
1281 m_page->focusController().focusedOrMainFrame().editor().decreaseSelectionListLevel();
1282}
1283
1284void WebPage::changeListType()
1285{
1286 m_page->focusController().focusedOrMainFrame().editor().changeSelectionListType();
1287}
1288
1289void WebPage::setBaseWritingDirection(WritingDirection direction)
1290{
1291 m_page->focusController().focusedOrMainFrame().editor().setBaseWritingDirection(direction);
1292}
1293
1294bool WebPage::isEditingCommandEnabled(const String& commandName)
1295{
1296 Frame& frame = m_page->focusController().focusedOrMainFrame();
1297
1298 if (PluginView* pluginView = focusedPluginViewForFrame(frame))
1299 return pluginView->isEditingCommandEnabled(commandName);
1300
1301 Editor::Command command = frame.editor().command(commandName);
1302 return command.isSupported() && command.isEnabled();
1303}
1304
1305void WebPage::clearMainFrameName()
1306{
1307 if (Frame* frame = mainFrame())
1308 frame->tree().clearName();
1309}
1310
1311void WebPage::enterAcceleratedCompositingMode(GraphicsLayer* layer)
1312{
1313 m_drawingArea->setRootCompositingLayer(layer);
1314}
1315
1316void WebPage::exitAcceleratedCompositingMode()
1317{
1318 m_drawingArea->setRootCompositingLayer(nullptr);
1319}
1320
1321void WebPage::close()
1322{
1323 if (m_isClosed)
1324 return;
1325
1326#if ENABLE(RESOURCE_LOAD_STATISTICS)
1327 WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::ClearPageSpecificDataForResourceLoadStatistics(sessionID(), m_pageID), 0);
1328#endif
1329
1330 m_isClosed = true;
1331
1332 // If there is still no URL, then we never loaded anything in this page, so nothing to report.
1333 if (!mainWebFrame()->url().isEmpty())
1334 reportUsedFeatures();
1335
1336 if (WebProcess::singleton().injectedBundle())
1337 WebProcess::singleton().injectedBundle()->willDestroyPage(this);
1338
1339 if (m_inspector) {
1340 m_inspector->disconnectFromPage();
1341 m_inspector = nullptr;
1342 }
1343
1344 m_page->inspectorController().disconnectAllFrontends();
1345
1346#if ENABLE(FULLSCREEN_API)
1347 m_fullScreenManager = nullptr;
1348#endif
1349
1350 if (m_activePopupMenu) {
1351 m_activePopupMenu->disconnectFromPage();
1352 m_activePopupMenu = nullptr;
1353 }
1354
1355 if (m_activeOpenPanelResultListener) {
1356 m_activeOpenPanelResultListener->disconnectFromPage();
1357 m_activeOpenPanelResultListener = nullptr;
1358 }
1359
1360#if ENABLE(INPUT_TYPE_COLOR)
1361 if (m_activeColorChooser) {
1362 m_activeColorChooser->disconnectFromPage();
1363 m_activeColorChooser = nullptr;
1364 }
1365#endif
1366
1367#if PLATFORM(GTK)
1368 if (m_printOperation) {
1369 m_printOperation->disconnectFromPage();
1370 m_printOperation = nullptr;
1371 }
1372#endif
1373
1374#if ENABLE(VIDEO) && USE(GSTREAMER)
1375 if (m_installMediaPluginsCallback) {
1376 m_installMediaPluginsCallback->invalidate();
1377 m_installMediaPluginsCallback = nullptr;
1378 }
1379#endif
1380
1381 m_sandboxExtensionTracker.invalidate();
1382
1383#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
1384 m_determinePrimarySnapshottedPlugInTimer.stop();
1385#endif
1386
1387#if ENABLE(VIEWPORT_RESIZING)
1388 m_shrinkToFitContentTimer.stop();
1389#endif
1390
1391#if ENABLE(CONTEXT_MENUS)
1392 m_contextMenuClient = std::make_unique<API::InjectedBundle::PageContextMenuClient>();
1393#endif
1394 m_editorClient = std::make_unique<API::InjectedBundle::EditorClient>();
1395 m_formClient = std::make_unique<API::InjectedBundle::FormClient>();
1396 m_loaderClient = std::make_unique<API::InjectedBundle::PageLoaderClient>();
1397 m_policyClient.initialize(0);
1398 m_resourceLoadClient = std::make_unique<API::InjectedBundle::ResourceLoadClient>();
1399 m_uiClient = std::make_unique<API::InjectedBundle::PageUIClient>();
1400#if ENABLE(FULLSCREEN_API)
1401 m_fullScreenClient.initialize(0);
1402#endif
1403
1404 m_printContext = nullptr;
1405 m_mainFrame->coreFrame()->loader().detachFromParent();
1406 m_drawingArea = nullptr;
1407
1408 DeferredPageDestructor::createDeferredPageDestructor(WTFMove(m_page), this);
1409
1410 bool isRunningModal = m_isRunningModal;
1411 m_isRunningModal = false;
1412
1413 auto& webProcess = WebProcess::singleton();
1414#if PLATFORM(COCOA)
1415 if (m_remoteObjectRegistry)
1416 m_remoteObjectRegistry->close();
1417#endif
1418#if ENABLE(ASYNC_SCROLLING)
1419 if (m_useAsyncScrolling)
1420 webProcess.eventDispatcher().removeScrollingTreeForPage(this);
1421#endif
1422 webProcess.removeMessageReceiver(Messages::WebPage::messageReceiverName(), m_pageID);
1423 // FIXME: This should be done in the object destructors, and the objects themselves should be message receivers.
1424 webProcess.removeMessageReceiver(Messages::WebInspector::messageReceiverName(), m_pageID);
1425 webProcess.removeMessageReceiver(Messages::WebInspectorUI::messageReceiverName(), m_pageID);
1426 webProcess.removeMessageReceiver(Messages::RemoteWebInspectorUI::messageReceiverName(), m_pageID);
1427#if ENABLE(FULLSCREEN_API)
1428 webProcess.removeMessageReceiver(Messages::WebFullScreenManager::messageReceiverName(), m_pageID);
1429#endif
1430#if PLATFORM(COCOA) || PLATFORM(GTK)
1431 m_viewGestureGeometryCollector = nullptr;
1432#endif
1433
1434 // The WebPage can be destroyed by this call.
1435 WebProcess::singleton().removeWebPage(m_pageID);
1436
1437 WebProcess::singleton().updateActivePages();
1438
1439 if (isRunningModal)
1440 RunLoop::main().stop();
1441}
1442
1443void WebPage::tryClose()
1444{
1445 SendStopResponsivenessTimer stopper;
1446
1447 if (!corePage()->userInputBridge().tryClosePage())
1448 return;
1449
1450 send(Messages::WebPageProxy::ClosePage(true));
1451}
1452
1453void WebPage::sendClose()
1454{
1455 send(Messages::WebPageProxy::ClosePage(false));
1456}
1457
1458void WebPage::suspendForProcessSwap()
1459{
1460 auto failedToSuspend = [this, protectedThis = makeRef(*this)] {
1461 send(Messages::WebPageProxy::DidFailToSuspendAfterProcessSwap());
1462 };
1463
1464 auto* currentHistoryItem = m_mainFrame->coreFrame()->loader().history().currentItem();
1465 if (!currentHistoryItem) {
1466 failedToSuspend();
1467 return;
1468 }
1469
1470 if (!PageCache::singleton().addIfCacheable(*currentHistoryItem, corePage())) {
1471 failedToSuspend();
1472 return;
1473 }
1474
1475 send(Messages::WebPageProxy::DidSuspendAfterProcessSwap());
1476}
1477
1478void WebPage::loadURLInFrame(URL&& url, uint64_t frameID)
1479{
1480 WebFrame* frame = WebProcess::singleton().webFrame(frameID);
1481 if (!frame)
1482 return;
1483
1484 frame->coreFrame()->loader().load(FrameLoadRequest(*frame->coreFrame(), ResourceRequest(url), ShouldOpenExternalURLsPolicy::ShouldNotAllow));
1485}
1486
1487void WebPage::loadDataInFrame(IPC::DataReference&& data, String&& MIMEType, String&& encodingName, URL&& baseURL, uint64_t frameID)
1488{
1489 WebFrame* frame = WebProcess::singleton().webFrame(frameID);
1490 if (!frame)
1491 return;
1492 ASSERT(mainWebFrame() != frame);
1493
1494 auto sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(data.data()), data.size());
1495 ResourceResponse response(baseURL, MIMEType, sharedBuffer->size(), encodingName);
1496 SubstituteData substituteData(WTFMove(sharedBuffer), baseURL, WTFMove(response), SubstituteData::SessionHistoryVisibility::Hidden);
1497 frame->coreFrame()->loader().load(FrameLoadRequest(*frame->coreFrame(), ResourceRequest(baseURL), ShouldOpenExternalURLsPolicy::ShouldNotAllow, WTFMove(substituteData)));
1498}
1499
1500#if !PLATFORM(COCOA)
1501void WebPage::platformDidReceiveLoadParameters(const LoadParameters& loadParameters)
1502{
1503}
1504#endif
1505
1506void WebPage::loadRequest(LoadParameters&& loadParameters)
1507{
1508 SendStopResponsivenessTimer stopper;
1509
1510 m_pendingNavigationID = loadParameters.navigationID;
1511 m_pendingWebsitePolicies = WTFMove(loadParameters.websitePolicies);
1512
1513 m_sandboxExtensionTracker.beginLoad(m_mainFrame.get(), WTFMove(loadParameters.sandboxExtensionHandle));
1514
1515 // Let the InjectedBundle know we are about to start the load, passing the user data from the UIProcess
1516 // to all the client to set up any needed state.
1517 m_loaderClient->willLoadURLRequest(*this, loadParameters.request, WebProcess::singleton().transformHandlesToObjects(loadParameters.userData.object()).get());
1518
1519 platformDidReceiveLoadParameters(loadParameters);
1520
1521 // Initate the load in WebCore.
1522 FrameLoadRequest frameLoadRequest { *m_mainFrame->coreFrame(), loadParameters.request, ShouldOpenExternalURLsPolicy::ShouldNotAllow };
1523 ShouldOpenExternalURLsPolicy externalURLsPolicy = static_cast<ShouldOpenExternalURLsPolicy>(loadParameters.shouldOpenExternalURLsPolicy);
1524 frameLoadRequest.setShouldOpenExternalURLsPolicy(externalURLsPolicy);
1525 frameLoadRequest.setShouldTreatAsContinuingLoad(loadParameters.shouldTreatAsContinuingLoad);
1526 frameLoadRequest.setLockHistory(loadParameters.lockHistory);
1527 frameLoadRequest.setlockBackForwardList(loadParameters.lockBackForwardList);
1528 frameLoadRequest.setClientRedirectSourceForHistory(loadParameters.clientRedirectSourceForHistory);
1529 frameLoadRequest.setIsRequestFromClientOrUserInput();
1530
1531 corePage()->userInputBridge().loadRequest(WTFMove(frameLoadRequest));
1532
1533 ASSERT(!m_pendingNavigationID);
1534 ASSERT(!m_pendingWebsitePolicies);
1535}
1536
1537void WebPage::loadDataImpl(uint64_t navigationID, bool shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& websitePolicies, Ref<SharedBuffer>&& sharedBuffer, const String& MIMEType, const String& encodingName, const URL& baseURL, const URL& unreachableURL, const UserData& userData)
1538{
1539 SendStopResponsivenessTimer stopper;
1540
1541 m_pendingNavigationID = navigationID;
1542 m_pendingWebsitePolicies = WTFMove(websitePolicies);
1543
1544 ResourceRequest request(baseURL);
1545 ResourceResponse response(URL(), MIMEType, sharedBuffer->size(), encodingName);
1546 SubstituteData substituteData(WTFMove(sharedBuffer), unreachableURL, response, SubstituteData::SessionHistoryVisibility::Hidden);
1547
1548 // Let the InjectedBundle know we are about to start the load, passing the user data from the UIProcess
1549 // to all the client to set up any needed state.
1550 m_loaderClient->willLoadDataRequest(*this, request, const_cast<SharedBuffer*>(substituteData.content()), substituteData.mimeType(), substituteData.textEncoding(), substituteData.failingURL(), WebProcess::singleton().transformHandlesToObjects(userData.object()).get());
1551
1552 // Initate the load in WebCore.
1553 FrameLoadRequest frameLoadRequest(*m_mainFrame->coreFrame(), request, ShouldOpenExternalURLsPolicy::ShouldNotAllow, substituteData);
1554 frameLoadRequest.setShouldTreatAsContinuingLoad(shouldTreatAsContinuingLoad);
1555 m_mainFrame->coreFrame()->loader().load(WTFMove(frameLoadRequest));
1556}
1557
1558void WebPage::loadData(LoadParameters&& loadParameters)
1559{
1560 platformDidReceiveLoadParameters(loadParameters);
1561
1562 auto sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(loadParameters.data.data()), loadParameters.data.size());
1563 URL baseURL = loadParameters.baseURLString.isEmpty() ? WTF::blankURL() : URL(URL(), loadParameters.baseURLString);
1564 loadDataImpl(loadParameters.navigationID, loadParameters.shouldTreatAsContinuingLoad, WTFMove(loadParameters.websitePolicies), WTFMove(sharedBuffer), loadParameters.MIMEType, loadParameters.encodingName, baseURL, URL(), loadParameters.userData);
1565}
1566
1567void WebPage::loadAlternateHTML(LoadParameters&& loadParameters)
1568{
1569 platformDidReceiveLoadParameters(loadParameters);
1570
1571 URL baseURL = loadParameters.baseURLString.isEmpty() ? WTF::blankURL() : URL(URL(), loadParameters.baseURLString);
1572 URL unreachableURL = loadParameters.unreachableURLString.isEmpty() ? URL() : URL(URL(), loadParameters.unreachableURLString);
1573 URL provisionalLoadErrorURL = loadParameters.provisionalLoadErrorURLString.isEmpty() ? URL() : URL(URL(), loadParameters.provisionalLoadErrorURLString);
1574 auto sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(loadParameters.data.data()), loadParameters.data.size());
1575 m_mainFrame->coreFrame()->loader().setProvisionalLoadErrorBeingHandledURL(provisionalLoadErrorURL);
1576 loadDataImpl(loadParameters.navigationID, loadParameters.shouldTreatAsContinuingLoad, WTFMove(loadParameters.websitePolicies), WTFMove(sharedBuffer), loadParameters.MIMEType, loadParameters.encodingName, baseURL, unreachableURL, loadParameters.userData);
1577 m_mainFrame->coreFrame()->loader().setProvisionalLoadErrorBeingHandledURL({ });
1578}
1579
1580void WebPage::navigateToPDFLinkWithSimulatedClick(const String& url, IntPoint documentPoint, IntPoint screenPoint)
1581{
1582 Frame* mainFrame = m_mainFrame->coreFrame();
1583 Document* mainFrameDocument = mainFrame->document();
1584 if (!mainFrameDocument)
1585 return;
1586
1587 const int singleClick = 1;
1588 // FIXME: Set modifier keys.
1589 // FIXME: This should probably set IsSimulated::Yes.
1590 auto mouseEvent = MouseEvent::create(eventNames().clickEvent, Event::CanBubble::Yes, Event::IsCancelable::Yes, Event::IsComposed::Yes,
1591 MonotonicTime::now(), nullptr, singleClick, screenPoint, documentPoint, { }, { }, 0, 0, nullptr, 0, WebCore::NoTap, nullptr);
1592
1593 mainFrame->loader().urlSelected(mainFrameDocument->completeURL(url), emptyString(), mouseEvent.ptr(), LockHistory::No, LockBackForwardList::No, ShouldSendReferrer::NeverSendReferrer, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
1594}
1595
1596void WebPage::stopLoadingFrame(uint64_t frameID)
1597{
1598 WebFrame* frame = WebProcess::singleton().webFrame(frameID);
1599 if (!frame)
1600 return;
1601
1602 corePage()->userInputBridge().stopLoadingFrame(frame->coreFrame());
1603}
1604
1605void WebPage::stopLoading()
1606{
1607 SendStopResponsivenessTimer stopper;
1608
1609 corePage()->userInputBridge().stopLoadingFrame(m_mainFrame->coreFrame());
1610}
1611
1612bool WebPage::defersLoading() const
1613{
1614 return m_page->defersLoading();
1615}
1616
1617void WebPage::setDefersLoading(bool defersLoading)
1618{
1619 m_page->setDefersLoading(defersLoading);
1620}
1621
1622void WebPage::reload(uint64_t navigationID, uint32_t reloadOptions, SandboxExtension::Handle&& sandboxExtensionHandle)
1623{
1624 SendStopResponsivenessTimer stopper;
1625
1626 ASSERT(!m_mainFrame->coreFrame()->loader().frameHasLoaded() || !m_pendingNavigationID);
1627 m_pendingNavigationID = navigationID;
1628
1629 m_sandboxExtensionTracker.beginReload(m_mainFrame.get(), WTFMove(sandboxExtensionHandle));
1630 corePage()->userInputBridge().reloadFrame(m_mainFrame->coreFrame(), OptionSet<ReloadOption>::fromRaw(reloadOptions));
1631
1632 if (m_pendingNavigationID) {
1633 // This can happen if FrameLoader::reload() returns early because the document URL is empty.
1634 // The reload does nothing so we need to reset the pending navigation. See webkit.org/b/153210.
1635 m_pendingNavigationID = 0;
1636 }
1637}
1638
1639void WebPage::goToBackForwardItem(uint64_t navigationID, const BackForwardItemIdentifier& backForwardItemID, FrameLoadType backForwardType, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& websitePolicies)
1640{
1641 SendStopResponsivenessTimer stopper;
1642
1643 ASSERT(isBackForwardLoadType(backForwardType));
1644
1645 HistoryItem* item = WebBackForwardListProxy::itemForID(backForwardItemID);
1646 ASSERT(item);
1647 if (!item)
1648 return;
1649
1650 LOG(Loading, "In WebProcess pid %i, WebPage %" PRIu64 " is navigating to back/forward URL %s", getCurrentProcessID(), m_pageID, item->url().string().utf8().data());
1651
1652 ASSERT(!m_pendingNavigationID);
1653 m_pendingNavigationID = navigationID;
1654 m_pendingWebsitePolicies = WTFMove(websitePolicies);
1655
1656 m_page->goToItem(*item, backForwardType, shouldTreatAsContinuingLoad);
1657}
1658
1659void WebPage::tryRestoreScrollPosition()
1660{
1661 m_page->mainFrame().loader().history().restoreScrollPositionAndViewState();
1662}
1663
1664WebPage* WebPage::fromCorePage(Page* page)
1665{
1666 return &static_cast<WebChromeClient&>(page->chrome().client()).page();
1667}
1668
1669void WebPage::setSize(const WebCore::IntSize& viewSize)
1670{
1671 if (m_viewSize == viewSize)
1672 return;
1673
1674 m_viewSize = viewSize;
1675 FrameView* view = m_page->mainFrame().view();
1676 view->resize(viewSize);
1677 m_drawingArea->setNeedsDisplay();
1678
1679#if USE(COORDINATED_GRAPHICS)
1680 if (view->useFixedLayout())
1681 sendViewportAttributesChanged(m_page->viewportArguments());
1682#endif
1683}
1684
1685#if USE(COORDINATED_GRAPHICS)
1686void WebPage::sendViewportAttributesChanged(const ViewportArguments& viewportArguments)
1687{
1688 FrameView* view = m_page->mainFrame().view();
1689 ASSERT(view && view->useFixedLayout());
1690
1691 // Viewport properties have no impact on zero sized fixed viewports.
1692 if (m_viewSize.isEmpty())
1693 return;
1694
1695 // Recalculate the recommended layout size, when the available size (device pixel) changes.
1696 Settings& settings = m_page->settings();
1697
1698 int minimumLayoutFallbackWidth = std::max(settings.layoutFallbackWidth(), m_viewSize.width());
1699
1700 // If unset we use the viewport dimensions. This fits with the behavior of desktop browsers.
1701 int deviceWidth = (settings.deviceWidth() > 0) ? settings.deviceWidth() : m_viewSize.width();
1702 int deviceHeight = (settings.deviceHeight() > 0) ? settings.deviceHeight() : m_viewSize.height();
1703
1704 ViewportAttributes attr = computeViewportAttributes(viewportArguments, minimumLayoutFallbackWidth, deviceWidth, deviceHeight, 1, m_viewSize);
1705
1706 // If no layout was done yet set contentFixedOrigin to (0,0).
1707 IntPoint contentFixedOrigin = view->didFirstLayout() ? view->fixedVisibleContentRect().location() : IntPoint();
1708
1709 // Put the width and height to the viewport width and height. In css units however.
1710 // Use FloatSize to avoid truncated values during scale.
1711 FloatSize contentFixedSize = m_viewSize;
1712
1713#if ENABLE(CSS_DEVICE_ADAPTATION)
1714 // CSS viewport descriptors might be applied to already affected viewport size
1715 // if the page enables/disables stylesheets, so need to keep initial viewport size.
1716 view->setInitialViewportSize(roundedIntSize(contentFixedSize));
1717#endif
1718
1719 contentFixedSize.scale(1 / attr.initialScale);
1720 view->setFixedVisibleContentRect(IntRect(contentFixedOrigin, roundedIntSize(contentFixedSize)));
1721
1722 attr.initialScale = m_page->viewportArguments().zoom; // Resets auto (-1) if no value was set by user.
1723
1724 // This also takes care of the relayout.
1725 setFixedLayoutSize(roundedIntSize(attr.layoutSize));
1726
1727#if USE(COORDINATED_GRAPHICS)
1728 m_drawingArea->didChangeViewportAttributes(WTFMove(attr));
1729#else
1730 send(Messages::WebPageProxy::DidChangeViewportProperties(attr));
1731#endif
1732}
1733#endif
1734
1735void WebPage::scrollMainFrameIfNotAtMaxScrollPosition(const IntSize& scrollOffset)
1736{
1737 FrameView* frameView = m_page->mainFrame().view();
1738
1739 ScrollPosition scrollPosition = frameView->scrollPosition();
1740 ScrollPosition maximumScrollPosition = frameView->maximumScrollPosition();
1741
1742 // If the current scroll position in a direction is the max scroll position
1743 // we don't want to scroll at all.
1744 IntSize newScrollOffset;
1745 if (scrollPosition.x() < maximumScrollPosition.x())
1746 newScrollOffset.setWidth(scrollOffset.width());
1747 if (scrollPosition.y() < maximumScrollPosition.y())
1748 newScrollOffset.setHeight(scrollOffset.height());
1749
1750 if (newScrollOffset.isZero())
1751 return;
1752
1753 frameView->setScrollPosition(frameView->scrollPosition() + newScrollOffset);
1754}
1755
1756void WebPage::drawRect(GraphicsContext& graphicsContext, const IntRect& rect)
1757{
1758#if PLATFORM(MAC)
1759 FrameView* mainFrameView = m_page->mainFrame().view();
1760 LocalDefaultSystemAppearance localAppearance(mainFrameView ? mainFrameView->useDarkAppearance() : false);
1761#endif
1762
1763 GraphicsContextStateSaver stateSaver(graphicsContext);
1764 graphicsContext.clip(rect);
1765
1766 m_mainFrame->coreFrame()->view()->paint(graphicsContext, rect);
1767}
1768
1769double WebPage::textZoomFactor() const
1770{
1771 PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1772 if (pluginView && pluginView->requiresUnifiedScaleFactor()) {
1773 if (pluginView->handlesPageScaleFactor())
1774 return pluginView->pageScaleFactor();
1775 return pageScaleFactor();
1776 }
1777
1778 Frame* frame = m_mainFrame->coreFrame();
1779 if (!frame)
1780 return 1;
1781 return frame->textZoomFactor();
1782}
1783
1784void WebPage::setTextZoomFactor(double zoomFactor)
1785{
1786 PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1787 if (pluginView && pluginView->requiresUnifiedScaleFactor()) {
1788 if (pluginView->handlesPageScaleFactor())
1789 pluginView->setPageScaleFactor(zoomFactor, IntPoint());
1790 else
1791 scalePage(zoomFactor, IntPoint());
1792 return;
1793 }
1794
1795 Frame* frame = m_mainFrame->coreFrame();
1796 if (!frame)
1797 return;
1798 frame->setTextZoomFactor(static_cast<float>(zoomFactor));
1799}
1800
1801double WebPage::pageZoomFactor() const
1802{
1803 PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1804 if (pluginView && pluginView->requiresUnifiedScaleFactor()) {
1805 if (pluginView->handlesPageScaleFactor())
1806 return pluginView->pageScaleFactor();
1807 return pageScaleFactor();
1808 }
1809
1810 Frame* frame = m_mainFrame->coreFrame();
1811 if (!frame)
1812 return 1;
1813 return frame->pageZoomFactor();
1814}
1815
1816void WebPage::setPageZoomFactor(double zoomFactor)
1817{
1818 PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1819 if (pluginView && pluginView->requiresUnifiedScaleFactor()) {
1820 if (pluginView->handlesPageScaleFactor())
1821 pluginView->setPageScaleFactor(zoomFactor, IntPoint());
1822 else
1823 scalePage(zoomFactor, IntPoint());
1824 return;
1825 }
1826
1827 Frame* frame = m_mainFrame->coreFrame();
1828 if (!frame)
1829 return;
1830 frame->setPageZoomFactor(static_cast<float>(zoomFactor));
1831}
1832
1833static void dumpHistoryItem(HistoryItem& item, size_t indent, bool isCurrentItem, StringBuilder& stringBuilder, const String& directoryName)
1834{
1835 if (isCurrentItem)
1836 stringBuilder.appendLiteral("curr-> ");
1837 else {
1838 for (size_t i = 0; i < indent; ++i)
1839 stringBuilder.append(' ');
1840 }
1841
1842 auto url = item.url();
1843 if (url.protocolIs("file")) {
1844 size_t start = url.string().find(directoryName);
1845 if (start == WTF::notFound)
1846 start = 0;
1847 else
1848 start += directoryName.length();
1849 stringBuilder.appendLiteral("(file test):");
1850 stringBuilder.append(url.string().substring(start));
1851 } else
1852 stringBuilder.append(url);
1853
1854 auto& target = item.target();
1855 if (target.length()) {
1856 stringBuilder.appendLiteral(" (in frame \"");
1857 stringBuilder.append(target);
1858 stringBuilder.appendLiteral("\")");
1859 }
1860
1861 if (item.isTargetItem())
1862 stringBuilder.appendLiteral(" **nav target**");
1863
1864 stringBuilder.append('\n');
1865
1866 Vector<Ref<HistoryItem>> children;
1867 children.reserveInitialCapacity(item.children().size());
1868 for (auto& child : item.children())
1869 children.uncheckedAppend(child.copyRef());
1870 std::stable_sort(children.begin(), children.end(), [] (auto& a, auto& b) {
1871 return codePointCompare(a->target(), b->target()) < 0;
1872 });
1873 for (auto& child : children)
1874 dumpHistoryItem(child, indent + 4, false, stringBuilder, directoryName);
1875}
1876
1877String WebPage::dumpHistoryForTesting(const String& directory)
1878{
1879 if (!m_page)
1880 return { };
1881
1882 auto& list = m_page->backForward();
1883
1884 StringBuilder builder;
1885 int begin = -list.backCount();
1886 if (list.itemAtIndex(begin)->url() == WTF::blankURL())
1887 ++begin;
1888 for (int i = begin; i <= static_cast<int>(list.forwardCount()); ++i)
1889 dumpHistoryItem(*list.itemAtIndex(i), 8, !i, builder, directory);
1890 return builder.toString();
1891}
1892
1893void WebPage::clearHistory()
1894{
1895 if (!m_page)
1896 return;
1897
1898 static_cast<WebBackForwardListProxy&>(m_page->backForward().client()).clear();
1899}
1900
1901void WebPage::setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor)
1902{
1903 PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1904 if (pluginView && pluginView->requiresUnifiedScaleFactor()) {
1905 if (pluginView->handlesPageScaleFactor())
1906 pluginView->setPageScaleFactor(pageZoomFactor, IntPoint());
1907 else
1908 scalePage(pageZoomFactor, IntPoint());
1909 return;
1910 }
1911
1912 Frame* frame = m_mainFrame->coreFrame();
1913 if (!frame)
1914 return;
1915 return frame->setPageAndTextZoomFactors(static_cast<float>(pageZoomFactor), static_cast<float>(textZoomFactor));
1916}
1917
1918void WebPage::windowScreenDidChange(uint32_t displayID)
1919{
1920 m_page->chrome().windowScreenDidChange(static_cast<PlatformDisplayID>(displayID));
1921}
1922
1923void WebPage::scalePage(double scale, const IntPoint& origin)
1924{
1925 double totalScale = scale * viewScaleFactor();
1926 bool willChangeScaleFactor = totalScale != totalScaleFactor();
1927
1928#if PLATFORM(IOS_FAMILY)
1929 if (willChangeScaleFactor) {
1930 if (!m_inDynamicSizeUpdate)
1931 m_dynamicSizeUpdateHistory.clear();
1932 m_scaleWasSetByUIProcess = false;
1933 }
1934#endif
1935 PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1936 if (pluginView && pluginView->handlesPageScaleFactor()) {
1937 // If the main-frame plugin wants to handle the page scale factor, make sure to reset WebCore's page scale.
1938 // Otherwise, we can end up with an immutable but non-1 page scale applied by WebCore on top of whatever the plugin does.
1939 if (m_page->pageScaleFactor() != 1) {
1940 m_page->setPageScaleFactor(1, origin);
1941 for (auto* pluginView : m_pluginViews)
1942 pluginView->pageScaleFactorDidChange();
1943 }
1944
1945 pluginView->setPageScaleFactor(totalScale, origin);
1946 return;
1947 }
1948
1949 m_page->setPageScaleFactor(totalScale, origin);
1950
1951 // We can't early return before setPageScaleFactor because the origin might be different.
1952 if (!willChangeScaleFactor)
1953 return;
1954
1955 for (auto* pluginView : m_pluginViews)
1956 pluginView->pageScaleFactorDidChange();
1957
1958#if USE(COORDINATED_GRAPHICS) || USE(TEXTURE_MAPPER)
1959 m_drawingArea->deviceOrPageScaleFactorChanged();
1960#endif
1961
1962 send(Messages::WebPageProxy::PageScaleFactorDidChange(scale));
1963}
1964
1965void WebPage::scalePageInViewCoordinates(double scale, IntPoint centerInViewCoordinates)
1966{
1967 double totalScale = scale * viewScaleFactor();
1968 if (totalScale == totalScaleFactor())
1969 return;
1970
1971 IntPoint scrollPositionAtNewScale = mainFrameView()->rootViewToContents(-centerInViewCoordinates);
1972 double scaleRatio = scale / pageScaleFactor();
1973 scrollPositionAtNewScale.scale(scaleRatio);
1974 scalePage(scale, scrollPositionAtNewScale);
1975}
1976
1977double WebPage::totalScaleFactor() const
1978{
1979 PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1980 if (pluginView && pluginView->handlesPageScaleFactor())
1981 return pluginView->pageScaleFactor();
1982
1983 return m_page->pageScaleFactor();
1984}
1985
1986double WebPage::pageScaleFactor() const
1987{
1988 return totalScaleFactor() / viewScaleFactor();
1989}
1990
1991double WebPage::viewScaleFactor() const
1992{
1993 return m_page->viewScaleFactor();
1994}
1995
1996void WebPage::scaleView(double scale)
1997{
1998 if (viewScaleFactor() == scale)
1999 return;
2000
2001 float pageScale = pageScaleFactor();
2002
2003 IntPoint scrollPositionAtNewScale;
2004 if (FrameView* mainFrameView = m_page->mainFrame().view()) {
2005 double scaleRatio = scale / viewScaleFactor();
2006 scrollPositionAtNewScale = mainFrameView->scrollPosition();
2007 scrollPositionAtNewScale.scale(scaleRatio);
2008 }
2009
2010 m_page->setViewScaleFactor(scale);
2011 scalePage(pageScale, scrollPositionAtNewScale);
2012}
2013
2014void WebPage::setDeviceScaleFactor(float scaleFactor)
2015{
2016 if (scaleFactor == m_page->deviceScaleFactor())
2017 return;
2018
2019 m_page->setDeviceScaleFactor(scaleFactor);
2020
2021 // Tell all our plug-in views that the device scale factor changed.
2022#if PLATFORM(MAC)
2023 for (auto* pluginView : m_pluginViews)
2024 pluginView->setDeviceScaleFactor(scaleFactor);
2025
2026 updateHeaderAndFooterLayersForDeviceScaleChange(scaleFactor);
2027#endif
2028
2029 if (findController().isShowingOverlay()) {
2030 // We must have updated layout to get the selection rects right.
2031 layoutIfNeeded();
2032 findController().deviceScaleFactorDidChange();
2033 }
2034
2035#if USE(COORDINATED_GRAPHICS) || USE(TEXTURE_MAPPER)
2036 m_drawingArea->deviceOrPageScaleFactorChanged();
2037#endif
2038}
2039
2040float WebPage::deviceScaleFactor() const
2041{
2042 return m_page->deviceScaleFactor();
2043}
2044
2045void WebPage::accessibilitySettingsDidChange()
2046{
2047 m_page->accessibilitySettingsDidChange();
2048}
2049
2050void WebPage::setUseFixedLayout(bool fixed)
2051{
2052 // Do not overwrite current settings if initially setting it to false.
2053 if (m_useFixedLayout == fixed)
2054 return;
2055 m_useFixedLayout = fixed;
2056
2057#if !PLATFORM(IOS_FAMILY)
2058 m_page->settings().setFixedElementsLayoutRelativeToFrame(fixed);
2059#endif
2060
2061 FrameView* view = mainFrameView();
2062 if (!view)
2063 return;
2064
2065 view->setUseFixedLayout(fixed);
2066 if (!fixed)
2067 setFixedLayoutSize(IntSize());
2068
2069 send(Messages::WebPageProxy::UseFixedLayoutDidChange(fixed));
2070}
2071
2072bool WebPage::setFixedLayoutSize(const IntSize& size)
2073{
2074 FrameView* view = mainFrameView();
2075 if (!view || view->fixedLayoutSize() == size)
2076 return false;
2077
2078 LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " setFixedLayoutSize " << size);
2079 view->setFixedLayoutSize(size);
2080
2081 send(Messages::WebPageProxy::FixedLayoutSizeDidChange(size));
2082 return true;
2083}
2084
2085IntSize WebPage::fixedLayoutSize() const
2086{
2087 FrameView* view = mainFrameView();
2088 if (!view)
2089 return IntSize();
2090 return view->fixedLayoutSize();
2091}
2092
2093void WebPage::disabledAdaptationsDidChange(const OptionSet<DisabledAdaptations>& disabledAdaptations)
2094{
2095#if PLATFORM(IOS_FAMILY)
2096 if (m_viewportConfiguration.setDisabledAdaptations(disabledAdaptations))
2097 viewportConfigurationChanged();
2098#else
2099 UNUSED_PARAM(disabledAdaptations);
2100#endif
2101}
2102
2103void WebPage::viewportPropertiesDidChange(const ViewportArguments& viewportArguments)
2104{
2105#if PLATFORM(IOS_FAMILY)
2106 if (m_viewportConfiguration.setViewportArguments(viewportArguments))
2107 viewportConfigurationChanged();
2108#endif
2109
2110#if USE(COORDINATED_GRAPHICS)
2111 FrameView* view = m_page->mainFrame().view();
2112 if (view && view->useFixedLayout())
2113 sendViewportAttributesChanged(viewportArguments);
2114 else
2115 m_drawingArea->didChangeViewportAttributes(ViewportAttributes());
2116#endif
2117
2118#if !PLATFORM(IOS_FAMILY) && !USE(COORDINATED_GRAPHICS)
2119 UNUSED_PARAM(viewportArguments);
2120#endif
2121}
2122
2123void WebPage::listenForLayoutMilestones(OptionSet<WebCore::LayoutMilestone> milestones)
2124{
2125 if (!m_page)
2126 return;
2127 m_page->addLayoutMilestones(milestones);
2128}
2129
2130void WebPage::setSuppressScrollbarAnimations(bool suppressAnimations)
2131{
2132 m_page->setShouldSuppressScrollbarAnimations(suppressAnimations);
2133}
2134
2135void WebPage::setEnableVerticalRubberBanding(bool enableVerticalRubberBanding)
2136{
2137 m_page->setVerticalScrollElasticity(enableVerticalRubberBanding ? ScrollElasticityAllowed : ScrollElasticityNone);
2138}
2139
2140void WebPage::setEnableHorizontalRubberBanding(bool enableHorizontalRubberBanding)
2141{
2142 m_page->setHorizontalScrollElasticity(enableHorizontalRubberBanding ? ScrollElasticityAllowed : ScrollElasticityNone);
2143}
2144
2145void WebPage::setBackgroundExtendsBeyondPage(bool backgroundExtendsBeyondPage)
2146{
2147 if (m_page->settings().backgroundShouldExtendBeyondPage() != backgroundExtendsBeyondPage)
2148 m_page->settings().setBackgroundShouldExtendBeyondPage(backgroundExtendsBeyondPage);
2149}
2150
2151void WebPage::setPaginationMode(uint32_t mode)
2152{
2153 Pagination pagination = m_page->pagination();
2154 pagination.mode = static_cast<Pagination::Mode>(mode);
2155 m_page->setPagination(pagination);
2156}
2157
2158void WebPage::setPaginationBehavesLikeColumns(bool behavesLikeColumns)
2159{
2160 Pagination pagination = m_page->pagination();
2161 pagination.behavesLikeColumns = behavesLikeColumns;
2162 m_page->setPagination(pagination);
2163}
2164
2165void WebPage::setPageLength(double pageLength)
2166{
2167 Pagination pagination = m_page->pagination();
2168 pagination.pageLength = pageLength;
2169 m_page->setPagination(pagination);
2170}
2171
2172void WebPage::setGapBetweenPages(double gap)
2173{
2174 Pagination pagination = m_page->pagination();
2175 pagination.gap = gap;
2176 m_page->setPagination(pagination);
2177}
2178
2179void WebPage::setPaginationLineGridEnabled(bool lineGridEnabled)
2180{
2181 m_page->setPaginationLineGridEnabled(lineGridEnabled);
2182}
2183
2184void WebPage::postInjectedBundleMessage(const String& messageName, const UserData& userData)
2185{
2186 auto& webProcess = WebProcess::singleton();
2187 InjectedBundle* injectedBundle = webProcess.injectedBundle();
2188 if (!injectedBundle)
2189 return;
2190
2191 injectedBundle->didReceiveMessageToPage(this, messageName, webProcess.transformHandlesToObjects(userData.object()).get());
2192}
2193
2194#if !PLATFORM(IOS_FAMILY)
2195
2196void WebPage::setHeaderPageBanner(PageBanner* pageBanner)
2197{
2198 if (m_headerBanner)
2199 m_headerBanner->detachFromPage();
2200
2201 m_headerBanner = pageBanner;
2202
2203 if (m_headerBanner)
2204 m_headerBanner->addToPage(PageBanner::Header, this);
2205}
2206
2207PageBanner* WebPage::headerPageBanner()
2208{
2209 return m_headerBanner.get();
2210}
2211
2212void WebPage::setFooterPageBanner(PageBanner* pageBanner)
2213{
2214 if (m_footerBanner)
2215 m_footerBanner->detachFromPage();
2216
2217 m_footerBanner = pageBanner;
2218
2219 if (m_footerBanner)
2220 m_footerBanner->addToPage(PageBanner::Footer, this);
2221}
2222
2223PageBanner* WebPage::footerPageBanner()
2224{
2225 return m_footerBanner.get();
2226}
2227
2228void WebPage::hidePageBanners()
2229{
2230 if (m_headerBanner)
2231 m_headerBanner->hide();
2232 if (m_footerBanner)
2233 m_footerBanner->hide();
2234}
2235
2236void WebPage::showPageBanners()
2237{
2238 if (m_headerBanner)
2239 m_headerBanner->showIfHidden();
2240 if (m_footerBanner)
2241 m_footerBanner->showIfHidden();
2242}
2243
2244void WebPage::setHeaderBannerHeightForTesting(int height)
2245{
2246 corePage()->setHeaderHeight(height);
2247}
2248
2249void WebPage::setFooterBannerHeightForTesting(int height)
2250{
2251 corePage()->setFooterHeight(height);
2252}
2253
2254#endif // !PLATFORM(IOS_FAMILY)
2255
2256void WebPage::takeSnapshot(IntRect snapshotRect, IntSize bitmapSize, uint32_t options, CallbackID callbackID)
2257{
2258 SnapshotOptions snapshotOptions = static_cast<SnapshotOptions>(options);
2259 snapshotOptions |= SnapshotOptionsShareable;
2260
2261 RefPtr<WebImage> image = snapshotAtSize(snapshotRect, bitmapSize, snapshotOptions);
2262
2263 ShareableBitmap::Handle handle;
2264 if (image)
2265 image->bitmap().createHandle(handle, SharedMemory::Protection::ReadOnly);
2266
2267 send(Messages::WebPageProxy::ImageCallback(handle, callbackID));
2268}
2269
2270RefPtr<WebImage> WebPage::scaledSnapshotWithOptions(const IntRect& rect, double additionalScaleFactor, SnapshotOptions options)
2271{
2272 IntRect snapshotRect = rect;
2273 IntSize bitmapSize = snapshotRect.size();
2274 if (options & SnapshotOptionsPrinting) {
2275 ASSERT(additionalScaleFactor == 1);
2276 Frame* coreFrame = m_mainFrame->coreFrame();
2277 if (!coreFrame)
2278 return nullptr;
2279 bitmapSize.setHeight(PrintContext::numberOfPages(*coreFrame, bitmapSize) * (bitmapSize.height() + 1) - 1);
2280 } else {
2281 double scaleFactor = additionalScaleFactor;
2282 if (!(options & SnapshotOptionsExcludeDeviceScaleFactor))
2283 scaleFactor *= corePage()->deviceScaleFactor();
2284 bitmapSize.scale(scaleFactor);
2285 }
2286
2287 return snapshotAtSize(rect, bitmapSize, options);
2288}
2289
2290static void paintSnapshotAtSize(const IntRect& rect, const IntSize& bitmapSize, SnapshotOptions options, Frame& frame, FrameView& frameView, GraphicsContext& graphicsContext)
2291{
2292 IntRect snapshotRect = rect;
2293 float horizontalScaleFactor = static_cast<float>(bitmapSize.width()) / rect.width();
2294 float verticalScaleFactor = static_cast<float>(bitmapSize.height()) / rect.height();
2295 float scaleFactor = std::max(horizontalScaleFactor, verticalScaleFactor);
2296
2297 if (options & SnapshotOptionsPrinting) {
2298 PrintContext::spoolAllPagesWithBoundaries(frame, graphicsContext, snapshotRect.size());
2299 return;
2300 }
2301
2302 Color documentBackgroundColor = frameView.documentBackgroundColor();
2303 Color backgroundColor = (frame.settings().backgroundShouldExtendBeyondPage() && documentBackgroundColor.isValid()) ? documentBackgroundColor : frameView.baseBackgroundColor();
2304 graphicsContext.fillRect(IntRect(IntPoint(), bitmapSize), backgroundColor);
2305
2306 if (!(options & SnapshotOptionsExcludeDeviceScaleFactor)) {
2307 double deviceScaleFactor = frame.page()->deviceScaleFactor();
2308 graphicsContext.applyDeviceScaleFactor(deviceScaleFactor);
2309 scaleFactor /= deviceScaleFactor;
2310 }
2311
2312 graphicsContext.scale(scaleFactor);
2313 graphicsContext.translate(-snapshotRect.location());
2314
2315 FrameView::SelectionInSnapshot shouldPaintSelection = FrameView::IncludeSelection;
2316 if (options & SnapshotOptionsExcludeSelectionHighlighting)
2317 shouldPaintSelection = FrameView::ExcludeSelection;
2318
2319 FrameView::CoordinateSpaceForSnapshot coordinateSpace = FrameView::DocumentCoordinates;
2320 if (options & SnapshotOptionsInViewCoordinates)
2321 coordinateSpace = FrameView::ViewCoordinates;
2322
2323 frameView.paintContentsForSnapshot(graphicsContext, snapshotRect, shouldPaintSelection, coordinateSpace);
2324
2325 if (options & SnapshotOptionsPaintSelectionRectangle) {
2326 FloatRect selectionRectangle = frame.selection().selectionBounds();
2327 graphicsContext.setStrokeColor(Color(0xFF, 0, 0));
2328 graphicsContext.strokeRect(selectionRectangle, 1);
2329 }
2330}
2331
2332static ShareableBitmap::Configuration snapshotOptionsToBitmapConfiguration(SnapshotOptions options, WebPage& page)
2333{
2334 ShareableBitmap::Configuration configuration;
2335#if USE(CG)
2336 if (options & SnapshotOptionsUseScreenColorSpace)
2337 configuration.colorSpace.cgColorSpace = screenColorSpace(page.corePage()->mainFrame().view());
2338#endif
2339 return configuration;
2340}
2341
2342RefPtr<WebImage> WebPage::snapshotAtSize(const IntRect& rect, const IntSize& bitmapSize, SnapshotOptions options)
2343{
2344 Frame* coreFrame = m_mainFrame->coreFrame();
2345 if (!coreFrame)
2346 return nullptr;
2347
2348 FrameView* frameView = coreFrame->view();
2349 if (!frameView)
2350 return nullptr;
2351
2352 auto snapshot = WebImage::create(bitmapSize, snapshotOptionsToImageOptions(options), snapshotOptionsToBitmapConfiguration(options, *this));
2353 if (!snapshot)
2354 return nullptr;
2355 auto graphicsContext = snapshot->bitmap().createGraphicsContext();
2356
2357 paintSnapshotAtSize(rect, bitmapSize, options, *coreFrame, *frameView, *graphicsContext);
2358
2359 return snapshot;
2360}
2361
2362#if USE(CF)
2363RetainPtr<CFDataRef> WebPage::pdfSnapshotAtSize(const IntRect& rect, const IntSize& bitmapSize, SnapshotOptions options)
2364{
2365 Frame* coreFrame = m_mainFrame->coreFrame();
2366 if (!coreFrame)
2367 return nullptr;
2368
2369 FrameView* frameView = coreFrame->view();
2370 if (!frameView)
2371 return nullptr;
2372
2373 auto data = adoptCF(CFDataCreateMutable(kCFAllocatorDefault, 0));
2374
2375#if USE(CG)
2376 auto dataConsumer = adoptCF(CGDataConsumerCreateWithCFData(data.get()));
2377 auto mediaBox = CGRectMake(0, 0, bitmapSize.width(), bitmapSize.height());
2378 auto pdfContext = adoptCF(CGPDFContextCreate(dataConsumer.get(), &mediaBox, nullptr));
2379
2380 CGPDFContextBeginPage(pdfContext.get(), nullptr);
2381
2382 GraphicsContext graphicsContext { pdfContext.get() };
2383 graphicsContext.scale({ 1, -1 });
2384 graphicsContext.translate(0, -bitmapSize.height());
2385 paintSnapshotAtSize(rect, bitmapSize, options, *coreFrame, *frameView, graphicsContext);
2386
2387 CGPDFContextEndPage(pdfContext.get());
2388 CGPDFContextClose(pdfContext.get());
2389#endif
2390
2391 return data;
2392}
2393#endif
2394
2395RefPtr<WebImage> WebPage::snapshotNode(WebCore::Node& node, SnapshotOptions options, unsigned maximumPixelCount)
2396{
2397 Frame* coreFrame = m_mainFrame->coreFrame();
2398 if (!coreFrame)
2399 return nullptr;
2400
2401 FrameView* frameView = coreFrame->view();
2402 if (!frameView)
2403 return nullptr;
2404
2405 if (!node.renderer())
2406 return nullptr;
2407
2408 LayoutRect topLevelRect;
2409 IntRect snapshotRect = snappedIntRect(node.renderer()->paintingRootRect(topLevelRect));
2410 if (snapshotRect.isEmpty())
2411 return nullptr;
2412
2413 double scaleFactor = 1;
2414 IntSize snapshotSize = snapshotRect.size();
2415 unsigned maximumHeight = maximumPixelCount / snapshotSize.width();
2416 if (maximumHeight < static_cast<unsigned>(snapshotSize.height())) {
2417 scaleFactor = static_cast<double>(maximumHeight) / snapshotSize.height();
2418 snapshotSize = IntSize(snapshotSize.width() * scaleFactor, maximumHeight);
2419 }
2420
2421 auto snapshot = WebImage::create(snapshotSize, snapshotOptionsToImageOptions(options), snapshotOptionsToBitmapConfiguration(options, *this));
2422 if (!snapshot)
2423 return nullptr;
2424 auto graphicsContext = snapshot->bitmap().createGraphicsContext();
2425
2426 if (!(options & SnapshotOptionsExcludeDeviceScaleFactor)) {
2427 double deviceScaleFactor = corePage()->deviceScaleFactor();
2428 graphicsContext->applyDeviceScaleFactor(deviceScaleFactor);
2429 scaleFactor /= deviceScaleFactor;
2430 }
2431
2432 graphicsContext->scale(scaleFactor);
2433 graphicsContext->translate(-snapshotRect.location());
2434
2435 Color savedBackgroundColor = frameView->baseBackgroundColor();
2436 frameView->setBaseBackgroundColor(Color::transparent);
2437 frameView->setNodeToDraw(&node);
2438
2439 frameView->paintContentsForSnapshot(*graphicsContext, snapshotRect, FrameView::ExcludeSelection, FrameView::DocumentCoordinates);
2440
2441 frameView->setBaseBackgroundColor(savedBackgroundColor);
2442 frameView->setNodeToDraw(nullptr);
2443
2444 return snapshot;
2445}
2446
2447void WebPage::pageDidScroll()
2448{
2449#if PLATFORM(IOS_FAMILY)
2450 if (!m_inDynamicSizeUpdate)
2451 m_dynamicSizeUpdateHistory.clear();
2452#endif
2453 m_uiClient->pageDidScroll(this);
2454
2455 m_pageScrolledHysteresis.impulse();
2456
2457 send(Messages::WebPageProxy::PageDidScroll());
2458}
2459
2460void WebPage::pageStoppedScrolling()
2461{
2462 // Maintain the current history item's scroll position up-to-date.
2463 if (Frame* frame = m_mainFrame->coreFrame())
2464 frame->loader().history().saveScrollPositionAndViewStateToItem(frame->loader().history().currentItem());
2465}
2466
2467#if ENABLE(CONTEXT_MENUS)
2468WebContextMenu* WebPage::contextMenu()
2469{
2470 if (!m_contextMenu)
2471 m_contextMenu = WebContextMenu::create(this);
2472 return m_contextMenu.get();
2473}
2474
2475WebContextMenu* WebPage::contextMenuAtPointInWindow(const IntPoint& point)
2476{
2477 corePage()->contextMenuController().clearContextMenu();
2478
2479 // Simulate a mouse click to generate the correct menu.
2480 PlatformMouseEvent mousePressEvent(point, point, RightButton, PlatformEvent::MousePressed, 1, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, WebCore::NoTap);
2481 corePage()->userInputBridge().handleMousePressEvent(mousePressEvent);
2482 bool handled = corePage()->userInputBridge().handleContextMenuEvent(mousePressEvent, corePage()->mainFrame());
2483 auto* menu = handled ? contextMenu() : nullptr;
2484 PlatformMouseEvent mouseReleaseEvent(point, point, RightButton, PlatformEvent::MouseReleased, 1, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, WebCore::NoTap);
2485 corePage()->userInputBridge().handleMouseReleaseEvent(mouseReleaseEvent);
2486
2487 return menu;
2488}
2489#endif
2490
2491// Events
2492
2493static const WebEvent* g_currentEvent = 0;
2494
2495// FIXME: WebPage::currentEvent is used by the plug-in code to avoid having to convert from DOM events back to
2496// WebEvents. When we get the event handling sorted out, this should go away and the Widgets should get the correct
2497// platform events passed to the event handler code.
2498const WebEvent* WebPage::currentEvent()
2499{
2500 return g_currentEvent;
2501}
2502
2503void WebPage::freezeLayerTree(LayerTreeFreezeReason reason)
2504{
2505 RELEASE_LOG(ProcessSuspension, "%p - WebPage (PageID=%llu) - Adding a reason %d to freeze layer tree; current reasons are %d",
2506 this, m_pageID, static_cast<unsigned>(reason), m_layerTreeFreezeReasons.toRaw());
2507 m_layerTreeFreezeReasons.add(reason);
2508 updateDrawingAreaLayerTreeFreezeState();
2509}
2510
2511void WebPage::unfreezeLayerTree(LayerTreeFreezeReason reason)
2512{
2513 RELEASE_LOG(ProcessSuspension, "%p - WebPage (PageID=%llu) - Removing a reason %d to freeze layer tree; current reasons are %d",
2514 this, m_pageID, static_cast<unsigned>(reason), m_layerTreeFreezeReasons.toRaw());
2515 m_layerTreeFreezeReasons.remove(reason);
2516 updateDrawingAreaLayerTreeFreezeState();
2517}
2518
2519void WebPage::updateDrawingAreaLayerTreeFreezeState()
2520{
2521 if (!m_drawingArea)
2522 return;
2523 m_drawingArea->setLayerTreeStateIsFrozen(!!m_layerTreeFreezeReasons);
2524}
2525
2526void WebPage::callVolatilityCompletionHandlers(bool succeeded)
2527{
2528 auto completionHandlers = WTFMove(m_markLayersAsVolatileCompletionHandlers);
2529 for (auto& completionHandler : completionHandlers)
2530 completionHandler(succeeded);
2531}
2532
2533void WebPage::layerVolatilityTimerFired()
2534{
2535 Seconds newInterval = m_layerVolatilityTimer.repeatInterval() * 2.;
2536 bool didSucceed = markLayersVolatileImmediatelyIfPossible();
2537 if (didSucceed || newInterval > maximumLayerVolatilityTimerInterval) {
2538 m_layerVolatilityTimer.stop();
2539 if (didSucceed)
2540 RELEASE_LOG_IF_ALLOWED("%p - WebPage - Succeeded in marking layers as volatile", this);
2541 else
2542 RELEASE_LOG_IF_ALLOWED("%p - WebPage - Failed to mark layers as volatile within %gms", this, maximumLayerVolatilityTimerInterval.milliseconds());
2543 callVolatilityCompletionHandlers(didSucceed);
2544 return;
2545 }
2546
2547 RELEASE_LOG_ERROR_IF_ALLOWED("%p - WebPage - Failed to mark all layers as volatile, will retry in %g ms", this, newInterval.milliseconds());
2548 m_layerVolatilityTimer.startRepeating(newInterval);
2549}
2550
2551bool WebPage::markLayersVolatileImmediatelyIfPossible()
2552{
2553 return !drawingArea() || drawingArea()->markLayersVolatileImmediatelyIfPossible();
2554}
2555
2556void WebPage::markLayersVolatile(WTF::Function<void (bool)>&& completionHandler)
2557{
2558 RELEASE_LOG_IF_ALLOWED("%p - WebPage::markLayersVolatile()", this);
2559
2560 if (m_layerVolatilityTimer.isActive())
2561 m_layerVolatilityTimer.stop();
2562
2563 if (completionHandler)
2564 m_markLayersAsVolatileCompletionHandlers.append(WTFMove(completionHandler));
2565
2566 bool didSucceed = markLayersVolatileImmediatelyIfPossible();
2567 if (didSucceed || m_isSuspendedUnderLock) {
2568 if (didSucceed)
2569 RELEASE_LOG_IF_ALLOWED("%p - WebPage - Successfully marked layers as volatile", this);
2570 else {
2571 // If we get suspended when locking the screen, it is expected that some IOSurfaces cannot be marked as purgeable so we do not keep retrying.
2572 RELEASE_LOG_IF_ALLOWED("%p - WebPage - Did what we could to mark IOSurfaces as purgeable after locking the screen", this);
2573 }
2574 callVolatilityCompletionHandlers(didSucceed);
2575 return;
2576 }
2577
2578 RELEASE_LOG_IF_ALLOWED("%p - Failed to mark all layers as volatile, will retry in %g ms", this, initialLayerVolatilityTimerInterval.milliseconds());
2579 m_layerVolatilityTimer.startRepeating(initialLayerVolatilityTimerInterval);
2580}
2581
2582void WebPage::cancelMarkLayersVolatile()
2583{
2584 RELEASE_LOG_IF_ALLOWED("%p - WebPage::cancelMarkLayersVolatile()", this);
2585 m_layerVolatilityTimer.stop();
2586 m_markLayersAsVolatileCompletionHandlers.clear();
2587}
2588
2589class CurrentEvent {
2590public:
2591 explicit CurrentEvent(const WebEvent& event)
2592 : m_previousCurrentEvent(g_currentEvent)
2593 {
2594 g_currentEvent = &event;
2595 }
2596
2597 ~CurrentEvent()
2598 {
2599 g_currentEvent = m_previousCurrentEvent;
2600 }
2601
2602private:
2603 const WebEvent* m_previousCurrentEvent;
2604};
2605
2606#if ENABLE(CONTEXT_MENUS)
2607static bool isContextClick(const PlatformMouseEvent& event)
2608{
2609#if PLATFORM(COCOA)
2610 return WebEventFactory::shouldBeHandledAsContextClick(event);
2611#else
2612 return event.button() == WebCore::RightButton;
2613#endif
2614}
2615
2616static bool handleContextMenuEvent(const PlatformMouseEvent& platformMouseEvent, WebPage* page)
2617{
2618 IntPoint point = page->corePage()->mainFrame().view()->windowToContents(platformMouseEvent.position());
2619 HitTestResult result = page->corePage()->mainFrame().eventHandler().hitTestResultAtPoint(point);
2620
2621 Frame* frame = &page->corePage()->mainFrame();
2622 if (result.innerNonSharedNode())
2623 frame = result.innerNonSharedNode()->document().frame();
2624
2625 bool handled = page->corePage()->userInputBridge().handleContextMenuEvent(platformMouseEvent, *frame);
2626 if (handled)
2627 page->contextMenu()->show();
2628
2629 return handled;
2630}
2631
2632void WebPage::contextMenuForKeyEvent()
2633{
2634 corePage()->contextMenuController().clearContextMenu();
2635
2636 Frame& frame = m_page->focusController().focusedOrMainFrame();
2637 bool handled = frame.eventHandler().sendContextMenuEventForKey();
2638 if (handled)
2639 contextMenu()->show();
2640}
2641#endif
2642
2643static bool handleMouseEvent(const WebMouseEvent& mouseEvent, WebPage* page)
2644{
2645 Frame& frame = page->corePage()->mainFrame();
2646 if (!frame.view())
2647 return false;
2648
2649 PlatformMouseEvent platformMouseEvent = platform(mouseEvent);
2650
2651 switch (platformMouseEvent.type()) {
2652 case PlatformEvent::MousePressed: {
2653#if ENABLE(CONTEXT_MENUS)
2654 if (isContextClick(platformMouseEvent))
2655 page->corePage()->contextMenuController().clearContextMenu();
2656#endif
2657
2658 bool handled = page->corePage()->userInputBridge().handleMousePressEvent(platformMouseEvent);
2659#if ENABLE(CONTEXT_MENUS)
2660 if (isContextClick(platformMouseEvent))
2661 handled = handleContextMenuEvent(platformMouseEvent, page);
2662#endif
2663 return handled;
2664 }
2665 case PlatformEvent::MouseReleased:
2666 return page->corePage()->userInputBridge().handleMouseReleaseEvent(platformMouseEvent);
2667
2668 case PlatformEvent::MouseMoved:
2669#if PLATFORM(COCOA)
2670 // We need to do a full, normal hit test during this mouse event if the page is active or if a mouse
2671 // button is currently pressed. It is possible that neither of those things will be true since on
2672 // Lion when legacy scrollbars are enabled, WebKit receives mouse events all the time. If it is one
2673 // of those cases where the page is not active and the mouse is not pressed, then we can fire a more
2674 // efficient scrollbars-only version of the event.
2675 if (!(page->corePage()->focusController().isActive() || (mouseEvent.button() != WebMouseEvent::NoButton)))
2676 return page->corePage()->userInputBridge().handleMouseMoveOnScrollbarEvent(platformMouseEvent);
2677#endif
2678 return page->corePage()->userInputBridge().handleMouseMoveEvent(platformMouseEvent);
2679
2680 case PlatformEvent::MouseForceChanged:
2681 case PlatformEvent::MouseForceDown:
2682 case PlatformEvent::MouseForceUp:
2683 return page->corePage()->userInputBridge().handleMouseForceEvent(platformMouseEvent);
2684
2685 default:
2686 ASSERT_NOT_REACHED();
2687 return false;
2688 }
2689}
2690
2691void WebPage::mouseEvent(const WebMouseEvent& mouseEvent)
2692{
2693 SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true };
2694
2695 m_userActivity.impulse();
2696
2697 bool shouldHandleEvent = true;
2698
2699#if ENABLE(CONTEXT_MENUS)
2700 // Don't try to handle any pending mouse events if a context menu is showing.
2701 if (m_isShowingContextMenu)
2702 shouldHandleEvent = false;
2703#endif
2704#if ENABLE(DRAG_SUPPORT)
2705 if (m_isStartingDrag)
2706 shouldHandleEvent = false;
2707#endif
2708
2709 if (!shouldHandleEvent) {
2710 send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(mouseEvent.type()), false));
2711 return;
2712 }
2713
2714 bool handled = false;
2715
2716#if !PLATFORM(IOS_FAMILY)
2717 if (!handled && m_headerBanner)
2718 handled = m_headerBanner->mouseEvent(mouseEvent);
2719 if (!handled && m_footerBanner)
2720 handled = m_footerBanner->mouseEvent(mouseEvent);
2721#endif // !PLATFORM(IOS_FAMILY)
2722
2723 if (!handled) {
2724 CurrentEvent currentEvent(mouseEvent);
2725 handled = handleMouseEvent(mouseEvent, this);
2726 }
2727
2728 send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(mouseEvent.type()), handled));
2729}
2730
2731static bool handleWheelEvent(const WebWheelEvent& wheelEvent, Page* page)
2732{
2733 Frame& frame = page->mainFrame();
2734 if (!frame.view())
2735 return false;
2736
2737 PlatformWheelEvent platformWheelEvent = platform(wheelEvent);
2738 return page->userInputBridge().handleWheelEvent(platformWheelEvent);
2739}
2740
2741void WebPage::wheelEvent(const WebWheelEvent& wheelEvent)
2742{
2743 m_userActivity.impulse();
2744
2745 CurrentEvent currentEvent(wheelEvent);
2746
2747 bool handled = handleWheelEvent(wheelEvent, m_page.get());
2748
2749 send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(wheelEvent.type()), handled));
2750}
2751
2752static bool handleKeyEvent(const WebKeyboardEvent& keyboardEvent, Page* page)
2753{
2754 if (!page->mainFrame().view())
2755 return false;
2756
2757 if (keyboardEvent.type() == WebEvent::Char && keyboardEvent.isSystemKey())
2758 return page->userInputBridge().handleAccessKeyEvent(platform(keyboardEvent));
2759 return page->userInputBridge().handleKeyEvent(platform(keyboardEvent));
2760}
2761
2762void WebPage::keyEvent(const WebKeyboardEvent& keyboardEvent)
2763{
2764 SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true };
2765
2766 m_userActivity.impulse();
2767
2768 PlatformKeyboardEvent::setCurrentModifierState(platform(keyboardEvent).modifiers());
2769
2770 CurrentEvent currentEvent(keyboardEvent);
2771
2772 bool handled = handleKeyEvent(keyboardEvent, m_page.get());
2773 // FIXME: Platform default behaviors should be performed during normal DOM event dispatch (in most cases, in default keydown event handler).
2774 if (!handled)
2775 handled = performDefaultBehaviorForKeyEvent(keyboardEvent);
2776
2777 send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(keyboardEvent.type()), handled));
2778}
2779
2780void WebPage::validateCommand(const String& commandName, CallbackID callbackID)
2781{
2782 bool isEnabled = false;
2783 int32_t state = 0;
2784 Frame& frame = m_page->focusController().focusedOrMainFrame();
2785 if (PluginView* pluginView = focusedPluginViewForFrame(frame))
2786 isEnabled = pluginView->isEditingCommandEnabled(commandName);
2787 else {
2788 Editor::Command command = frame.editor().command(commandName);
2789 state = command.state();
2790 isEnabled = command.isSupported() && command.isEnabled();
2791 }
2792
2793 send(Messages::WebPageProxy::ValidateCommandCallback(commandName, isEnabled, state, callbackID));
2794}
2795
2796void WebPage::executeEditCommand(const String& commandName, const String& argument)
2797{
2798 executeEditingCommand(commandName, argument);
2799}
2800
2801void WebPage::setNeedsFontAttributes(bool needsFontAttributes)
2802{
2803 if (m_needsFontAttributes == needsFontAttributes)
2804 return;
2805
2806 m_needsFontAttributes = needsFontAttributes;
2807
2808 if (m_needsFontAttributes)
2809 scheduleFullEditorStateUpdate();
2810}
2811
2812void WebPage::restoreSessionInternal(const Vector<BackForwardListItemState>& itemStates, WasRestoredByAPIRequest restoredByAPIRequest, WebBackForwardListProxy::OverwriteExistingItem overwrite)
2813{
2814 // Since we're merely restoring HistoryItems from the UIProcess, there is no need to send HistoryItem update notifications back to the UIProcess.
2815 // Also, with process-swap on navigation, these updates may actually overwrite important state in the UIProcess such as the scroll position.
2816 SetForScope<void (*)(WebCore::HistoryItem&)> bypassHistoryItemUpdateNotifications(WebCore::notifyHistoryItemChanged, [](WebCore::HistoryItem&){});
2817 for (const auto& itemState : itemStates) {
2818 auto historyItem = toHistoryItem(itemState);
2819 historyItem->setWasRestoredFromSession(restoredByAPIRequest == WasRestoredByAPIRequest::Yes);
2820 static_cast<WebBackForwardListProxy&>(corePage()->backForward().client()).addItemFromUIProcess(itemState.identifier, WTFMove(historyItem), m_pageID, overwrite);
2821 }
2822}
2823
2824void WebPage::restoreSession(const Vector<BackForwardListItemState>& itemStates)
2825{
2826 restoreSessionInternal(itemStates, WasRestoredByAPIRequest::Yes, WebBackForwardListProxy::OverwriteExistingItem::No);
2827}
2828
2829void WebPage::updateBackForwardListForReattach(const Vector<WebKit::BackForwardListItemState>& itemStates)
2830{
2831 restoreSessionInternal(itemStates, WasRestoredByAPIRequest::No, WebBackForwardListProxy::OverwriteExistingItem::Yes);
2832}
2833
2834void WebPage::setCurrentHistoryItemForReattach(WebKit::BackForwardListItemState&& itemState)
2835{
2836 auto historyItem = toHistoryItem(itemState);
2837 auto& historyItemRef = historyItem.get();
2838 static_cast<WebBackForwardListProxy&>(corePage()->backForward().client()).addItemFromUIProcess(itemState.identifier, WTFMove(historyItem), m_pageID, WebBackForwardListProxy::OverwriteExistingItem::Yes);
2839 corePage()->mainFrame().loader().history().setCurrentItem(historyItemRef);
2840}
2841
2842void WebPage::requestFontAttributesAtSelectionStart(CallbackID callbackID)
2843{
2844 auto attributes = m_page->focusController().focusedOrMainFrame().editor().fontAttributesAtSelectionStart();
2845 send(Messages::WebPageProxy::FontAttributesCallback(attributes, callbackID));
2846}
2847
2848void WebPage::cancelGesturesBlockedOnSynchronousReplies()
2849{
2850#if ENABLE(IOS_TOUCH_EVENTS)
2851 if (auto reply = WTFMove(m_pendingSynchronousTouchEventReply))
2852 reply(true);
2853#endif
2854
2855#if PLATFORM(IOS_FAMILY)
2856 if (auto reply = WTFMove(m_pendingSynchronousPositionInformationReply))
2857 reply(InteractionInformationAtPosition::invalidInformation());
2858#endif
2859}
2860
2861#if ENABLE(TOUCH_EVENTS)
2862static bool handleTouchEvent(const WebTouchEvent& touchEvent, Page* page)
2863{
2864 if (!page->mainFrame().view())
2865 return false;
2866
2867 return page->mainFrame().eventHandler().handleTouchEvent(platform(touchEvent));
2868}
2869#endif
2870
2871#if ENABLE(IOS_TOUCH_EVENTS)
2872void WebPage::dispatchTouchEvent(const WebTouchEvent& touchEvent, bool& handled)
2873{
2874 SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true };
2875
2876 auto oldFocusedFrame = makeRefPtr(m_page->focusController().focusedFrame());
2877 auto oldFocusedElement = makeRefPtr(oldFocusedFrame ? oldFocusedFrame->document()->focusedElement() : nullptr);
2878
2879 m_lastInteractionLocation = touchEvent.position();
2880 CurrentEvent currentEvent(touchEvent);
2881 handled = handleTouchEvent(touchEvent, m_page.get());
2882 updatePotentialTapSecurityOrigin(touchEvent, handled);
2883
2884 if (handled && oldFocusedElement) {
2885 auto newFocusedFrame = makeRefPtr(m_page->focusController().focusedFrame());
2886 auto newFocusedElement = makeRefPtr(newFocusedFrame ? newFocusedFrame->document()->focusedElement() : nullptr);
2887 if (oldFocusedElement == newFocusedElement)
2888 elementDidRefocus(*newFocusedElement);
2889 }
2890}
2891
2892void WebPage::touchEventSync(const WebTouchEvent& touchEvent, CompletionHandler<void(bool)>&& reply)
2893{
2894 m_pendingSynchronousTouchEventReply = WTFMove(reply);
2895
2896 EventDispatcher::TouchEventQueue queuedEvents;
2897 WebProcess::singleton().eventDispatcher().getQueuedTouchEventsForPage(*this, queuedEvents);
2898 dispatchAsynchronousTouchEvents(queuedEvents);
2899
2900 bool handled = true;
2901 dispatchTouchEvent(touchEvent, handled);
2902
2903 if (auto reply = WTFMove(m_pendingSynchronousTouchEventReply))
2904 reply(handled);
2905}
2906
2907void WebPage::updatePotentialTapSecurityOrigin(const WebTouchEvent& touchEvent, bool wasHandled)
2908{
2909 if (wasHandled)
2910 return;
2911
2912 if (!touchEvent.isPotentialTap())
2913 return;
2914
2915 if (touchEvent.type() != WebEvent::TouchStart)
2916 return;
2917
2918 auto& mainFrame = m_page->mainFrame();
2919 auto document = mainFrame.document();
2920 if (!document)
2921 return;
2922
2923 if (!document->handlingTouchEvent())
2924 return;
2925
2926 Frame* touchEventTargetFrame = &mainFrame;
2927 while (auto subframe = touchEventTargetFrame->eventHandler().touchEventTargetSubframe())
2928 touchEventTargetFrame = subframe;
2929
2930 auto& touches = touchEventTargetFrame->eventHandler().touches();
2931 if (touches.isEmpty())
2932 return;
2933
2934 ASSERT(touches.size() == 1);
2935
2936 if (auto targetDocument = touchEventTargetFrame->document())
2937 m_potentialTapSecurityOrigin = &targetDocument->securityOrigin();
2938}
2939#elif ENABLE(TOUCH_EVENTS)
2940void WebPage::touchEvent(const WebTouchEvent& touchEvent)
2941{
2942 CurrentEvent currentEvent(touchEvent);
2943
2944 bool handled = handleTouchEvent(touchEvent, m_page.get());
2945
2946 send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(touchEvent.type()), handled));
2947}
2948#endif
2949
2950#if ENABLE(POINTER_EVENTS)
2951void WebPage::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint)
2952{
2953 m_page->pointerCaptureController().cancelPointer(pointerId, documentPoint);
2954}
2955#endif
2956
2957#if ENABLE(MAC_GESTURE_EVENTS)
2958static bool handleGestureEvent(const WebGestureEvent& event, Page* page)
2959{
2960 if (!page->mainFrame().view())
2961 return false;
2962
2963 return page->mainFrame().eventHandler().handleGestureEvent(platform(event));
2964}
2965
2966void WebPage::gestureEvent(const WebGestureEvent& gestureEvent)
2967{
2968 CurrentEvent currentEvent(gestureEvent);
2969 bool handled = handleGestureEvent(gestureEvent, m_page.get());
2970 send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(gestureEvent.type()), handled));
2971}
2972#endif
2973
2974bool WebPage::scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity)
2975{
2976 return page->userInputBridge().scrollRecursively(direction, granularity);
2977}
2978
2979bool WebPage::logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity)
2980{
2981 return page->userInputBridge().logicalScrollRecursively(direction, granularity);
2982}
2983
2984bool WebPage::scrollBy(uint32_t scrollDirection, uint32_t scrollGranularity)
2985{
2986 return scroll(m_page.get(), static_cast<ScrollDirection>(scrollDirection), static_cast<ScrollGranularity>(scrollGranularity));
2987}
2988
2989void WebPage::centerSelectionInVisibleArea()
2990{
2991 Frame& frame = m_page->focusController().focusedOrMainFrame();
2992 frame.selection().revealSelection(SelectionRevealMode::Reveal, ScrollAlignment::alignCenterAlways);
2993 findController().showFindIndicatorInSelection();
2994}
2995
2996bool WebPage::isControlledByAutomation() const
2997{
2998 return m_page->isControlledByAutomation();
2999}
3000
3001void WebPage::setControlledByAutomation(bool controlled)
3002{
3003 m_page->setControlledByAutomation(controlled);
3004}
3005
3006void WebPage::connectInspector(const String& targetId, Inspector::FrontendChannel::ConnectionType connectionType)
3007{
3008 m_inspectorTargetController->connectInspector(targetId, connectionType);
3009}
3010
3011void WebPage::disconnectInspector(const String& targetId)
3012{
3013 m_inspectorTargetController->disconnectInspector(targetId);
3014}
3015
3016void WebPage::sendMessageToTargetBackend(const String& targetId, const String& message)
3017{
3018 m_inspectorTargetController->sendMessageToTargetBackend(targetId, message);
3019}
3020
3021void WebPage::insertNewlineInQuotedContent()
3022{
3023 Frame& frame = m_page->focusController().focusedOrMainFrame();
3024 if (frame.selection().isNone())
3025 return;
3026 frame.editor().insertParagraphSeparatorInQuotedContent();
3027}
3028
3029#if ENABLE(REMOTE_INSPECTOR)
3030void WebPage::setIndicating(bool indicating)
3031{
3032 m_page->inspectorController().setIndicating(indicating);
3033}
3034#endif
3035
3036void WebPage::setBackgroundColor(const Optional<WebCore::Color>& backgroundColor)
3037{
3038 if (m_backgroundColor == backgroundColor)
3039 return;
3040
3041 m_backgroundColor = backgroundColor;
3042
3043 if (FrameView* frameView = mainFrameView())
3044 frameView->updateBackgroundRecursively(backgroundColor);
3045
3046 m_drawingArea->setNeedsDisplay();
3047}
3048
3049#if PLATFORM(COCOA)
3050void WebPage::setTopContentInsetFenced(float contentInset, IPC::Attachment fencePort)
3051{
3052 if (fencePort.disposition() != MACH_MSG_TYPE_MOVE_SEND) {
3053 LOG(Layers, "WebPage::setTopContentInsetFenced(%g, fencePort) Received an invalid fence port: %d, disposition: %d", contentInset, fencePort.port(), fencePort.disposition());
3054 return;
3055 }
3056
3057 m_drawingArea->addFence(MachSendRight::create(fencePort.port()));
3058
3059 setTopContentInset(contentInset);
3060
3061 deallocateSendRightSafely(fencePort.port());
3062}
3063#endif
3064
3065void WebPage::setTopContentInset(float contentInset)
3066{
3067 if (contentInset == m_page->topContentInset())
3068 return;
3069
3070 m_page->setTopContentInset(contentInset);
3071
3072 for (auto* pluginView : m_pluginViews)
3073 pluginView->topContentInsetDidChange();
3074}
3075
3076void WebPage::viewWillStartLiveResize()
3077{
3078 if (!m_page)
3079 return;
3080
3081 // FIXME: This should propagate to all ScrollableAreas.
3082 Frame& frame = m_page->focusController().focusedOrMainFrame();
3083 if (FrameView* view = frame.view())
3084 view->willStartLiveResize();
3085}
3086
3087void WebPage::viewWillEndLiveResize()
3088{
3089 if (!m_page)
3090 return;
3091
3092 // FIXME: This should propagate to all ScrollableAreas.
3093 Frame& frame = m_page->focusController().focusedOrMainFrame();
3094 if (FrameView* view = frame.view())
3095 view->willEndLiveResize();
3096}
3097
3098void WebPage::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& event, CallbackID callbackID)
3099{
3100 if (!m_page)
3101 return;
3102
3103 SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true };
3104
3105 Frame& frame = m_page->focusController().focusedOrMainFrame();
3106 frame.document()->setFocusedElement(0);
3107
3108 if (isKeyboardEventValid && event.type() == WebEvent::KeyDown) {
3109 PlatformKeyboardEvent platformEvent(platform(event));
3110 platformEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
3111 m_page->focusController().setInitialFocus(forward ? FocusDirectionForward : FocusDirectionBackward, &KeyboardEvent::create(platformEvent, &frame.windowProxy()).get());
3112
3113 send(Messages::WebPageProxy::VoidCallback(callbackID));
3114 return;
3115 }
3116
3117 m_page->focusController().setInitialFocus(forward ? FocusDirectionForward : FocusDirectionBackward, nullptr);
3118 send(Messages::WebPageProxy::VoidCallback(callbackID));
3119}
3120
3121void WebPage::setCanStartMediaTimerFired()
3122{
3123 if (m_page)
3124 m_page->setCanStartMedia(true);
3125}
3126
3127void WebPage::updateIsInWindow(bool isInitialState)
3128{
3129 bool isInWindow = m_activityState.contains(WebCore::ActivityState::IsInWindow);
3130
3131 if (!isInWindow) {
3132 m_setCanStartMediaTimer.stop();
3133 m_page->setCanStartMedia(false);
3134
3135 // The WebProcess does not yet know about this page; no need to tell it we're leaving the window.
3136 if (!isInitialState)
3137 WebProcess::singleton().pageWillLeaveWindow(m_pageID);
3138 } else {
3139 // Defer the call to Page::setCanStartMedia() since it ends up sending a synchronous message to the UI process
3140 // in order to get plug-in connections, and the UI process will be waiting for the Web process to update the backing
3141 // store after moving the view into a window, until it times out and paints white. See <rdar://problem/9242771>.
3142 if (m_mayStartMediaWhenInWindow)
3143 m_setCanStartMediaTimer.startOneShot(0_s);
3144
3145 WebProcess::singleton().pageDidEnterWindow(m_pageID);
3146 }
3147
3148 if (isInWindow)
3149 layoutIfNeeded();
3150}
3151
3152void WebPage::visibilityDidChange()
3153{
3154 bool isVisible = m_activityState.contains(ActivityState::IsVisible);
3155 if (!isVisible) {
3156 // We save the document / scroll state when backgrounding a tab so that we are able to restore it
3157 // if it gets terminated while in the background.
3158 if (auto* frame = m_mainFrame->coreFrame())
3159 frame->loader().history().saveDocumentAndScrollState();
3160 }
3161}
3162
3163void WebPage::setActivityState(OptionSet<ActivityState::Flag> activityState, ActivityStateChangeID activityStateChangeID, const Vector<CallbackID>& callbackIDs)
3164{
3165 LOG_WITH_STREAM(ActivityState, stream << "WebPage " << pageID() << " setActivityState to " << activityState);
3166
3167 auto changed = m_activityState ^ activityState;
3168 m_activityState = activityState;
3169
3170 if (changed)
3171 updateThrottleState();
3172
3173 ASSERT_WITH_MESSAGE(m_page, "setActivityState called on %" PRIu64 " but WebCore page was null", pageID());
3174 if (m_page) {
3175 SetForScope<OptionSet<ActivityState::Flag>> currentlyChangingActivityState { m_lastActivityStateChanges, changed };
3176 m_page->setActivityState(activityState);
3177 }
3178
3179 for (auto* pluginView : m_pluginViews)
3180 pluginView->activityStateDidChange(changed);
3181
3182 m_drawingArea->activityStateDidChange(changed, activityStateChangeID, callbackIDs);
3183 WebProcess::singleton().pageActivityStateDidChange(m_pageID, changed);
3184
3185 if (changed & ActivityState::IsInWindow)
3186 updateIsInWindow();
3187
3188 if (changed & ActivityState::IsVisible)
3189 visibilityDidChange();
3190}
3191
3192void WebPage::setLayerHostingMode(LayerHostingMode layerHostingMode)
3193{
3194 m_layerHostingMode = layerHostingMode;
3195
3196 m_drawingArea->setLayerHostingMode(m_layerHostingMode);
3197
3198 for (auto* pluginView : m_pluginViews)
3199 pluginView->setLayerHostingMode(m_layerHostingMode);
3200}
3201
3202void WebPage::setSessionID(PAL::SessionID sessionID)
3203{
3204 m_page->setSessionID(sessionID);
3205}
3206
3207void WebPage::didReceivePolicyDecision(uint64_t frameID, uint64_t listenerID, PolicyCheckIdentifier identifier, PolicyAction policyAction, uint64_t navigationID, const DownloadID& downloadID, Optional<WebsitePoliciesData>&& websitePolicies)
3208{
3209 WebFrame* frame = WebProcess::singleton().webFrame(frameID);
3210 if (!frame)
3211 return;
3212 frame->didReceivePolicyDecision(listenerID, identifier, policyAction, navigationID, downloadID, WTFMove(websitePolicies));
3213}
3214
3215void WebPage::continueWillSubmitForm(uint64_t frameID, uint64_t listenerID)
3216{
3217 WebFrame* frame = WebProcess::singleton().webFrame(frameID);
3218 if (!frame)
3219 return;
3220 frame->continueWillSubmitForm(listenerID);
3221}
3222
3223void WebPage::didStartPageTransition()
3224{
3225 freezeLayerTree(LayerTreeFreezeReason::PageTransition);
3226
3227#if PLATFORM(MAC)
3228 bool hasPreviouslyFocusedDueToUserInteraction = m_hasEverFocusedElementDueToUserInteractionSincePageTransition;
3229#endif
3230 m_hasEverFocusedElementDueToUserInteractionSincePageTransition = false;
3231 m_lastEditorStateWasContentEditable = EditorStateIsContentEditable::Unset;
3232#if PLATFORM(MAC)
3233 if (hasPreviouslyFocusedDueToUserInteraction)
3234 send(Messages::WebPageProxy::SetHasHadSelectionChangesFromUserInteraction(m_hasEverFocusedElementDueToUserInteractionSincePageTransition));
3235 if (m_isTouchBarUpdateSupressedForHiddenContentEditable) {
3236 m_isTouchBarUpdateSupressedForHiddenContentEditable = false;
3237 send(Messages::WebPageProxy::SetIsTouchBarUpdateSupressedForHiddenContentEditable(m_isTouchBarUpdateSupressedForHiddenContentEditable));
3238 }
3239 if (m_isNeverRichlyEditableForTouchBar) {
3240 m_isNeverRichlyEditableForTouchBar = false;
3241 send(Messages::WebPageProxy::SetIsNeverRichlyEditableForTouchBar(m_isNeverRichlyEditableForTouchBar));
3242 }
3243#endif
3244#if PLATFORM(IOS_FAMILY)
3245 m_isShowingInputViewForFocusedElement = false;
3246#endif
3247}
3248
3249void WebPage::didCompletePageTransition()
3250{
3251 unfreezeLayerTree(LayerTreeFreezeReason::PageTransition);
3252
3253 RELEASE_LOG_IF_ALLOWED("%p - WebPage - Did complete page transition", this);
3254
3255 bool isInitialEmptyDocument = !m_mainFrame;
3256 if (!isInitialEmptyDocument)
3257 unfreezeLayerTree(LayerTreeFreezeReason::ProcessSwap);
3258}
3259
3260void WebPage::show()
3261{
3262 send(Messages::WebPageProxy::ShowPage());
3263}
3264
3265String WebPage::userAgent(const URL& webCoreURL) const
3266{
3267 String userAgent = platformUserAgent(webCoreURL);
3268 if (!userAgent.isEmpty())
3269 return userAgent;
3270 return m_userAgent;
3271}
3272
3273void WebPage::setUserAgent(const String& userAgent)
3274{
3275 if (m_userAgent == userAgent)
3276 return;
3277
3278 m_userAgent = userAgent;
3279
3280 if (m_page)
3281 m_page->userAgentChanged();
3282}
3283
3284void WebPage::suspendActiveDOMObjectsAndAnimations()
3285{
3286 m_page->suspendActiveDOMObjectsAndAnimations();
3287}
3288
3289void WebPage::resumeActiveDOMObjectsAndAnimations()
3290{
3291 m_page->resumeActiveDOMObjectsAndAnimations();
3292}
3293
3294IntPoint WebPage::screenToRootView(const IntPoint& point)
3295{
3296 IntPoint windowPoint;
3297 sendSync(Messages::WebPageProxy::ScreenToRootView(point), Messages::WebPageProxy::ScreenToRootView::Reply(windowPoint));
3298 return windowPoint;
3299}
3300
3301IntRect WebPage::rootViewToScreen(const IntRect& rect)
3302{
3303 IntRect screenRect;
3304 sendSync(Messages::WebPageProxy::RootViewToScreen(rect), Messages::WebPageProxy::RootViewToScreen::Reply(screenRect));
3305 return screenRect;
3306}
3307
3308IntPoint WebPage::accessibilityScreenToRootView(const IntPoint& point)
3309{
3310 IntPoint windowPoint;
3311 sendSync(Messages::WebPageProxy::AccessibilityScreenToRootView(point), Messages::WebPageProxy::AccessibilityScreenToRootView::Reply(windowPoint));
3312 return windowPoint;
3313}
3314
3315IntRect WebPage::rootViewToAccessibilityScreen(const IntRect& rect)
3316{
3317 IntRect screenRect;
3318 sendSync(Messages::WebPageProxy::RootViewToAccessibilityScreen(rect), Messages::WebPageProxy::RootViewToAccessibilityScreen::Reply(screenRect));
3319 return screenRect;
3320}
3321
3322KeyboardUIMode WebPage::keyboardUIMode()
3323{
3324 bool fullKeyboardAccessEnabled = WebProcess::singleton().fullKeyboardAccessEnabled();
3325 return static_cast<KeyboardUIMode>((fullKeyboardAccessEnabled ? KeyboardAccessFull : KeyboardAccessDefault) | (m_tabToLinks ? KeyboardAccessTabsToLinks : 0));
3326}
3327
3328void WebPage::runJavaScript(WebFrame* frame, const String& script, bool forceUserGesture, const Optional<String>& worldName, CallbackID callbackID)
3329{
3330 // NOTE: We need to be careful when running scripts that the objects we depend on don't
3331 // disappear during script execution.
3332
3333 RefPtr<SerializedScriptValue> serializedResultValue;
3334 JSLockHolder lock(commonVM());
3335 bool hadException = true;
3336 ExceptionDetails details;
3337 auto* world = worldName ? InjectedBundleScriptWorld::find(worldName.value()) : &InjectedBundleScriptWorld::normalWorld();
3338 if (frame && frame->coreFrame() && world) {
3339 if (JSValue resultValue = frame->coreFrame()->script().executeUserAgentScriptInWorld(world->coreWorld(), script, forceUserGesture, &details)) {
3340 hadException = false;
3341 serializedResultValue = SerializedScriptValue::create(frame->jsContextForWorld(world),
3342 toRef(frame->coreFrame()->script().globalObject(world->coreWorld())->globalExec(), resultValue), nullptr);
3343 }
3344 }
3345
3346 IPC::DataReference dataReference;
3347 if (serializedResultValue)
3348 dataReference = serializedResultValue->data();
3349 send(Messages::WebPageProxy::ScriptValueCallback(dataReference, hadException, details, callbackID));
3350}
3351
3352void WebPage::runJavaScriptInMainFrameScriptWorld(const String& script, bool forceUserGesture, const Optional<String>& worldName, CallbackID callbackID)
3353{
3354 runJavaScript(mainWebFrame(), script, forceUserGesture, worldName, callbackID);
3355}
3356
3357void WebPage::runJavaScriptInFrame(uint64_t frameID, const String& script, bool forceUserGesture, CallbackID callbackID)
3358{
3359 WebFrame* frame = WebProcess::singleton().webFrame(frameID);
3360 ASSERT(mainWebFrame() != frame);
3361 runJavaScript(frame, script, forceUserGesture, WTF::nullopt, callbackID);
3362}
3363
3364void WebPage::getContentsAsString(CallbackID callbackID)
3365{
3366 String resultString = m_mainFrame->contentsAsString();
3367 send(Messages::WebPageProxy::StringCallback(resultString, callbackID));
3368}
3369
3370#if ENABLE(MHTML)
3371void WebPage::getContentsAsMHTMLData(CallbackID callbackID)
3372{
3373 send(Messages::WebPageProxy::DataCallback({ MHTMLArchive::generateMHTMLData(m_page.get()) }, callbackID));
3374}
3375#endif
3376
3377void WebPage::getRenderTreeExternalRepresentation(CallbackID callbackID)
3378{
3379 String resultString = renderTreeExternalRepresentation();
3380 send(Messages::WebPageProxy::StringCallback(resultString, callbackID));
3381}
3382
3383static Frame* frameWithSelection(Page* page)
3384{
3385 for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
3386 if (frame->selection().isRange())
3387 return frame;
3388 }
3389
3390 return 0;
3391}
3392
3393void WebPage::getSelectionAsWebArchiveData(CallbackID callbackID)
3394{
3395#if PLATFORM(COCOA)
3396 RetainPtr<CFDataRef> data;
3397 if (Frame* frame = frameWithSelection(m_page.get()))
3398 data = LegacyWebArchive::createFromSelection(frame)->rawDataRepresentation();
3399#endif
3400
3401 IPC::SharedBufferDataReference dataReference;
3402#if PLATFORM(COCOA)
3403 if (data)
3404 dataReference = { CFDataGetBytePtr(data.get()), static_cast<size_t>(CFDataGetLength(data.get())) };
3405#endif
3406 send(Messages::WebPageProxy::DataCallback(dataReference, callbackID));
3407}
3408
3409void WebPage::getSelectionOrContentsAsString(CallbackID callbackID)
3410{
3411 WebFrame* focusedOrMainFrame = WebFrame::fromCoreFrame(m_page->focusController().focusedOrMainFrame());
3412 String resultString = focusedOrMainFrame->selectionAsString();
3413 if (resultString.isEmpty())
3414 resultString = focusedOrMainFrame->contentsAsString();
3415 send(Messages::WebPageProxy::StringCallback(resultString, callbackID));
3416}
3417
3418void WebPage::getSourceForFrame(uint64_t frameID, CallbackID callbackID)
3419{
3420 String resultString;
3421 if (WebFrame* frame = WebProcess::singleton().webFrame(frameID))
3422 resultString = frame->source();
3423
3424 send(Messages::WebPageProxy::StringCallback(resultString, callbackID));
3425}
3426
3427void WebPage::getMainResourceDataOfFrame(uint64_t frameID, CallbackID callbackID)
3428{
3429 RefPtr<SharedBuffer> buffer;
3430 if (WebFrame* frame = WebProcess::singleton().webFrame(frameID)) {
3431 if (PluginView* pluginView = pluginViewForFrame(frame->coreFrame()))
3432 buffer = pluginView->liveResourceData();
3433 if (!buffer) {
3434 if (DocumentLoader* loader = frame->coreFrame()->loader().documentLoader())
3435 buffer = loader->mainResourceData();
3436 }
3437 }
3438
3439 IPC::SharedBufferDataReference dataReference;
3440 if (buffer)
3441 dataReference = { *buffer };
3442 send(Messages::WebPageProxy::DataCallback(dataReference, callbackID));
3443}
3444
3445static RefPtr<SharedBuffer> resourceDataForFrame(Frame* frame, const URL& resourceURL)
3446{
3447 DocumentLoader* loader = frame->loader().documentLoader();
3448 if (!loader)
3449 return nullptr;
3450
3451 RefPtr<ArchiveResource> subresource = loader->subresource(resourceURL);
3452 if (!subresource)
3453 return nullptr;
3454
3455 return &subresource->data();
3456}
3457
3458void WebPage::getResourceDataFromFrame(uint64_t frameID, const String& resourceURLString, CallbackID callbackID)
3459{
3460 RefPtr<SharedBuffer> buffer;
3461 if (auto* frame = WebProcess::singleton().webFrame(frameID)) {
3462 URL resourceURL(URL(), resourceURLString);
3463 buffer = resourceDataForFrame(frame->coreFrame(), resourceURL);
3464 }
3465
3466 IPC::SharedBufferDataReference dataReference;
3467 if (buffer)
3468 dataReference = { *buffer };
3469 send(Messages::WebPageProxy::DataCallback(dataReference, callbackID));
3470}
3471
3472void WebPage::getWebArchiveOfFrame(uint64_t frameID, CallbackID callbackID)
3473{
3474#if PLATFORM(COCOA)
3475 RetainPtr<CFDataRef> data;
3476 if (WebFrame* frame = WebProcess::singleton().webFrame(frameID))
3477 data = frame->webArchiveData(nullptr, nullptr);
3478#else
3479 UNUSED_PARAM(frameID);
3480#endif
3481
3482 IPC::SharedBufferDataReference dataReference;
3483#if PLATFORM(COCOA)
3484 if (data)
3485 dataReference = { CFDataGetBytePtr(data.get()), static_cast<size_t>(CFDataGetLength(data.get())) };
3486#endif
3487 send(Messages::WebPageProxy::DataCallback(dataReference, callbackID));
3488}
3489
3490void WebPage::forceRepaintWithoutCallback()
3491{
3492 m_drawingArea->forceRepaint();
3493}
3494
3495void WebPage::forceRepaint(CallbackID callbackID)
3496{
3497 if (m_drawingArea->forceRepaintAsync(callbackID))
3498 return;
3499
3500 forceRepaintWithoutCallback();
3501 send(Messages::WebPageProxy::VoidCallback(callbackID));
3502}
3503
3504void WebPage::preferencesDidChange(const WebPreferencesStore& store)
3505{
3506 WebPreferencesStore::removeTestRunnerOverrides();
3507 updatePreferences(store);
3508}
3509
3510void WebPage::updatePreferences(const WebPreferencesStore& store)
3511{
3512 updatePreferencesGenerated(store);
3513
3514 Settings& settings = m_page->settings();
3515
3516#if !PLATFORM(GTK)
3517 if (!settings.acceleratedCompositingEnabled()) {
3518 RELEASE_LOG_IF_ALLOWED("%p - WebPage - acceleratedCompositingEnabled setting was false. WebKit cannot function in this mode; changing setting to true", this);
3519 settings.setAcceleratedCompositingEnabled(true);
3520 }
3521#endif
3522
3523 bool requiresUserGestureForMedia = store.getBoolValueForKey(WebPreferencesKey::requiresUserGestureForMediaPlaybackKey());
3524 settings.setVideoPlaybackRequiresUserGesture(requiresUserGestureForMedia || store.getBoolValueForKey(WebPreferencesKey::requiresUserGestureForVideoPlaybackKey()));
3525 settings.setAudioPlaybackRequiresUserGesture(requiresUserGestureForMedia || store.getBoolValueForKey(WebPreferencesKey::requiresUserGestureForAudioPlaybackKey()));
3526 settings.setLayoutInterval(Seconds(store.getDoubleValueForKey(WebPreferencesKey::layoutIntervalKey())));
3527 settings.setUserInterfaceDirectionPolicy(static_cast<WebCore::UserInterfaceDirectionPolicy>(store.getUInt32ValueForKey(WebPreferencesKey::userInterfaceDirectionPolicyKey())));
3528 settings.setSystemLayoutDirection(static_cast<TextDirection>(store.getUInt32ValueForKey(WebPreferencesKey::systemLayoutDirectionKey())));
3529 settings.setJavaScriptRuntimeFlags(static_cast<RuntimeFlags>(store.getUInt32ValueForKey(WebPreferencesKey::javaScriptRuntimeFlagsKey())));
3530 settings.setStorageBlockingPolicy(static_cast<SecurityOrigin::StorageBlockingPolicy>(store.getUInt32ValueForKey(WebPreferencesKey::storageBlockingPolicyKey())));
3531 settings.setFrameFlattening(store.getBoolValueForKey(WebPreferencesKey::frameFlatteningEnabledKey()) ? WebCore::FrameFlattening::FullyEnabled : WebCore::FrameFlattening::Disabled);
3532 settings.setEditableLinkBehavior(static_cast<WebCore::EditableLinkBehavior>(store.getUInt32ValueForKey(WebPreferencesKey::editableLinkBehaviorKey())));
3533#if ENABLE(DATA_DETECTION)
3534 settings.setDataDetectorTypes(static_cast<DataDetectorTypes>(store.getUInt32ValueForKey(WebPreferencesKey::dataDetectorTypesKey())));
3535#endif
3536
3537 DatabaseManager::singleton().setIsAvailable(store.getBoolValueForKey(WebPreferencesKey::databasesEnabledKey()));
3538
3539 m_tabToLinks = store.getBoolValueForKey(WebPreferencesKey::tabsToLinksKey());
3540 m_asynchronousPluginInitializationEnabled = store.getBoolValueForKey(WebPreferencesKey::asynchronousPluginInitializationEnabledKey());
3541 m_asynchronousPluginInitializationEnabledForAllPlugins = store.getBoolValueForKey(WebPreferencesKey::asynchronousPluginInitializationEnabledForAllPluginsKey());
3542 m_artificialPluginInitializationDelayEnabled = store.getBoolValueForKey(WebPreferencesKey::artificialPluginInitializationDelayEnabledKey());
3543
3544 m_scrollingPerformanceLoggingEnabled = store.getBoolValueForKey(WebPreferencesKey::scrollingPerformanceLoggingEnabledKey());
3545 settings.setScrollingPerformanceLoggingEnabled(m_scrollingPerformanceLoggingEnabled);
3546
3547 if (store.getBoolValueForKey(WebPreferencesKey::privateBrowsingEnabledKey()) && !usesEphemeralSession())
3548 setSessionID(PAL::SessionID::legacyPrivateSessionID());
3549 else if (!store.getBoolValueForKey(WebPreferencesKey::privateBrowsingEnabledKey()) && sessionID() == PAL::SessionID::legacyPrivateSessionID())
3550 setSessionID(PAL::SessionID::defaultSessionID());
3551
3552 bool isAppNapEnabled = store.getBoolValueForKey(WebPreferencesKey::pageVisibilityBasedProcessSuppressionEnabledKey());
3553 if (m_isAppNapEnabled != isAppNapEnabled) {
3554 m_isAppNapEnabled = isAppNapEnabled;
3555 updateThrottleState();
3556 }
3557
3558#if PLATFORM(COCOA)
3559 m_pdfPluginEnabled = store.getBoolValueForKey(WebPreferencesKey::pdfPluginEnabledKey());
3560#endif
3561#if ENABLE(PAYMENT_REQUEST)
3562 settings.setPaymentRequestEnabled(store.getBoolValueForKey(WebPreferencesKey::applePayEnabledKey()));
3563#endif
3564
3565 // FIXME: This is both a RuntimeEnabledFeatures (generated) and a setting. It should pick one.
3566 settings.setInteractiveFormValidationEnabled(store.getBoolValueForKey(WebPreferencesKey::interactiveFormValidationEnabledKey()));
3567
3568#if PLATFORM(IOS_FAMILY)
3569 m_ignoreViewportScalingConstraints = store.getBoolValueForKey(WebPreferencesKey::ignoreViewportScalingConstraintsKey());
3570 m_viewportConfiguration.setCanIgnoreScalingConstraints(m_ignoreViewportScalingConstraints);
3571 setForceAlwaysUserScalable(m_forceAlwaysUserScalable || store.getBoolValueForKey(WebPreferencesKey::forceAlwaysUserScalableKey()));
3572
3573 settings.setUseImageDocumentForSubframePDF(true);
3574#if HAVE(AVKIT)
3575 DeprecatedGlobalSettings::setAVKitEnabled(true);
3576#endif
3577#endif
3578
3579#if ENABLE(SERVICE_WORKER)
3580 if (store.getBoolValueForKey(WebPreferencesKey::serviceWorkersEnabledKey())) {
3581 ASSERT(parentProcessHasServiceWorkerEntitlement());
3582 if (!parentProcessHasServiceWorkerEntitlement())
3583 RuntimeEnabledFeatures::sharedFeatures().setServiceWorkerEnabled(false);
3584 }
3585#endif
3586
3587 settings.setLayoutViewportHeightExpansionFactor(store.getDoubleValueForKey(WebPreferencesKey::layoutViewportHeightExpansionFactorKey()));
3588
3589 if (m_drawingArea)
3590 m_drawingArea->updatePreferences(store);
3591}
3592
3593#if ENABLE(DATA_DETECTION)
3594
3595void WebPage::setDataDetectionResults(NSArray *detectionResults)
3596{
3597 DataDetectionResult dataDetectionResult;
3598 dataDetectionResult.results = detectionResults;
3599 send(Messages::WebPageProxy::SetDataDetectionResult(dataDetectionResult));
3600}
3601
3602void WebPage::removeDataDetectedLinks(CompletionHandler<void(const DataDetectionResult&)>&& completionHandler)
3603{
3604 for (auto frame = makeRefPtr(&m_page->mainFrame()); frame; frame = frame->tree().traverseNext()) {
3605 auto document = makeRefPtr(frame->document());
3606 if (!document)
3607 continue;
3608
3609 DataDetection::removeDataDetectedLinksInDocument(*document);
3610 frame->setDataDetectionResults(nullptr);
3611 }
3612 completionHandler({ m_page->mainFrame().dataDetectionResults() });
3613}
3614
3615void WebPage::detectDataInAllFrames(uint64_t types, CompletionHandler<void(const DataDetectionResult&)>&& completionHandler)
3616{
3617 auto dataDetectorTypes = static_cast<WebCore::DataDetectorTypes>(types);
3618 for (auto frame = makeRefPtr(&m_page->mainFrame()); frame; frame = frame->tree().traverseNext()) {
3619 auto document = makeRefPtr(frame->document());
3620 if (!document)
3621 continue;
3622
3623 RefPtr<Range> range = Range::create(*document, Position { document.get(), Position::PositionIsBeforeChildren }, Position { document.get(), Position::PositionIsAfterChildren });
3624 frame->setDataDetectionResults(DataDetection::detectContentInRange(range, dataDetectorTypes, m_dataDetectionContext.get()));
3625 }
3626 completionHandler({ m_page->mainFrame().dataDetectionResults() });
3627}
3628
3629#endif // ENABLE(DATA_DETECTION)
3630
3631#if PLATFORM(COCOA)
3632void WebPage::willCommitLayerTree(RemoteLayerTreeTransaction& layerTransaction)
3633{
3634 FrameView* frameView = corePage()->mainFrame().view();
3635 if (!frameView)
3636 return;
3637
3638 layerTransaction.setContentsSize(frameView->contentsSize());
3639 layerTransaction.setScrollOrigin(frameView->scrollOrigin());
3640 layerTransaction.setPageScaleFactor(corePage()->pageScaleFactor());
3641 layerTransaction.setRenderTreeSize(corePage()->renderTreeSize());
3642 layerTransaction.setPageExtendedBackgroundColor(corePage()->pageExtendedBackgroundColor());
3643
3644 layerTransaction.setBaseLayoutViewportSize(frameView->baseLayoutViewportSize());
3645 layerTransaction.setMinStableLayoutViewportOrigin(frameView->minStableLayoutViewportOrigin());
3646 layerTransaction.setMaxStableLayoutViewportOrigin(frameView->maxStableLayoutViewportOrigin());
3647
3648#if PLATFORM(IOS_FAMILY)
3649 layerTransaction.setScaleWasSetByUIProcess(scaleWasSetByUIProcess());
3650 layerTransaction.setMinimumScaleFactor(m_viewportConfiguration.minimumScale());
3651 layerTransaction.setMaximumScaleFactor(m_viewportConfiguration.maximumScale());
3652 layerTransaction.setInitialScaleFactor(m_viewportConfiguration.initialScale());
3653 layerTransaction.setViewportMetaTagWidth(m_viewportConfiguration.viewportArguments().width);
3654 layerTransaction.setViewportMetaTagWidthWasExplicit(m_viewportConfiguration.viewportArguments().widthWasExplicit);
3655 layerTransaction.setViewportMetaTagCameFromImageDocument(m_viewportConfiguration.viewportArguments().type == ViewportArguments::ImageDocument);
3656 layerTransaction.setAvoidsUnsafeArea(m_viewportConfiguration.avoidsUnsafeArea());
3657 layerTransaction.setIsInStableState(m_isInStableState);
3658 layerTransaction.setAllowsUserScaling(allowsUserScaling());
3659 if (m_pendingDynamicViewportSizeUpdateID) {
3660 layerTransaction.setDynamicViewportSizeUpdateID(*m_pendingDynamicViewportSizeUpdateID);
3661 m_pendingDynamicViewportSizeUpdateID = WTF::nullopt;
3662 }
3663 if (m_lastTransactionPageScaleFactor != layerTransaction.pageScaleFactor()) {
3664 m_lastTransactionPageScaleFactor = layerTransaction.pageScaleFactor();
3665 m_lastTransactionIDWithScaleChange = layerTransaction.transactionID();
3666 }
3667#endif
3668
3669 layerTransaction.setScrollPosition(frameView->scrollPosition());
3670
3671 if (m_hasPendingEditorStateUpdate) {
3672 layerTransaction.setEditorState(editorState());
3673 m_hasPendingEditorStateUpdate = false;
3674 }
3675}
3676
3677void WebPage::didFlushLayerTreeAtTime(MonotonicTime timestamp)
3678{
3679#if PLATFORM(IOS_FAMILY)
3680 if (m_oldestNonStableUpdateVisibleContentRectsTimestamp != MonotonicTime()) {
3681 Seconds elapsed = timestamp - m_oldestNonStableUpdateVisibleContentRectsTimestamp;
3682 m_oldestNonStableUpdateVisibleContentRectsTimestamp = MonotonicTime();
3683
3684 m_estimatedLatency = m_estimatedLatency * 0.80 + elapsed * 0.20;
3685 }
3686#else
3687 UNUSED_PARAM(timestamp);
3688#endif
3689}
3690#endif
3691
3692void WebPage::layoutIfNeeded()
3693{
3694 m_page->layoutIfNeeded();
3695}
3696
3697void WebPage::updateRendering()
3698{
3699 m_page->updateRendering();
3700}
3701
3702WebInspector* WebPage::inspector(LazyCreationPolicy behavior)
3703{
3704 if (m_isClosed)
3705 return nullptr;
3706 if (!m_inspector && behavior == LazyCreationPolicy::CreateIfNeeded)
3707 m_inspector = WebInspector::create(this);
3708 return m_inspector.get();
3709}
3710
3711WebInspectorUI* WebPage::inspectorUI()
3712{
3713 if (m_isClosed)
3714 return nullptr;
3715 if (!m_inspectorUI)
3716 m_inspectorUI = WebInspectorUI::create(*this);
3717 return m_inspectorUI.get();
3718}
3719
3720RemoteWebInspectorUI* WebPage::remoteInspectorUI()
3721{
3722 if (m_isClosed)
3723 return nullptr;
3724 if (!m_remoteInspectorUI)
3725 m_remoteInspectorUI = RemoteWebInspectorUI::create(*this);
3726 return m_remoteInspectorUI.get();
3727}
3728
3729void WebPage::inspectorFrontendCountChanged(unsigned count)
3730{
3731 send(Messages::WebPageProxy::DidChangeInspectorFrontendCount(count));
3732}
3733
3734#if (PLATFORM(IOS_FAMILY) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
3735PlaybackSessionManager& WebPage::playbackSessionManager()
3736{
3737 if (!m_playbackSessionManager)
3738 m_playbackSessionManager = PlaybackSessionManager::create(*this);
3739 return *m_playbackSessionManager;
3740}
3741
3742VideoFullscreenManager& WebPage::videoFullscreenManager()
3743{
3744 if (!m_videoFullscreenManager)
3745 m_videoFullscreenManager = VideoFullscreenManager::create(*this, playbackSessionManager());
3746 return *m_videoFullscreenManager;
3747}
3748
3749void WebPage::videoControlsManagerDidChange()
3750{
3751#if ENABLE(FULLSCREEN_API)
3752 if (auto* manager = fullScreenManager())
3753 manager->videoControlsManagerDidChange();
3754#endif
3755}
3756
3757#endif
3758
3759#if PLATFORM(IOS_FAMILY)
3760void WebPage::setAllowsMediaDocumentInlinePlayback(bool allows)
3761{
3762 m_page->setAllowsMediaDocumentInlinePlayback(allows);
3763}
3764#endif
3765
3766#if ENABLE(FULLSCREEN_API)
3767WebFullScreenManager* WebPage::fullScreenManager()
3768{
3769 if (!m_fullScreenManager)
3770 m_fullScreenManager = WebFullScreenManager::create(this);
3771 return m_fullScreenManager.get();
3772}
3773#endif
3774
3775void WebPage::addConsoleMessage(uint64_t frameID, MessageSource messageSource, MessageLevel messageLevel, const String& message, uint64_t requestID)
3776{
3777 if (auto* frame = WebProcess::singleton().webFrame(frameID))
3778 frame->addConsoleMessage(messageSource, messageLevel, message, requestID);
3779}
3780
3781void WebPage::sendCSPViolationReport(uint64_t frameID, const URL& reportURL, IPC::FormDataReference&& reportData)
3782{
3783 auto report = reportData.takeData();
3784 if (!report)
3785 return;
3786 if (auto* frame = WebProcess::singleton().webFrame(frameID))
3787 PingLoader::sendViolationReport(*frame->coreFrame(), reportURL, report.releaseNonNull(), ViolationReportType::ContentSecurityPolicy);
3788}
3789
3790void WebPage::enqueueSecurityPolicyViolationEvent(uint64_t frameID, SecurityPolicyViolationEvent::Init&& eventInit)
3791{
3792 auto* frame = WebProcess::singleton().webFrame(frameID);
3793 if (!frame)
3794 return;
3795 auto* coreFrame = frame->coreFrame();
3796 if (!coreFrame)
3797 return;
3798 if (auto* document = coreFrame->document())
3799 document->enqueueSecurityPolicyViolationEvent(WTFMove(eventInit));
3800}
3801
3802NotificationPermissionRequestManager* WebPage::notificationPermissionRequestManager()
3803{
3804 if (m_notificationPermissionRequestManager)
3805 return m_notificationPermissionRequestManager.get();
3806
3807 m_notificationPermissionRequestManager = NotificationPermissionRequestManager::create(this);
3808 return m_notificationPermissionRequestManager.get();
3809}
3810
3811#if ENABLE(DRAG_SUPPORT)
3812
3813#if PLATFORM(GTK)
3814void WebPage::performDragControllerAction(DragControllerAction action, const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t draggingSourceOperationMask, WebSelectionData&& selection, uint32_t flags)
3815{
3816 if (!m_page) {
3817 send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, DragHandlingMethod::None, false, 0, { }, { }));
3818 return;
3819 }
3820
3821 DragData dragData(selection.selectionData.ptr(), clientPosition, globalPosition, static_cast<DragOperation>(draggingSourceOperationMask), static_cast<DragApplicationFlags>(flags));
3822 switch (action) {
3823 case DragControllerAction::Entered: {
3824 DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData);
3825 send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().dragHandlingMethod(), m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), { }, { }));
3826 return;
3827 }
3828 case DragControllerAction::Updated: {
3829 DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData);
3830 send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().dragHandlingMethod(), m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), { }, { }));
3831 return;
3832 }
3833 case DragControllerAction::Exited:
3834 m_page->dragController().dragExited(dragData);
3835 return;
3836
3837 case DragControllerAction::PerformDragOperation: {
3838 m_page->dragController().performDragOperation(dragData);
3839 return;
3840 }
3841 }
3842 ASSERT_NOT_REACHED();
3843}
3844#else
3845void WebPage::performDragControllerAction(DragControllerAction action, const WebCore::DragData& dragData, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsHandleArray)
3846{
3847 if (!m_page) {
3848 send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, DragHandlingMethod::None, false, 0, { }, { }));
3849 return;
3850 }
3851
3852 switch (action) {
3853 case DragControllerAction::Entered: {
3854 DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData);
3855 send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().dragHandlingMethod(), m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), m_page->dragCaretController().caretRectInRootViewCoordinates(), m_page->dragCaretController().editableElementRectInRootViewCoordinates()));
3856 return;
3857 }
3858 case DragControllerAction::Updated: {
3859 DragOperation resolvedDragOperation = m_page->dragController().dragUpdated(dragData);
3860 send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().dragHandlingMethod(), m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), m_page->dragCaretController().caretRectInRootViewCoordinates(), m_page->dragCaretController().editableElementRectInRootViewCoordinates()));
3861 return;
3862 }
3863 case DragControllerAction::Exited:
3864 m_page->dragController().dragExited(dragData);
3865 send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, DragHandlingMethod::None, false, 0, { }, { }));
3866 return;
3867
3868 case DragControllerAction::PerformDragOperation: {
3869 ASSERT(!m_pendingDropSandboxExtension);
3870
3871 m_pendingDropSandboxExtension = SandboxExtension::create(WTFMove(sandboxExtensionHandle));
3872 for (size_t i = 0; i < sandboxExtensionsHandleArray.size(); i++) {
3873 if (auto extension = SandboxExtension::create(WTFMove(sandboxExtensionsHandleArray[i])))
3874 m_pendingDropExtensionsForFileUpload.append(extension);
3875 }
3876
3877 bool handled = m_page->dragController().performDragOperation(dragData);
3878
3879 // If we started loading a local file, the sandbox extension tracker would have adopted this
3880 // pending drop sandbox extension. If not, we'll play it safe and clear it.
3881 m_pendingDropSandboxExtension = nullptr;
3882
3883 m_pendingDropExtensionsForFileUpload.clear();
3884 send(Messages::WebPageProxy::DidPerformDragOperation(handled));
3885 return;
3886 }
3887 }
3888 ASSERT_NOT_REACHED();
3889}
3890#endif
3891
3892void WebPage::dragEnded(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t operation)
3893{
3894 IntPoint adjustedClientPosition(clientPosition.x() + m_page->dragController().dragOffset().x(), clientPosition.y() + m_page->dragController().dragOffset().y());
3895 IntPoint adjustedGlobalPosition(globalPosition.x() + m_page->dragController().dragOffset().x(), globalPosition.y() + m_page->dragController().dragOffset().y());
3896
3897 m_page->dragController().dragEnded();
3898 FrameView* view = m_page->mainFrame().view();
3899 if (!view)
3900 return;
3901 // FIXME: These are fake modifier keys here, but they should be real ones instead.
3902 PlatformMouseEvent event(adjustedClientPosition, adjustedGlobalPosition, LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, WallTime::now(), 0, WebCore::NoTap);
3903 m_page->mainFrame().eventHandler().dragSourceEndedAt(event, (DragOperation)operation);
3904
3905 send(Messages::WebPageProxy::DidEndDragging());
3906}
3907
3908void WebPage::willPerformLoadDragDestinationAction()
3909{
3910 m_sandboxExtensionTracker.willPerformLoadDragDestinationAction(WTFMove(m_pendingDropSandboxExtension));
3911}
3912
3913void WebPage::mayPerformUploadDragDestinationAction()
3914{
3915 for (size_t i = 0; i < m_pendingDropExtensionsForFileUpload.size(); i++)
3916 m_pendingDropExtensionsForFileUpload[i]->consumePermanently();
3917 m_pendingDropExtensionsForFileUpload.clear();
3918}
3919
3920void WebPage::didStartDrag()
3921{
3922 m_isStartingDrag = false;
3923 m_page->mainFrame().eventHandler().didStartDrag();
3924}
3925
3926void WebPage::dragCancelled()
3927{
3928 m_isStartingDrag = false;
3929 m_page->mainFrame().eventHandler().dragCancelled();
3930}
3931
3932#endif // ENABLE(DRAG_SUPPORT)
3933
3934WebUndoStep* WebPage::webUndoStep(WebUndoStepID stepID)
3935{
3936 return m_undoStepMap.get(stepID);
3937}
3938
3939void WebPage::addWebUndoStep(WebUndoStepID stepID, Ref<WebUndoStep>&& entry)
3940{
3941 auto addResult = m_undoStepMap.set(stepID, WTFMove(entry));
3942 ASSERT_UNUSED(addResult, addResult.isNewEntry);
3943}
3944
3945void WebPage::removeWebEditCommand(WebUndoStepID stepID)
3946{
3947 if (auto undoStep = m_undoStepMap.take(stepID))
3948 undoStep->didRemoveFromUndoManager();
3949}
3950
3951bool WebPage::isAlwaysOnLoggingAllowed() const
3952{
3953 return corePage() && corePage()->isAlwaysOnLoggingAllowed();
3954}
3955
3956void WebPage::unapplyEditCommand(WebUndoStepID stepID)
3957{
3958 auto* step = webUndoStep(stepID);
3959 if (!step)
3960 return;
3961
3962 step->step().unapply();
3963}
3964
3965void WebPage::reapplyEditCommand(WebUndoStepID stepID)
3966{
3967 auto* step = webUndoStep(stepID);
3968 if (!step)
3969 return;
3970
3971 m_isInRedo = true;
3972 step->step().reapply();
3973 m_isInRedo = false;
3974}
3975
3976void WebPage::didRemoveEditCommand(WebUndoStepID commandID)
3977{
3978 removeWebEditCommand(commandID);
3979}
3980
3981void WebPage::setActivePopupMenu(WebPopupMenu* menu)
3982{
3983 m_activePopupMenu = menu;
3984}
3985
3986#if ENABLE(INPUT_TYPE_COLOR)
3987
3988void WebPage::setActiveColorChooser(WebColorChooser* colorChooser)
3989{
3990 m_activeColorChooser = colorChooser;
3991}
3992
3993void WebPage::didEndColorPicker()
3994{
3995 m_activeColorChooser->didEndChooser();
3996}
3997
3998void WebPage::didChooseColor(const WebCore::Color& color)
3999{
4000 m_activeColorChooser->didChooseColor(color);
4001}
4002
4003#endif
4004
4005#if ENABLE(DATALIST_ELEMENT)
4006
4007void WebPage::setActiveDataListSuggestionPicker(WebDataListSuggestionPicker* dataListSuggestionPicker)
4008{
4009 m_activeDataListSuggestionPicker = makeWeakPtr(dataListSuggestionPicker);
4010}
4011
4012void WebPage::didSelectDataListOption(const String& selectedOption)
4013{
4014 if (m_activeDataListSuggestionPicker)
4015 m_activeDataListSuggestionPicker->didSelectOption(selectedOption);
4016}
4017
4018void WebPage::didCloseSuggestions()
4019{
4020 if (auto picker = std::exchange(m_activeDataListSuggestionPicker, nullptr))
4021 picker->didCloseSuggestions();
4022}
4023
4024#endif
4025
4026void WebPage::setActiveOpenPanelResultListener(Ref<WebOpenPanelResultListener>&& openPanelResultListener)
4027{
4028 m_activeOpenPanelResultListener = WTFMove(openPanelResultListener);
4029}
4030
4031bool WebPage::findStringFromInjectedBundle(const String& target, FindOptions options)
4032{
4033 return m_page->findString(target, core(options));
4034}
4035
4036void WebPage::findStringMatchesFromInjectedBundle(const String& target, FindOptions options)
4037{
4038 findController().findStringMatches(target, options, 0);
4039}
4040
4041void WebPage::replaceStringMatchesFromInjectedBundle(const Vector<uint32_t>& matchIndices, const String& replacementText, bool selectionOnly)
4042{
4043 findController().replaceMatches(matchIndices, replacementText, selectionOnly);
4044}
4045
4046void WebPage::findString(const String& string, uint32_t options, uint32_t maxMatchCount)
4047{
4048 findController().findString(string, static_cast<FindOptions>(options), maxMatchCount);
4049}
4050
4051void WebPage::findStringMatches(const String& string, uint32_t options, uint32_t maxMatchCount)
4052{
4053 findController().findStringMatches(string, static_cast<FindOptions>(options), maxMatchCount);
4054}
4055
4056void WebPage::getImageForFindMatch(uint32_t matchIndex)
4057{
4058 findController().getImageForFindMatch(matchIndex);
4059}
4060
4061void WebPage::selectFindMatch(uint32_t matchIndex)
4062{
4063 findController().selectFindMatch(matchIndex);
4064}
4065
4066void WebPage::hideFindUI()
4067{
4068 findController().hideFindUI();
4069}
4070
4071void WebPage::countStringMatches(const String& string, uint32_t options, uint32_t maxMatchCount)
4072{
4073 findController().countStringMatches(string, static_cast<FindOptions>(options), maxMatchCount);
4074}
4075
4076void WebPage::replaceMatches(const Vector<uint32_t>& matchIndices, const String& replacementText, bool selectionOnly, CallbackID callbackID)
4077{
4078 auto numberOfReplacements = findController().replaceMatches(matchIndices, replacementText, selectionOnly);
4079 send(Messages::WebPageProxy::UnsignedCallback(numberOfReplacements, callbackID));
4080}
4081
4082void WebPage::didChangeSelectedIndexForActivePopupMenu(int32_t newIndex)
4083{
4084 changeSelectedIndex(newIndex);
4085 m_activePopupMenu = nullptr;
4086}
4087
4088void WebPage::changeSelectedIndex(int32_t index)
4089{
4090 if (!m_activePopupMenu)
4091 return;
4092
4093 m_activePopupMenu->didChangeSelectedIndex(index);
4094}
4095
4096#if PLATFORM(IOS_FAMILY)
4097void WebPage::didChooseFilesForOpenPanelWithDisplayStringAndIcon(const Vector<String>& files, const String& displayString, const IPC::DataReference& iconData)
4098{
4099 if (!m_activeOpenPanelResultListener)
4100 return;
4101
4102 RefPtr<Icon> icon;
4103 if (!iconData.isEmpty()) {
4104 RetainPtr<CFDataRef> dataRef = adoptCF(CFDataCreate(nullptr, iconData.data(), iconData.size()));
4105 RetainPtr<CGDataProviderRef> imageProviderRef = adoptCF(CGDataProviderCreateWithCFData(dataRef.get()));
4106 RetainPtr<CGImageRef> imageRef = adoptCF(CGImageCreateWithJPEGDataProvider(imageProviderRef.get(), nullptr, true, kCGRenderingIntentDefault));
4107 icon = Icon::createIconForImage(imageRef.get());
4108 }
4109
4110 m_activeOpenPanelResultListener->didChooseFilesWithDisplayStringAndIcon(files, displayString, icon.get());
4111 m_activeOpenPanelResultListener = nullptr;
4112}
4113#endif
4114
4115void WebPage::didChooseFilesForOpenPanel(const Vector<String>& files)
4116{
4117 if (!m_activeOpenPanelResultListener)
4118 return;
4119
4120 m_activeOpenPanelResultListener->didChooseFiles(files);
4121 m_activeOpenPanelResultListener = nullptr;
4122}
4123
4124void WebPage::didCancelForOpenPanel()
4125{
4126 m_activeOpenPanelResultListener = nullptr;
4127}
4128
4129#if ENABLE(SANDBOX_EXTENSIONS)
4130void WebPage::extendSandboxForFilesFromOpenPanel(SandboxExtension::HandleArray&& handles)
4131{
4132 for (size_t i = 0; i < handles.size(); ++i) {
4133 bool result = SandboxExtension::consumePermanently(handles[i]);
4134 if (!result) {
4135 // We have reports of cases where this fails for some unknown reason, <rdar://problem/10156710>.
4136 WTFLogAlways("WebPage::extendSandboxForFileFromOpenPanel(): Could not consume a sandbox extension");
4137 }
4138 }
4139}
4140#endif
4141
4142#if ENABLE(GEOLOCATION)
4143void WebPage::didReceiveGeolocationPermissionDecision(uint64_t geolocationID, bool allowed)
4144{
4145 geolocationPermissionRequestManager().didReceiveGeolocationPermissionDecision(geolocationID, allowed);
4146}
4147#endif
4148
4149void WebPage::didReceiveNotificationPermissionDecision(uint64_t notificationID, bool allowed)
4150{
4151 notificationPermissionRequestManager()->didReceiveNotificationPermissionDecision(notificationID, allowed);
4152}
4153
4154#if ENABLE(MEDIA_STREAM)
4155
4156void WebPage::userMediaAccessWasGranted(uint64_t userMediaID, WebCore::CaptureDevice&& audioDevice, WebCore::CaptureDevice&& videoDevice, String&& mediaDeviceIdentifierHashSalt, CompletionHandler<void()>&& completionHandler)
4157{
4158 m_userMediaPermissionRequestManager->userMediaAccessWasGranted(userMediaID, WTFMove(audioDevice), WTFMove(videoDevice), WTFMove(mediaDeviceIdentifierHashSalt), WTFMove(completionHandler));
4159}
4160
4161void WebPage::userMediaAccessWasDenied(uint64_t userMediaID, uint64_t reason, String&& invalidConstraint)
4162{
4163 m_userMediaPermissionRequestManager->userMediaAccessWasDenied(userMediaID, static_cast<UserMediaRequest::MediaAccessDenialReason>(reason), WTFMove(invalidConstraint));
4164}
4165
4166void WebPage::didCompleteMediaDeviceEnumeration(uint64_t userMediaID, const Vector<CaptureDevice>& devices, String&& deviceIdentifierHashSalt, bool originHasPersistentAccess)
4167{
4168 m_userMediaPermissionRequestManager->didCompleteMediaDeviceEnumeration(userMediaID, devices, WTFMove(deviceIdentifierHashSalt), originHasPersistentAccess);
4169}
4170
4171void WebPage::captureDevicesChanged()
4172{
4173 m_userMediaPermissionRequestManager->captureDevicesChanged();
4174}
4175
4176#endif
4177
4178#if !PLATFORM(IOS_FAMILY)
4179void WebPage::advanceToNextMisspelling(bool startBeforeSelection)
4180{
4181 Frame& frame = m_page->focusController().focusedOrMainFrame();
4182 frame.editor().advanceToNextMisspelling(startBeforeSelection);
4183}
4184#endif
4185
4186bool WebPage::hasRichlyEditableSelection() const
4187{
4188 auto& frame = m_page->focusController().focusedOrMainFrame();
4189 if (m_page->dragCaretController().isContentRichlyEditable())
4190 return true;
4191
4192 return frame.selection().selection().isContentRichlyEditable();
4193}
4194
4195void WebPage::changeSpellingToWord(const String& word)
4196{
4197 replaceSelectionWithText(&m_page->focusController().focusedOrMainFrame(), word);
4198}
4199
4200void WebPage::unmarkAllMisspellings()
4201{
4202 for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
4203 if (Document* document = frame->document())
4204 document->markers().removeMarkers(DocumentMarker::Spelling);
4205 }
4206}
4207
4208void WebPage::unmarkAllBadGrammar()
4209{
4210 for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
4211 if (Document* document = frame->document())
4212 document->markers().removeMarkers(DocumentMarker::Grammar);
4213 }
4214}
4215
4216#if USE(APPKIT)
4217void WebPage::uppercaseWord()
4218{
4219 m_page->focusController().focusedOrMainFrame().editor().uppercaseWord();
4220}
4221
4222void WebPage::lowercaseWord()
4223{
4224 m_page->focusController().focusedOrMainFrame().editor().lowercaseWord();
4225}
4226
4227void WebPage::capitalizeWord()
4228{
4229 m_page->focusController().focusedOrMainFrame().editor().capitalizeWord();
4230}
4231#endif
4232
4233void WebPage::setTextForActivePopupMenu(int32_t index)
4234{
4235 if (!m_activePopupMenu)
4236 return;
4237
4238 m_activePopupMenu->setTextForIndex(index);
4239}
4240
4241#if PLATFORM(GTK)
4242void WebPage::failedToShowPopupMenu()
4243{
4244 if (!m_activePopupMenu)
4245 return;
4246
4247 m_activePopupMenu->client()->popupDidHide();
4248}
4249#endif
4250
4251#if ENABLE(CONTEXT_MENUS)
4252void WebPage::didSelectItemFromActiveContextMenu(const WebContextMenuItemData& item)
4253{
4254 if (auto contextMenu = std::exchange(m_contextMenu, nullptr))
4255 contextMenu->itemSelected(item);
4256}
4257#endif
4258
4259void WebPage::replaceSelectionWithText(Frame* frame, const String& text)
4260{
4261 return frame->editor().replaceSelectionWithText(text, WebCore::Editor::SelectReplacement::Yes, WebCore::Editor::SmartReplace::No);
4262}
4263
4264#if !PLATFORM(IOS_FAMILY)
4265void WebPage::clearSelection()
4266{
4267 m_page->focusController().focusedOrMainFrame().selection().clear();
4268}
4269#endif
4270
4271void WebPage::restoreSelectionInFocusedEditableElement()
4272{
4273 Frame& frame = m_page->focusController().focusedOrMainFrame();
4274 if (!frame.selection().isNone())
4275 return;
4276
4277 if (auto document = frame.document()) {
4278 if (auto element = document->focusedElement())
4279 element->updateFocusAppearance(SelectionRestorationMode::Restore, SelectionRevealMode::DoNotReveal);
4280 }
4281}
4282
4283bool WebPage::mainFrameHasCustomContentProvider() const
4284{
4285 if (Frame* frame = mainFrame()) {
4286 WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(frame->loader().client());
4287 ASSERT(webFrameLoaderClient);
4288 return webFrameLoaderClient->frameHasCustomContentProvider();
4289 }
4290
4291 return false;
4292}
4293
4294void WebPage::addMIMETypeWithCustomContentProvider(const String& mimeType)
4295{
4296 m_mimeTypesWithCustomContentProviders.add(mimeType);
4297}
4298
4299void WebPage::updateMainFrameScrollOffsetPinning()
4300{
4301 Frame& frame = m_page->mainFrame();
4302 ScrollPosition scrollPosition = frame.view()->scrollPosition();
4303 ScrollPosition maximumScrollPosition = frame.view()->maximumScrollPosition();
4304 ScrollPosition minimumScrollPosition = frame.view()->minimumScrollPosition();
4305
4306 bool isPinnedToLeftSide = (scrollPosition.x() <= minimumScrollPosition.x());
4307 bool isPinnedToRightSide = (scrollPosition.x() >= maximumScrollPosition.x());
4308 bool isPinnedToTopSide = (scrollPosition.y() <= minimumScrollPosition.y());
4309 bool isPinnedToBottomSide = (scrollPosition.y() >= maximumScrollPosition.y());
4310
4311 if (isPinnedToLeftSide != m_cachedMainFrameIsPinnedToLeftSide || isPinnedToRightSide != m_cachedMainFrameIsPinnedToRightSide || isPinnedToTopSide != m_cachedMainFrameIsPinnedToTopSide || isPinnedToBottomSide != m_cachedMainFrameIsPinnedToBottomSide) {
4312 send(Messages::WebPageProxy::DidChangeScrollOffsetPinningForMainFrame(isPinnedToLeftSide, isPinnedToRightSide, isPinnedToTopSide, isPinnedToBottomSide));
4313
4314 m_cachedMainFrameIsPinnedToLeftSide = isPinnedToLeftSide;
4315 m_cachedMainFrameIsPinnedToRightSide = isPinnedToRightSide;
4316 m_cachedMainFrameIsPinnedToTopSide = isPinnedToTopSide;
4317 m_cachedMainFrameIsPinnedToBottomSide = isPinnedToBottomSide;
4318 }
4319}
4320
4321void WebPage::mainFrameDidLayout()
4322{
4323 unsigned pageCount = m_page->pageCount();
4324 if (pageCount != m_cachedPageCount) {
4325 send(Messages::WebPageProxy::DidChangePageCount(pageCount));
4326 m_cachedPageCount = pageCount;
4327 }
4328
4329#if PLATFORM(COCOA) || PLATFORM(GTK)
4330 if (m_viewGestureGeometryCollector)
4331 m_viewGestureGeometryCollector->mainFrameDidLayout();
4332#endif
4333#if PLATFORM(IOS_FAMILY)
4334 if (FrameView* frameView = mainFrameView()) {
4335 IntSize newContentSize = frameView->contentsSize();
4336 LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " mainFrameDidLayout setting content size to " << newContentSize);
4337 if (m_viewportConfiguration.setContentsSize(newContentSize))
4338 viewportConfigurationChanged();
4339 }
4340 findController().redraw();
4341#endif
4342}
4343
4344void WebPage::addPluginView(PluginView* pluginView)
4345{
4346 ASSERT(!m_pluginViews.contains(pluginView));
4347
4348 m_pluginViews.add(pluginView);
4349 m_hasSeenPlugin = true;
4350#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
4351 LOG(Plugins, "Primary Plug-In Detection: triggering detection from addPluginView(%p)", pluginView);
4352 m_determinePrimarySnapshottedPlugInTimer.startOneShot(0_s);
4353#endif
4354}
4355
4356void WebPage::removePluginView(PluginView* pluginView)
4357{
4358 ASSERT(m_pluginViews.contains(pluginView));
4359
4360 m_pluginViews.remove(pluginView);
4361#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
4362 LOG(Plugins, "Primary Plug-In Detection: removePluginView(%p)", pluginView);
4363#endif
4364}
4365
4366void WebPage::sendSetWindowFrame(const FloatRect& windowFrame)
4367{
4368#if PLATFORM(COCOA)
4369 m_hasCachedWindowFrame = false;
4370#endif
4371 send(Messages::WebPageProxy::SetWindowFrame(windowFrame));
4372}
4373
4374#if PLATFORM(COCOA)
4375void WebPage::windowAndViewFramesChanged(const FloatRect& windowFrameInScreenCoordinates, const FloatRect& windowFrameInUnflippedScreenCoordinates, const FloatRect& viewFrameInWindowCoordinates, const FloatPoint& accessibilityViewCoordinates)
4376{
4377 m_windowFrameInScreenCoordinates = windowFrameInScreenCoordinates;
4378 m_windowFrameInUnflippedScreenCoordinates = windowFrameInUnflippedScreenCoordinates;
4379 m_viewFrameInWindowCoordinates = viewFrameInWindowCoordinates;
4380 m_accessibilityPosition = accessibilityViewCoordinates;
4381
4382 // Tell all our plug-in views that the window and view frames have changed.
4383 for (auto* pluginView : m_pluginViews)
4384 pluginView->windowAndViewFramesChanged(enclosingIntRect(windowFrameInScreenCoordinates), enclosingIntRect(viewFrameInWindowCoordinates));
4385
4386 m_hasCachedWindowFrame = !m_windowFrameInUnflippedScreenCoordinates.isEmpty();
4387}
4388#endif
4389
4390void WebPage::setMainFrameIsScrollable(bool isScrollable)
4391{
4392 m_mainFrameIsScrollable = isScrollable;
4393 m_drawingArea->mainFrameScrollabilityChanged(isScrollable);
4394
4395 if (FrameView* frameView = m_mainFrame->coreFrame()->view()) {
4396 frameView->setCanHaveScrollbars(isScrollable);
4397 frameView->setProhibitsScrolling(!isScrollable);
4398 }
4399}
4400
4401bool WebPage::windowIsFocused() const
4402{
4403 return m_page->focusController().isActive();
4404}
4405
4406bool WebPage::windowAndWebPageAreFocused() const
4407{
4408 if (!isVisible())
4409 return false;
4410
4411 return m_page->focusController().isFocused() && m_page->focusController().isActive();
4412}
4413
4414void WebPage::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
4415{
4416 if (decoder.messageReceiverName() == Messages::WebInspector::messageReceiverName()) {
4417 if (WebInspector* inspector = this->inspector())
4418 inspector->didReceiveMessage(connection, decoder);
4419 return;
4420 }
4421
4422 if (decoder.messageReceiverName() == Messages::WebInspectorUI::messageReceiverName()) {
4423 if (WebInspectorUI* inspectorUI = this->inspectorUI())
4424 inspectorUI->didReceiveMessage(connection, decoder);
4425 return;
4426 }
4427
4428 if (decoder.messageReceiverName() == Messages::RemoteWebInspectorUI::messageReceiverName()) {
4429 if (RemoteWebInspectorUI* remoteInspectorUI = this->remoteInspectorUI())
4430 remoteInspectorUI->didReceiveMessage(connection, decoder);
4431 return;
4432 }
4433
4434#if ENABLE(FULLSCREEN_API)
4435 if (decoder.messageReceiverName() == Messages::WebFullScreenManager::messageReceiverName()) {
4436 fullScreenManager()->didReceiveMessage(connection, decoder);
4437 return;
4438 }
4439#endif
4440
4441 didReceiveWebPageMessage(connection, decoder);
4442}
4443
4444void WebPage::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder)
4445{
4446 didReceiveSyncWebPageMessage(connection, decoder, replyEncoder);
4447}
4448
4449#if ENABLE(ASYNC_SCROLLING)
4450ScrollingCoordinator* WebPage::scrollingCoordinator() const
4451{
4452 return m_page->scrollingCoordinator();
4453}
4454#endif
4455
4456WebPage::SandboxExtensionTracker::~SandboxExtensionTracker()
4457{
4458 invalidate();
4459}
4460
4461void WebPage::SandboxExtensionTracker::invalidate()
4462{
4463 m_pendingProvisionalSandboxExtension = nullptr;
4464
4465 if (m_provisionalSandboxExtension) {
4466 m_provisionalSandboxExtension->revoke();
4467 m_provisionalSandboxExtension = nullptr;
4468 }
4469
4470 if (m_committedSandboxExtension) {
4471 m_committedSandboxExtension->revoke();
4472 m_committedSandboxExtension = nullptr;
4473 }
4474}
4475
4476void WebPage::SandboxExtensionTracker::willPerformLoadDragDestinationAction(RefPtr<SandboxExtension>&& pendingDropSandboxExtension)
4477{
4478 setPendingProvisionalSandboxExtension(WTFMove(pendingDropSandboxExtension));
4479}
4480
4481void WebPage::SandboxExtensionTracker::beginLoad(WebFrame* frame, SandboxExtension::Handle&& handle)
4482{
4483 ASSERT_UNUSED(frame, frame->isMainFrame());
4484
4485 setPendingProvisionalSandboxExtension(SandboxExtension::create(WTFMove(handle)));
4486}
4487
4488void WebPage::SandboxExtensionTracker::beginReload(WebFrame* frame, SandboxExtension::Handle&& handle)
4489{
4490 ASSERT_UNUSED(frame, frame->isMainFrame());
4491
4492 // Maintain existing provisional SandboxExtension in case of a reload, if the new handle is null. This is needed
4493 // because the UIProcess sends us a null handle if it already sent us a handle for this path in the past.
4494 if (auto sandboxExtension = SandboxExtension::create(WTFMove(handle)))
4495 setPendingProvisionalSandboxExtension(WTFMove(sandboxExtension));
4496}
4497
4498void WebPage::SandboxExtensionTracker::setPendingProvisionalSandboxExtension(RefPtr<SandboxExtension>&& pendingProvisionalSandboxExtension)
4499{
4500 m_pendingProvisionalSandboxExtension = WTFMove(pendingProvisionalSandboxExtension);
4501}
4502
4503bool WebPage::SandboxExtensionTracker::shouldReuseCommittedSandboxExtension(WebFrame* frame)
4504{
4505 ASSERT(frame->isMainFrame());
4506
4507 FrameLoader& frameLoader = frame->coreFrame()->loader();
4508 FrameLoadType frameLoadType = frameLoader.loadType();
4509
4510 // If the page is being reloaded, it should reuse whatever extension is committed.
4511 if (isReload(frameLoadType))
4512 return true;
4513
4514 if (m_pendingProvisionalSandboxExtension)
4515 return false;
4516
4517 DocumentLoader* documentLoader = frameLoader.documentLoader();
4518 DocumentLoader* provisionalDocumentLoader = frameLoader.provisionalDocumentLoader();
4519 if (!documentLoader || !provisionalDocumentLoader)
4520 return false;
4521
4522 if (documentLoader->url().isLocalFile() && provisionalDocumentLoader->url().isLocalFile())
4523 return true;
4524
4525 return false;
4526}
4527
4528void WebPage::SandboxExtensionTracker::didStartProvisionalLoad(WebFrame* frame)
4529{
4530 if (!frame->isMainFrame())
4531 return;
4532
4533 // We should only reuse the commited sandbox extension if it is not null. It can be
4534 // null if the last load was for an error page.
4535 if (m_committedSandboxExtension && shouldReuseCommittedSandboxExtension(frame))
4536 m_pendingProvisionalSandboxExtension = m_committedSandboxExtension;
4537
4538 ASSERT(!m_provisionalSandboxExtension);
4539
4540 m_provisionalSandboxExtension = WTFMove(m_pendingProvisionalSandboxExtension);
4541 if (!m_provisionalSandboxExtension)
4542 return;
4543
4544 ASSERT(!m_provisionalSandboxExtension || frame->coreFrame()->loader().provisionalDocumentLoader()->url().isLocalFile());
4545
4546 m_provisionalSandboxExtension->consume();
4547}
4548
4549void WebPage::SandboxExtensionTracker::didCommitProvisionalLoad(WebFrame* frame)
4550{
4551 if (!frame->isMainFrame())
4552 return;
4553
4554 if (m_committedSandboxExtension)
4555 m_committedSandboxExtension->revoke();
4556
4557 m_committedSandboxExtension = WTFMove(m_provisionalSandboxExtension);
4558
4559 // We can also have a non-null m_pendingProvisionalSandboxExtension if a new load is being started.
4560 // This extension is not cleared, because it does not pertain to the failed load, and will be needed.
4561}
4562
4563void WebPage::SandboxExtensionTracker::didFailProvisionalLoad(WebFrame* frame)
4564{
4565 if (!frame->isMainFrame())
4566 return;
4567
4568 if (!m_provisionalSandboxExtension)
4569 return;
4570
4571 m_provisionalSandboxExtension->revoke();
4572 m_provisionalSandboxExtension = nullptr;
4573
4574 // We can also have a non-null m_pendingProvisionalSandboxExtension if a new load is being started
4575 // (notably, if the current one fails because the new one cancels it). This extension is not cleared,
4576 // because it does not pertain to the failed load, and will be needed.
4577}
4578
4579bool WebPage::hasLocalDataForURL(const URL& url)
4580{
4581 if (url.isLocalFile())
4582 return true;
4583
4584 DocumentLoader* documentLoader = m_page->mainFrame().loader().documentLoader();
4585 if (documentLoader && documentLoader->subresource(url))
4586 return true;
4587
4588 return false;
4589}
4590
4591void WebPage::setCustomTextEncodingName(const String& encoding)
4592{
4593 m_page->mainFrame().loader().reloadWithOverrideEncoding(encoding);
4594}
4595
4596void WebPage::didRemoveBackForwardItem(const BackForwardItemIdentifier& itemID)
4597{
4598 WebBackForwardListProxy::removeItem(itemID);
4599}
4600
4601#if PLATFORM(COCOA)
4602
4603bool WebPage::isSpeaking()
4604{
4605 bool result;
4606 return sendSync(Messages::WebPageProxy::GetIsSpeaking(), Messages::WebPageProxy::GetIsSpeaking::Reply(result)) && result;
4607}
4608
4609void WebPage::speak(const String& string)
4610{
4611 send(Messages::WebPageProxy::Speak(string));
4612}
4613
4614void WebPage::stopSpeaking()
4615{
4616 send(Messages::WebPageProxy::StopSpeaking());
4617}
4618
4619#endif
4620
4621#if PLATFORM(MAC)
4622
4623RetainPtr<PDFDocument> WebPage::pdfDocumentForPrintingFrame(Frame* coreFrame)
4624{
4625 PluginView* pluginView = pluginViewForFrame(coreFrame);
4626 if (!pluginView)
4627 return nullptr;
4628
4629 return pluginView->pdfDocumentForPrinting();
4630}
4631
4632void WebPage::setUseSystemAppearance(bool useSystemAppearance)
4633{
4634 corePage()->setUseSystemAppearance(useSystemAppearance);
4635}
4636
4637#endif
4638
4639#if !PLATFORM(GTK)
4640void WebPage::effectiveAppearanceDidChange(bool useDarkAppearance, bool useInactiveAppearance)
4641{
4642 corePage()->effectiveAppearanceDidChange(useDarkAppearance, useInactiveAppearance);
4643}
4644#endif
4645
4646void WebPage::beginPrinting(uint64_t frameID, const PrintInfo& printInfo)
4647{
4648 WebFrame* frame = WebProcess::singleton().webFrame(frameID);
4649 if (!frame)
4650 return;
4651
4652 Frame* coreFrame = frame->coreFrame();
4653 if (!coreFrame)
4654 return;
4655
4656#if PLATFORM(MAC)
4657 if (pdfDocumentForPrintingFrame(coreFrame))
4658 return;
4659#endif
4660
4661 if (!m_printContext) {
4662 m_printContext = std::make_unique<PrintContext>(coreFrame);
4663 m_page->dispatchBeforePrintEvent();
4664 }
4665
4666 freezeLayerTree(LayerTreeFreezeReason::Printing);
4667
4668 auto computedPageSize = m_printContext->computedPageSize(FloatSize(printInfo.availablePaperWidth, printInfo.availablePaperHeight), printInfo.margin);
4669 m_printContext->begin(computedPageSize.width(), computedPageSize.height());
4670
4671 float fullPageHeight;
4672 m_printContext->computePageRects(FloatRect(0, 0, computedPageSize.width(), computedPageSize.height()), 0, 0, printInfo.pageSetupScaleFactor, fullPageHeight, true);
4673
4674#if PLATFORM(GTK)
4675 if (!m_printOperation)
4676 m_printOperation = WebPrintOperationGtk::create(this, printInfo);
4677#endif
4678}
4679
4680void WebPage::endPrinting()
4681{
4682 unfreezeLayerTree(LayerTreeFreezeReason::Printing);
4683
4684 if (m_printContext) {
4685 m_printContext = nullptr;
4686 m_page->dispatchAfterPrintEvent();
4687 }
4688}
4689
4690void WebPage::computePagesForPrinting(uint64_t frameID, const PrintInfo& printInfo, CallbackID callbackID)
4691{
4692 Vector<IntRect> resultPageRects;
4693 double resultTotalScaleFactorForPrinting = 1;
4694 auto computedPageMargin = printInfo.margin;
4695 computePagesForPrintingImpl(frameID, printInfo, resultPageRects, resultTotalScaleFactorForPrinting, computedPageMargin);
4696 send(Messages::WebPageProxy::ComputedPagesCallback(resultPageRects, resultTotalScaleFactorForPrinting, computedPageMargin, callbackID));
4697}
4698
4699void WebPage::computePagesForPrintingImpl(uint64_t frameID, const PrintInfo& printInfo, Vector<WebCore::IntRect>& resultPageRects, double& resultTotalScaleFactorForPrinting, FloatBoxExtent& computedPageMargin)
4700{
4701 ASSERT(resultPageRects.isEmpty());
4702
4703 beginPrinting(frameID, printInfo);
4704
4705 if (m_printContext) {
4706 resultPageRects = m_printContext->pageRects();
4707 computedPageMargin = m_printContext->computedPageMargin(printInfo.margin);
4708 auto computedPageSize = m_printContext->computedPageSize(FloatSize(printInfo.availablePaperWidth, printInfo.availablePaperHeight), printInfo.margin);
4709 resultTotalScaleFactorForPrinting = m_printContext->computeAutomaticScaleFactor(computedPageSize) * printInfo.pageSetupScaleFactor;
4710 }
4711#if PLATFORM(COCOA)
4712 else
4713 computePagesForPrintingPDFDocument(frameID, printInfo, resultPageRects);
4714#endif // PLATFORM(COCOA)
4715
4716 // If we're asked to print, we should actually print at least a blank page.
4717 if (resultPageRects.isEmpty())
4718 resultPageRects.append(IntRect(0, 0, 1, 1));
4719}
4720
4721#if PLATFORM(COCOA)
4722void WebPage::drawRectToImage(uint64_t frameID, const PrintInfo& printInfo, const IntRect& rect, const WebCore::IntSize& imageSize, CallbackID callbackID)
4723{
4724 WebFrame* frame = WebProcess::singleton().webFrame(frameID);
4725 Frame* coreFrame = frame ? frame->coreFrame() : 0;
4726
4727 RefPtr<WebImage> image;
4728
4729#if USE(CG)
4730 if (coreFrame) {
4731#if PLATFORM(MAC)
4732 ASSERT(coreFrame->document()->printing() || pdfDocumentForPrintingFrame(coreFrame));
4733#else
4734 ASSERT(coreFrame->document()->printing());
4735#endif
4736
4737 auto bitmap = ShareableBitmap::createShareable(imageSize, { });
4738 if (!bitmap) {
4739 ASSERT_NOT_REACHED();
4740 return;
4741 }
4742 auto graphicsContext = bitmap->createGraphicsContext();
4743
4744 float printingScale = static_cast<float>(imageSize.width()) / rect.width();
4745 graphicsContext->scale(printingScale);
4746
4747#if PLATFORM(MAC)
4748 if (RetainPtr<PDFDocument> pdfDocument = pdfDocumentForPrintingFrame(coreFrame)) {
4749 ASSERT(!m_printContext);
4750 graphicsContext->scale(FloatSize(1, -1));
4751 graphicsContext->translate(0, -rect.height());
4752 drawPDFDocument(graphicsContext->platformContext(), pdfDocument.get(), printInfo, rect);
4753 } else
4754#endif
4755 {
4756 m_printContext->spoolRect(*graphicsContext, rect);
4757 }
4758
4759 image = WebImage::create(bitmap.releaseNonNull());
4760 }
4761#endif
4762
4763 ShareableBitmap::Handle handle;
4764
4765 if (image)
4766 image->bitmap().createHandle(handle, SharedMemory::Protection::ReadOnly);
4767
4768 send(Messages::WebPageProxy::ImageCallback(handle, callbackID));
4769}
4770
4771void WebPage::drawPagesToPDF(uint64_t frameID, const PrintInfo& printInfo, uint32_t first, uint32_t count, CallbackID callbackID)
4772{
4773 RetainPtr<CFMutableDataRef> pdfPageData;
4774 drawPagesToPDFImpl(frameID, printInfo, first, count, pdfPageData);
4775 send(Messages::WebPageProxy::DataCallback({ CFDataGetBytePtr(pdfPageData.get()), static_cast<size_t>(CFDataGetLength(pdfPageData.get())) }, callbackID));
4776}
4777
4778void WebPage::drawPagesToPDFImpl(uint64_t frameID, const PrintInfo& printInfo, uint32_t first, uint32_t count, RetainPtr<CFMutableDataRef>& pdfPageData)
4779{
4780 WebFrame* frame = WebProcess::singleton().webFrame(frameID);
4781 Frame* coreFrame = frame ? frame->coreFrame() : 0;
4782
4783 pdfPageData = adoptCF(CFDataCreateMutable(0, 0));
4784
4785#if USE(CG)
4786 if (coreFrame) {
4787
4788#if PLATFORM(MAC)
4789 ASSERT(coreFrame->document()->printing() || pdfDocumentForPrintingFrame(coreFrame));
4790#else
4791 ASSERT(coreFrame->document()->printing());
4792#endif
4793
4794 // FIXME: Use CGDataConsumerCreate with callbacks to avoid copying the data.
4795 RetainPtr<CGDataConsumerRef> pdfDataConsumer = adoptCF(CGDataConsumerCreateWithCFData(pdfPageData.get()));
4796
4797 CGRect mediaBox = (m_printContext && m_printContext->pageCount()) ? m_printContext->pageRect(0) : CGRectMake(0, 0, printInfo.availablePaperWidth, printInfo.availablePaperHeight);
4798 RetainPtr<CGContextRef> context = adoptCF(CGPDFContextCreate(pdfDataConsumer.get(), &mediaBox, 0));
4799
4800#if PLATFORM(MAC)
4801 if (RetainPtr<PDFDocument> pdfDocument = pdfDocumentForPrintingFrame(coreFrame)) {
4802 ASSERT(!m_printContext);
4803 drawPagesToPDFFromPDFDocument(context.get(), pdfDocument.get(), printInfo, first, count);
4804 } else
4805#endif
4806 {
4807 size_t pageCount = m_printContext->pageCount();
4808 for (uint32_t page = first; page < first + count; ++page) {
4809 if (page >= pageCount)
4810 break;
4811
4812 RetainPtr<CFDictionaryRef> pageInfo = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
4813 CGPDFContextBeginPage(context.get(), pageInfo.get());
4814
4815 GraphicsContext ctx(context.get());
4816 ctx.scale(FloatSize(1, -1));
4817 ctx.translate(0, -m_printContext->pageRect(page).height());
4818 m_printContext->spoolPage(ctx, page, m_printContext->pageRect(page).width());
4819
4820 CGPDFContextEndPage(context.get());
4821 }
4822 }
4823 CGPDFContextClose(context.get());
4824 }
4825#endif
4826}
4827
4828#elif PLATFORM(GTK)
4829void WebPage::drawPagesForPrinting(uint64_t frameID, const PrintInfo& printInfo, CallbackID callbackID)
4830{
4831 beginPrinting(frameID, printInfo);
4832 if (m_printContext && m_printOperation) {
4833 m_printOperation->startPrint(m_printContext.get(), callbackID);
4834 return;
4835 }
4836
4837 send(Messages::WebPageProxy::VoidCallback(callbackID));
4838}
4839
4840void WebPage::didFinishPrintOperation(const WebCore::ResourceError& error, CallbackID callbackID)
4841{
4842 send(Messages::WebPageProxy::PrintFinishedCallback(error, callbackID));
4843 m_printOperation = nullptr;
4844}
4845#endif
4846
4847void WebPage::savePDFToFileInDownloadsFolder(const String& suggestedFilename, const URL& originatingURL, const uint8_t* data, unsigned long size)
4848{
4849 send(Messages::WebPageProxy::SavePDFToFileInDownloadsFolder(suggestedFilename, originatingURL, IPC::DataReference(data, size)));
4850}
4851
4852#if PLATFORM(COCOA)
4853void WebPage::savePDFToTemporaryFolderAndOpenWithNativeApplication(const String& suggestedFilename, const String& originatingURLString, const uint8_t* data, unsigned long size, const String& pdfUUID)
4854{
4855 send(Messages::WebPageProxy::SavePDFToTemporaryFolderAndOpenWithNativeApplication(suggestedFilename, originatingURLString, IPC::DataReference(data, size), pdfUUID));
4856}
4857#endif
4858
4859void WebPage::addResourceRequest(unsigned long identifier, const WebCore::ResourceRequest& request)
4860{
4861 if (!request.url().protocolIsInHTTPFamily())
4862 return;
4863
4864 if (m_mainFrameProgressCompleted && !UserGestureIndicator::processingUserGesture())
4865 return;
4866
4867 ASSERT(!m_trackedNetworkResourceRequestIdentifiers.contains(identifier));
4868 bool wasEmpty = m_trackedNetworkResourceRequestIdentifiers.isEmpty();
4869 m_trackedNetworkResourceRequestIdentifiers.add(identifier);
4870 if (wasEmpty)
4871 send(Messages::WebPageProxy::SetNetworkRequestsInProgress(true));
4872}
4873
4874void WebPage::removeResourceRequest(unsigned long identifier)
4875{
4876 if (!m_trackedNetworkResourceRequestIdentifiers.remove(identifier))
4877 return;
4878
4879 if (m_trackedNetworkResourceRequestIdentifiers.isEmpty())
4880 send(Messages::WebPageProxy::SetNetworkRequestsInProgress(false));
4881}
4882
4883void WebPage::setMediaVolume(float volume)
4884{
4885 m_page->setMediaVolume(volume);
4886}
4887
4888void WebPage::setMuted(MediaProducer::MutedStateFlags state)
4889{
4890 m_page->setMuted(state);
4891}
4892
4893void WebPage::stopMediaCapture()
4894{
4895#if ENABLE(MEDIA_STREAM)
4896 m_page->stopMediaCapture();
4897#endif
4898}
4899
4900#if ENABLE(MEDIA_SESSION)
4901void WebPage::handleMediaEvent(uint32_t eventType)
4902{
4903 m_page->handleMediaEvent(static_cast<MediaEventType>(eventType));
4904}
4905
4906void WebPage::setVolumeOfMediaElement(double volume, uint64_t elementID)
4907{
4908 m_page->setVolumeOfMediaElement(volume, elementID);
4909}
4910#endif
4911
4912void WebPage::setMayStartMediaWhenInWindow(bool mayStartMedia)
4913{
4914 if (mayStartMedia == m_mayStartMediaWhenInWindow)
4915 return;
4916
4917 m_mayStartMediaWhenInWindow = mayStartMedia;
4918 if (m_mayStartMediaWhenInWindow && m_page->isInWindow())
4919 m_setCanStartMediaTimer.startOneShot(0_s);
4920}
4921
4922void WebPage::runModal()
4923{
4924 if (m_isClosed)
4925 return;
4926 if (m_isRunningModal)
4927 return;
4928
4929 m_isRunningModal = true;
4930 send(Messages::WebPageProxy::RunModal());
4931#if !ASSERT_DISABLED
4932 Ref<WebPage> protector(*this);
4933#endif
4934 RunLoop::run();
4935 ASSERT(!m_isRunningModal);
4936}
4937
4938bool WebPage::canHandleRequest(const WebCore::ResourceRequest& request)
4939{
4940 if (SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(request.url().protocol().toStringWithoutCopying()))
4941 return true;
4942
4943 if (request.url().protocolIsBlob())
4944 return true;
4945
4946 return platformCanHandleRequest(request);
4947}
4948
4949#if PLATFORM(COCOA)
4950void WebPage::handleAlternativeTextUIResult(const String& result)
4951{
4952 Frame& frame = m_page->focusController().focusedOrMainFrame();
4953 frame.editor().handleAlternativeTextUIResult(result);
4954}
4955#endif
4956
4957void WebPage::simulateMouseDown(int button, WebCore::IntPoint position, int clickCount, WKEventModifiers modifiers, WallTime time)
4958{
4959 static_assert(sizeof(WKEventModifiers) >= sizeof(WebEvent::Modifier), "WKEventModifiers must be greater than or equal to the size of WebEvent::Modifier");
4960 mouseEvent(WebMouseEvent(WebMouseEvent::MouseDown, static_cast<WebMouseEvent::Button>(button), 0, position, position, 0, 0, 0, clickCount, OptionSet<WebEvent::Modifier>::fromRaw(modifiers), time, WebCore::ForceAtClick, WebMouseEvent::NoTap));
4961}
4962
4963void WebPage::simulateMouseUp(int button, WebCore::IntPoint position, int clickCount, WKEventModifiers modifiers, WallTime time)
4964{
4965 static_assert(sizeof(WKEventModifiers) >= sizeof(WebEvent::Modifier), "WKEventModifiers must be greater than or equal to the size of WebEvent::Modifier");
4966 mouseEvent(WebMouseEvent(WebMouseEvent::MouseUp, static_cast<WebMouseEvent::Button>(button), 0, position, position, 0, 0, 0, clickCount, OptionSet<WebEvent::Modifier>::fromRaw(modifiers), time, WebCore::ForceAtClick, WebMouseEvent::NoTap));
4967}
4968
4969void WebPage::simulateMouseMotion(WebCore::IntPoint position, WallTime time)
4970{
4971 mouseEvent(WebMouseEvent(WebMouseEvent::MouseMove, WebMouseEvent::NoButton, 0, position, position, 0, 0, 0, 0, OptionSet<WebEvent::Modifier> { }, time, 0, WebMouseEvent::NoTap));
4972}
4973
4974void WebPage::setCompositionForTesting(const String& compositionString, uint64_t from, uint64_t length, bool suppressUnderline)
4975{
4976 Frame& frame = m_page->focusController().focusedOrMainFrame();
4977 if (!frame.editor().canEdit())
4978 return;
4979
4980 Vector<CompositionUnderline> underlines;
4981 if (!suppressUnderline)
4982 underlines.append(CompositionUnderline(0, compositionString.length(), CompositionUnderlineColor::TextColor, Color(Color::black), false));
4983
4984 frame.editor().setComposition(compositionString, underlines, from, from + length);
4985}
4986
4987bool WebPage::hasCompositionForTesting()
4988{
4989 Frame& frame = m_page->focusController().focusedOrMainFrame();
4990 return frame.editor().hasComposition();
4991}
4992
4993void WebPage::confirmCompositionForTesting(const String& compositionString)
4994{
4995 Frame& frame = m_page->focusController().focusedOrMainFrame();
4996 if (!frame.editor().canEdit())
4997 return;
4998
4999 if (compositionString.isNull())
5000 frame.editor().confirmComposition();
5001 frame.editor().confirmComposition(compositionString);
5002}
5003
5004void WebPage::wheelEventHandlersChanged(bool hasHandlers)
5005{
5006 if (m_hasWheelEventHandlers == hasHandlers)
5007 return;
5008
5009 m_hasWheelEventHandlers = hasHandlers;
5010 recomputeShortCircuitHorizontalWheelEventsState();
5011}
5012
5013static bool hasEnabledHorizontalScrollbar(ScrollableArea* scrollableArea)
5014{
5015 if (Scrollbar* scrollbar = scrollableArea->horizontalScrollbar())
5016 return scrollbar->enabled();
5017
5018 return false;
5019}
5020
5021static bool pageContainsAnyHorizontalScrollbars(Frame* mainFrame)
5022{
5023 if (FrameView* frameView = mainFrame->view()) {
5024 if (hasEnabledHorizontalScrollbar(frameView))
5025 return true;
5026 }
5027
5028 for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) {
5029 FrameView* frameView = frame->view();
5030 if (!frameView)
5031 continue;
5032
5033 const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
5034 if (!scrollableAreas)
5035 continue;
5036
5037 for (HashSet<ScrollableArea*>::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
5038 ScrollableArea* scrollableArea = *it;
5039 if (!scrollableArea->scrollbarsCanBeActive())
5040 continue;
5041
5042 if (hasEnabledHorizontalScrollbar(scrollableArea))
5043 return true;
5044 }
5045 }
5046
5047 return false;
5048}
5049
5050void WebPage::recomputeShortCircuitHorizontalWheelEventsState()
5051{
5052 bool canShortCircuitHorizontalWheelEvents = !m_hasWheelEventHandlers;
5053
5054 if (canShortCircuitHorizontalWheelEvents) {
5055 // Check if we have any horizontal scroll bars on the page.
5056 if (pageContainsAnyHorizontalScrollbars(mainFrame()))
5057 canShortCircuitHorizontalWheelEvents = false;
5058 }
5059
5060 if (m_canShortCircuitHorizontalWheelEvents == canShortCircuitHorizontalWheelEvents)
5061 return;
5062
5063 m_canShortCircuitHorizontalWheelEvents = canShortCircuitHorizontalWheelEvents;
5064 send(Messages::WebPageProxy::SetCanShortCircuitHorizontalWheelEvents(m_canShortCircuitHorizontalWheelEvents));
5065}
5066
5067Frame* WebPage::mainFrame() const
5068{
5069 return m_page ? &m_page->mainFrame() : nullptr;
5070}
5071
5072FrameView* WebPage::mainFrameView() const
5073{
5074 if (Frame* frame = mainFrame())
5075 return frame->view();
5076
5077 return nullptr;
5078}
5079
5080void WebPage::setScrollingPerformanceLoggingEnabled(bool enabled)
5081{
5082 m_scrollingPerformanceLoggingEnabled = enabled;
5083
5084 FrameView* frameView = m_mainFrame->coreFrame()->view();
5085 if (!frameView)
5086 return;
5087
5088 frameView->setScrollingPerformanceLoggingEnabled(enabled);
5089}
5090
5091bool WebPage::canPluginHandleResponse(const ResourceResponse& response)
5092{
5093#if ENABLE(NETSCAPE_PLUGIN_API)
5094 uint32_t pluginLoadPolicy;
5095 bool allowOnlyApplicationPlugins = !m_mainFrame->coreFrame()->loader().subframeLoader().allowPlugins();
5096
5097 uint64_t pluginProcessToken;
5098 String newMIMEType;
5099 String unavailabilityDescription;
5100 bool isUnsupported = false;
5101 if (!sendSync(Messages::WebPageProxy::FindPlugin(response.mimeType(), PluginProcessTypeNormal, response.url().string(), response.url().string(), response.url().string(), allowOnlyApplicationPlugins), Messages::WebPageProxy::FindPlugin::Reply(pluginProcessToken, newMIMEType, pluginLoadPolicy, unavailabilityDescription, isUnsupported)))
5102 return false;
5103
5104 ASSERT(!isUnsupported);
5105 bool isBlockedPlugin = (pluginLoadPolicy == PluginModuleBlockedForSecurity) || (pluginLoadPolicy == PluginModuleBlockedForCompatibility);
5106 return !isUnsupported && !isBlockedPlugin && pluginProcessToken;
5107#else
5108 UNUSED_PARAM(response);
5109 return false;
5110#endif
5111}
5112
5113bool WebPage::shouldUseCustomContentProviderForResponse(const ResourceResponse& response)
5114{
5115 auto& mimeType = response.mimeType();
5116 if (mimeType.isNull())
5117 return false;
5118
5119 // If a plug-in exists that claims to support this response, it should take precedence over the custom content provider.
5120 // canPluginHandleResponse() is called last because it performs synchronous IPC.
5121 return m_mimeTypesWithCustomContentProviders.contains(mimeType) && !canPluginHandleResponse(response);
5122}
5123
5124#if PLATFORM(COCOA)
5125
5126void WebPage::setTextAsync(const String& text)
5127{
5128 auto frame = makeRef(m_page->focusController().focusedOrMainFrame());
5129 if (frame->selection().selection().isContentEditable()) {
5130 UserTypingGestureIndicator indicator(frame.get());
5131 frame->selection().selectAll();
5132 if (text.isEmpty())
5133 frame->editor().deleteSelectionWithSmartDelete(false);
5134 else
5135 frame->editor().insertText(text, nullptr, TextEventInputKeyboard);
5136 return;
5137 }
5138
5139 if (is<HTMLInputElement>(m_focusedElement.get())) {
5140 downcast<HTMLInputElement>(*m_focusedElement).setValueForUser(text);
5141 return;
5142 }
5143
5144 ASSERT_NOT_REACHED();
5145}
5146
5147void WebPage::insertTextAsync(const String& text, const EditingRange& replacementEditingRange, InsertTextOptions&& options)
5148{
5149 Frame& frame = m_page->focusController().focusedOrMainFrame();
5150
5151 Ref<Frame> protector(frame);
5152
5153 UserGestureIndicator gestureIndicator { options.processingUserGesture ? ProcessingUserGesture : NotProcessingUserGesture, frame.document() };
5154
5155 bool replacesText = false;
5156 if (replacementEditingRange.location != notFound) {
5157 if (auto replacementRange = EditingRange::toRange(frame, replacementEditingRange, options.editingRangeIsRelativeTo)) {
5158 SetForScope<bool> isSelectingTextWhileInsertingAsynchronously(m_isSelectingTextWhileInsertingAsynchronously, options.suppressSelectionUpdate);
5159 frame.selection().setSelection(VisibleSelection(*replacementRange, SEL_DEFAULT_AFFINITY));
5160 replacesText = replacementEditingRange.length;
5161 }
5162 }
5163
5164 if (options.registerUndoGroup)
5165 send(Messages::WebPageProxy::RegisterInsertionUndoGrouping());
5166
5167 if (!frame.editor().hasComposition()) {
5168 // An insertText: might be handled by other responders in the chain if we don't handle it.
5169 // One example is space bar that results in scrolling down the page.
5170 frame.editor().insertText(text, nullptr, replacesText ? TextEventInputAutocompletion : TextEventInputKeyboard);
5171 } else
5172 frame.editor().confirmComposition(text);
5173}
5174
5175void WebPage::getMarkedRangeAsync(CallbackID callbackID)
5176{
5177 Frame& frame = m_page->focusController().focusedOrMainFrame();
5178 auto editingRange = EditingRange::fromRange(frame, frame.editor().compositionRange().get());
5179 send(Messages::WebPageProxy::EditingRangeCallback(editingRange, callbackID));
5180}
5181
5182void WebPage::getSelectedRangeAsync(CallbackID callbackID)
5183{
5184 Frame& frame = m_page->focusController().focusedOrMainFrame();
5185 auto editingRange = EditingRange::fromRange(frame, frame.selection().toNormalizedRange().get());
5186 send(Messages::WebPageProxy::EditingRangeCallback(editingRange, callbackID));
5187}
5188
5189void WebPage::characterIndexForPointAsync(const WebCore::IntPoint& point, CallbackID callbackID)
5190{
5191 HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(point);
5192 Frame* frame = result.innerNonSharedNode() ? result.innerNodeFrame() : &m_page->focusController().focusedOrMainFrame();
5193
5194 RefPtr<Range> range = frame->rangeForPoint(result.roundedPointInInnerNodeFrame());
5195 auto editingRange = EditingRange::fromRange(*frame, range.get());
5196 send(Messages::WebPageProxy::UnsignedCallback(static_cast<uint64_t>(editingRange.location), callbackID));
5197}
5198
5199void WebPage::firstRectForCharacterRangeAsync(const EditingRange& editingRange, CallbackID callbackID)
5200{
5201 Frame& frame = m_page->focusController().focusedOrMainFrame();
5202 IntRect result(IntPoint(0, 0), IntSize(0, 0));
5203
5204 RefPtr<Range> range = EditingRange::toRange(frame, editingRange);
5205 if (!range) {
5206 send(Messages::WebPageProxy::RectForCharacterRangeCallback(result, EditingRange(notFound, 0), callbackID));
5207 return;
5208 }
5209
5210 result = frame.view()->contentsToWindow(frame.editor().firstRectForRange(range.get()));
5211
5212 // FIXME: Update actualRange to match the range of first rect.
5213 send(Messages::WebPageProxy::RectForCharacterRangeCallback(result, editingRange, callbackID));
5214}
5215
5216void WebPage::setCompositionAsync(const String& text, const Vector<CompositionUnderline>& underlines, const EditingRange& selection, const EditingRange& replacementEditingRange)
5217{
5218 Frame& frame = m_page->focusController().focusedOrMainFrame();
5219
5220 if (frame.selection().selection().isContentEditable()) {
5221 RefPtr<Range> replacementRange;
5222 if (replacementEditingRange.location != notFound) {
5223 replacementRange = EditingRange::toRange(frame, replacementEditingRange);
5224 if (replacementRange)
5225 frame.selection().setSelection(VisibleSelection(*replacementRange, SEL_DEFAULT_AFFINITY));
5226 }
5227
5228 frame.editor().setComposition(text, underlines, selection.location, selection.location + selection.length);
5229 }
5230}
5231
5232void WebPage::confirmCompositionAsync()
5233{
5234 Frame& frame = m_page->focusController().focusedOrMainFrame();
5235 frame.editor().confirmComposition();
5236}
5237
5238#endif // PLATFORM(COCOA)
5239
5240#if PLATFORM(GTK)
5241static Frame* targetFrameForEditing(WebPage* page)
5242{
5243 Frame& targetFrame = page->corePage()->focusController().focusedOrMainFrame();
5244
5245 Editor& editor = targetFrame.editor();
5246 if (!editor.canEdit())
5247 return nullptr;
5248
5249 if (editor.hasComposition()) {
5250 // We should verify the parent node of this IME composition node are
5251 // editable because JavaScript may delete a parent node of the composition
5252 // node. In this case, WebKit crashes while deleting texts from the parent
5253 // node, which doesn't exist any longer.
5254 if (auto range = editor.compositionRange()) {
5255 if (!range->startContainer().isContentEditable())
5256 return nullptr;
5257 }
5258 }
5259 return &targetFrame;
5260}
5261
5262void WebPage::confirmComposition(const String& compositionString, int64_t selectionStart, int64_t selectionLength)
5263{
5264 Frame* targetFrame = targetFrameForEditing(this);
5265 if (!targetFrame) {
5266 send(Messages::WebPageProxy::EditorStateChanged(editorState()));
5267 return;
5268 }
5269
5270 targetFrame->editor().confirmComposition(compositionString);
5271
5272 if (selectionStart == -1) {
5273 send(Messages::WebPageProxy::EditorStateChanged(editorState()));
5274 return;
5275 }
5276
5277 Element* scope = targetFrame->selection().selection().rootEditableElement();
5278 RefPtr<Range> selectionRange = TextIterator::rangeFromLocationAndLength(scope, selectionStart, selectionLength);
5279 ASSERT_WITH_MESSAGE(selectionRange, "Invalid selection: [%lld:%lld] in text of length %d", static_cast<long long>(selectionStart), static_cast<long long>(selectionLength), scope->innerText().length());
5280
5281 if (selectionRange) {
5282 VisibleSelection selection(*selectionRange, SEL_DEFAULT_AFFINITY);
5283 targetFrame->selection().setSelection(selection);
5284 }
5285 send(Messages::WebPageProxy::EditorStateChanged(editorState()));
5286}
5287
5288void WebPage::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, uint64_t selectionStart, uint64_t selectionLength, uint64_t replacementStart, uint64_t replacementLength)
5289{
5290 Frame* targetFrame = targetFrameForEditing(this);
5291 if (!targetFrame || !targetFrame->selection().selection().isContentEditable()) {
5292 send(Messages::WebPageProxy::EditorStateChanged(editorState()));
5293 return;
5294 }
5295
5296 Ref<Frame> protector(*targetFrame);
5297
5298 if (replacementLength > 0) {
5299 // The layout needs to be uptodate before setting a selection
5300 targetFrame->document()->updateLayout();
5301
5302 Element* scope = targetFrame->selection().selection().rootEditableElement();
5303 RefPtr<Range> replacementRange = TextIterator::rangeFromLocationAndLength(scope, replacementStart, replacementLength);
5304 targetFrame->editor().setIgnoreSelectionChanges(true);
5305 targetFrame->selection().setSelection(VisibleSelection(*replacementRange, SEL_DEFAULT_AFFINITY));
5306 targetFrame->editor().setIgnoreSelectionChanges(false);
5307 }
5308
5309 targetFrame->editor().setComposition(text, underlines, selectionStart, selectionStart + selectionLength);
5310 send(Messages::WebPageProxy::EditorStateChanged(editorState()));
5311}
5312
5313void WebPage::cancelComposition()
5314{
5315 if (Frame* targetFrame = targetFrameForEditing(this))
5316 targetFrame->editor().cancelComposition();
5317 send(Messages::WebPageProxy::EditorStateChanged(editorState()));
5318}
5319#endif
5320
5321void WebPage::didApplyStyle()
5322{
5323 sendEditorStateUpdate();
5324}
5325
5326void WebPage::didChangeContents()
5327{
5328 sendEditorStateUpdate();
5329}
5330
5331void WebPage::didChangeOverflowScrollPosition()
5332{
5333 didChangeSelectionOrOverflowScrollPosition();
5334}
5335
5336void WebPage::didChangeSelection()
5337{
5338 didChangeSelectionOrOverflowScrollPosition();
5339}
5340
5341void WebPage::didChangeSelectionOrOverflowScrollPosition()
5342{
5343 Frame& frame = m_page->focusController().focusedOrMainFrame();
5344 // The act of getting Dictionary Popup info can make selection changes that we should not propagate to the UIProcess.
5345 // Specifically, if there is a caret selection, it will change to a range selection of the word around the caret. And
5346 // then it will change back.
5347 if (frame.editor().isGettingDictionaryPopupInfo())
5348 return;
5349
5350 // Similarly, we don't want to propagate changes to the web process when inserting text asynchronously, since we will
5351 // end up with a range selection very briefly right before inserting the text.
5352 if (m_isSelectingTextWhileInsertingAsynchronously)
5353 return;
5354
5355#if PLATFORM(MAC)
5356 bool hasPreviouslyFocusedDueToUserInteraction = m_hasEverFocusedElementDueToUserInteractionSincePageTransition;
5357 m_hasEverFocusedElementDueToUserInteractionSincePageTransition |= m_userIsInteracting;
5358
5359 if (!hasPreviouslyFocusedDueToUserInteraction && m_hasEverFocusedElementDueToUserInteractionSincePageTransition) {
5360 if (frame.document()->quirks().isTouchBarUpdateSupressedForHiddenContentEditable()) {
5361 m_isTouchBarUpdateSupressedForHiddenContentEditable = true;
5362 send(Messages::WebPageProxy::SetIsTouchBarUpdateSupressedForHiddenContentEditable(m_isTouchBarUpdateSupressedForHiddenContentEditable));
5363 }
5364
5365 if (frame.document()->quirks().isNeverRichlyEditableForTouchBar()) {
5366 m_isNeverRichlyEditableForTouchBar = true;
5367 send(Messages::WebPageProxy::SetIsNeverRichlyEditableForTouchBar(m_isNeverRichlyEditableForTouchBar));
5368 }
5369
5370 send(Messages::WebPageProxy::SetHasHadSelectionChangesFromUserInteraction(m_hasEverFocusedElementDueToUserInteractionSincePageTransition));
5371 }
5372
5373 // Abandon the current inline input session if selection changed for any other reason but an input method direct action.
5374 // FIXME: This logic should be in WebCore.
5375 // FIXME: Many changes that affect composition node do not go through didChangeSelection(). We need to do something when DOM manipulation affects the composition, because otherwise input method's idea about it will be different from Editor's.
5376 // FIXME: We can't cancel composition when selection changes to NoSelection, but we probably should.
5377 if (frame.editor().hasComposition() && !frame.editor().ignoreSelectionChanges() && !frame.selection().isNone()) {
5378 frame.editor().cancelComposition();
5379 discardedComposition();
5380 return;
5381 }
5382#endif
5383
5384 scheduleFullEditorStateUpdate();
5385}
5386
5387void WebPage::resetFocusedElementForFrame(WebFrame* frame)
5388{
5389 if (!m_focusedElement)
5390 return;
5391
5392 if (frame->isMainFrame() || m_focusedElement->document().frame() == frame->coreFrame()) {
5393#if PLATFORM(IOS_FAMILY)
5394 send(Messages::WebPageProxy::ElementDidBlur());
5395#elif PLATFORM(MAC)
5396 send(Messages::WebPageProxy::SetEditableElementIsFocused(false));
5397#endif
5398 m_focusedElement = nullptr;
5399 }
5400}
5401
5402void WebPage::elementDidRefocus(WebCore::Element& element)
5403{
5404 elementDidFocus(element);
5405
5406 if (m_userIsInteracting)
5407 scheduleFullEditorStateUpdate();
5408}
5409
5410bool WebPage::shouldDispatchUpdateAfterFocusingElement(const Element& element) const
5411{
5412 if (m_focusedElement == &element || m_recentlyBlurredElement == &element) {
5413#if PLATFORM(IOS_FAMILY)
5414 return !m_isShowingInputViewForFocusedElement;
5415#else
5416 return false;
5417#endif
5418 }
5419 return true;
5420}
5421
5422static bool isTextFormControlOrEditableContent(const WebCore::Element& element)
5423{
5424 return is<HTMLTextFormControlElement>(element) || element.hasEditableStyle();
5425}
5426
5427void WebPage::elementDidFocus(WebCore::Element& element)
5428{
5429 if (!shouldDispatchUpdateAfterFocusingElement(element)) {
5430 m_focusedElement = &element;
5431 m_recentlyBlurredElement = nullptr;
5432 return;
5433 }
5434
5435 if (is<HTMLSelectElement>(element) || isTextFormControlOrEditableContent(element)) {
5436 m_focusedElement = &element;
5437
5438#if PLATFORM(IOS_FAMILY)
5439
5440#if ENABLE(FULLSCREEN_API)
5441 if (element.document().fullscreenManager().isFullscreen())
5442 element.document().fullscreenManager().cancelFullscreen();
5443#endif
5444
5445 ++m_currentFocusedElementIdentifier;
5446 FocusedElementInformation information;
5447 getFocusedElementInformation(information);
5448 RefPtr<API::Object> userData;
5449
5450 m_formClient->willBeginInputSession(this, &element, WebFrame::fromCoreFrame(*element.document().frame()), m_userIsInteracting, userData);
5451
5452 send(Messages::WebPageProxy::ElementDidFocus(information, m_userIsInteracting, m_recentlyBlurredElement, m_lastActivityStateChanges, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())));
5453#elif PLATFORM(MAC)
5454 // FIXME: This can be unified with the iOS code above by bringing ElementDidFocus to macOS.
5455 // This also doesn't take other noneditable controls into account, such as input type color.
5456 send(Messages::WebPageProxy::SetEditableElementIsFocused(!element.hasTagName(WebCore::HTMLNames::selectTag)));
5457#endif
5458 m_recentlyBlurredElement = nullptr;
5459 }
5460}
5461
5462void WebPage::elementDidBlur(WebCore::Element& element)
5463{
5464 if (m_focusedElement == &element) {
5465 m_recentlyBlurredElement = WTFMove(m_focusedElement);
5466 callOnMainThread([protectedThis = makeRefPtr(this)] {
5467 if (protectedThis->m_recentlyBlurredElement) {
5468#if PLATFORM(IOS_FAMILY)
5469 protectedThis->send(Messages::WebPageProxy::ElementDidBlur());
5470#elif PLATFORM(MAC)
5471 protectedThis->send(Messages::WebPageProxy::SetEditableElementIsFocused(false));
5472#endif
5473 }
5474 protectedThis->m_recentlyBlurredElement = nullptr;
5475 });
5476 }
5477}
5478
5479void WebPage::focusedElementDidChangeInputMode(WebCore::Element& element, WebCore::InputMode mode)
5480{
5481 if (m_focusedElement != &element)
5482 return;
5483
5484#if PLATFORM(IOS_FAMILY)
5485 ASSERT(is<HTMLElement>(element));
5486 ASSERT(downcast<HTMLElement>(element).canonicalInputMode() == mode);
5487
5488 if (!isTextFormControlOrEditableContent(element))
5489 return;
5490
5491 send(Messages::WebPageProxy::FocusedElementDidChangeInputMode(mode));
5492#else
5493 UNUSED_PARAM(mode);
5494#endif
5495}
5496
5497void WebPage::didUpdateComposition()
5498{
5499 sendEditorStateUpdate();
5500}
5501
5502void WebPage::didEndUserTriggeredSelectionChanges()
5503{
5504 Frame& frame = m_page->focusController().focusedOrMainFrame();
5505 if (!frame.editor().ignoreSelectionChanges())
5506 sendEditorStateUpdate();
5507}
5508
5509void WebPage::discardedComposition()
5510{
5511 send(Messages::WebPageProxy::CompositionWasCanceled());
5512 sendEditorStateUpdate();
5513}
5514
5515void WebPage::canceledComposition()
5516{
5517 send(Messages::WebPageProxy::CompositionWasCanceled());
5518 sendEditorStateUpdate();
5519}
5520
5521void WebPage::setAlwaysShowsHorizontalScroller(bool alwaysShowsHorizontalScroller)
5522{
5523 if (alwaysShowsHorizontalScroller == m_alwaysShowsHorizontalScroller)
5524 return;
5525
5526 m_alwaysShowsHorizontalScroller = alwaysShowsHorizontalScroller;
5527 auto view = corePage()->mainFrame().view();
5528 if (!alwaysShowsHorizontalScroller)
5529 view->setHorizontalScrollbarLock(false);
5530 view->setHorizontalScrollbarMode(alwaysShowsHorizontalScroller ? ScrollbarAlwaysOn : m_mainFrameIsScrollable ? ScrollbarAuto : ScrollbarAlwaysOff, alwaysShowsHorizontalScroller || !m_mainFrameIsScrollable);
5531}
5532
5533void WebPage::setAlwaysShowsVerticalScroller(bool alwaysShowsVerticalScroller)
5534{
5535 if (alwaysShowsVerticalScroller == m_alwaysShowsVerticalScroller)
5536 return;
5537
5538 m_alwaysShowsVerticalScroller = alwaysShowsVerticalScroller;
5539 auto view = corePage()->mainFrame().view();
5540 if (!alwaysShowsVerticalScroller)
5541 view->setVerticalScrollbarLock(false);
5542 view->setVerticalScrollbarMode(alwaysShowsVerticalScroller ? ScrollbarAlwaysOn : m_mainFrameIsScrollable ? ScrollbarAuto : ScrollbarAlwaysOff, alwaysShowsVerticalScroller || !m_mainFrameIsScrollable);
5543}
5544
5545void WebPage::setViewLayoutSize(const IntSize& viewLayoutSize)
5546{
5547 if (m_viewLayoutSize == viewLayoutSize)
5548 return;
5549
5550 m_viewLayoutSize = viewLayoutSize;
5551 if (viewLayoutSize.width() <= 0) {
5552 corePage()->mainFrame().view()->enableAutoSizeMode(false, { });
5553 return;
5554 }
5555
5556 int viewLayoutWidth = viewLayoutSize.width();
5557 int viewLayoutHeight = std::max(viewLayoutSize.height(), 1);
5558 corePage()->mainFrame().view()->enableAutoSizeMode(true, { viewLayoutWidth, viewLayoutHeight });
5559}
5560
5561void WebPage::setAutoSizingShouldExpandToViewHeight(bool shouldExpand)
5562{
5563 if (m_autoSizingShouldExpandToViewHeight == shouldExpand)
5564 return;
5565
5566 m_autoSizingShouldExpandToViewHeight = shouldExpand;
5567
5568 corePage()->mainFrame().view()->setAutoSizeFixedMinimumHeight(shouldExpand ? m_viewSize.height() : 0);
5569}
5570
5571void WebPage::setViewportSizeForCSSViewportUnits(Optional<WebCore::IntSize> viewportSize)
5572{
5573 if (m_viewportSizeForCSSViewportUnits == viewportSize)
5574 return;
5575
5576 m_viewportSizeForCSSViewportUnits = viewportSize;
5577 if (m_viewportSizeForCSSViewportUnits)
5578 corePage()->mainFrame().view()->setViewportSizeForCSSViewportUnits(*m_viewportSizeForCSSViewportUnits);
5579}
5580
5581bool WebPage::isSmartInsertDeleteEnabled()
5582{
5583 return m_page->settings().smartInsertDeleteEnabled();
5584}
5585
5586void WebPage::setSmartInsertDeleteEnabled(bool enabled)
5587{
5588 if (m_page->settings().smartInsertDeleteEnabled() != enabled) {
5589 m_page->settings().setSmartInsertDeleteEnabled(enabled);
5590 setSelectTrailingWhitespaceEnabled(!enabled);
5591 }
5592}
5593
5594bool WebPage::isSelectTrailingWhitespaceEnabled() const
5595{
5596 return m_page->settings().selectTrailingWhitespaceEnabled();
5597}
5598
5599void WebPage::setSelectTrailingWhitespaceEnabled(bool enabled)
5600{
5601 if (m_page->settings().selectTrailingWhitespaceEnabled() != enabled) {
5602 m_page->settings().setSelectTrailingWhitespaceEnabled(enabled);
5603 setSmartInsertDeleteEnabled(!enabled);
5604 }
5605}
5606
5607bool WebPage::canShowResponse(const WebCore::ResourceResponse& response) const
5608{
5609 return canShowMIMEType(response.mimeType(), [&](auto& mimeType, auto allowedPlugins) {
5610 return m_page->pluginData().supportsWebVisibleMimeTypeForURL(mimeType, allowedPlugins, response.url());
5611 });
5612}
5613
5614bool WebPage::canShowMIMEType(const String& mimeType) const
5615{
5616 return canShowMIMEType(mimeType, [&](auto& mimeType, auto allowedPlugins) {
5617 return m_page->pluginData().supportsWebVisibleMimeType(mimeType, allowedPlugins);
5618 });
5619}
5620
5621bool WebPage::canShowMIMEType(const String& mimeType, const Function<bool(const String&, PluginData::AllowedPluginTypes)>& pluginsSupport) const
5622{
5623 if (MIMETypeRegistry::canShowMIMEType(mimeType))
5624 return true;
5625
5626 if (!mimeType.isNull() && m_mimeTypesWithCustomContentProviders.contains(mimeType))
5627 return true;
5628
5629 if (corePage()->mainFrame().loader().subframeLoader().allowPlugins() && pluginsSupport(mimeType, PluginData::AllPlugins))
5630 return true;
5631
5632 // We can use application plugins even if plugins aren't enabled.
5633 if (pluginsSupport(mimeType, PluginData::OnlyApplicationPlugins))
5634 return true;
5635
5636 return false;
5637}
5638
5639void WebPage::addTextCheckingRequest(uint64_t requestID, Ref<TextCheckingRequest>&& request)
5640{
5641 m_pendingTextCheckingRequestMap.add(requestID, WTFMove(request));
5642}
5643
5644void WebPage::didFinishCheckingText(uint64_t requestID, const Vector<TextCheckingResult>& result)
5645{
5646 RefPtr<TextCheckingRequest> request = m_pendingTextCheckingRequestMap.take(requestID);
5647 if (!request)
5648 return;
5649
5650 request->didSucceed(result);
5651}
5652
5653void WebPage::didCancelCheckingText(uint64_t requestID)
5654{
5655 RefPtr<TextCheckingRequest> request = m_pendingTextCheckingRequestMap.take(requestID);
5656 if (!request)
5657 return;
5658
5659 request->didCancel();
5660}
5661
5662void WebPage::willReplaceMultipartContent(const WebFrame& frame)
5663{
5664#if PLATFORM(IOS_FAMILY)
5665 if (!frame.isMainFrame())
5666 return;
5667
5668 m_previousExposedContentRect = m_drawingArea->exposedContentRect();
5669#endif
5670}
5671
5672void WebPage::didReplaceMultipartContent(const WebFrame& frame)
5673{
5674#if PLATFORM(IOS_FAMILY)
5675 if (!frame.isMainFrame())
5676 return;
5677
5678 // Restore the previous exposed content rect so that it remains fixed when replacing content
5679 // from multipart/x-mixed-replace streams.
5680 m_drawingArea->setExposedContentRect(m_previousExposedContentRect);
5681#endif
5682}
5683
5684void WebPage::didCommitLoad(WebFrame* frame)
5685{
5686#if PLATFORM(IOS_FAMILY)
5687 frame->setFirstLayerTreeTransactionIDAfterDidCommitLoad(downcast<RemoteLayerTreeDrawingArea>(*m_drawingArea).nextTransactionID());
5688 cancelPotentialTapInFrame(*frame);
5689#endif
5690 resetFocusedElementForFrame(frame);
5691
5692 if (!frame->isMainFrame())
5693 return;
5694
5695 // If previous URL is invalid, then it's not a real page that's being navigated away from.
5696 // Most likely, this is actually the first load to be committed in this page.
5697 if (frame->coreFrame()->loader().previousURL().isValid())
5698 reportUsedFeatures();
5699
5700 // Only restore the scale factor for standard frame loads (of the main frame).
5701 if (frame->coreFrame()->loader().loadType() == FrameLoadType::Standard) {
5702 Page* page = frame->coreFrame()->page();
5703
5704#if PLATFORM(MAC)
5705 // As a very special case, we disable non-default layout modes in WKView for main-frame PluginDocuments.
5706 // Ideally we would only worry about this in WKView or the WKViewLayoutStrategies, but if we allow
5707 // a round-trip to the UI process, you'll see the wrong scale temporarily. So, we reset it here, and then
5708 // again later from the UI process.
5709 if (frame->coreFrame()->document()->isPluginDocument()) {
5710 scaleView(1);
5711 setUseFixedLayout(false);
5712 }
5713#endif
5714
5715 if (page && page->pageScaleFactor() != 1)
5716 scalePage(1, IntPoint());
5717 }
5718#if PLATFORM(IOS_FAMILY)
5719 m_hasReceivedVisibleContentRectsAfterDidCommitLoad = false;
5720 m_hasRestoredExposedContentRectAfterDidCommitLoad = false;
5721 m_scaleWasSetByUIProcess = false;
5722 m_userHasChangedPageScaleFactor = false;
5723 m_estimatedLatency = Seconds(1.0 / 60);
5724
5725#if ENABLE(IOS_TOUCH_EVENTS)
5726 WebProcess::singleton().eventDispatcher().clearQueuedTouchEventsForPage(*this);
5727#endif
5728
5729 resetViewportDefaultConfiguration(frame);
5730 const Frame* coreFrame = frame->coreFrame();
5731
5732 bool viewportChanged = false;
5733
5734 LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " didCommitLoad setting content size to " << coreFrame->view()->contentsSize());
5735 if (m_viewportConfiguration.setContentsSize(coreFrame->view()->contentsSize()))
5736 viewportChanged = true;
5737
5738 if (m_viewportConfiguration.setViewportArguments(coreFrame->document()->viewportArguments()))
5739 viewportChanged = true;
5740
5741 if (viewportChanged)
5742 viewportConfigurationChanged();
5743#endif
5744
5745#if ENABLE(VIEWPORT_RESIZING)
5746 m_shrinkToFitContentTimer.stop();
5747#endif
5748
5749#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
5750 resetPrimarySnapshottedPlugIn();
5751#endif
5752
5753#if USE(OS_STATE)
5754 m_loadCommitTime = WallTime::now();
5755#endif
5756
5757 WebProcess::singleton().updateActivePages();
5758
5759 updateMainFrameScrollOffsetPinning();
5760}
5761
5762void WebPage::didFinishDocumentLoad(WebFrame& frame)
5763{
5764 if (!frame.isMainFrame())
5765 return;
5766
5767#if ENABLE(VIEWPORT_RESIZING)
5768 scheduleShrinkToFitContent();
5769#endif
5770}
5771
5772void WebPage::didFinishLoad(WebFrame& frame)
5773{
5774 if (!frame.isMainFrame())
5775 return;
5776
5777 WebProcess::singleton().sendPrewarmInformation(frame.url());
5778
5779#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
5780 m_readyToFindPrimarySnapshottedPlugin = true;
5781 LOG(Plugins, "Primary Plug-In Detection: triggering detection from didFinishLoad (marking as ready to detect).");
5782 m_determinePrimarySnapshottedPlugInTimer.startOneShot(0_s);
5783#else
5784 UNUSED_PARAM(frame);
5785#endif
5786
5787#if ENABLE(VIEWPORT_RESIZING)
5788 scheduleShrinkToFitContent();
5789#endif
5790}
5791
5792void WebPage::didInsertMenuElement(HTMLMenuElement& element)
5793{
5794#if PLATFORM(COCOA)
5795 sendTouchBarMenuDataAddedUpdate(element);
5796#else
5797 UNUSED_PARAM(element);
5798#endif
5799}
5800
5801void WebPage::didRemoveMenuElement(HTMLMenuElement& element)
5802{
5803#if PLATFORM(COCOA)
5804 sendTouchBarMenuDataRemovedUpdate(element);
5805#else
5806 UNUSED_PARAM(element);
5807#endif
5808}
5809
5810void WebPage::didInsertMenuItemElement(HTMLMenuItemElement& element)
5811{
5812#if PLATFORM(COCOA)
5813 sendTouchBarMenuItemDataAddedUpdate(element);
5814#else
5815 UNUSED_PARAM(element);
5816#endif
5817}
5818
5819void WebPage::didRemoveMenuItemElement(HTMLMenuItemElement& element)
5820{
5821#if PLATFORM(COCOA)
5822 sendTouchBarMenuItemDataRemovedUpdate(element);
5823#else
5824 UNUSED_PARAM(element);
5825#endif
5826}
5827
5828#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
5829static const int primarySnapshottedPlugInSearchLimit = 3000;
5830static const float primarySnapshottedPlugInSearchBucketSize = 1.1;
5831static const int primarySnapshottedPlugInMinimumWidth = 400;
5832static const int primarySnapshottedPlugInMinimumHeight = 300;
5833static const unsigned maxPrimarySnapshottedPlugInDetectionAttempts = 2;
5834static const Seconds deferredPrimarySnapshottedPlugInDetectionDelay = 3_s;
5835static const float overlappingImageBoundsScale = 1.1;
5836static const float minimumOverlappingImageToPluginDimensionScale = .9;
5837
5838#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
5839void WebPage::determinePrimarySnapshottedPlugInTimerFired()
5840{
5841 if (!m_page)
5842 return;
5843
5844 Settings& settings = m_page->settings();
5845 if (!settings.snapshotAllPlugIns() && settings.primaryPlugInSnapshotDetectionEnabled())
5846 determinePrimarySnapshottedPlugIn();
5847}
5848#endif
5849
5850void WebPage::determinePrimarySnapshottedPlugIn()
5851{
5852 if (!m_page->settings().plugInSnapshottingEnabled())
5853 return;
5854
5855 LOG(Plugins, "Primary Plug-In Detection: began.");
5856
5857 if (!m_readyToFindPrimarySnapshottedPlugin) {
5858 LOG(Plugins, "Primary Plug-In Detection: exiting - not ready to find plugins.");
5859 return;
5860 }
5861
5862 if (!m_hasSeenPlugin) {
5863 LOG(Plugins, "Primary Plug-In Detection: exiting - we never saw a plug-in get added to the page.");
5864 return;
5865 }
5866
5867 if (m_didFindPrimarySnapshottedPlugin) {
5868 LOG(Plugins, "Primary Plug-In Detection: exiting - we've already found a primary plug-in.");
5869 return;
5870 }
5871
5872 ++m_numberOfPrimarySnapshotDetectionAttempts;
5873
5874 layoutIfNeeded();
5875
5876 RefPtr<FrameView> mainFrameView = corePage()->mainFrame().view();
5877 if (!mainFrameView)
5878 return;
5879
5880 IntRect searchRect = IntRect(IntPoint(), corePage()->mainFrame().view()->contentsSize());
5881 searchRect.intersect(IntRect(IntPoint(), IntSize(primarySnapshottedPlugInSearchLimit, primarySnapshottedPlugInSearchLimit)));
5882
5883 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowUserAgentShadowContent);
5884
5885 RefPtr<HTMLPlugInImageElement> candidatePlugIn;
5886 unsigned candidatePlugInArea = 0;
5887
5888 for (RefPtr<Frame> frame = &corePage()->mainFrame(); frame; frame = frame->tree().traverseNextRendered()) {
5889 if (!frame->loader().subframeLoader().containsPlugins())
5890 continue;
5891 if (!frame->document() || !frame->view())
5892 continue;
5893
5894 Vector<Ref<HTMLPlugInImageElement>> nonPlayingPlugInImageElements;
5895 for (auto& plugInImageElement : descendantsOfType<HTMLPlugInImageElement>(*frame->document())) {
5896 if (plugInImageElement.displayState() == HTMLPlugInElement::Playing)
5897 continue;
5898 nonPlayingPlugInImageElements.append(plugInImageElement);
5899 }
5900
5901 for (auto& plugInImageElement : nonPlayingPlugInImageElements) {
5902 auto pluginRenderer = plugInImageElement->renderer();
5903 if (!pluginRenderer || !pluginRenderer->isBox())
5904 continue;
5905 auto& pluginRenderBox = downcast<RenderBox>(*pluginRenderer);
5906 if (!plugInIntersectsSearchRect(plugInImageElement.get()))
5907 continue;
5908
5909 IntRect plugInRectRelativeToView = plugInImageElement->clientRect();
5910 ScrollPosition scrollPosition = mainFrameView->documentScrollPositionRelativeToViewOrigin();
5911 IntRect plugInRectRelativeToTopDocument(plugInRectRelativeToView.location() + scrollPosition, plugInRectRelativeToView.size());
5912 HitTestResult hitTestResult(plugInRectRelativeToTopDocument.center());
5913
5914 if (!mainFrameView->renderView())
5915 return;
5916 mainFrameView->renderView()->hitTest(request, hitTestResult);
5917
5918 RefPtr<Element> element = hitTestResult.targetElement();
5919 if (!element)
5920 continue;
5921
5922 IntRect elementRectRelativeToView = element->clientRect();
5923 IntRect elementRectRelativeToTopDocument(elementRectRelativeToView.location() + scrollPosition, elementRectRelativeToView.size());
5924 LayoutRect inflatedPluginRect = plugInRectRelativeToTopDocument;
5925 LayoutUnit xOffset = (inflatedPluginRect.width() * overlappingImageBoundsScale - inflatedPluginRect.width()) / 2;
5926 LayoutUnit yOffset = (inflatedPluginRect.height() * overlappingImageBoundsScale - inflatedPluginRect.height()) / 2;
5927 inflatedPluginRect.inflateX(xOffset);
5928 inflatedPluginRect.inflateY(yOffset);
5929
5930 if (element != plugInImageElement.ptr()) {
5931 if (!(is<HTMLImageElement>(*element)
5932 && inflatedPluginRect.contains(elementRectRelativeToTopDocument)
5933 && elementRectRelativeToTopDocument.width() > pluginRenderBox.width() * minimumOverlappingImageToPluginDimensionScale
5934 && elementRectRelativeToTopDocument.height() > pluginRenderBox.height() * minimumOverlappingImageToPluginDimensionScale))
5935 continue;
5936 LOG(Plugins, "Primary Plug-In Detection: Plug-in is hidden by an image that is roughly aligned with it, autoplaying regardless of whether or not it's actually the primary plug-in.");
5937 plugInImageElement->restartSnapshottedPlugIn();
5938 }
5939
5940 if (plugInIsPrimarySize(plugInImageElement, candidatePlugInArea))
5941 candidatePlugIn = WTFMove(plugInImageElement);
5942 }
5943 }
5944 if (!candidatePlugIn) {
5945 LOG(Plugins, "Primary Plug-In Detection: fail - did not find a candidate plug-in.");
5946 if (m_numberOfPrimarySnapshotDetectionAttempts < maxPrimarySnapshottedPlugInDetectionAttempts) {
5947 LOG(Plugins, "Primary Plug-In Detection: will attempt again in %.1f s.", deferredPrimarySnapshottedPlugInDetectionDelay.value());
5948 m_determinePrimarySnapshottedPlugInTimer.startOneShot(deferredPrimarySnapshottedPlugInDetectionDelay);
5949 }
5950 return;
5951 }
5952
5953 LOG(Plugins, "Primary Plug-In Detection: success - found a candidate plug-in - inform it.");
5954 m_didFindPrimarySnapshottedPlugin = true;
5955 m_primaryPlugInPageOrigin = m_page->mainFrame().document()->baseURL().host().toString();
5956 m_primaryPlugInOrigin = candidatePlugIn->loadedUrl().host().toString();
5957 m_primaryPlugInMimeType = candidatePlugIn->serviceType();
5958
5959 candidatePlugIn->setIsPrimarySnapshottedPlugIn(true);
5960}
5961
5962void WebPage::resetPrimarySnapshottedPlugIn()
5963{
5964 m_readyToFindPrimarySnapshottedPlugin = false;
5965 m_didFindPrimarySnapshottedPlugin = false;
5966 m_numberOfPrimarySnapshotDetectionAttempts = 0;
5967 m_hasSeenPlugin = false;
5968}
5969
5970bool WebPage::matchesPrimaryPlugIn(const String& pageOrigin, const String& pluginOrigin, const String& mimeType) const
5971{
5972 if (!m_didFindPrimarySnapshottedPlugin)
5973 return false;
5974
5975 return (pageOrigin == m_primaryPlugInPageOrigin && pluginOrigin == m_primaryPlugInOrigin && mimeType == m_primaryPlugInMimeType);
5976}
5977
5978bool WebPage::plugInIntersectsSearchRect(HTMLPlugInImageElement& plugInImageElement)
5979{
5980 auto& mainFrame = corePage()->mainFrame();
5981 if (!mainFrame.view())
5982 return false;
5983 if (!mainFrame.view()->renderView())
5984 return false;
5985
5986 IntRect searchRect = IntRect(IntPoint(), corePage()->mainFrame().view()->contentsSize());
5987 searchRect.intersect(IntRect(IntPoint(), IntSize(primarySnapshottedPlugInSearchLimit, primarySnapshottedPlugInSearchLimit)));
5988
5989 IntRect plugInRectRelativeToView = plugInImageElement.clientRect();
5990 if (plugInRectRelativeToView.isEmpty())
5991 return false;
5992 ScrollPosition scrollPosition = mainFrame.view()->documentScrollPositionRelativeToViewOrigin();
5993 IntRect plugInRectRelativeToTopDocument(plugInRectRelativeToView.location() + toIntSize(scrollPosition), plugInRectRelativeToView.size());
5994
5995 return plugInRectRelativeToTopDocument.intersects(searchRect);
5996}
5997
5998bool WebPage::plugInIsPrimarySize(WebCore::HTMLPlugInImageElement& plugInImageElement, unsigned& candidatePlugInArea)
5999{
6000 auto* renderer = plugInImageElement.renderer();
6001 if (!is<RenderBox>(renderer))
6002 return false;
6003
6004 auto& box = downcast<RenderBox>(*renderer);
6005 if (box.contentWidth() < primarySnapshottedPlugInMinimumWidth || box.contentHeight() < primarySnapshottedPlugInMinimumHeight)
6006 return false;
6007
6008 LayoutUnit contentArea = box.contentWidth() * box.contentHeight();
6009 if (contentArea > candidatePlugInArea * primarySnapshottedPlugInSearchBucketSize) {
6010 candidatePlugInArea = contentArea.toUnsigned();
6011 return true;
6012 }
6013
6014 return false;
6015}
6016
6017#endif // ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
6018
6019RefPtr<Range> WebPage::currentSelectionAsRange()
6020{
6021 auto* frame = frameWithSelection(m_page.get());
6022 if (!frame)
6023 return nullptr;
6024
6025 return frame->selection().toNormalizedRange();
6026}
6027
6028void WebPage::reportUsedFeatures()
6029{
6030 Vector<String> namedFeatures;
6031 m_loaderClient->featuresUsedInPage(*this, namedFeatures);
6032}
6033
6034void WebPage::sendEditorStateUpdate()
6035{
6036 Frame& frame = m_page->focusController().focusedOrMainFrame();
6037 if (frame.editor().ignoreSelectionChanges())
6038 return;
6039
6040 m_hasPendingEditorStateUpdate = false;
6041
6042 // If we immediately dispatch an EditorState update to the UI process, layout may not be up to date yet.
6043 // If that is the case, just send what we have (i.e. don't include post-layout data) and wait until the
6044 // next layer tree commit to compute and send the complete EditorState over.
6045 auto state = editorState();
6046 send(Messages::WebPageProxy::EditorStateChanged(state), pageID());
6047
6048 if (state.isMissingPostLayoutData)
6049 scheduleFullEditorStateUpdate();
6050}
6051
6052void WebPage::scheduleFullEditorStateUpdate()
6053{
6054 if (m_hasPendingEditorStateUpdate)
6055 return;
6056
6057 m_hasPendingEditorStateUpdate = true;
6058 // FIXME: Scheduling a compositing layer flush here can be more expensive than necessary.
6059 // Instead, we should just compute and send post-layout editor state during the next frame.
6060 m_drawingArea->scheduleCompositingLayerFlush();
6061}
6062
6063#if PLATFORM(COCOA)
6064void WebPage::sendTouchBarMenuDataRemovedUpdate(HTMLMenuElement& element)
6065{
6066 send(Messages::WebPageProxy::TouchBarMenuDataChanged(TouchBarMenuData { }));
6067}
6068
6069void WebPage::sendTouchBarMenuDataAddedUpdate(HTMLMenuElement& element)
6070{
6071 send(Messages::WebPageProxy::TouchBarMenuDataChanged(TouchBarMenuData {element}));
6072}
6073
6074void WebPage::sendTouchBarMenuItemDataAddedUpdate(HTMLMenuItemElement& element)
6075{
6076 send(Messages::WebPageProxy::TouchBarMenuItemDataAdded(TouchBarMenuItemData {element}));
6077}
6078
6079void WebPage::sendTouchBarMenuItemDataRemovedUpdate(HTMLMenuItemElement& element)
6080{
6081 send(Messages::WebPageProxy::TouchBarMenuItemDataRemoved(TouchBarMenuItemData {element}));
6082}
6083#endif
6084
6085void WebPage::flushPendingEditorStateUpdate()
6086{
6087 if (!m_hasPendingEditorStateUpdate)
6088 return;
6089
6090 Frame& frame = m_page->focusController().focusedOrMainFrame();
6091 if (frame.editor().ignoreSelectionChanges())
6092 return;
6093
6094 sendEditorStateUpdate();
6095}
6096
6097void WebPage::updateWebsitePolicies(WebsitePoliciesData&& websitePolicies)
6098{
6099 if (!m_page)
6100 return;
6101
6102 auto* documentLoader = m_page->mainFrame().loader().documentLoader();
6103 if (!documentLoader)
6104 return;
6105
6106 WebsitePoliciesData::applyToDocumentLoader(WTFMove(websitePolicies), *documentLoader);
6107
6108#if ENABLE(VIDEO)
6109 m_page->updateMediaElementRateChangeRestrictions();
6110#endif
6111}
6112
6113unsigned WebPage::extendIncrementalRenderingSuppression()
6114{
6115 unsigned token = m_maximumRenderingSuppressionToken + 1;
6116 while (!HashSet<unsigned>::isValidValue(token) || m_activeRenderingSuppressionTokens.contains(token))
6117 token++;
6118
6119 m_activeRenderingSuppressionTokens.add(token);
6120 m_page->mainFrame().view()->setVisualUpdatesAllowedByClient(false);
6121
6122 m_maximumRenderingSuppressionToken = token;
6123
6124 return token;
6125}
6126
6127void WebPage::stopExtendingIncrementalRenderingSuppression(unsigned token)
6128{
6129 if (!m_activeRenderingSuppressionTokens.remove(token))
6130 return;
6131
6132 m_page->mainFrame().view()->setVisualUpdatesAllowedByClient(!shouldExtendIncrementalRenderingSuppression());
6133}
6134
6135void WebPage::setScrollPinningBehavior(uint32_t pinning)
6136{
6137 m_scrollPinningBehavior = static_cast<ScrollPinningBehavior>(pinning);
6138 m_page->mainFrame().view()->setScrollPinningBehavior(m_scrollPinningBehavior);
6139}
6140
6141void WebPage::setScrollbarOverlayStyle(Optional<uint32_t> scrollbarStyle)
6142{
6143 if (scrollbarStyle)
6144 m_scrollbarOverlayStyle = static_cast<ScrollbarOverlayStyle>(scrollbarStyle.value());
6145 else
6146 m_scrollbarOverlayStyle = Optional<ScrollbarOverlayStyle>();
6147 m_page->mainFrame().view()->recalculateScrollbarOverlayStyle();
6148}
6149
6150Ref<DocumentLoader> WebPage::createDocumentLoader(Frame& frame, const ResourceRequest& request, const SubstituteData& substituteData)
6151{
6152 Ref<WebDocumentLoader> documentLoader = WebDocumentLoader::create(request, substituteData);
6153
6154 if (frame.isMainFrame()) {
6155 if (m_pendingNavigationID) {
6156 documentLoader->setNavigationID(m_pendingNavigationID);
6157 m_pendingNavigationID = 0;
6158 }
6159
6160 if (m_pendingWebsitePolicies) {
6161 WebsitePoliciesData::applyToDocumentLoader(WTFMove(*m_pendingWebsitePolicies), documentLoader);
6162 m_pendingWebsitePolicies = WTF::nullopt;
6163 }
6164 }
6165
6166 return documentLoader;
6167}
6168
6169void WebPage::updateCachedDocumentLoader(WebDocumentLoader& documentLoader, Frame& frame)
6170{
6171 if (m_pendingNavigationID && frame.isMainFrame()) {
6172 documentLoader.setNavigationID(m_pendingNavigationID);
6173 m_pendingNavigationID = 0;
6174 }
6175}
6176
6177void WebPage::getBytecodeProfile(CallbackID callbackID)
6178{
6179 if (LIKELY(!commonVM().m_perBytecodeProfiler)) {
6180 send(Messages::WebPageProxy::StringCallback(String(), callbackID));
6181 return;
6182 }
6183
6184 String result = commonVM().m_perBytecodeProfiler->toJSON();
6185 ASSERT(result.length());
6186 send(Messages::WebPageProxy::StringCallback(result, callbackID));
6187}
6188
6189void WebPage::getSamplingProfilerOutput(CallbackID callbackID)
6190{
6191#if ENABLE(SAMPLING_PROFILER)
6192 SamplingProfiler* samplingProfiler = commonVM().samplingProfiler();
6193 if (!samplingProfiler) {
6194 send(Messages::WebPageProxy::InvalidateStringCallback(callbackID));
6195 return;
6196 }
6197
6198 StringPrintStream result;
6199 samplingProfiler->reportTopFunctions(result);
6200 samplingProfiler->reportTopBytecodes(result);
6201 send(Messages::WebPageProxy::StringCallback(result.toString(), callbackID));
6202#else
6203 send(Messages::WebPageProxy::InvalidateStringCallback(callbackID));
6204#endif
6205}
6206
6207void WebPage::didChangeScrollOffsetForFrame(Frame* frame)
6208{
6209 if (!frame->isMainFrame())
6210 return;
6211
6212 // If this is called when tearing down a FrameView, the WebCore::Frame's
6213 // current FrameView will be null.
6214 if (!frame->view())
6215 return;
6216
6217 updateMainFrameScrollOffsetPinning();
6218}
6219
6220void WebPage::postMessage(const String& messageName, API::Object* messageBody)
6221{
6222 send(Messages::WebPageProxy::HandleMessage(messageName, UserData(WebProcess::singleton().transformObjectsToHandles(messageBody))));
6223}
6224
6225void WebPage::postMessageIgnoringFullySynchronousMode(const String& messageName, API::Object* messageBody)
6226{
6227 send(Messages::WebPageProxy::HandleMessage(messageName, UserData(WebProcess::singleton().transformObjectsToHandles(messageBody))), pageID(), IPC::SendOption::IgnoreFullySynchronousMode);
6228}
6229
6230void WebPage::postSynchronousMessageForTesting(const String& messageName, API::Object* messageBody, RefPtr<API::Object>& returnData)
6231{
6232 UserData returnUserData;
6233
6234 auto& webProcess = WebProcess::singleton();
6235 if (!sendSync(Messages::WebPageProxy::HandleSynchronousMessage(messageName, UserData(webProcess.transformObjectsToHandles(messageBody))), Messages::WebPageProxy::HandleSynchronousMessage::Reply(returnUserData), Seconds::infinity(), IPC::SendSyncOption::UseFullySynchronousModeForTesting))
6236 returnData = nullptr;
6237 else
6238 returnData = webProcess.transformHandlesToObjects(returnUserData.object());
6239}
6240
6241void WebPage::clearWheelEventTestTrigger()
6242{
6243 if (!m_page)
6244 return;
6245
6246 m_page->clearTrigger();
6247}
6248
6249void WebPage::setShouldScaleViewToFitDocument(bool shouldScaleViewToFitDocument)
6250{
6251 if (!m_drawingArea)
6252 return;
6253
6254 m_drawingArea->setShouldScaleViewToFitDocument(shouldScaleViewToFitDocument);
6255}
6256
6257void WebPage::imageOrMediaDocumentSizeChanged(const IntSize& newSize)
6258{
6259 send(Messages::WebPageProxy::ImageOrMediaDocumentSizeChanged(newSize));
6260}
6261
6262void WebPage::addUserScript(String&& source, WebCore::UserContentInjectedFrames injectedFrames, WebCore::UserScriptInjectionTime injectionTime)
6263{
6264 WebCore::UserScript userScript { WTFMove(source), URL(WTF::blankURL()), Vector<String>(), Vector<String>(), injectionTime, injectedFrames };
6265
6266 m_userContentController->addUserScript(InjectedBundleScriptWorld::normalWorld(), WTFMove(userScript));
6267}
6268
6269void WebPage::addUserStyleSheet(const String& source, WebCore::UserContentInjectedFrames injectedFrames)
6270{
6271 WebCore::UserStyleSheet userStyleSheet {source, WTF::blankURL(), Vector<String>(), Vector<String>(), injectedFrames, UserStyleUserLevel };
6272
6273 m_userContentController->addUserStyleSheet(InjectedBundleScriptWorld::normalWorld(), WTFMove(userStyleSheet));
6274}
6275
6276void WebPage::removeAllUserContent()
6277{
6278 m_userContentController->removeAllUserContent();
6279}
6280
6281void WebPage::updateIntrinsicContentSizeIfNeeded(const WebCore::IntSize& size)
6282{
6283 if (!viewLayoutSize().width())
6284 return;
6285 ASSERT(mainFrameView());
6286 ASSERT(mainFrameView()->isAutoSizeEnabled());
6287 ASSERT(!mainFrameView()->needsLayout());
6288 if (m_lastSentIntrinsicContentSize == size)
6289 return;
6290 m_lastSentIntrinsicContentSize = size;
6291 send(Messages::WebPageProxy::DidChangeIntrinsicContentSize(size));
6292}
6293
6294void WebPage::dispatchDidReachLayoutMilestone(OptionSet<WebCore::LayoutMilestone> milestones)
6295{
6296 RefPtr<API::Object> userData;
6297 injectedBundleLoaderClient().didReachLayoutMilestone(*this, milestones, userData);
6298
6299 // Clients should not set userData for this message, and it won't be passed through.
6300 ASSERT(!userData);
6301
6302 // The drawing area might want to defer dispatch of didLayout to the UI process.
6303 if (m_drawingArea) {
6304 static auto paintMilestones = OptionSet<WebCore::LayoutMilestone> { DidHitRelevantRepaintedObjectsAreaThreshold, DidFirstFlushForHeaderLayer, DidFirstPaintAfterSuppressedIncrementalRendering, DidRenderSignificantAmountOfText, DidFirstMeaningfulPaint };
6305 auto drawingAreaRelatedMilestones = milestones & paintMilestones;
6306 if (drawingAreaRelatedMilestones && m_drawingArea->addMilestonesToDispatch(drawingAreaRelatedMilestones))
6307 milestones.remove(drawingAreaRelatedMilestones);
6308 }
6309 if (milestones.contains(DidFirstLayout) && mainFrameView()) {
6310 // Ensure we never send DidFirstLayout milestone without updating the intrinsic size.
6311 updateIntrinsicContentSizeIfNeeded(mainFrameView()->autoSizingIntrinsicContentSize());
6312 }
6313
6314 send(Messages::WebPageProxy::DidReachLayoutMilestone(milestones));
6315}
6316
6317void WebPage::didRestoreScrollPosition()
6318{
6319 send(Messages::WebPageProxy::DidRestoreScrollPosition());
6320}
6321
6322void WebPage::setResourceCachingDisabled(bool disabled)
6323{
6324 m_page->setResourceCachingDisabled(disabled);
6325}
6326
6327void WebPage::setUserInterfaceLayoutDirection(uint32_t direction)
6328{
6329 m_userInterfaceLayoutDirection = static_cast<WebCore::UserInterfaceLayoutDirection>(direction);
6330 m_page->setUserInterfaceLayoutDirection(m_userInterfaceLayoutDirection);
6331}
6332
6333#if ENABLE(GAMEPAD)
6334
6335void WebPage::gamepadActivity(const Vector<GamepadData>& gamepadDatas, bool shouldMakeGamepadsVisible)
6336{
6337 WebGamepadProvider::singleton().gamepadActivity(gamepadDatas, shouldMakeGamepadsVisible);
6338}
6339
6340#endif
6341
6342#if ENABLE(POINTER_LOCK)
6343void WebPage::didAcquirePointerLock()
6344{
6345 corePage()->pointerLockController().didAcquirePointerLock();
6346}
6347
6348void WebPage::didNotAcquirePointerLock()
6349{
6350 corePage()->pointerLockController().didNotAcquirePointerLock();
6351}
6352
6353void WebPage::didLosePointerLock()
6354{
6355 corePage()->pointerLockController().didLosePointerLock();
6356}
6357#endif
6358
6359void WebPage::didGetLoadDecisionForIcon(bool decision, CallbackID loadIdentifier, OptionalCallbackID newCallbackID)
6360{
6361 if (auto* documentLoader = corePage()->mainFrame().loader().documentLoader())
6362 documentLoader->didGetLoadDecisionForIcon(decision, loadIdentifier.toInteger(), newCallbackID.toInteger());
6363}
6364
6365void WebPage::setUseIconLoadingClient(bool useIconLoadingClient)
6366{
6367 static_cast<WebFrameLoaderClient&>(corePage()->mainFrame().loader().client()).setUseIconLoadingClient(useIconLoadingClient);
6368}
6369
6370WebURLSchemeHandlerProxy* WebPage::urlSchemeHandlerForScheme(const String& scheme)
6371{
6372 return m_schemeToURLSchemeHandlerProxyMap.get(scheme);
6373}
6374
6375void WebPage::stopAllURLSchemeTasks()
6376{
6377 HashSet<WebURLSchemeHandlerProxy*> handlers;
6378 for (auto& handler : m_schemeToURLSchemeHandlerProxyMap.values())
6379 handlers.add(handler.get());
6380
6381 for (auto* handler : handlers)
6382 handler->stopAllTasks();
6383}
6384
6385void WebPage::registerURLSchemeHandler(uint64_t handlerIdentifier, const String& scheme)
6386{
6387 auto schemeResult = m_schemeToURLSchemeHandlerProxyMap.add(scheme, WebURLSchemeHandlerProxy::create(*this, handlerIdentifier));
6388 m_identifierToURLSchemeHandlerProxyMap.add(handlerIdentifier, schemeResult.iterator->value.get());
6389}
6390
6391void WebPage::urlSchemeTaskDidPerformRedirection(uint64_t handlerIdentifier, uint64_t taskIdentifier, ResourceResponse&& response, ResourceRequest&& request)
6392{
6393 auto* handler = m_identifierToURLSchemeHandlerProxyMap.get(handlerIdentifier);
6394 ASSERT(handler);
6395
6396 handler->taskDidPerformRedirection(taskIdentifier, WTFMove(response), WTFMove(request));
6397}
6398
6399void WebPage::urlSchemeTaskDidReceiveResponse(uint64_t handlerIdentifier, uint64_t taskIdentifier, const ResourceResponse& response)
6400{
6401 auto* handler = m_identifierToURLSchemeHandlerProxyMap.get(handlerIdentifier);
6402 ASSERT(handler);
6403
6404 handler->taskDidReceiveResponse(taskIdentifier, response);
6405}
6406
6407void WebPage::urlSchemeTaskDidReceiveData(uint64_t handlerIdentifier, uint64_t taskIdentifier, const IPC::DataReference& data)
6408{
6409 auto* handler = m_identifierToURLSchemeHandlerProxyMap.get(handlerIdentifier);
6410 ASSERT(handler);
6411
6412 handler->taskDidReceiveData(taskIdentifier, data.size(), data.data());
6413}
6414
6415void WebPage::urlSchemeTaskDidComplete(uint64_t handlerIdentifier, uint64_t taskIdentifier, const ResourceError& error)
6416{
6417 auto* handler = m_identifierToURLSchemeHandlerProxyMap.get(handlerIdentifier);
6418 ASSERT(handler);
6419
6420 handler->taskDidComplete(taskIdentifier, error);
6421}
6422
6423void WebPage::setIsSuspended(bool suspended)
6424{
6425 if (m_isSuspended == suspended)
6426 return;
6427
6428 m_isSuspended = suspended;
6429
6430 if (!suspended)
6431 return;
6432
6433 // Unfrozen on drawing area reset.
6434 freezeLayerTree(LayerTreeFreezeReason::PageSuspended);
6435
6436 WebProcess::singleton().sendPrewarmInformation(mainWebFrame()->url());
6437
6438 suspendForProcessSwap();
6439}
6440
6441void WebPage::frameBecameRemote(uint64_t frameID, GlobalFrameIdentifier&& remoteFrameIdentifier, GlobalWindowIdentifier&& remoteWindowIdentifier)
6442{
6443 RefPtr<WebFrame> frame = WebProcess::singleton().webFrame(frameID);
6444 if (!frame)
6445 return;
6446
6447 if (frame->page() != this)
6448 return;
6449
6450 auto* coreFrame = frame->coreFrame();
6451 auto* previousWindow = coreFrame->window();
6452 if (!previousWindow)
6453 return;
6454
6455 auto remoteFrame = RemoteFrame::create(WTFMove(remoteFrameIdentifier));
6456 auto remoteWindow = RemoteDOMWindow::create(remoteFrame.copyRef(), WTFMove(remoteWindowIdentifier));
6457
6458 remoteFrame->setOpener(frame->coreFrame()->loader().opener());
6459
6460 auto jsWindowProxies = frame->coreFrame()->windowProxy().releaseJSWindowProxies();
6461 remoteFrame->windowProxy().setJSWindowProxies(WTFMove(jsWindowProxies));
6462 remoteFrame->windowProxy().setDOMWindow(remoteWindow.ptr());
6463
6464 coreFrame->setView(nullptr);
6465 coreFrame->willDetachPage();
6466 coreFrame->detachFromPage();
6467
6468 if (frame->isMainFrame())
6469 close();
6470}
6471
6472#if ENABLE(RESOURCE_LOAD_STATISTICS)
6473void WebPage::hasStorageAccess(RegistrableDomain&& subFrameDomain, RegistrableDomain&& topFrameDomain, uint64_t frameID, CompletionHandler<void(bool)>&& completionHandler)
6474{
6475 WebProcess::singleton().ensureNetworkProcessConnection().connection().sendWithAsyncReply(Messages::NetworkConnectionToWebProcess::HasStorageAccess(sessionID(), WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, m_pageID), WTFMove(completionHandler));
6476}
6477
6478void WebPage::requestStorageAccess(RegistrableDomain&& subFrameDomain, RegistrableDomain&& topFrameDomain, uint64_t frameID, CompletionHandler<void(WebCore::StorageAccessWasGranted, WebCore::StorageAccessPromptWasShown)>&& completionHandler)
6479{
6480 WebProcess::singleton().ensureNetworkProcessConnection().connection().sendWithAsyncReply(Messages::NetworkConnectionToWebProcess::RequestStorageAccess(sessionID(), WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, m_pageID), WTFMove(completionHandler));
6481}
6482#endif
6483
6484#if ENABLE(DEVICE_ORIENTATION)
6485void WebPage::shouldAllowDeviceOrientationAndMotionAccess(uint64_t frameID, WebCore::SecurityOriginData&& origin, bool mayPrompt, CompletionHandler<void(DeviceOrientationOrMotionPermissionState)>&& completionHandler)
6486{
6487 sendWithAsyncReply(Messages::WebPageProxy::ShouldAllowDeviceOrientationAndMotionAccess(frameID, WTFMove(origin), mayPrompt), WTFMove(completionHandler));
6488}
6489#endif
6490
6491static ShareSheetCallbackID nextShareSheetCallbackID()
6492{
6493 static ShareSheetCallbackID nextCallbackID = 0;
6494 return ++nextCallbackID;
6495}
6496
6497void WebPage::showShareSheet(ShareDataWithParsedURL& shareData, WTF::CompletionHandler<void(bool)>&& callback)
6498{
6499 ShareSheetCallbackID callbackID = nextShareSheetCallbackID();
6500 auto addResult = m_shareSheetResponseCallbackMap.add(callbackID, WTFMove(callback));
6501 ASSERT(addResult.isNewEntry);
6502 if (addResult.iterator->value)
6503 send(Messages::WebPageProxy::ShowShareSheet(WTFMove(shareData), callbackID));
6504 else
6505 callback(false);
6506}
6507
6508void WebPage::didCompleteShareSheet(bool wasGranted, ShareSheetCallbackID callbackID)
6509{
6510 auto callback = m_shareSheetResponseCallbackMap.take(callbackID);
6511 callback(wasGranted);
6512}
6513
6514WebCore::DOMPasteAccessResponse WebPage::requestDOMPasteAccess(const String& originIdentifier)
6515{
6516 auto response = WebCore::DOMPasteAccessResponse::DeniedForGesture;
6517#if PLATFORM(IOS_FAMILY)
6518 // FIXME: Computing and sending an autocorrection context is a workaround for the fact that autocorrection context
6519 // requests on iOS are currently synchronous in the web process. This allows us to immediately fulfill pending
6520 // autocorrection context requests in the UI process on iOS before handling the DOM paste request. This workaround
6521 // should be removed once <rdar://problem/16207002> is resolved.
6522 send(Messages::WebPageProxy::HandleAutocorrectionContext(autocorrectionContext()));
6523#endif
6524 sendSyncWithDelayedReply(Messages::WebPageProxy::RequestDOMPasteAccess(rectForElementAtInteractionLocation(), originIdentifier), Messages::WebPageProxy::RequestDOMPasteAccess::Reply(response));
6525 return response;
6526}
6527
6528void WebPage::simulateDeviceOrientationChange(double alpha, double beta, double gamma)
6529{
6530#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY)
6531 auto* frame = mainFrame();
6532 if (!frame || !frame->document())
6533 return;
6534
6535 frame->document()->simulateDeviceOrientationChange(alpha, beta, gamma);
6536#endif
6537}
6538
6539#if ENABLE(SPEECH_SYNTHESIS)
6540void WebPage::speakingErrorOccurred()
6541{
6542 corePage()->speechSynthesisClient()->observer()->speakingErrorOccurred();
6543}
6544
6545void WebPage::boundaryEventOccurred(bool wordBoundary, unsigned charIndex)
6546{
6547 corePage()->speechSynthesisClient()->observer()->boundaryEventOccurred(wordBoundary, charIndex);
6548}
6549
6550void WebPage::voicesDidChange()
6551{
6552 corePage()->speechSynthesisClient()->observer()->voicesChanged();
6553}
6554#endif
6555
6556#if ENABLE(ATTACHMENT_ELEMENT)
6557
6558void WebPage::insertAttachment(const String& identifier, Optional<uint64_t>&& fileSize, const String& fileName, const String& contentType, CallbackID callbackID)
6559{
6560 auto& frame = m_page->focusController().focusedOrMainFrame();
6561 frame.editor().insertAttachment(identifier, WTFMove(fileSize), fileName, contentType);
6562 send(Messages::WebPageProxy::VoidCallback(callbackID));
6563}
6564
6565void WebPage::updateAttachmentAttributes(const String& identifier, Optional<uint64_t>&& fileSize, const String& contentType, const String& fileName, const IPC::DataReference& enclosingImageData, CallbackID callbackID)
6566{
6567 if (auto attachment = attachmentElementWithIdentifier(identifier)) {
6568 attachment->document().updateLayout();
6569 attachment->updateAttributes(WTFMove(fileSize), contentType, fileName);
6570 attachment->updateEnclosingImageWithData(contentType, SharedBuffer::create(enclosingImageData.data(), enclosingImageData.size()));
6571 }
6572 send(Messages::WebPageProxy::VoidCallback(callbackID));
6573}
6574
6575RefPtr<HTMLAttachmentElement> WebPage::attachmentElementWithIdentifier(const String& identifier) const
6576{
6577 // FIXME: Handle attachment elements in subframes too as well.
6578 auto* frame = mainFrame();
6579 if (!frame || !frame->document())
6580 return nullptr;
6581
6582 return frame->document()->attachmentForIdentifier(identifier);
6583}
6584
6585#endif // ENABLE(ATTACHMENT_ELEMENT)
6586
6587#if ENABLE(APPLICATION_MANIFEST)
6588void WebPage::getApplicationManifest(CallbackID callbackID)
6589{
6590 ASSERT(callbackID.isValid());
6591 Document* mainFrameDocument = m_mainFrame->coreFrame()->document();
6592 DocumentLoader* loader = mainFrameDocument ? mainFrameDocument->loader() : nullptr;
6593
6594 if (!loader) {
6595 send(Messages::WebPageProxy::ApplicationManifestCallback(WTF::nullopt, callbackID));
6596 return;
6597 }
6598
6599 auto coreCallbackID = loader->loadApplicationManifest();
6600 if (!coreCallbackID) {
6601 send(Messages::WebPageProxy::ApplicationManifestCallback(WTF::nullopt, callbackID));
6602 return;
6603 }
6604
6605 m_applicationManifestFetchCallbackMap.add(coreCallbackID, callbackID.toInteger());
6606}
6607
6608void WebPage::didFinishLoadingApplicationManifest(uint64_t coreCallbackID, const Optional<WebCore::ApplicationManifest>& manifest)
6609{
6610 auto callbackID = CallbackID::fromInteger(m_applicationManifestFetchCallbackMap.take(coreCallbackID));
6611 send(Messages::WebPageProxy::ApplicationManifestCallback(manifest, callbackID));
6612}
6613#endif // ENABLE(APPLICATION_MANIFEST)
6614
6615void WebPage::updateCurrentModifierState(OptionSet<PlatformEvent::Modifier> modifiers)
6616{
6617 PlatformKeyboardEvent::setCurrentModifierState(modifiers);
6618}
6619
6620#if !PLATFORM(IOS_FAMILY)
6621
6622WebCore::IntRect WebPage::rectForElementAtInteractionLocation() const
6623{
6624 return { };
6625}
6626
6627#endif // !PLATFORM(IOS_FAMILY)
6628
6629static IntRect elementRectInRootViewCoordinates(const Element& element, const Frame& frame)
6630{
6631 auto* view = frame.view();
6632 if (!view)
6633 return { };
6634
6635 auto* renderer = element.renderer();
6636 if (!renderer)
6637 return { };
6638
6639 return view->contentsToRootView(renderer->absoluteBoundingBoxRect());
6640}
6641
6642static bool isEditableTextInputElement(Element& element)
6643{
6644 if (is<HTMLTextFormControlElement>(element)) {
6645 if (!element.isTextField() && !is<HTMLTextAreaElement>(element))
6646 return false;
6647 return downcast<HTMLTextFormControlElement>(element).isInnerTextElementEditable();
6648 }
6649
6650 return element.isRootEditableElement();
6651}
6652
6653void WebPage::textInputContextsInRect(WebCore::FloatRect searchRect, CompletionHandler<void(const Vector<TextInputContext>&)>&& completionHandler)
6654{
6655 Vector<WebKit::TextInputContext> textInputContexts;
6656
6657 for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
6658 Document* document = frame->document();
6659 if (!document)
6660 continue;
6661
6662 Deque<Node*> nodesToSearch;
6663 nodesToSearch.append(document);
6664 while (!nodesToSearch.isEmpty()) {
6665 auto node = nodesToSearch.takeFirst();
6666
6667 // It is possible to have nested text input contexts (e.g. <input type='text'> inside contenteditable) but
6668 // in this case we just take the outermost context and skip the rest.
6669 if (!is<Element>(*node) || !isEditableTextInputElement(downcast<Element>(*node))) {
6670 for (auto* child = node->firstChild(); child; child = child->nextSibling())
6671 nodesToSearch.append(child);
6672 continue;
6673 }
6674
6675 auto& element = downcast<Element>(*node);
6676
6677 IntRect elementRect = elementRectInRootViewCoordinates(element, *frame);
6678 if (!searchRect.intersects(elementRect))
6679 continue;
6680
6681 WebKit::TextInputContext context;
6682 context.webPageIdentifier = m_pageID;
6683 context.documentIdentifier = document->identifier();
6684 context.elementIdentifier = document->identifierForElement(element);
6685 context.boundingRect = elementRect;
6686
6687 textInputContexts.append(context);
6688 }
6689 }
6690
6691 completionHandler(textInputContexts);
6692}
6693
6694void WebPage::focusTextInputContext(const TextInputContext& textInputContext, CompletionHandler<void(bool)>&& completionHandler)
6695{
6696 RefPtr<Element> element = elementForTextInputContext(textInputContext);
6697
6698 if (element)
6699 element->focus();
6700
6701 completionHandler(element);
6702}
6703
6704Element* WebPage::elementForTextInputContext(const TextInputContext& textInputContext)
6705{
6706 if (textInputContext.webPageIdentifier != m_pageID)
6707 return nullptr;
6708
6709 auto* document = Document::allDocumentsMap().get(textInputContext.documentIdentifier);
6710 if (!document)
6711 return nullptr;
6712
6713 if (document->page() != m_page.get())
6714 return nullptr;
6715
6716 return document->searchForElementByIdentifier(textInputContext.elementIdentifier);
6717}
6718
6719void WebPage::configureLoggingChannel(const String& channelName, WTFLogChannelState state, WTFLogLevel level)
6720{
6721 send(Messages::WebPageProxy::ConfigureLoggingChannel(channelName, state, level));
6722}
6723
6724} // namespace WebKit
6725
6726#undef RELEASE_LOG_IF_ALLOWED
6727#undef RELEASE_LOG_ERROR_IF_ALLOWED
6728