blob: 57c6e71cc244de55ba9230753464b0b343129d6e [file]
/*
* Copyright (C) 2010-2025 Apple Inc. All rights reserved.
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WebChromeClient.h"
#include "APIArray.h"
#include "APIDictionary.h"
#include "APIInjectedBundleFormClient.h"
#include "APIInjectedBundlePageUIClient.h"
#include "APINumber.h"
#include "APIObject.h"
#include "APISecurityOrigin.h"
#include "APIString.h"
#include "DrawingArea.h"
#include "FindController.h"
#include "FrameInfoData.h"
#include "HangDetectionDisabler.h"
#include "ImageBufferShareableBitmapBackend.h"
#include "InjectedBundleNodeHandle.h"
#include "MessageSenderInlines.h"
#include "ModelDowncastConvertToBackingContext.h"
#include "NavigationActionData.h"
#include "NetworkConnectionToWebProcessMessages.h"
#include "NetworkProcessConnection.h"
#include "PageBanner.h"
#include "PluginView.h"
#include "RemoteBarcodeDetectorProxy.h"
#include "RemoteFaceDetectorProxy.h"
#include "RemoteGPUProxy.h"
#include "RemoteImageBufferProxy.h"
#include "RemoteRenderingBackendProxy.h"
#include "RemoteTextDetectorProxy.h"
#include "SharedBufferReference.h"
#include "UserData.h"
#include "WebColorChooser.h"
#include "WebDataListSuggestionPicker.h"
#include "WebDateTimeChooser.h"
#include "WebFrame.h"
#include "WebFullScreenManager.h"
#include "WebGPUDowncastConvertToBackingContext.h"
#include "WebHitTestResultData.h"
#include "WebImage.h"
#include "WebLocalFrameLoaderClient.h"
#include "WebOpenPanelResultListener.h"
#include "WebPage.h"
#include "WebPageCreationParameters.h"
#include "WebPageProxyMessages.h"
#include "WebPopupMenu.h"
#include "WebProcess.h"
#include "WebProcessPoolMessages.h"
#include "WebProcessProxyMessages.h"
#include "WebSearchPopupMenu.h"
#include "WebWorkerClient.h"
#include <WebCore/AXObjectCache.h>
#include <WebCore/AppHighlight.h>
#include <WebCore/BarcodeDetectorInterface.h>
#include <WebCore/ColorChooser.h>
#include <WebCore/ColorChooserClient.h>
#include <WebCore/ContentRuleListMatchedRule.h>
#include <WebCore/ContentRuleListResults.h>
#include <WebCore/CookieConsentDecisionResult.h>
#include <WebCore/DataListSuggestionPicker.h>
#include <WebCore/DatabaseTracker.h>
#include <WebCore/DocumentFullscreen.h>
#include <WebCore/DocumentLoader.h>
#include <WebCore/DocumentPage.h>
#include <WebCore/DocumentStorageAccess.h>
#include <WebCore/DocumentView.h>
#include <WebCore/ElementInlines.h>
#include <WebCore/FaceDetectorInterface.h>
#include <WebCore/FileChooser.h>
#include <WebCore/FileIconLoader.h>
#include <WebCore/FocusController.h>
#include <WebCore/FocusControllerTypes.h>
#include <WebCore/FocusOptions.h>
#include <WebCore/Frame.h>
#include <WebCore/FrameDestructionObserverInlines.h>
#include <WebCore/FrameLoader.h>
#include <WebCore/HTMLInputElement.h>
#include <WebCore/HTMLMediaElement.h>
#include <WebCore/HTMLNames.h>
#include <WebCore/HTMLParserIdioms.h>
#include <WebCore/HTMLPlugInElement.h>
#include <WebCore/Icon.h>
#include <WebCore/ImageBuffer.h>
#include <WebCore/LocalFrameInlines.h>
#include <WebCore/LocalFrameView.h>
#include <WebCore/NotImplemented.h>
#include <WebCore/PointerLockController.h>
#include <WebCore/PopupMenuClient.h>
#include <WebCore/RegistrableDomain.h>
#include <WebCore/ScriptController.h>
#include <WebCore/SecurityOrigin.h>
#include <WebCore/SecurityOriginData.h>
#include <WebCore/Settings.h>
#include <WebCore/SystemPreviewInfo.h>
#include <WebCore/TextDetectorInterface.h>
#include <WebCore/TextIndicator.h>
#include <WebCore/TextRecognitionOptions.h>
#include <WebCore/ViewportConfiguration.h>
#include <WebCore/WindowFeatures.h>
#include <wtf/JSONValues.h>
#include <wtf/TZoneMallocInlines.h>
#if HAVE(WEBGPU_IMPLEMENTATION)
#import <WebCore/WebGPUCreateImpl.h>
#endif
#if HAVE(SHAPE_DETECTION_API_IMPLEMENTATION)
#import <WebCore/BarcodeDetectorImplementation.h>
#import <WebCore/FaceDetectorImplementation.h>
#import <WebCore/TextDetectorImplementation.h>
#endif
#if ENABLE(APPLE_PAY_AMS_UI)
#include <WebCore/ApplePayAMSUIRequest.h>
#endif
#if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
#include "PlaybackSessionManager.h"
#endif
#if ENABLE(VIDEO_PRESENTATION_MODE)
#include "VideoPresentationManager.h"
#endif
#if ENABLE(ASYNC_SCROLLING)
#include "RemoteScrollingCoordinator.h"
#endif
#if ENABLE(WEB_AUTHN)
#include <WebCore/MockWebAuthenticationConfiguration.h>
#endif
#if ENABLE(WEBGL) && ENABLE(GPU_PROCESS)
#include "RemoteGraphicsContextGLProxy.h"
#endif
#if ENABLE(WEBGL)
#include <WebCore/GraphicsContextGL.h>
#endif
#if ENABLE(WEBXR)
#include "PlatformXRSystemProxy.h"
#endif
#if PLATFORM(MAC)
#include "TiledCoreAnimationScrollingCoordinator.h"
#endif
#if USE(COORDINATED_GRAPHICS)
#include "ScrollingCoordinatorCoordinated.h"
#endif
#if PLATFORM(COCOA)
#include "WebIconUtilities.h"
#endif
#if PLATFORM(MAC)
#include "RemoteScrollbarsController.h"
#endif
#if PLATFORM(MAC) || USE(COORDINATED_GRAPHICS_ASYNC_SCROLLBAR)
#include <WebCore/ScrollbarsControllerMock.h>
#endif
#if USE(COORDINATED_GRAPHICS_ASYNC_SCROLLBAR)
#include "ScrollbarsControllerCoordinated.h"
#endif
#if ENABLE(DAMAGE_TRACKING)
#include <WebCore/Damage.h>
#endif
#if ENABLE(VIDEO)
#include <WebCore/HTMLMediaElement.h>
#endif
namespace WebKit {
using namespace WebCore;
using namespace HTMLNames;
AXRelayProcessSuspendedNotification::AXRelayProcessSuspendedNotification(WebPage& page, AutomaticallySend automaticallySend)
: m_page(page)
, m_automaticallySend(automaticallySend)
{
if (m_automaticallySend == AutomaticallySend::Yes)
sendProcessSuspendMessage(true);
}
AXRelayProcessSuspendedNotification::~AXRelayProcessSuspendedNotification()
{
if (m_automaticallySend == AutomaticallySend::Yes)
sendProcessSuspendMessage(false);
}
#if !PLATFORM(COCOA)
void AXRelayProcessSuspendedNotification::sendProcessSuspendMessage(bool) { }
#endif
WTF_MAKE_TZONE_ALLOCATED_IMPL(WebChromeClient);
WebChromeClient::WebChromeClient(WebPage& page)
: m_page(page)
{
}
WebChromeClient::~WebChromeClient() = default;
void WebChromeClient::chromeDestroyed()
{
}
void WebChromeClient::setWindowRect(const FloatRect& windowFrame)
{
if (RefPtr page = m_page.get())
page->sendSetWindowFrame(windowFrame);
}
FloatRect WebChromeClient::windowRect() const
{
#if PLATFORM(IOS_FAMILY)
return FloatRect();
#else
RefPtr page = m_page.get();
if (!page)
return { };
#if PLATFORM(MAC)
if (page->hasCachedWindowFrame())
return page->windowFrameInUnflippedScreenCoordinates();
#endif
auto sendResult = WebProcess::singleton().protectedParentProcessConnection()->sendSync(Messages::WebPageProxy::GetWindowFrame(), page->identifier());
auto [newWindowFrame] = sendResult.takeReplyOr(FloatRect { });
return newWindowFrame;
#endif
}
FloatRect WebChromeClient::pageRect() const
{
if (!m_page)
return { };
return FloatRect(FloatPoint(), m_page->size());
}
void WebChromeClient::focus()
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::SetFocus(true));
}
void WebChromeClient::unfocus()
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::SetFocus(false));
}
#if PLATFORM(COCOA)
void WebChromeClient::elementDidFocus(Element& element, const FocusOptions& options)
{
if (RefPtr page = m_page.get())
page->elementDidFocus(element, options);
}
void WebChromeClient::elementDidRefocus(Element& element, const FocusOptions& options)
{
if (RefPtr page = m_page.get())
page->elementDidRefocus(element, options);
}
void WebChromeClient::elementDidBlur(Element& element)
{
if (RefPtr page = m_page.get())
page->elementDidBlur(element);
}
void WebChromeClient::focusedElementDidChangeInputMode(Element& element, InputMode mode)
{
if (RefPtr page = m_page.get())
page->focusedElementDidChangeInputMode(element, mode);
}
void WebChromeClient::focusedSelectElementDidChangeOptions(const WebCore::HTMLSelectElement& element)
{
if (RefPtr page = m_page.get())
page->focusedSelectElementDidChangeOptions(element);
}
void WebChromeClient::makeFirstResponder()
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::MakeFirstResponder());
}
void WebChromeClient::assistiveTechnologyMakeFirstResponder()
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::AssistiveTechnologyMakeFirstResponder());
}
#endif
bool WebChromeClient::canTakeFocus(FocusDirection) const
{
notImplemented();
return true;
}
void WebChromeClient::takeFocus(FocusDirection direction)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::TakeFocus(direction));
}
void WebChromeClient::focusedElementChanged(Element* element, LocalFrame* frame, FocusOptions options, BroadcastFocusedElement broadcast)
{
RefPtr coreFrame = element ? element->document().frame() : frame;
RefPtr webFrame = coreFrame ? WebFrame::fromCoreFrame(*coreFrame) : nullptr;
RefPtr page = m_page.get();
if (page && broadcast == BroadcastFocusedElement::Yes)
WebProcess::singleton().protectedParentProcessConnection()->send(Messages::WebPageProxy::FocusedElementChanged(webFrame ? std::make_optional(webFrame->frameID()) : std::nullopt, options), page->identifier());
RefPtr inputElement = dynamicDowncast<HTMLInputElement>(element);
if (!inputElement || !inputElement->isText())
return;
ASSERT(webFrame);
if (page)
page->injectedBundleFormClient().didFocusTextField(page.get(), *inputElement, webFrame.get());
}
void WebChromeClient::focusedFrameChanged(Frame* frame)
{
if (!m_page)
return;
RefPtr webFrame = frame ? WebFrame::fromCoreFrame(*frame) : nullptr;
WebProcess::singleton().protectedParentProcessConnection()->send(Messages::WebPageProxy::FocusedFrameChanged(webFrame ? std::make_optional(webFrame->frameID()) : std::nullopt), m_page->identifier());
}
RefPtr<Page> WebChromeClient::createWindow(LocalFrame& frame, const String& openedMainFrameName, const WindowFeatures& windowFeatures, const NavigationAction& navigationAction)
{
#if ENABLE(FULLSCREEN_API)
if (RefPtr document = frame.document())
document->protectedFullscreen()->fullyExitFullscreen();
#endif
auto& webProcess = WebProcess::singleton();
auto& mouseEventData = navigationAction.mouseEventData();
RefPtr webFrame = WebFrame::fromCoreFrame(frame);
RefPtr page = m_page.get();
if (!page)
return nullptr;
auto& originalRequest = navigationAction.originalRequest();
NavigationActionData navigationActionData {
navigationAction.type(),
modifiersForNavigationAction(navigationAction),
mouseButton(navigationAction),
syntheticClickType(navigationAction),
webProcess.userGestureTokenIdentifier(navigationAction.requester()->pageID, navigationAction.userGestureToken()),
navigationAction.userGestureToken() ? navigationAction.userGestureToken()->authorizationToken() : std::nullopt,
page->canHandleRequest(navigationAction.originalRequest()),
navigationAction.shouldOpenExternalURLsPolicy(),
navigationAction.downloadAttribute(),
mouseEventData ? mouseEventData->locationInRootViewCoordinates : FloatPoint { },
{ }, /* redirectResponse */
navigationAction.isRequestFromClientOrUserInput(),
false, /* treatAsSameOriginNavigation */
false, /* hasOpenedFrames */
false, /* openedByDOMWithOpener */
navigationAction.newFrameOpenerPolicy() == NewFrameOpenerPolicy::Allow, /* hasOpener */
frame.loader().navigationUpgradeToHTTPSBehavior(),
navigationAction.isInitialFrameSrcLoad(),
navigationAction.isContentRuleListRedirect(),
openedMainFrameName,
std::nullopt, /* targetBackForwardItemIdentifier */
std::nullopt, /* sourceBackForwardItemIdentifier */
WebCore::LockHistory::No,
WebCore::LockBackForwardList::No,
{ }, /* clientRedirectSourceForHistory */
frame.effectiveSandboxFlags(),
frame.document()->referrerPolicy(),
std::nullopt, /* ownerPermissionsPolicy */
navigationAction.privateClickMeasurement(),
{ }, /* advancedPrivacyProtections */
{ }, /* originatorAdvancedPrivacyProtections */
#if PLATFORM(MAC) || HAVE(UIKIT_WITH_MOUSE_SUPPORT)
std::nullopt, /* webHitTestResultData */
#endif
webFrame->info(), /* originatingFrameInfoData */
webFrame->page()->webPageProxyIdentifier(),
webFrame->info(), /* frameInfo */
std::nullopt, /* navigationID */
originalRequest, /* originalRequest */
originalRequest, /* request */
originalRequest.url().isValid() ? String() : originalRequest.url().string(), /* invalidURLString */
navigationAction.requester(), /* requester */
};
auto sendResult = webProcess.protectedParentProcessConnection()->sendSync(Messages::WebPageProxy::CreateNewPage(windowFeatures, navigationActionData), page->identifier(), IPC::Timeout::infinity(), { IPC::SendSyncOption::MaintainOrderingWithAsyncMessages });
if (!sendResult.succeeded())
return nullptr;
auto [newPageID, parameters] = sendResult.takeReply();
if (!newPageID)
return nullptr;
ASSERT(parameters);
parameters->oldPageID = page->identifier();
webProcess.createWebPage(*newPageID, WTF::move(*parameters));
return webProcess.webPage(*newPageID)->corePage();
}
bool WebChromeClient::testProcessIncomingSyncMessagesWhenWaitingForSyncReply()
{
if (!m_page)
return false;
IPC::UnboundedSynchronousIPCScope unboundedSynchronousIPCScope;
auto sendResult = WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::TestProcessIncomingSyncMessagesWhenWaitingForSyncReply(m_page->webPageProxyIdentifier()), 0);
auto [handled] = sendResult.takeReplyOr(false);
return handled;
}
void WebChromeClient::show()
{
if (RefPtr page = m_page.get())
page->show();
}
bool WebChromeClient::canRunModal() const
{
RefPtr page = m_page.get();
return page && page->canRunModal();
}
void WebChromeClient::runModal()
{
if (RefPtr page = m_page.get())
page->runModal();
}
void WebChromeClient::reportProcessCPUTime(Seconds cpuTime, ActivityStateForCPUSampling activityState)
{
WebProcess::singleton().send(Messages::WebProcessPool::ReportWebContentCPUTime(cpuTime, static_cast<uint64_t>(activityState)), 0);
}
bool WebChromeClient::toolbarsVisible() const
{
RefPtr page = m_page.get();
if (!page)
return false;
return page->toolbarsAreVisible();
}
bool WebChromeClient::statusbarVisible() const
{
RefPtr page = m_page.get();
if (!page)
return false;
return page->statusBarIsVisible();
}
bool WebChromeClient::scrollbarsVisible() const
{
notImplemented();
return true;
}
bool WebChromeClient::menubarVisible() const
{
RefPtr page = m_page.get();
if (!page)
return false;
return page->menuBarIsVisible();
}
void WebChromeClient::setResizable(bool resizable)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::SetIsResizable(resizable));
}
void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, unsigned columnNumber, const String& sourceID)
{
RefPtr page = m_page.get();
if (!page)
return;
#if !PLATFORM(COCOA)
page->injectedBundleUIClient().willAddMessageToConsole(page.get(), source, level, message, lineNumber, columnNumber, sourceID);
#endif
if (!page->shouldSendConsoleLogsToUIProcessForTesting())
return;
page->send(Messages::WebPageProxy::AddMessageToConsoleForTesting(message.length() > String::MaxLength / 2 ? "Out of memory"_s : message), IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply);
}
bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
{
RefPtr page = m_page.get();
return page && page->canRunBeforeUnloadConfirmPanel();
}
bool WebChromeClient::runBeforeUnloadConfirmPanel(String&& message, LocalFrame& frame)
{
auto webFrame = WebFrame::fromCoreFrame(frame);
HangDetectionDisabler hangDetectionDisabler;
RefPtr page = m_page.get();
if (!page)
return false;
auto relay = AXRelayProcessSuspendedNotification(*page);
auto sendResult = page->sendSyncWithDelayedReply(Messages::WebPageProxy::RunBeforeUnloadConfirmPanel(webFrame->frameID(), webFrame->info(), WTF::move(message)));
auto [shouldClose] = sendResult.takeReplyOr(false);
return shouldClose;
}
void WebChromeClient::closeWindow()
{
// FIXME: This code assumes that the client will respond to a close page
// message by actually closing the page. Safari does this, but there is
// no guarantee that other applications will, which will leave this page
// half detached. This approach is an inherent limitation making parts of
// a close execute synchronously as part of window.close, but other parts
// later on.
RefPtr page = m_page.get();
if (!page)
return;
page->protectedCorePage()->setGroupName(String());
Ref frame = page->mainWebFrame();
if (RefPtr coreFrame = frame->coreLocalFrame())
coreFrame->loader().stopForUserCancel();
page->sendClose();
}
void WebChromeClient::rootFrameAdded(const WebCore::LocalFrame& frame)
{
if (!m_page)
return;
if (RefPtr drawingArea = m_page->drawingArea())
drawingArea->addRootFrame(frame.frameID());
}
void WebChromeClient::rootFrameRemoved(const WebCore::LocalFrame& frame)
{
if (!m_page)
return;
if (RefPtr drawingArea = m_page->drawingArea())
drawingArea->removeRootFrame(frame.frameID());
}
static bool shouldSuppressJavaScriptDialogs(LocalFrame& frame)
{
if (frame.opener() && frame.loader().stateMachine().isDisplayingInitialEmptyDocument() && frame.loader().provisionalDocumentLoader())
return true;
return false;
}
void WebChromeClient::runJavaScriptAlert(LocalFrame& frame, const String& alertText)
{
if (shouldSuppressJavaScriptDialogs(frame))
return;
auto webFrame = WebFrame::fromCoreFrame(frame);
ASSERT(webFrame);
// Notify the bundle client.
RefPtr page = m_page.get();
if (!page)
return;
page->prepareToRunModalJavaScriptDialog();
HangDetectionDisabler hangDetectionDisabler;
IPC::UnboundedSynchronousIPCScope unboundedSynchronousIPCScope;
auto relay = AXRelayProcessSuspendedNotification(*page);
page->sendSyncWithDelayedReply(Messages::WebPageProxy::RunJavaScriptAlert(webFrame->frameID(), webFrame->info(), alertText), { IPC::SendSyncOption::MaintainOrderingWithAsyncMessages });
}
bool WebChromeClient::runJavaScriptConfirm(LocalFrame& frame, const String& message)
{
if (shouldSuppressJavaScriptDialogs(frame))
return false;
auto webFrame = WebFrame::fromCoreFrame(frame);
ASSERT(webFrame);
// Notify the bundle client.
RefPtr page = m_page.get();
if (!page)
return false;
page->prepareToRunModalJavaScriptDialog();
HangDetectionDisabler hangDetectionDisabler;
IPC::UnboundedSynchronousIPCScope unboundedSynchronousIPCScope;
auto relay = AXRelayProcessSuspendedNotification(*page);
auto sendResult = page->sendSyncWithDelayedReply(Messages::WebPageProxy::RunJavaScriptConfirm(webFrame->frameID(), webFrame->info(), message), { IPC::SendSyncOption::MaintainOrderingWithAsyncMessages });
auto [result] = sendResult.takeReplyOr(false);
return result;
}
bool WebChromeClient::runJavaScriptPrompt(LocalFrame& frame, const String& message, const String& defaultValue, String& result)
{
if (shouldSuppressJavaScriptDialogs(frame))
return false;
auto webFrame = WebFrame::fromCoreFrame(frame);
ASSERT(webFrame);
// Notify the bundle client.
RefPtr page = m_page.get();
if (!page)
return false;
page->prepareToRunModalJavaScriptDialog();
HangDetectionDisabler hangDetectionDisabler;
IPC::UnboundedSynchronousIPCScope unboundedSynchronousIPCScope;
auto relay = AXRelayProcessSuspendedNotification(*page);
auto sendResult = page->sendSyncWithDelayedReply(Messages::WebPageProxy::RunJavaScriptPrompt(webFrame->frameID(), webFrame->info(), message, defaultValue), { IPC::SendSyncOption::MaintainOrderingWithAsyncMessages });
if (!sendResult.succeeded())
return false;
std::tie(result) = sendResult.takeReply();
return !result.isNull();
}
KeyboardUIMode WebChromeClient::keyboardUIMode()
{
RefPtr page = m_page.get();
return page ? page->keyboardUIMode() : KeyboardAccessDefault;
}
bool WebChromeClient::hasAccessoryMousePointingDevice() const
{
RefPtr page = m_page.get();
return page && page->hasAccessoryMousePointingDevice();
}
bool WebChromeClient::hoverSupportedByPrimaryPointingDevice() const
{
RefPtr page = m_page.get();
return page && page->hoverSupportedByPrimaryPointingDevice();
}
bool WebChromeClient::hoverSupportedByAnyAvailablePointingDevice() const
{
RefPtr page = m_page.get();
return page && page->hoverSupportedByAnyAvailablePointingDevice();
}
std::optional<PointerCharacteristics> WebChromeClient::pointerCharacteristicsOfPrimaryPointingDevice() const
{
RefPtr page = m_page.get();
return page ? page->pointerCharacteristicsOfPrimaryPointingDevice() : std::nullopt;
}
OptionSet<PointerCharacteristics> WebChromeClient::pointerCharacteristicsOfAllAvailablePointingDevices() const
{
RefPtr page = m_page.get();
if (!page)
return { };
return page->pointerCharacteristicsOfAllAvailablePointingDevices();
}
#if ENABLE(POINTER_LOCK)
void WebChromeClient::requestPointerLock(CompletionHandler<void(WebCore::PointerLockRequestResult)>&& completionHandler)
{
RefPtr page = m_page.get();
if (!page) {
completionHandler(WebCore::PointerLockRequestResult::Failure);
return;
}
page->sendWithAsyncReply(Messages::WebPageProxy::RequestPointerLock(), [completionHandler = WTF::move(completionHandler)](bool result) mutable {
if (result)
completionHandler(WebCore::PointerLockRequestResult::Success);
else
completionHandler(WebCore::PointerLockRequestResult::Failure);
});
}
void WebChromeClient::requestPointerUnlock(CompletionHandler<void(bool)>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->sendWithAsyncReply(Messages::WebPageProxy::RequestPointerUnlock(), WTF::move(completionHandler));
else
completionHandler(false);
}
#endif
void WebChromeClient::invalidateRootView(const IntRect&)
{
// Do nothing here, there's no concept of invalidating the window in the web process.
}
void WebChromeClient::invalidateContentsAndRootView(const IntRect& rect)
{
RefPtr page = m_page.get();
if (!page)
return;
RefPtr corePage = page->corePage();
if (!corePage)
return;
if (RefPtr document = corePage->localTopDocument()) {
if (document->printing())
return;
}
page->protectedDrawingArea()->setNeedsDisplayInRect(rect);
}
void WebChromeClient::invalidateContentsForSlowScroll(const IntRect& rect)
{
RefPtr page = m_page.get();
if (!page)
return;
RefPtr corePage = page->corePage();
if (!corePage)
return;
if (RefPtr document = corePage->localTopDocument()) {
if (document->printing())
return;
}
page->pageDidScroll();
page->protectedDrawingArea()->setNeedsDisplayInRect(rect);
}
void WebChromeClient::scroll(const IntSize& scrollDelta, const IntRect& scrollRect, const IntRect& clipRect)
{
RefPtr page = m_page.get();
if (!page)
return;
page->pageDidScroll();
page->protectedDrawingArea()->scroll(intersection(scrollRect, clipRect), scrollDelta);
}
IntPoint WebChromeClient::screenToRootView(const IntPoint& point) const
{
RefPtr page = m_page.get();
return page ? page->screenToRootView(point) : IntPoint();
}
IntPoint WebChromeClient::rootViewToScreen(const IntPoint& point) const
{
RefPtr page = m_page.get();
return page ? page->rootViewToScreen(point) : IntPoint();
}
IntRect WebChromeClient::rootViewToScreen(const IntRect& rect) const
{
RefPtr page = m_page.get();
return page ? page->rootViewToScreen(rect) : IntRect();
}
IntPoint WebChromeClient::accessibilityScreenToRootView(const IntPoint& point) const
{
RefPtr page = m_page.get();
return page ? page->accessibilityScreenToRootView(point) : IntPoint();
}
IntRect WebChromeClient::rootViewToAccessibilityScreen(const IntRect& rect) const
{
RefPtr page = m_page.get();
return page ? page->rootViewToAccessibilityScreen(rect) : IntRect();
}
void WebChromeClient::mainFrameDidChange()
{
if (RefPtr page = m_page.get())
page->platformReinitializeAccessibilityToken();
}
void WebChromeClient::didFinishLoadingImageForElement(HTMLImageElement& element)
{
if (RefPtr page = m_page.get())
page->didFinishLoadingImageForElement(element);
}
#if ENABLE(MODEL_PROCESS)
void WebChromeClient::setHasModelElement(bool hasModelElement)
{
if (RefPtr page = m_page.get())
page->setHasModelElement(hasModelElement);
}
#endif
PlatformPageClient WebChromeClient::platformPageClient() const
{
notImplemented();
return 0;
}
void WebChromeClient::intrinsicContentsSizeChanged(const IntSize& size) const
{
if (RefPtr page = m_page.get())
page->scheduleIntrinsicContentSizeUpdate(size);
}
void WebChromeClient::contentsSizeChanged(LocalFrame& frame, const IntSize& size) const
{
RefPtr frameView = frame.view();
if (&frame.page()->mainFrame() != &frame)
return;
RefPtr page = m_page.get();
if (!page)
return;
page->send(Messages::WebPageProxy::DidChangeContentSize(size));
page->protectedDrawingArea()->mainFrameContentSizeChanged(frame.frameID(), size);
if (frameView && !frameView->delegatesScrollingToNativeView()) {
bool hasHorizontalScrollbar = frameView->horizontalScrollbar();
bool hasVerticalScrollbar = frameView->verticalScrollbar();
if (hasHorizontalScrollbar != m_cachedMainFrameHasHorizontalScrollbar || hasVerticalScrollbar != m_cachedMainFrameHasVerticalScrollbar) {
page->send(Messages::WebPageProxy::DidChangeScrollbarsForMainFrame(hasHorizontalScrollbar, hasVerticalScrollbar));
m_cachedMainFrameHasHorizontalScrollbar = hasHorizontalScrollbar;
m_cachedMainFrameHasVerticalScrollbar = hasVerticalScrollbar;
}
}
}
void WebChromeClient::scrollMainFrameToRevealRect(const IntRect& rect) const
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::RequestScrollToRect(rect, rect.center()));
}
void WebChromeClient::scrollContainingScrollViewsToRevealRect(const IntRect&) const
{
notImplemented();
}
bool WebChromeClient::shouldUnavailablePluginMessageBeButton(PluginUnavailabilityReason pluginUnavailabilityReason) const
{
switch (pluginUnavailabilityReason) {
case PluginUnavailabilityReason::PluginMissing:
// FIXME: <rdar://problem/8794397> We should only return true when there is a
// missingPluginButtonClicked callback defined on the Page UI client.
case PluginUnavailabilityReason::InsecurePluginVersion:
return true;
case PluginUnavailabilityReason::PluginCrashed:
case PluginUnavailabilityReason::PluginBlockedByContentSecurityPolicy:
case PluginUnavailabilityReason::UnsupportedPlugin:
case PluginUnavailabilityReason::PluginTooSmall:
return false;
}
ASSERT_NOT_REACHED();
return false;
}
void WebChromeClient::unavailablePluginButtonClicked(Element& element, PluginUnavailabilityReason pluginUnavailabilityReason) const
{
UNUSED_PARAM(element);
UNUSED_PARAM(pluginUnavailabilityReason);
}
void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& hitTestResult, OptionSet<WebCore::PlatformEventModifier> modifiers, const String& toolTip, TextDirection)
{
auto wkModifiers = modifiersFromPlatformEventModifiers(modifiers);
RefPtr page = m_page.get();
if (!page)
return;
// Notify the UIProcess.
WebHitTestResultData webHitTestResultData(hitTestResult, toolTip);
webHitTestResultData.elementBoundingBox = webHitTestResultData.elementBoundingBox.toRectWithExtentsClippedToNumericLimits();
page->send(Messages::WebPageProxy::MouseDidMoveOverElement(webHitTestResultData, wkModifiers));
}
void WebChromeClient::print(LocalFrame& frame, const StringWithDirection& title)
{
static constexpr unsigned maxTitleLength = 1000; // Closest power of 10 above the W3C recommendation for Title length.
auto webFrame = WebFrame::fromCoreFrame(frame);
ASSERT(webFrame);
WebCore::FloatSize pdfFirstPageSize;
#if ENABLE(PDF_PLUGIN)
if (RefPtr pluginView = WebPage::pluginViewForFrame(&frame))
pdfFirstPageSize = pluginView->pdfDocumentSizeForPrinting();
#endif
auto truncatedTitle = truncateFromEnd(title, maxTitleLength);
RefPtr page = m_page.get();
if (!page)
return;
auto relay = AXRelayProcessSuspendedNotification(*page);
IPC::UnboundedSynchronousIPCScope unboundedSynchronousIPCScope;
page->sendSyncWithDelayedReply(Messages::WebPageProxy::PrintFrame(webFrame->frameID(), truncatedTitle.string, pdfFirstPageSize));
}
RefPtr<ColorChooser> WebChromeClient::createColorChooser(ColorChooserClient& client, const Color& initialColor)
{
RefPtr page = m_page.get();
return WebColorChooser::create(page.get(), &client, initialColor);
}
RefPtr<DataListSuggestionPicker> WebChromeClient::createDataListSuggestionPicker(DataListSuggestionsClient& client)
{
RefPtr page = m_page.get();
if (!page)
return nullptr;
return WebDataListSuggestionPicker::create(page.releaseNonNull(), client);
}
bool WebChromeClient::canShowDataListSuggestionLabels() const
{
#if PLATFORM(MAC)
return true;
#else
return false;
#endif
}
RefPtr<DateTimeChooser> WebChromeClient::createDateTimeChooser(DateTimeChooserClient& client)
{
RefPtr page = m_page.get();
if (!page)
return nullptr;
return WebDateTimeChooser::create(page.releaseNonNull(), client);
}
void WebChromeClient::runOpenPanel(LocalFrame& frame, FileChooser& fileChooser)
{
RefPtr page = m_page.get();
if (!page || page->activeOpenPanelResultListener())
return;
page->setActiveOpenPanelResultListener(WebOpenPanelResultListener::create(*page, fileChooser));
auto webFrame = WebFrame::fromCoreFrame(frame);
ASSERT(webFrame);
page->send(Messages::WebPageProxy::RunOpenPanel(webFrame->frameID(), webFrame->info(), fileChooser.settings()));
}
void WebChromeClient::showShareSheet(ShareDataWithParsedURL&& shareData, CompletionHandler<void(bool)>&& callback)
{
if (RefPtr page = m_page.get())
page->showShareSheet(WTF::move(shareData), WTF::move(callback));
}
void WebChromeClient::showContactPicker(WebCore::ContactsRequestData&& requestData, WTF::CompletionHandler<void(std::optional<Vector<WebCore::ContactInfo>>&&)>&& callback)
{
if (RefPtr page = m_page.get())
page->showContactPicker(WTF::move(requestData), WTF::move(callback));
}
#if HAVE(DIGITAL_CREDENTIALS_UI)
void WebChromeClient::showDigitalCredentialsPicker(const WebCore::DigitalCredentialsRequestData& requestData, WTF::CompletionHandler<void(Expected<WebCore::DigitalCredentialsResponseData, WebCore::ExceptionData>&&)>&& callback)
{
if (RefPtr page = m_page.get())
page->showDigitalCredentialsPicker(requestData, WTF::move(callback));
}
void WebChromeClient::dismissDigitalCredentialsPicker(WTF::CompletionHandler<void(bool)>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->dismissDigitalCredentialsPicker(WTF::move(completionHandler));
}
#endif
void WebChromeClient::loadIconForFiles(const Vector<String>& filenames, FileIconLoader& loader)
{
loader.iconLoaded(createIconForFiles(filenames));
}
void WebChromeClient::setCursor(const Cursor& cursor)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::SetCursor(cursor));
}
void WebChromeClient::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::SetCursorHiddenUntilMouseMoves(hiddenUntilMouseMoves));
}
#if !PLATFORM(COCOA)
RefPtr<Icon> WebChromeClient::createIconForFiles(const Vector<String>& filenames)
{
return Icon::createIconForFiles(filenames);
}
#endif
void WebChromeClient::didAssociateFormControls(const Vector<Ref<Element>>& elements, WebCore::LocalFrame& frame)
{
auto webFrame = WebFrame::fromCoreFrame(frame);
ASSERT(webFrame);
if (RefPtr page = m_page.get())
page->injectedBundleFormClient().didAssociateFormControls(page.get(), elements, webFrame.get());
}
bool WebChromeClient::shouldNotifyOnFormChanges()
{
RefPtr page = m_page.get();
return page && page->injectedBundleFormClient().shouldNotifyOnFormChanges(page.get());
}
bool WebChromeClient::selectItemWritingDirectionIsNatural()
{
return false;
}
bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
{
return true;
}
RefPtr<PopupMenu> WebChromeClient::createPopupMenu(PopupMenuClient& client) const
{
RefPtr page = m_page.get();
return WebPopupMenu::create(page.get(), &client);
}
RefPtr<SearchPopupMenu> WebChromeClient::createSearchPopupMenu(PopupMenuClient& client) const
{
RefPtr page = m_page.get();
return WebSearchPopupMenu::create(page.get(), &client);
}
GraphicsLayerFactory* WebChromeClient::graphicsLayerFactory() const
{
RefPtr page = m_page.get();
if (!page)
return nullptr;
if (RefPtr drawingArea = page->drawingArea())
return drawingArea->graphicsLayerFactory();
return nullptr;
}
WebCore::DisplayRefreshMonitorFactory* WebChromeClient::displayRefreshMonitorFactory() const
{
return m_page ? m_page->drawingArea() : nullptr;
}
#if ENABLE(GPU_PROCESS)
RefPtr<ImageBuffer> WebChromeClient::createImageBuffer(const FloatSize& size, RenderingMode renderingMode, RenderingPurpose purpose, float resolutionScale, const DestinationColorSpace& colorSpace, ImageBufferFormat pixelFormat) const
{
if (WebProcess::singleton().shouldUseRemoteRenderingFor(purpose)) {
RefPtr page = m_page.get();
if (!page)
return nullptr;
return page->ensureProtectedRemoteRenderingBackendProxy()->createImageBuffer(size, renderingMode, purpose, resolutionScale, colorSpace, pixelFormat);
}
if (purpose == RenderingPurpose::ShareableSnapshot || purpose == RenderingPurpose::ShareableLocalSnapshot)
return ImageBuffer::create<ImageBufferShareableBitmapBackend>(size, resolutionScale, colorSpace, { PixelFormat::BGRA8 }, purpose, { });
return nullptr;
}
RefPtr<ImageBuffer> WebChromeClient::sinkIntoImageBuffer(std::unique_ptr<SerializedImageBuffer> imageBuffer)
{
if (!is<RemoteSerializedImageBufferProxy>(imageBuffer))
return SerializedImageBuffer::sinkIntoImageBuffer(WTF::move(imageBuffer));
RefPtr page = m_page.get();
if (!page)
return nullptr;
auto remote = std::unique_ptr<RemoteSerializedImageBufferProxy>(static_cast<RemoteSerializedImageBufferProxy*>(imageBuffer.release()));
return RemoteSerializedImageBufferProxy::sinkIntoImageBuffer(WTF::move(remote), page->ensureProtectedRemoteRenderingBackendProxy());
}
#endif
std::unique_ptr<WebCore::WorkerClient> WebChromeClient::createWorkerClient(SerialFunctionDispatcher& dispatcher)
{
RefPtr page = m_page.get();
if (!page)
return nullptr;
return WebWorkerClient::create(*page->protectedCorePage(), dispatcher).moveToUniquePtr();
}
#if ENABLE(WEBGL)
RefPtr<GraphicsContextGL> WebChromeClient::createGraphicsContextGL(const GraphicsContextGLAttributes& attributes) const
{
#if PLATFORM(GTK)
WebProcess::singleton().initializePlatformDisplayIfNeeded();
#endif
#if ENABLE(GPU_PROCESS)
if (WebProcess::singleton().shouldUseRemoteRenderingForWebGL()) {
RefPtr page = m_page.get();
if (!page)
return nullptr;
return RemoteGraphicsContextGLProxy::create(attributes, page.releaseNonNull());
}
#endif
return WebCore::createWebProcessGraphicsContextGL(attributes);
}
#endif
#if HAVE(WEBGPU_IMPLEMENTATION)
RefPtr<WebCore::WebGPU::GPU> WebChromeClient::createGPUForWebGPU() const
{
#if ENABLE(GPU_PROCESS)
RefPtr page = m_page.get();
if (!page)
return nullptr;
return RemoteGPUProxy::create(WebGPU::DowncastConvertToBackingContext::create(), DDModel::DowncastConvertToBackingContext::create(), page.releaseNonNull());
#else
return WebCore::WebGPU::create([](WebCore::WebGPU::WorkItem&& workItem) {
callOnMainRunLoop(WTF::move(workItem));
}, nullptr);
#endif
}
#endif
RefPtr<WebCore::ShapeDetection::BarcodeDetector> WebChromeClient::createBarcodeDetector(const WebCore::ShapeDetection::BarcodeDetectorOptions& barcodeDetectorOptions) const
{
#if ENABLE(GPU_PROCESS)
RefPtr page = m_page.get();
if (!page)
return nullptr;
Ref renderingBackend = page->ensureRemoteRenderingBackendProxy();
return renderingBackend->createBarcodeDetector(barcodeDetectorOptions);
#elif HAVE(SHAPE_DETECTION_API_IMPLEMENTATION)
return WebCore::ShapeDetection::BarcodeDetectorImpl::create(barcodeDetectorOptions);
#else
return nullptr;
#endif
}
void WebChromeClient::getBarcodeDetectorSupportedFormats(CompletionHandler<void(Vector<WebCore::ShapeDetection::BarcodeFormat>&&)>&& completionHandler) const
{
#if ENABLE(GPU_PROCESS)
RefPtr page = m_page.get();
if (!page) {
completionHandler({ });
return;
}
Ref renderingBackend = page->ensureRemoteRenderingBackendProxy();
renderingBackend->supportedBarcodeDetectorBarcodeFormats(WTF::move(completionHandler));
#elif HAVE(SHAPE_DETECTION_API_IMPLEMENTATION)
WebCore::ShapeDetection::BarcodeDetectorImpl::getSupportedFormats(WTF::move(completionHandler));
#else
completionHandler({ });
#endif
}
RefPtr<WebCore::ShapeDetection::FaceDetector> WebChromeClient::createFaceDetector(const WebCore::ShapeDetection::FaceDetectorOptions& faceDetectorOptions) const
{
#if ENABLE(GPU_PROCESS)
RefPtr page = m_page.get();
if (!page)
return nullptr;
Ref renderingBackend = page->ensureRemoteRenderingBackendProxy();
return renderingBackend->createFaceDetector(faceDetectorOptions);
#elif HAVE(SHAPE_DETECTION_API_IMPLEMENTATION)
return WebCore::ShapeDetection::FaceDetectorImpl::create(faceDetectorOptions);
#else
return nullptr;
#endif
}
RefPtr<WebCore::ShapeDetection::TextDetector> WebChromeClient::createTextDetector() const
{
#if ENABLE(GPU_PROCESS)
RefPtr page = m_page.get();
if (!page)
return nullptr;
Ref renderingBackend = page->ensureRemoteRenderingBackendProxy();
return renderingBackend->createTextDetector();
#elif HAVE(SHAPE_DETECTION_API_IMPLEMENTATION)
return WebCore::ShapeDetection::TextDetectorImpl::create();
#else
return nullptr;
#endif
}
void WebChromeClient::attachRootGraphicsLayer(LocalFrame& frame, GraphicsLayer* layer)
{
RefPtr page = m_page.get();
if (!page)
return;
if (layer)
page->enterAcceleratedCompositingMode(frame, layer);
else
page->exitAcceleratedCompositingMode(frame);
}
void WebChromeClient::attachViewOverlayGraphicsLayer(GraphicsLayer* graphicsLayer)
{
RefPtr page = m_page.get();
if (!page)
return;
RefPtr drawingArea = page->drawingArea();
if (!drawingArea)
return;
// FIXME: Support view overlays in iframe processes if needed. <rdar://116202544>
if (page->mainWebFrame().coreLocalFrame())
drawingArea->attachViewOverlayGraphicsLayer(page->mainWebFrame().frameID(), graphicsLayer);
}
void WebChromeClient::setNeedsOneShotDrawingSynchronization()
{
notImplemented();
}
bool WebChromeClient::shouldTriggerRenderingUpdate(unsigned rescheduledRenderingUpdateCount) const
{
RefPtr page = m_page.get();
return page && page->shouldTriggerRenderingUpdate(rescheduledRenderingUpdateCount);
}
void WebChromeClient::triggerRenderingUpdate()
{
RefPtr page = m_page.get();
if (!page)
return;
if (RefPtr drawingArea = page->drawingArea())
drawingArea->triggerRenderingUpdate();
}
bool WebChromeClient::scheduleRenderingUpdate()
{
RefPtr page = m_page.get();
if (!page)
return false;
if (RefPtr drawingArea = page->drawingArea())
return drawingArea->scheduleRenderingUpdate();
return false;
}
void WebChromeClient::renderingUpdateFramesPerSecondChanged()
{
RefPtr page = m_page.get();
if (!page)
return;
if (RefPtr drawingArea = page->drawingArea())
drawingArea->renderingUpdateFramesPerSecondChanged();
}
unsigned WebChromeClient::remoteImagesCountForTesting() const
{
RefPtr page = m_page.get();
return page ? page->remoteImagesCountForTesting() : 0;
}
void WebChromeClient::registerBlobPathForTesting(const String& path, CompletionHandler<void()>&& completionHandler)
{
WebProcess::singleton().ensureNetworkProcessConnection().connection().sendWithAsyncReply(Messages::NetworkConnectionToWebProcess::RegisterBlobPathForTesting(path), WTF::move(completionHandler));
}
void WebChromeClient::contentRuleListNotification(const URL& url, const ContentRuleListResults& results)
{
#if ENABLE(CONTENT_EXTENSIONS)
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::ContentRuleListNotification(url, results));
#endif
}
void WebChromeClient::contentRuleListMatchedRule(const WebCore::ContentRuleListMatchedRule& matchedRule)
{
#if ENABLE(CONTENT_EXTENSIONS)
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::ContentRuleListMatchedRule(matchedRule));
#endif
}
bool WebChromeClient::layerTreeStateIsFrozen() const
{
RefPtr page = m_page.get();
if (!page)
return false;
if (RefPtr drawingArea = page->drawingArea())
return drawingArea->layerTreeStateIsFrozen();
return false;
}
#if ENABLE(ASYNC_SCROLLING)
RefPtr<WebCore::ScrollingCoordinator> WebChromeClient::createScrollingCoordinator(Page& corePage) const
{
RefPtr page = m_page.get();
if (!page)
return nullptr;
ASSERT_UNUSED(corePage, page->corePage() == &corePage);
#if ENABLE(TILED_CA_DRAWING_AREA)
switch (page->protectedDrawingArea()->type()) {
case DrawingAreaType::TiledCoreAnimation:
return TiledCoreAnimationScrollingCoordinator::create(page.get());
case DrawingAreaType::RemoteLayerTree:
return RemoteScrollingCoordinator::create(page.get());
}
#elif PLATFORM(COCOA)
return RemoteScrollingCoordinator::create(page.get());
#elif USE(COORDINATED_GRAPHICS)
return ScrollingCoordinatorCoordinated::create(page.get());
#else
return nullptr;
#endif
}
#endif
#if PLATFORM(MAC) || USE(COORDINATED_GRAPHICS_ASYNC_SCROLLBAR)
void WebChromeClient::ensureScrollbarsController(Page& corePage, ScrollableArea& area, bool update) const
{
RefPtr page = m_page.get();
if (!page)
return;
ASSERT(page->corePage() == &corePage);
auto* currentScrollbarsController = area.existingScrollbarsController();
if (area.mockScrollbarsControllerEnabled() || (update && !currentScrollbarsController)) {
ASSERT(!currentScrollbarsController || is<ScrollbarsControllerMock>(currentScrollbarsController));
return;
}
#if PLATFORM(MAC)
#if ENABLE(TILED_CA_DRAWING_AREA)
switch (page->protectedDrawingArea()->type()) {
case DrawingAreaType::RemoteLayerTree: {
if (!area.usesCompositedScrolling() && (!currentScrollbarsController || is<RemoteScrollbarsController>(currentScrollbarsController)))
area.setScrollbarsController(ScrollbarsController::create(area));
else if (area.usesCompositedScrolling() && (!currentScrollbarsController || !is<RemoteScrollbarsController>(currentScrollbarsController)))
area.setScrollbarsController(makeUnique<RemoteScrollbarsController>(area, corePage.scrollingCoordinator()));
return;
}
default: {
if (!currentScrollbarsController)
area.setScrollbarsController(ScrollbarsController::create(area));
}
}
#else
if (!area.usesCompositedScrolling() && (!currentScrollbarsController || is<RemoteScrollbarsController>(currentScrollbarsController)))
area.setScrollbarsController(ScrollbarsController::create(area));
else if (area.usesCompositedScrolling() && (!currentScrollbarsController || !is<RemoteScrollbarsController>(currentScrollbarsController)))
area.setScrollbarsController(makeUnique<RemoteScrollbarsController>(area, corePage.scrollingCoordinator()));
#endif
#elif USE(COORDINATED_GRAPHICS_ASYNC_SCROLLBAR)
if (area.usesCompositedScrolling()) {
if (!currentScrollbarsController || !is<ScrollbarsControllerCoordinated>(currentScrollbarsController))
area.setScrollbarsController(makeUnique<ScrollbarsControllerCoordinated>(area, corePage.scrollingCoordinator()));
} else {
if (!currentScrollbarsController || is<ScrollbarsControllerCoordinated>(currentScrollbarsController))
area.setScrollbarsController(ScrollbarsController::create(area));
}
#endif
}
#endif
#if ENABLE(VIDEO_PRESENTATION_MODE)
void WebChromeClient::prepareForVideoFullscreen()
{
if (RefPtr page = m_page.get())
page->videoPresentationManager();
}
bool WebChromeClient::canEnterVideoFullscreen(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode) const
{
RefPtr page = m_page.get();
return page && page->protectedVideoPresentationManager()->canEnterVideoFullscreen(videoElement, mode);
}
bool WebChromeClient::supportsVideoFullscreen(HTMLMediaElementEnums::VideoFullscreenMode mode)
{
RefPtr page = m_page.get();
return page && page->protectedVideoPresentationManager()->supportsVideoFullscreen(mode);
}
bool WebChromeClient::supportsVideoFullscreenStandby()
{
RefPtr page = m_page.get();
return page && page->protectedVideoPresentationManager()->supportsVideoFullscreenStandby();
}
void WebChromeClient::setMockVideoPresentationModeEnabled(bool enabled)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::SetMockVideoPresentationModeEnabled(enabled));
}
void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode, bool standby)
{
#if ENABLE(FULLSCREEN_API) && PLATFORM(IOS_FAMILY)
ASSERT(standby || mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
#else
ASSERT(mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
#endif
if (RefPtr page = m_page.get())
page->protectedVideoPresentationManager()->enterVideoFullscreenForVideoElement(videoElement, mode, standby);
}
void WebChromeClient::setPlayerIdentifierForVideoElement(HTMLVideoElement& videoElement)
{
if (RefPtr page = m_page.get())
page->protectedVideoPresentationManager()->setPlayerIdentifierForVideoElement(videoElement);
}
void WebChromeClient::exitVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, CompletionHandler<void(bool)>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->protectedVideoPresentationManager()->exitVideoFullscreenForVideoElement(videoElement, WTF::move(completionHandler));
}
void WebChromeClient::setUpPlaybackControlsManager(HTMLMediaElement& mediaElement)
{
if (RefPtr page = m_page.get())
page->protectedPlaybackSessionManager()->setUpPlaybackControlsManager(mediaElement);
}
void WebChromeClient::clearPlaybackControlsManager()
{
if (RefPtr page = m_page.get())
page->protectedPlaybackSessionManager()->clearPlaybackControlsManager();
}
void WebChromeClient::mediaEngineChanged(WebCore::HTMLMediaElement& mediaElement)
{
if (RefPtr page = m_page.get())
page->protectedPlaybackSessionManager()->mediaEngineChanged(mediaElement);
}
#endif
#if ENABLE(MEDIA_USAGE)
void WebChromeClient::addMediaUsageManagerSession(MediaSessionIdentifier identifier, const String& bundleIdentifier, const URL& pageURL)
{
if (RefPtr page = m_page.get())
page->addMediaUsageManagerSession(identifier, bundleIdentifier, pageURL);
}
void WebChromeClient::updateMediaUsageManagerSessionState(MediaSessionIdentifier identifier, const MediaUsageInfo& usage)
{
if (RefPtr page = m_page.get())
page->updateMediaUsageManagerSessionState(identifier, usage);
}
void WebChromeClient::removeMediaUsageManagerSession(MediaSessionIdentifier identifier)
{
if (RefPtr page = m_page.get())
page->removeMediaUsageManagerSession(identifier);
}
#endif // ENABLE(MEDIA_USAGE)
#if ENABLE(VIDEO_PRESENTATION_MODE)
void WebChromeClient::exitVideoFullscreenToModeWithoutAnimation(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode targetMode)
{
if (RefPtr page = m_page.get())
page->protectedVideoPresentationManager()->exitVideoFullscreenToModeWithoutAnimation(videoElement, targetMode);
}
void WebChromeClient::setVideoFullscreenMode(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode)
{
if (RefPtr page = m_page.get())
page->protectedVideoPresentationManager()->setVideoFullscreenMode(videoElement, mode);
}
void WebChromeClient::clearVideoFullscreenMode(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode)
{
if (RefPtr page = m_page.get())
page->protectedVideoPresentationManager()->clearVideoFullscreenMode(videoElement, mode);
}
#endif
#if ENABLE(FULLSCREEN_API)
bool WebChromeClient::supportsFullScreenForElement(const Element& element, bool withKeyboard)
{
RefPtr page = m_page.get();
return page && page->protectedFullscreenManager()->supportsFullScreenForElement(element, withKeyboard);
}
void WebChromeClient::enterFullScreenForElement(Element& element, HTMLMediaElementEnums::VideoFullscreenMode mode, CompletionHandler<void(ExceptionOr<void>)>&& willEnterFullscreen, CompletionHandler<bool(bool)>&& didEnterFullscreen)
{
RefPtr page = m_page.get();
ASSERT(page);
page->protectedFullscreenManager()->enterFullScreenForElement(element, mode, WTF::move(willEnterFullscreen), WTF::move(didEnterFullscreen));
#if ENABLE(VIDEO_PRESENTATION_MODE)
if (RefPtr videoElement = dynamicDowncast<HTMLVideoElement>(element); videoElement && mode == HTMLMediaElementEnums::VideoFullscreenModeInWindow)
setVideoFullscreenMode(*videoElement, mode);
#endif
}
#if ENABLE(QUICKLOOK_FULLSCREEN)
void WebChromeClient::updateImageSource(Element& element)
{
if (RefPtr page = m_page.get())
page->fullScreenManager().updateImageSource(element);
}
#endif // ENABLE(QUICKLOOK_FULLSCREEN)
void WebChromeClient::exitFullScreenForElement(Element* element, CompletionHandler<void()>&& completionHandler)
{
#if ENABLE(VIDEO_PRESENTATION_MODE)
bool exitingInWindowFullscreen = false;
if (element) {
if (RefPtr videoElement = dynamicDowncast<HTMLVideoElement>(*element))
exitingInWindowFullscreen = videoElement->fullscreenMode() == HTMLMediaElementEnums::VideoFullscreenModeInWindow;
}
#endif
if (RefPtr page = m_page.get())
page->protectedFullscreenManager()->exitFullScreenForElement(element, WTF::move(completionHandler));
#if ENABLE(VIDEO_PRESENTATION_MODE)
if (exitingInWindowFullscreen)
clearVideoFullscreenMode(*dynamicDowncast<HTMLVideoElement>(*element), HTMLMediaElementEnums::VideoFullscreenModeInWindow);
#endif
}
#endif
#if PLATFORM(IOS_FAMILY)
FloatSize WebChromeClient::screenSize() const
{
RefPtr page = m_page.get();
return page ? page->screenSize() : FloatSize();
}
FloatSize WebChromeClient::availableScreenSize() const
{
RefPtr page = m_page.get();
return page ? page->availableScreenSize() : FloatSize();
}
FloatSize WebChromeClient::overrideScreenSize() const
{
RefPtr page = m_page.get();
return page ? page->overrideScreenSize() : FloatSize();
}
FloatSize WebChromeClient::overrideAvailableScreenSize() const
{
RefPtr page = m_page.get();
return page ? page->overrideAvailableScreenSize() : FloatSize();
}
#endif
FloatSize WebChromeClient::screenSizeForFingerprintingProtections(const LocalFrame& frame, FloatSize defaultSize) const
{
RefPtr page = m_page.get();
return page ? page->screenSizeForFingerprintingProtections(frame, defaultSize) : FloatSize();
}
void WebChromeClient::dispatchDisabledAdaptationsDidChange(const OptionSet<DisabledAdaptations>& disabledAdaptations) const
{
if (RefPtr page = m_page.get())
page->disabledAdaptationsDidChange(disabledAdaptations);
}
void WebChromeClient::dispatchViewportPropertiesDidChange(const ViewportArguments& viewportArguments) const
{
if (RefPtr page = m_page.get())
page->viewportPropertiesDidChange(viewportArguments);
}
void WebChromeClient::notifyScrollerThumbIsVisibleInRect(const IntRect& scrollerThumb)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::NotifyScrollerThumbIsVisibleInRect(scrollerThumb));
}
void WebChromeClient::recommendedScrollbarStyleDidChange(ScrollbarStyle newStyle)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::RecommendedScrollbarStyleDidChange(static_cast<int32_t>(newStyle)));
}
std::optional<ScrollbarOverlayStyle> WebChromeClient::preferredScrollbarOverlayStyle()
{
RefPtr page = m_page.get();
return page ? page->scrollbarOverlayStyle() : std::nullopt;
}
Color WebChromeClient::underlayColor() const
{
RefPtr page = m_page.get();
return page ? page->underlayColor() : Color();
}
void WebChromeClient::themeColorChanged() const
{
if (RefPtr page = m_page.get())
page->themeColorChanged();
}
void WebChromeClient::pageExtendedBackgroundColorDidChange() const
{
if (RefPtr page = m_page.get())
page->pageExtendedBackgroundColorDidChange();
}
void WebChromeClient::sampledPageTopColorChanged() const
{
if (RefPtr page = m_page.get())
page->sampledPageTopColorChanged();
}
#if ENABLE(WEB_PAGE_SPATIAL_BACKDROP)
void WebChromeClient::spatialBackdropSourceChanged() const
{
if (RefPtr page = m_page.get())
page->spatialBackdropSourceChanged();
}
#endif
#if ENABLE(MODEL_ELEMENT_IMMERSIVE)
void WebChromeClient::allowImmersiveElement(const Element& element, CompletionHandler<void(bool)>&& completion) const
{
if (RefPtr page = m_page.get())
page->allowImmersiveElement(element, WTF::move(completion));
else
completion(false);
}
void WebChromeClient::presentImmersiveElement(const Element& element, const LayerHostingContextIdentifier contextID, CompletionHandler<void(bool)>&& completion) const
{
if (RefPtr page = m_page.get())
page->presentImmersiveElement(element, contextID, WTF::move(completion));
else
completion(false);
}
void WebChromeClient::dismissImmersiveElement(const Element& element, CompletionHandler<void()>&& completion) const
{
if (RefPtr page = m_page.get())
page->dismissImmersiveElement(element, WTF::move(completion));
else
completion();
}
#endif
#if ENABLE(APP_HIGHLIGHTS)
WebCore::HighlightVisibility WebChromeClient::appHighlightsVisiblility() const
{
if (!m_page)
return { };
return m_page->appHighlightsVisiblility();
}
#endif
void WebChromeClient::wheelEventHandlersChanged(bool hasHandlers)
{
if (RefPtr page = m_page.get())
page->wheelEventHandlersChanged(hasHandlers);
}
void WebChromeClient::enableSuddenTermination()
{
if (RefPtr page = m_page.get())
page->send(Messages::WebProcessProxy::EnableSuddenTermination());
}
void WebChromeClient::disableSuddenTermination()
{
if (RefPtr page = m_page.get())
page->send(Messages::WebProcessProxy::DisableSuddenTermination());
}
void WebChromeClient::didAddHeaderLayer(GraphicsLayer& headerParent)
{
#if HAVE(RUBBER_BANDING)
RefPtr page = m_page.get();
if (!page)
return;
if (RefPtr banner = page->headerPageBanner())
banner->didAddParentLayer(&headerParent);
#else
UNUSED_PARAM(headerParent);
#endif
}
void WebChromeClient::didAddFooterLayer(GraphicsLayer& footerParent)
{
#if HAVE(RUBBER_BANDING)
RefPtr page = m_page.get();
if (!page)
return;
if (RefPtr banner = page->footerPageBanner())
banner->didAddParentLayer(&footerParent);
#else
UNUSED_PARAM(footerParent);
#endif
}
bool WebChromeClient::shouldUseTiledBackingForFrameView(const LocalFrameView& frameView) const
{
RefPtr page = m_page.get();
return page && page->protectedDrawingArea()->shouldUseTiledBackingForFrameView(frameView);
}
void WebChromeClient::frameViewLayoutOrVisualViewportChanged(const LocalFrameView& frameView)
{
RefPtr page = m_page.get();
if (!page)
return;
page->frameViewLayoutOrVisualViewportChanged(frameView);
}
#if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL)
void WebChromeClient::isAnyAnimationAllowedToPlayDidChange(bool anyAnimationCanPlay)
{
if (RefPtr page = m_page.get())
page->isAnyAnimationAllowedToPlayDidChange(anyAnimationCanPlay);
}
#endif
void WebChromeClient::resolveAccessibilityHitTestForTesting(FrameIdentifier frameID, const IntPoint& point, CompletionHandler<void(String)>&& callback)
{
if (RefPtr page = m_page.get())
page->sendWithAsyncReply(Messages::WebPageProxy::ResolveAccessibilityHitTestForTesting(frameID, point), WTF::move(callback));
else
callback({ });
}
void WebChromeClient::isPlayingMediaDidChange(MediaProducerMediaStateFlags state)
{
if (RefPtr page = m_page.get())
page->isPlayingMediaDidChange(state);
}
void WebChromeClient::handleAutoplayEvent(AutoplayEvent event, OptionSet<AutoplayEventFlags> flags)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::HandleAutoplayEvent(event, flags));
}
void WebChromeClient::setTextIndicator(RefPtr<WebCore::TextIndicator>&& textIndicator) const
{
if (RefPtr page = m_page.get())
page->setTextIndicator(WTF::move(textIndicator));
}
void WebChromeClient::updateTextIndicator(RefPtr<WebCore::TextIndicator>&& textIndicator) const
{
if (RefPtr page = m_page.get())
page->updateTextIndicator(WTF::move(textIndicator));
}
#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(MAC)
void WebChromeClient::handleTelephoneNumberClick(const String& number, const IntPoint& point, const IntRect& rect)
{
if (RefPtr page = m_page.get())
page->handleTelephoneNumberClick(number, point, rect);
}
#endif
#if ENABLE(DATA_DETECTION)
void WebChromeClient::handleClickForDataDetectionResult(const DataDetectorElementInfo& info, const IntPoint& clickLocation)
{
if (RefPtr page = m_page.get())
page->handleClickForDataDetectionResult(info, clickLocation);
}
#endif
#if ENABLE(SERVICE_CONTROLS)
void WebChromeClient::handleSelectionServiceClick(WebCore::FrameIdentifier frameID, FrameSelection& selection, const Vector<String>& telephoneNumbers, const IntPoint& point)
{
if (RefPtr page = m_page.get())
page->handleSelectionServiceClick(frameID, selection, telephoneNumbers, point);
}
bool WebChromeClient::hasRelevantSelectionServices(bool isTextOnly) const
{
return (isTextOnly && WebProcess::singleton().hasSelectionServices()) || WebProcess::singleton().hasRichContentServices();
}
void WebChromeClient::handleImageServiceClick(WebCore::FrameIdentifier frameID, const IntPoint& point, Image& image, HTMLImageElement& element)
{
if (RefPtr page = m_page.get())
page->handleImageServiceClick(frameID, point, image, element);
}
void WebChromeClient::handlePDFServiceClick(WebCore::FrameIdentifier frameID, const IntPoint& point, HTMLAttachmentElement& element)
{
if (RefPtr page = m_page.get())
page->handlePDFServiceClick(frameID, point, element);
}
#endif
bool WebChromeClient::shouldDispatchFakeMouseMoveEvents() const
{
RefPtr page = m_page.get();
return page && page->shouldDispatchFakeMouseMoveEvents();
}
RefPtr<API::Object> userDataFromJSONData(JSON::Value& value)
{
switch (value.type()) {
case JSON::Value::Type::Null:
return API::String::createNull(); // FIXME: Encode nil properly.
case JSON::Value::Type::Boolean:
return API::Boolean::create(*value.asBoolean());
case JSON::Value::Type::Double:
return API::Double::create(*value.asDouble());
case JSON::Value::Type::Integer:
return API::Int64::create(*value.asInteger());
case JSON::Value::Type::String:
return API::String::create(value.asString());
case JSON::Value::Type::Object: {
auto result = API::Dictionary::create();
RefPtr jsonObject = value.asObject();
for (auto [key, value] : *jsonObject)
result->add(key, userDataFromJSONData(value));
return result;
}
case JSON::Value::Type::Array: {
auto array = value.asArray();
Vector<RefPtr<API::Object>> result;
RefPtr jsonArray = value.asArray();
for (auto& item : *jsonArray)
result.append(userDataFromJSONData(item));
return API::Array::create(WTF::move(result));
}
}
ASSERT_NOT_REACHED();
return nullptr;
}
void WebChromeClient::handleAutoFillButtonClick(HTMLInputElement& inputElement)
{
RefPtr page = m_page.get();
if (!page)
return;
RefPtr<API::Object> userData;
// Notify the bundle client.
auto nodeHandle = InjectedBundleNodeHandle::getOrCreate(inputElement);
page->injectedBundleUIClient().didClickAutoFillButton(*page, nodeHandle.get(), userData);
if (!userData) {
auto userInfo = inputElement.userInfo();
if (!userInfo.isNull()) {
if (auto data = JSON::Value::parseJSON(inputElement.userInfo()))
userData = userDataFromJSONData(*data);
}
}
// Notify the UIProcess.
page->send(Messages::WebPageProxy::HandleAutoFillButtonClick(UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())));
}
void WebChromeClient::inputElementDidResignStrongPasswordAppearance(HTMLInputElement& inputElement)
{
RefPtr page = m_page.get();
if (!page)
return;
page->send(Messages::WebPageProxy::DidResignInputElementStrongPasswordAppearance { UserData { } });
}
void WebChromeClient::performSwitchHapticFeedback()
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::PerformSwitchHapticFeedback());
}
#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
void WebChromeClient::addPlaybackTargetPickerClient(PlaybackTargetClientContextIdentifier contextId)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::AddPlaybackTargetPickerClient(contextId));
}
void WebChromeClient::removePlaybackTargetPickerClient(PlaybackTargetClientContextIdentifier contextId)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::RemovePlaybackTargetPickerClient(contextId));
}
void WebChromeClient::showPlaybackTargetPicker(PlaybackTargetClientContextIdentifier contextId, const IntPoint& position, bool isVideo)
{
RefPtr page = m_page.get();
if (!page)
return;
RefPtr frameView = page->localMainFrameView();
if (!frameView)
return;
FloatRect rect(frameView->contentsToRootView(frameView->windowToContents(position)), FloatSize());
page->send(Messages::WebPageProxy::ShowPlaybackTargetPicker(contextId, rect, isVideo));
}
void WebChromeClient::playbackTargetPickerClientStateDidChange(PlaybackTargetClientContextIdentifier contextId, MediaProducerMediaStateFlags state)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::PlaybackTargetPickerClientStateDidChange(contextId, state));
}
void WebChromeClient::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::SetMockMediaPlaybackTargetPickerEnabled(enabled));
}
void WebChromeClient::setMockMediaPlaybackTargetPickerState(const String& name, MediaPlaybackTargetMockState state)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::SetMockMediaPlaybackTargetPickerState(name, state));
}
void WebChromeClient::mockMediaPlaybackTargetPickerDismissPopup()
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::MockMediaPlaybackTargetPickerDismissPopup());
}
#endif
void WebChromeClient::imageOrMediaDocumentSizeChanged(const IntSize& newSize)
{
if (RefPtr page = m_page.get())
page->imageOrMediaDocumentSizeChanged(newSize);
}
void WebChromeClient::didInvalidateDocumentMarkerRects()
{
if (RefPtr page = m_page.get())
page->findController().didInvalidateFindRects();
}
void WebChromeClient::hasStorageAccess(RegistrableDomain&& subFrameDomain, RegistrableDomain&& topFrameDomain, LocalFrame& frame, CompletionHandler<void(bool)>&& completionHandler)
{
auto webFrame = WebFrame::fromCoreFrame(frame);
ASSERT(webFrame);
if (RefPtr page = m_page.get())
page->hasStorageAccess(WTF::move(subFrameDomain), WTF::move(topFrameDomain), *webFrame, WTF::move(completionHandler));
else
completionHandler(false);
}
void WebChromeClient::requestStorageAccess(RegistrableDomain&& subFrameDomain, RegistrableDomain&& topFrameDomain, LocalFrame& frame, StorageAccessScope scope, HasOrShouldIgnoreUserGesture hasOrShouldIgnoreUserGesture, CompletionHandler<void(RequestStorageAccessResult)>&& completionHandler)
{
auto webFrame = WebFrame::fromCoreFrame(frame);
ASSERT(webFrame);
if (RefPtr page = m_page.get())
page->requestStorageAccess(WTF::move(subFrameDomain), WTF::move(topFrameDomain), *webFrame, scope, hasOrShouldIgnoreUserGesture, WTF::move(completionHandler));
else
completionHandler({ });
}
void WebChromeClient::setLoginStatus(RegistrableDomain&& domain, IsLoggedIn loggedInStatus, CompletionHandler<void()>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->setLoginStatus(WTF::move(domain), loggedInStatus, WTF::move(completionHandler));
else
completionHandler();
}
void WebChromeClient::isLoggedIn(RegistrableDomain&& domain, CompletionHandler<void(bool)>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->isLoggedIn(WTF::move(domain), WTF::move(completionHandler));
else
completionHandler(false);
}
bool WebChromeClient::hasPageLevelStorageAccess(const WebCore::RegistrableDomain& topLevelDomain, const WebCore::RegistrableDomain& resourceDomain) const
{
RefPtr page = m_page.get();
return page && page->hasPageLevelStorageAccess(topLevelDomain, resourceDomain);
}
#if ENABLE(DEVICE_ORIENTATION)
void WebChromeClient::shouldAllowDeviceOrientationAndMotionAccess(LocalFrame& frame, bool mayPrompt, CompletionHandler<void(DeviceOrientationOrMotionPermissionState)>&& callback)
{
auto webFrame = WebFrame::fromCoreFrame(frame);
ASSERT(webFrame);
if (RefPtr page = m_page.get())
page->shouldAllowDeviceOrientationAndMotionAccess(webFrame->frameID(), webFrame->info(), mayPrompt, WTF::move(callback));
else
callback(DeviceOrientationOrMotionPermissionState::Denied);
}
#endif
#if ENABLE(ORIENTATION_EVENTS) && !PLATFORM(IOS_FAMILY)
IntDegrees WebChromeClient::deviceOrientation() const
{
notImplemented();
return 0;
}
#endif
void WebChromeClient::configureLoggingChannel(const String& channelName, WTFLogChannelState state, WTFLogLevel level)
{
if (RefPtr page = m_page.get())
page->configureLoggingChannel(channelName, state, level);
}
bool WebChromeClient::userIsInteracting() const
{
RefPtr page = m_page.get();
return page && page->userIsInteracting();
}
void WebChromeClient::setUserIsInteracting(bool userIsInteracting)
{
if (RefPtr page = m_page.get())
page->setUserIsInteracting(userIsInteracting);
}
#if ENABLE(WEB_AUTHN)
void WebChromeClient::setMockWebAuthenticationConfiguration(const MockWebAuthenticationConfiguration& configuration)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::SetMockWebAuthenticationConfiguration(configuration));
}
#endif
#if PLATFORM(PLAYSTATION)
void WebChromeClient::postAccessibilityNotification(WebCore::AccessibilityObject&, WebCore::AXNotification)
{
notImplemented();
}
void WebChromeClient::postAccessibilityNodeTextChangeNotification(WebCore::AccessibilityObject*, WebCore::AXTextChange, unsigned, const String&)
{
notImplemented();
}
void WebChromeClient::postAccessibilityFrameLoadingEventNotification(WebCore::AccessibilityObject*, WebCore::AXLoadingEvent)
{
notImplemented();
}
#endif
void WebChromeClient::animationDidFinishForElement(const Element& element)
{
if (RefPtr page = m_page.get())
page->animationDidFinishForElement(element);
}
#if PLATFORM(MAC)
void WebChromeClient::changeUniversalAccessZoomFocus(const WebCore::IntRect& viewRect, const WebCore::IntRect& selectionRect)
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::ChangeUniversalAccessZoomFocus(viewRect, selectionRect));
}
#endif
#if ENABLE(IMAGE_ANALYSIS)
void WebChromeClient::requestTextRecognition(Element& element, TextRecognitionOptions&& options, CompletionHandler<void(RefPtr<Element>&&)>&& completion)
{
if (RefPtr page = m_page.get())
page->requestTextRecognition(element, WTF::move(options), WTF::move(completion));
else
completion(nullptr);
}
#endif
std::pair<URL, DidFilterLinkDecoration> WebChromeClient::applyLinkDecorationFilteringWithResult(const URL& url, LinkDecorationFilteringTrigger trigger) const
{
RefPtr page = m_page.get();
if (!page)
return { };
return page->applyLinkDecorationFilteringWithResult(url, trigger);
}
URL WebChromeClient::allowedQueryParametersForAdvancedPrivacyProtections(const URL& url) const
{
RefPtr page = m_page.get();
return page ? page->allowedQueryParametersForAdvancedPrivacyProtections(url) : URL();
}
void WebChromeClient::didAddOrRemoveViewportConstrainedObjects()
{
if (RefPtr page = m_page.get())
page->didAddOrRemoveViewportConstrainedObjects();
}
#if ENABLE(TEXT_AUTOSIZING)
void WebChromeClient::textAutosizingUsesIdempotentModeChanged()
{
if (RefPtr page = m_page.get())
page->textAutosizingUsesIdempotentModeChanged();
}
#endif
bool WebChromeClient::needsScrollGeometryUpdates() const
{
if (RefPtr page = m_page.get())
return page->needsScrollGeometryUpdates();
return false;
}
#if ENABLE(META_VIEWPORT)
double WebChromeClient::baseViewportLayoutSizeScaleFactor() const
{
RefPtr page = m_page.get();
return page ? page->baseViewportLayoutSizeScaleFactor() : 0;
}
#endif
#if ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
void WebChromeClient::showMediaControlsContextMenu(FloatRect&& targetFrame, Vector<MediaControlsContextMenuItem>&& items, HTMLMediaElement& element, CompletionHandler<void(MediaControlsContextMenuItem::ID)>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->showMediaControlsContextMenu(WTF::move(targetFrame), WTF::move(items), element.identifier(), WTF::move(completionHandler));
else
completionHandler({ });
}
#endif // ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
#if ENABLE(WEBXR)
void WebChromeClient::enumerateImmersiveXRDevices(CompletionHandler<void(const PlatformXR::DeviceList&)>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->xrSystemProxy().enumerateImmersiveXRDevices(WTF::move(completionHandler));
else
completionHandler({ });
}
void WebChromeClient::requestPermissionOnXRSessionFeatures(const SecurityOriginData& origin, PlatformXR::SessionMode mode, const PlatformXR::Device::FeatureList& granted, const PlatformXR::Device::FeatureList& consentRequired, const PlatformXR::Device::FeatureList& consentOptional, const PlatformXR::Device::FeatureList& requiredFeaturesRequested, const PlatformXR::Device::FeatureList& optionalFeaturesRequested, CompletionHandler<void(std::optional<PlatformXR::Device::FeatureList>&&)>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->xrSystemProxy().requestPermissionOnSessionFeatures(origin, mode, granted, consentRequired, consentOptional, requiredFeaturesRequested, optionalFeaturesRequested, WTF::move(completionHandler));
else
completionHandler(std::nullopt);
}
#endif
#if ENABLE(APPLE_PAY_AMS_UI)
void WebChromeClient::startApplePayAMSUISession(const URL& originatingURL, const ApplePayAMSUIRequest& request, CompletionHandler<void(std::optional<bool>&&)>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->sendWithAsyncReply(Messages::WebPageProxy::StartApplePayAMSUISession(originatingURL, request), WTF::move(completionHandler));
else
completionHandler(false);
}
void WebChromeClient::abortApplePayAMSUISession()
{
if (RefPtr page = m_page.get())
page->send(Messages::WebPageProxy::AbortApplePayAMSUISession());
}
#endif // ENABLE(APPLE_PAY_AMS_UI)
#if USE(SYSTEM_PREVIEW)
void WebChromeClient::beginSystemPreview(const URL& url, const SecurityOriginData& topOrigin, const SystemPreviewInfo& systemPreviewInfo, CompletionHandler<void()>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->sendWithAsyncReply(Messages::WebPageProxy::BeginSystemPreview(url, topOrigin, systemPreviewInfo), WTF::move(completionHandler));
else
completionHandler();
}
#endif
void WebChromeClient::requestCookieConsent(CompletionHandler<void(CookieConsentDecisionResult)>&& completion)
{
if (RefPtr page = m_page.get())
page->sendWithAsyncReply(Messages::WebPageProxy::RequestCookieConsent(), WTF::move(completion));
else
completion(CookieConsentDecisionResult::NotSupported);
}
bool WebChromeClient::isUsingUISideCompositing() const
{
#if ENABLE(TILED_CA_DRAWING_AREA)
RefPtr page = m_page.get();
return page && page->protectedDrawingArea()->type() == DrawingAreaType::RemoteLayerTree;
#elif PLATFORM(COCOA)
return true;
#else
return false;
#endif
}
bool WebChromeClient::isInStableState() const
{
#if PLATFORM(IOS_FAMILY)
RefPtr page = m_page.get();
return page && page->isInStableState();
#else
// FIXME (255877): Implement this client hook on macOS.
return true;
#endif
}
void WebChromeClient::didAdjustVisibilityWithSelectors(Vector<String>&& selectors)
{
if (RefPtr page = m_page.get())
page->didAdjustVisibilityWithSelectors(WTF::move(selectors));
}
#if ENABLE(GAMEPAD)
void WebChromeClient::gamepadsRecentlyAccessed()
{
if (RefPtr page = m_page.get())
page->gamepadsRecentlyAccessed();
}
#endif
#if ENABLE(WRITING_TOOLS)
void WebChromeClient::proofreadingSessionShowDetailsForSuggestionWithIDRelativeToRect(const WebCore::WritingTools::TextSuggestion::ID& replacementID, WebCore::IntRect selectionBoundsInRootView)
{
if (RefPtr page = m_page.get())
page->proofreadingSessionShowDetailsForSuggestionWithIDRelativeToRect(replacementID, selectionBoundsInRootView);
}
void WebChromeClient::proofreadingSessionUpdateStateForSuggestionWithID(WritingTools::TextSuggestion::State state, const WritingTools::TextSuggestion::ID& replacementID)
{
if (RefPtr page = m_page.get())
page->proofreadingSessionUpdateStateForSuggestionWithID(state, replacementID);
}
void WebChromeClient::removeTextAnimationForAnimationID(const WTF::UUID& animationID)
{
if (RefPtr page = m_page.get())
page->removeTextAnimationForAnimationID(animationID);
}
void WebChromeClient::removeInitialTextAnimationForActiveWritingToolsSession()
{
if (RefPtr page = m_page.get())
page->removeInitialTextAnimationForActiveWritingToolsSession();
}
void WebChromeClient::addInitialTextAnimationForActiveWritingToolsSession()
{
if (RefPtr page = m_page.get())
page->addInitialTextAnimationForActiveWritingToolsSession();
}
void WebChromeClient::addSourceTextAnimationForActiveWritingToolsSession(const WTF::UUID& sourceAnimationUUID, const WTF::UUID& destinationAnimationUUID, bool finished, const CharacterRange& range, const String& string, CompletionHandler<void(WebCore::TextAnimationRunMode)>&& completionHandler)
{
if (RefPtr page = m_page.get())
page->addSourceTextAnimationForActiveWritingToolsSession(sourceAnimationUUID, destinationAnimationUUID, finished, range, string, WTF::move(completionHandler));
}
void WebChromeClient::addDestinationTextAnimationForActiveWritingToolsSession(const WTF::UUID& sourceAnimationUUID, const WTF::UUID& destinationAnimationUUID, const std::optional<CharacterRange>& range, const String& string)
{
if (RefPtr page = m_page.get())
page->addDestinationTextAnimationForActiveWritingToolsSession(sourceAnimationUUID, destinationAnimationUUID, range, string);
}
void WebChromeClient::saveSnapshotOfTextPlaceholderForAnimation(const WebCore::SimpleRange& placeholderRange)
{
if (RefPtr page = m_page.get())
page->saveSnapshotOfTextPlaceholderForAnimation(placeholderRange);
}
void WebChromeClient::clearAnimationsForActiveWritingToolsSession()
{
if (RefPtr page = m_page.get())
page->clearAnimationsForActiveWritingToolsSession();
}
#endif
void WebChromeClient::setIsInRedo(bool isInRedo)
{
if (RefPtr page = m_page.get())
page->setIsInRedo(isInRedo);
}
void WebChromeClient::hasActiveNowPlayingSessionChanged(bool hasActiveNowPlayingSession)
{
if (RefPtr page = m_page.get())
page->hasActiveNowPlayingSessionChanged(hasActiveNowPlayingSession);
}
#if ENABLE(GPU_PROCESS)
void WebChromeClient::getImageBufferResourceLimitsForTesting(CompletionHandler<void(std::optional<ImageBufferResourceLimits>)>&& callback) const
{
if (RefPtr page = m_page.get())
page->ensureProtectedRemoteRenderingBackendProxy()->getImageBufferResourceLimitsForTesting(WTF::move(callback));
else
callback(std::nullopt);
}
#endif
bool WebChromeClient::requiresScriptTrackingPrivacyProtections(const URL& url, const SecurityOrigin& topOrigin) const
{
return WebProcess::singleton().requiresScriptTrackingPrivacyProtections(url, topOrigin);
}
bool WebChromeClient::shouldAllowScriptAccess(const URL& url, const SecurityOrigin& topOrigin, ScriptTrackingPrivacyCategory category) const
{
return WebProcess::singleton().shouldAllowScriptAccess(url, topOrigin, category);
}
void WebChromeClient::callAfterPendingSyntheticClick(CompletionHandler<void(SyntheticClickResult)>&& completion)
{
if (RefPtr page = m_page.get())
page->callAfterPendingSyntheticClick(WTF::move(completion));
else
completion(SyntheticClickResult::Failed);
}
void WebChromeClient::didDispatchClickEvent(const PlatformMouseEvent& event, Node& node)
{
if (RefPtr page = m_page.get())
page->didDispatchClickEvent(event, node);
}
void WebChromeClient::didProgrammaticallyClearTextFormControl(const HTMLTextFormControlElement& element)
{
if (RefPtr page = m_page.get())
page->didProgrammaticallyClearTextFormControl(element);
}
#if ENABLE(DAMAGE_TRACKING)
void WebChromeClient::resetDamageHistoryForTesting()
{
if (!m_page)
return;
if (RefPtr drawingArea = m_page->drawingArea())
drawingArea->resetDamageHistoryForTesting();
}
void WebChromeClient::foreachRegionInDamageHistoryForTesting(Function<void(const Region&)>&& callback) const
{
if (!m_page)
return;
if (const RefPtr drawingArea = m_page->drawingArea())
drawingArea->foreachRegionInDamageHistoryForTesting(WTF::move(callback));
}
#endif
void WebChromeClient::setNeedsFixedContainerEdgesUpdate()
{
m_page->setNeedsFixedContainerEdgesUpdate();
}
bool WebChromeClient::usePluginRendererScrollableArea(LocalFrame& frame) const
{
#if ENABLE(PDF_PLUGIN)
if (RefPtr pluginView = WebPage::pluginViewForFrame(&frame))
return !pluginView->pluginDelegatesScrollingToMainFrame();
#endif
return true;
}
#if ENABLE(VIDEO)
void WebChromeClient::showCaptionDisplaySettings(HTMLMediaElement& element, const ResolvedCaptionDisplaySettingsOptions& options, CompletionHandler<void(ExceptionOr<void>)>&& completionHandler)
{
RefPtr page = m_page.get();
if (!page) {
completionHandler(Exception { ExceptionCode::NotSupportedError, "Caption Display Settings are not supported."_s });
return;
}
page->sendWithAsyncReply(Messages::WebPageProxy::ShowCaptionDisplaySettings(element.identifier(), options), [completionHandler = WTF::move(completionHandler)] (auto&& expected) mutable {
if (expected)
completionHandler({ });
else
completionHandler(expected.error().toException());
});
}
#endif
} // namespace WebKit