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