From 090ff4042ad985eea0ea5b463094a686bcaf450d Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Fri, 18 Aug 2023 15:11:00 +0200 Subject: [PATCH 01/55] [PSON] Disable PSON for the WPE port --- Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp index 14c655bdd47bf..184d84cb6ceea 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp @@ -430,8 +430,12 @@ static void webkitWebContextConstructed(GObject* object) #if PLATFORM(GTK) && !USE(GTK4) && USE(CAIRO) configuration.setProcessSwapsOnNavigation(priv->psonEnabled); configuration.setUseSystemAppearanceForScrollbars(priv->useSystemAppearanceForScrollbars); +#else +#if PLATFORM(WPE) + configuration.setProcessSwapsOnNavigation(false); #else configuration.setProcessSwapsOnNavigation(true); +#endif #endif if (priv->memoryPressureSettings) { configuration.setMemoryPressureHandlerConfiguration(webkitMemoryPressureSettingsGetMemoryPressureHandlerConfiguration(priv->memoryPressureSettings)); From e496014e63cc04f0905645985486f269aaa9b94d Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Tue, 29 Nov 2022 11:11:42 +0100 Subject: [PATCH 02/55] Ensure we check for WEBKIT_EXEC_PATH even without developer mode --- Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp b/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp index 40d482a186059..38d1b704c2760 100644 --- a/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp +++ b/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp @@ -32,7 +32,6 @@ namespace WebKit { -#if ENABLE(DEVELOPER_MODE) static String getExecutablePath() { CString executablePath = FileSystem::currentExecutablePath(); @@ -40,11 +39,9 @@ static String getExecutablePath() return FileSystem::parentPath(FileSystem::stringFromFileSystemRepresentation(executablePath.data())); return { }; } -#endif static String findWebKitProcess(const char* processName) { -#if ENABLE(DEVELOPER_MODE) static const char* execDirectory = g_getenv("WEBKIT_EXEC_PATH"); if (execDirectory) { String processPath = FileSystem::pathByAppendingComponent(FileSystem::stringFromFileSystemRepresentation(execDirectory), StringView::fromLatin1(processName)); @@ -58,7 +55,6 @@ static String findWebKitProcess(const char* processName) if (FileSystem::fileExists(processPath)) return processPath; } -#endif return FileSystem::pathByAppendingComponent(FileSystem::stringFromFileSystemRepresentation(PKGLIBEXECDIR), StringView::fromLatin1(processName)); } From ae62fccd35836a055b5611b04d45d1b7f1422ca7 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Wed, 30 Nov 2022 07:44:59 +0100 Subject: [PATCH 03/55] Allow WEBKIT_INJECTED_BUNDLE_PATH even in non developer mode --- Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp index 184d84cb6ceea..ac1736af22af4 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp @@ -333,11 +333,9 @@ void webkitWebContextWillCloseAutomationSession(WebKitWebContext* webContext) static const char* injectedBundleDirectory() { -#if ENABLE(DEVELOPER_MODE) const char* bundleDirectory = g_getenv("WEBKIT_INJECTED_BUNDLE_PATH"); if (bundleDirectory && g_file_test(bundleDirectory, G_FILE_TEST_IS_DIR)) return bundleDirectory; -#endif static const char* injectedBundlePath = PKGLIBDIR G_DIR_SEPARATOR_S "injected-bundle" G_DIR_SEPARATOR_S; return injectedBundlePath; From abc5ee38cd9c04844f3d845bc3d4fabd8dcf3669 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Wed, 16 Nov 2022 15:12:14 +0100 Subject: [PATCH 04/55] Relax user agent validation We need to configure UA for some apps that don't pass isValidUserAgentHeaderValue check, but it is still a valid header value. --- Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp index b8d3249532dee..197c549be2313 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp @@ -3147,7 +3147,7 @@ void webkit_settings_set_user_agent(WebKitSettings* settings, const char* userAg String userAgentString; if (userAgent && *userAgent) { userAgentString = String::fromUTF8(userAgent); - g_return_if_fail(WebCore::isValidUserAgentHeaderValue(userAgentString)); + g_return_if_fail(WebCore::isValidHTTPHeaderValue(userAgentString)); } else userAgentString = WebCore::standardUserAgent(emptyString()); From 2523172418b031592125da804e8233fdf09b63a0 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Mon, 28 Aug 2023 15:50:11 +0200 Subject: [PATCH 05/55] Use API version 1.1 instead of 2.0 --- Source/cmake/OptionsWPE.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index e0c8dc92717c3..8a921cd25198c 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -93,7 +93,7 @@ WEBKIT_OPTION_DEFINE(ENABLE_WPE_PLATFORM_DRM "Whether to enable support for DRM WEBKIT_OPTION_DEFINE(ENABLE_WPE_PLATFORM_HEADLESS "Whether to enable support for headless platform" PUBLIC ON) WEBKIT_OPTION_DEFINE(ENABLE_WPE_PLATFORM_WAYLAND "Whether to enable support for Wayland platform" PUBLIC ON) WEBKIT_OPTION_DEFINE(ENABLE_WPE_QT_API "Whether to enable support for the Qt5/QML plugin" PUBLIC ${ENABLE_DEVELOPER_MODE}) -WEBKIT_OPTION_DEFINE(ENABLE_WPE_1_1_API "Whether to build WPE 1.1 instead of WPE 2.0" PUBLIC OFF) +WEBKIT_OPTION_DEFINE(ENABLE_WPE_1_1_API "Whether to build WPE 1.1 instead of WPE 2.0" PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_ATK "Whether to enable usage of ATK." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_GBM "Whether to enable usage of GBM." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_LIBBACKTRACE "Whether to enable usage of libbacktrace." PUBLIC ON) From 695c76a6541424a4be66323ca836b0d153c7af46 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Wed, 23 Aug 2023 12:16:05 +0200 Subject: [PATCH 06/55] Add web extensions API to allowlist access to a security origin Fix Security Origin handling in network process Currently, when a custom uri scheme handler is registered, its existence is not passed to the network process. Consequently, when creating a SecurityOrigin object for an URI that uses a custom scheme handler, the instance may be created as unique due shouldTreatAsUniqueOrigin() not detecting the associated scheme as registered (in LegacySchemeRegistry). This will cause calls to SecurityPolicy::isAccessAllowed() to not return the correct authorization in case a custom URI is whitelisted using webkit_web_extension_add_origin_access_whitelist_entry() API, which leads to the inclusion of the "Origin" header with the custom URI in network requests when it should not be included in such case. --- Source/WebCore/page/SecurityOrigin.cpp | 3 ++ .../NetworkConnectionToWebProcess.cpp | 6 ++++ .../NetworkConnectionToWebProcess.h | 2 ++ .../NetworkConnectionToWebProcess.messages.in | 1 + Source/WebKit/PlatformWPE.cmake | 1 + .../API/glib/WebKitSecurityOrigin.h.in | 2 +- .../API/glib/WebKitWebExtension.cpp | 28 +++++++++++++++++++ .../API/glib/WebKitWebExtension.h.in | 18 ++++++++++++ Source/WebKit/WebProcess/WebPage/WebPage.cpp | 1 + 9 files changed, 61 insertions(+), 1 deletion(-) diff --git a/Source/WebCore/page/SecurityOrigin.cpp b/Source/WebCore/page/SecurityOrigin.cpp index 21a809b53acab..ded0e5adf2eb2 100644 --- a/Source/WebCore/page/SecurityOrigin.cpp +++ b/Source/WebCore/page/SecurityOrigin.cpp @@ -32,6 +32,7 @@ #include "BlobURL.h" #include "LegacySchemeRegistry.h" #include "OriginAccessEntry.h" +#include "OriginAccessPatterns.h" #include "PublicSuffixStore.h" #include "RuntimeApplicationChecks.h" #include "SecurityPolicy.h" @@ -290,6 +291,8 @@ bool SecurityOrigin::isSameOriginDomain(const SecurityOrigin& other) const if (canAccess && isLocal()) canAccess = passesFileCheck(other); + canAccess |= SecurityPolicy::isAccessAllowed(*this, other, other.toURL(), EmptyOriginAccessPatterns::singleton()); + return canAccess; } diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp index caf9b8fe4c94e..562c3d90e6ff5 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp @@ -82,6 +82,7 @@ #include #include #include +#include #include #include #include @@ -771,6 +772,11 @@ void NetworkConnectionToWebProcess::registerURLSchemesAsCORSEnabled(VectorregisterURLSchemeAsCORSEnabled(WTFMove(scheme)); } +void NetworkConnectionToWebProcess::registerURLSchemeAsHandledBySchemeHandler(const String& scheme) +{ + WebCore::LegacySchemeRegistry::registerURLSchemeAsHandledBySchemeHandler(scheme); +} + void NetworkConnectionToWebProcess::cookiesForDOM(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, FrameIdentifier frameID, PageIdentifier pageID, IncludeSecureCookies includeSecureCookies, ApplyTrackingPrevention applyTrackingPrevention, ShouldRelaxThirdPartyCookieBlocking shouldRelaxThirdPartyCookieBlocking, CompletionHandler&& completionHandler) { MESSAGE_CHECK_COMPLETION(m_networkProcess->allowsFirstPartyForCookies(m_webProcessIdentifier, firstParty), completionHandler({ }, false)); diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h index a9fd7f7625ca6..c3673fdc8cb86 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h @@ -271,6 +271,8 @@ class NetworkConnectionToWebProcess void registerURLSchemesAsCORSEnabled(Vector&& schemes); + void registerURLSchemeAsHandledBySchemeHandler(const String& scheme); + void cookiesForDOM(const URL& firstParty, const WebCore::SameSiteInfo&, const URL&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::IncludeSecureCookies, WebCore::ApplyTrackingPrevention, WebCore::ShouldRelaxThirdPartyCookieBlocking, CompletionHandler&&); void setCookiesFromDOM(const URL& firstParty, const WebCore::SameSiteInfo&, const URL&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::ApplyTrackingPrevention, const String& cookieString, WebCore::ShouldRelaxThirdPartyCookieBlocking); void cookieRequestHeaderFieldValue(const URL& firstParty, const WebCore::SameSiteInfo&, const URL&, std::optional, std::optional, WebCore::IncludeSecureCookies, WebCore::ApplyTrackingPrevention, WebCore::ShouldRelaxThirdPartyCookieBlocking, CompletionHandler&&); diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in index b90021dcc3e4d..4069eca70f63b 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in @@ -109,6 +109,7 @@ messages -> NetworkConnectionToWebProcess LegacyReceiver { PostMessageToRemote(struct WebCore::MessageWithMessagePorts message, struct WebCore::MessagePortIdentifier remote) DidDeliverMessagePortMessages(uint64_t messageBatchIdentifier) RegisterURLSchemesAsCORSEnabled(Vector schemes); + RegisterURLSchemeAsHandledBySchemeHandler(String scheme) SetCORSDisablingPatterns(WebCore::PageIdentifier pageIdentifier, Vector patterns) #if PLATFORM(MAC) GetProcessDisplayName(struct WebKit::CoreIPCAuditToken auditToken) -> (String displayName) diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake index 235e5a2e48e89..fbabac60dc8f1 100644 --- a/Source/WebKit/PlatformWPE.cmake +++ b/Source/WebKit/PlatformWPE.cmake @@ -730,6 +730,7 @@ GI_INTROSPECT(${WPE_WEB_PROCESS_EXTENSION_API_NAME} ${WPE_API_VERSION} wpe/${WPE ${DERIVED_SOURCES_WPE_API_DIR}/WebKitContextMenuActions.h ${DERIVED_SOURCES_WPE_API_DIR}/WebKitContextMenuItem.h ${DERIVED_SOURCES_WPE_API_DIR}/WebKitHitTestResult.h + ${DERIVED_SOURCES_WPE_API_DIR}/WebKitSecurityOrigin.h ${DERIVED_SOURCES_WPE_API_DIR}/WebKitUserMessage.h ${DERIVED_SOURCES_WPE_API_DIR}/WebKitURIRequest.h ${DERIVED_SOURCES_WPE_API_DIR}/WebKitURIResponse.h diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSecurityOrigin.h.in b/Source/WebKit/UIProcess/API/glib/WebKitSecurityOrigin.h.in index 782196bb894e3..77eedb9f0e411 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSecurityOrigin.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitSecurityOrigin.h.in @@ -17,7 +17,7 @@ * Boston, MA 02110-1301, USA. */ -@API_SINGLE_HEADER_CHECK@ +@SHARED_API_SINGLE_HEADER_CHECK@ #ifndef WebKitSecurityOrigin_h #define WebKitSecurityOrigin_h diff --git a/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.cpp b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.cpp index cefd10c2d8b22..a380ac0c83124 100644 --- a/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.cpp +++ b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.cpp @@ -23,6 +23,7 @@ #include "APIDictionary.h" #include "APIInjectedBundleBundleClient.h" #include "APIString.h" +#include "WebKitSecurityOriginPrivate.h" #include "WebKitUserMessagePrivate.h" #include "WebKitWebPagePrivate.h" #include "WebKitWebProcessExtensionPrivate.h" @@ -122,6 +123,7 @@ enum { typedef HashMap > WebPageMap; struct _WebKitWebExtensionPrivate { + RefPtr bundle; WebPageMap pages; #if ENABLE(DEVELOPER_MODE) bool garbageCollectOnPageDestroy; @@ -204,6 +206,7 @@ class WebExtensionInjectedBundleClient final : public API::InjectedBundle::Clien WebKitWebExtension* webkitWebProcessExtensionCreate(InjectedBundle* bundle) { WebKitWebExtension* extension = WEBKIT_WEB_EXTENSION(g_object_new(WEBKIT_TYPE_WEB_EXTENSION, NULL)); + extension->priv->bundle = bundle; bundle->setClient(makeUnique(extension)); return extension; } @@ -246,6 +249,31 @@ WebKitWebPage* webkit_web_extension_get_page(WebKitWebExtension* extension, guin return 0; } +void webkit_web_extension_add_origin_access_whitelist_entry(WebKitWebExtension* extension, WebKitSecurityOrigin* origin, const char* protocol, const char* host, gboolean allowSubdomains) +{ + g_return_if_fail(WEBKIT_IS_WEB_EXTENSION(extension)); + g_return_if_fail(origin); + g_return_if_fail(protocol); + + extension->priv->bundle->addOriginAccessAllowListEntry(webkitSecurityOriginGetSecurityOriginData(origin).toString(), String::fromUTF8(protocol), String::fromUTF8(host), host ? allowSubdomains : true); +} + +void webkit_web_extension_remove_origin_access_whitelist_entry(WebKitWebExtension* extension, WebKitSecurityOrigin* origin, const char* protocol, const char* host, gboolean allowSubdomains) +{ + g_return_if_fail(WEBKIT_IS_WEB_EXTENSION(extension)); + g_return_if_fail(origin); + g_return_if_fail(protocol); + + extension->priv->bundle->removeOriginAccessAllowListEntry(webkitSecurityOriginGetSecurityOriginData(origin).toString(), String::fromUTF8(protocol), String::fromUTF8(host), host ? allowSubdomains : true); +} + +void webkit_web_extension_reset_origin_access_whitelists(WebKitWebExtension* extension) +{ + g_return_if_fail(WEBKIT_IS_WEB_EXTENSION(extension)); + + extension->priv->bundle->resetOriginAccessAllowLists(); +} + /** * webkit_web_extension_send_message_to_context: * @extension: a #WebKitWebExtension diff --git a/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.h.in b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.h.in index 1238fc3300927..10925fb0472c7 100644 --- a/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.h.in +++ b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.h.in @@ -24,6 +24,7 @@ #include #include <@API_INCLUDE_PREFIX@/WebKitDefines.h> +#include <@API_INCLUDE_PREFIX@/WebKitSecurityOrigin.h> #include <@API_INCLUDE_PREFIX@/WebKitUserMessage.h> #include <@API_INCLUDE_PREFIX@/WebKitWebPage.h> @@ -74,6 +75,23 @@ WEBKIT_API WebKitWebPage * webkit_web_extension_get_page (WebKitWebExtension *extension, guint64 page_id); +WEBKIT_API void +webkit_web_extension_add_origin_access_whitelist_entry (WebKitWebExtension *extension, + WebKitSecurityOrigin *origin, + const gchar *protocol, + const gchar *host, + gboolean allow_subdomains); + +WEBKIT_API void +webkit_web_extension_remove_origin_access_whitelist_entry (WebKitWebExtension *extension, + WebKitSecurityOrigin *origin, + const gchar *protocol, + const gchar *host, + gboolean allow_subdomains); + +WEBKIT_API void +webkit_web_extension_reset_origin_access_whitelists (WebKitWebExtension *extension); + WEBKIT_API void webkit_web_extension_send_message_to_context (WebKitWebExtension *extension, WebKitUserMessage *message, diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp index 00d770be33c78..ec4bd58b65341 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp @@ -8115,6 +8115,7 @@ void WebPage::registerURLSchemeHandler(WebURLSchemeHandlerIdentifier handlerIden WebCore::LegacySchemeRegistry::registerURLSchemeAsCORSEnabled(scheme); auto schemeResult = m_schemeToURLSchemeHandlerProxyMap.add(scheme, WebURLSchemeHandlerProxy::create(*this, handlerIdentifier)); m_identifierToURLSchemeHandlerProxyMap.add(handlerIdentifier, *schemeResult.iterator->value); + WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::RegisterURLSchemeAsHandledBySchemeHandler { scheme }, 0); } void WebPage::urlSchemeTaskWillPerformRedirection(WebURLSchemeHandlerIdentifier handlerIdentifier, WebCore::ResourceLoaderIdentifier taskIdentifier, ResourceResponse&& response, ResourceRequest&& request, CompletionHandler&& completionHandler) From 3fd2ed5e9a80ea274cd5250e3efa326f7ee99dc2 Mon Sep 17 00:00:00 2001 From: Jacek Manko Date: Thu, 20 Jul 2023 17:44:58 +0200 Subject: [PATCH 07/55] Implement mixed content whitelist API is exposed via WebKitWebExtension, similiar to the CORS whitelist. Wildcards can be used, with '*' replacing any string --- Source/WebCore/loader/MixedContentChecker.cpp | 85 ++++++++++++++++++- Source/WebCore/loader/MixedContentChecker.h | 6 ++ .../API/glib/WebKitWebExtension.cpp | 21 +++++ .../API/glib/WebKitWebExtension.h.in | 13 +++ .../InjectedBundle/InjectedBundle.cpp | 16 ++++ .../InjectedBundle/InjectedBundle.h | 3 + 6 files changed, 143 insertions(+), 1 deletion(-) diff --git a/Source/WebCore/loader/MixedContentChecker.cpp b/Source/WebCore/loader/MixedContentChecker.cpp index a9b3dc279f225..04fb0374cb248 100644 --- a/Source/WebCore/loader/MixedContentChecker.cpp +++ b/Source/WebCore/loader/MixedContentChecker.cpp @@ -47,7 +47,60 @@ namespace WebCore { -static bool isMixedContent(const Document& document, const URL& url) +static WTF::Vector> m_whitelist = {}; + +static bool wildcardMatch(const String& pattern, const String& url) +{ + int patternLen = pattern.length(); + int patternPos = 0; + int urlLen = url.length(); + int urlPos = 0; + int wildcardPos = -1; + int wildcardMatchEnd = 0; + + while (urlPos < urlLen) { + if (patternPos < patternLen && pattern[patternPos] == url[urlPos]) { + // characters match + patternPos++; + urlPos++; + } else if (patternPos < patternLen && pattern[patternPos] == '*') { + // mark wildcard position, start matching the rest of the pattern + wildcardPos = patternPos; + wildcardMatchEnd = urlPos; + patternPos++; + } else if (wildcardPos != -1) { + // no match, but we have a wildcard - assume wildcard handles a match to this position, + // revert patternPos to after last * + patternPos = wildcardPos + 1; + wildcardMatchEnd++; + urlPos = wildcardMatchEnd; + } else { + // no match, no wildcard - pattern does not match + return false; + } + } + + // url matches so far, and we're at the end of it + // skip any remaining wildcards + while (patternPos < patternLen && pattern[patternPos] == '*') { + patternPos++; + } + // if we're at the end of pattern, that's a match + // otherwise, the remaining part of the pattern can't be matched + return patternPos == patternLen; +} + +static bool isWhitelisted(const String& origin, const String& domain) +{ + for (auto kvPair : m_whitelist) { + if (wildcardMatch(kvPair.key, origin) && wildcardMatch(kvPair.value, domain)) { + return true; + } + } + return false; +} + +static bool isMixedContent(const Document& document, const WTF::URL& url) { // FIXME: Use document.isSecureContext(), instead of comparing against "https" scheme, when all ports stop using loopback in LayoutTests // sandboxed iframes have an opaque origin so we should perform the mixed content check considering the origin @@ -124,6 +177,11 @@ static bool frameAndAncestorsCanDisplayInsecureContent(LocalFrame& frame, MixedC return true; RefPtr document = frame.document(); + if (isWhitelisted(document->securityOrigin().toString(), url.protocolHostAndPort())) { + logConsoleWarning(frame, true, "display"_s, url); + return true; + } + if (!document->checkedContentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url)) return false; @@ -146,6 +204,11 @@ bool MixedContentChecker::frameAndAncestorsCanRunInsecureContent(LocalFrame& fra if (!foundMixedContentInFrameTree(frame, url)) return true; + if (isWhitelisted(securityOrigin.toString(), url.protocolHostAndPort())) { + logConsoleWarning(frame, true, "run"_s, url); + return true; + } + RefPtr document = frame.document(); if (!document->checkedContentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url)) return false; @@ -242,5 +305,25 @@ void MixedContentChecker::checkFormForMixedContent(LocalFrame& frame, const URL& frame.checkedLoader()->client().didDisplayInsecureContent(); } +void MixedContentChecker::addMixedContentWhitelistEntry(const String& origin, const String& domain) +{ + m_whitelist.append(makeKeyValuePair(origin, domain)); +} + +void MixedContentChecker::removeMixedContentWhitelistEntry(const String& origin, const String& domain) +{ + for (size_t i = 0; i < m_whitelist.size(); i++) { + if (m_whitelist[i].key == origin && m_whitelist[i].value == domain) { + m_whitelist.remove(i); + break; + } + } +} +void MixedContentChecker::resetMixedContentWhitelist() +{ + m_whitelist.clear(); + +} } // namespace WebCore + diff --git a/Source/WebCore/loader/MixedContentChecker.h b/Source/WebCore/loader/MixedContentChecker.h index 71d09c759033d..18de5a05b7b0d 100644 --- a/Source/WebCore/loader/MixedContentChecker.h +++ b/Source/WebCore/loader/MixedContentChecker.h @@ -31,6 +31,8 @@ #include "FetchOptions.h" #include +#include +#include namespace WebCore { @@ -55,5 +57,9 @@ bool shouldBlockRequestForDisplayableContent(LocalFrame&, const URL&, ContentTyp bool shouldBlockRequestForRunnableContent(LocalFrame&, SecurityOrigin&, const URL&, ShouldLogWarning = ShouldLogWarning::Yes); void checkFormForMixedContent(LocalFrame&, const URL&); +void addMixedContentWhitelistEntry(const String& origin, const String& domain); +void removeMixedContentWhitelistEntry(const String& origin, const String& domain); +void resetMixedContentWhitelist(); + } // namespace MixedContentChecker } // namespace WebCore diff --git a/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.cpp b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.cpp index a380ac0c83124..c568945fa8884 100644 --- a/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.cpp +++ b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.cpp @@ -274,6 +274,27 @@ void webkit_web_extension_reset_origin_access_whitelists(WebKitWebExtension* ext extension->priv->bundle->resetOriginAccessAllowLists(); } +void webkit_web_extension_add_mixed_content_whitelist_entry(WebKitWebExtension *extension, const gchar* origin, const gchar* domain) +{ + g_return_if_fail(WEBKIT_IS_WEB_EXTENSION(extension)); + + extension->priv->bundle->addMixedContentWhitelistEntry(String::fromUTF8(origin), String::fromUTF8(domain)); +} + +void webkit_web_extension_remove_mixed_content_whitelist_entry(WebKitWebExtension *extension, const gchar* origin, const gchar* domain) +{ + g_return_if_fail(WEBKIT_IS_WEB_EXTENSION(extension)); + + extension->priv->bundle->removeMixedContentWhitelistEntry(String::fromUTF8(origin), String::fromUTF8(domain)); +} + +void webkit_web_extension_reset_mixed_content_whitelist_entry(WebKitWebExtension *extension) +{ + g_return_if_fail(WEBKIT_IS_WEB_EXTENSION(extension)); + + extension->priv->bundle->resetMixedContentWhitelist(); +} + /** * webkit_web_extension_send_message_to_context: * @extension: a #WebKitWebExtension diff --git a/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.h.in b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.h.in index 10925fb0472c7..948eefc4108a5 100644 --- a/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.h.in +++ b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.h.in @@ -92,6 +92,19 @@ webkit_web_extension_remove_origin_access_whitelist_entry (WebKitWebExtension WEBKIT_API void webkit_web_extension_reset_origin_access_whitelists (WebKitWebExtension *extension); +WEBKIT_API void +webkit_web_extension_add_mixed_content_whitelist_entry (WebKitWebExtension *extension, + const gchar *origin, + const gchar *domain); + +WEBKIT_API void +webkit_web_extension_remove_mixed_content_whitelist_entry (WebKitWebExtension *extension, + const gchar *origin, + const gchar *domain); + +WEBKIT_API void +webkit_web_extension_reset_mixed_content_whitelist_entry (WebKitWebExtension *extension); + WEBKIT_API void webkit_web_extension_send_message_to_context (WebKitWebExtension *extension, WebKitUserMessage *message, diff --git a/Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.cpp b/Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.cpp index f93498dc3323c..44459bc642cd7 100644 --- a/Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.cpp +++ b/Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.cpp @@ -80,6 +80,8 @@ #include #include +#include + #if ENABLE(NOTIFICATIONS) #include "WebNotificationManager.h" #endif @@ -165,6 +167,20 @@ void InjectedBundle::resetOriginAccessAllowLists() WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::ResetOriginAccessAllowLists { }, 0); } +void InjectedBundle::addMixedContentWhitelistEntry(const String& origin, const String& domain) +{ + MixedContentChecker::addMixedContentWhitelistEntry(origin, domain); +} + +void InjectedBundle::removeMixedContentWhitelistEntry(const String& origin, const String& domain) +{ + MixedContentChecker::removeMixedContentWhitelistEntry(origin, domain); +} +void InjectedBundle::resetMixedContentWhitelist() +{ + MixedContentChecker::resetMixedContentWhitelist(); +} + void InjectedBundle::setAsynchronousSpellCheckingEnabled(bool enabled) { Page::forEachPage([enabled](Page& page) { diff --git a/Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.h b/Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.h index 64a388920b104..10be23970b763 100644 --- a/Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.h +++ b/Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.h @@ -97,6 +97,9 @@ class InjectedBundle : public API::ObjectImpl { void addOriginAccessAllowListEntry(const String&, const String&, const String&, bool); void removeOriginAccessAllowListEntry(const String&, const String&, const String&, bool); void resetOriginAccessAllowLists(); + void addMixedContentWhitelistEntry(const String&, const String&); + void removeMixedContentWhitelistEntry(const String&, const String&); + void resetMixedContentWhitelist(); void setAsynchronousSpellCheckingEnabled(bool); int numberOfPages(WebFrame*, double, double); int pageNumberForElementById(WebFrame*, const String&, double, double); From 1dd3034fd3b5ddc9b358bca338c4649333aca4fb Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Wed, 7 Dec 2022 12:39:25 +0100 Subject: [PATCH 08/55] [API] Add webkit_web_context_garbage_collect_javascript_objects method --- .../UIProcess/API/glib/WebKitWebContext.cpp | 15 +++++++++++++++ .../UIProcess/API/glib/WebKitWebContext.h.in | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp index ac1736af22af4..ba7d0cc7ff959 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp @@ -1996,6 +1996,21 @@ const gchar* webkit_web_context_get_time_zone_override(WebKitWebContext* context return context->priv->timeZoneOverride.data(); } +/** + * webkit_web_context_garbage_collect_javascript_objects: + * @context: the #WebKitWebContext + * + * Requests a garbage collection of the javascript objects to all processes. + * + * Since: 2.28 + */ +void webkit_web_context_garbage_collect_javascript_objects(WebKitWebContext* context) +{ + g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context)); + + context->priv->processPool->garbageCollectJavaScriptObjects(); +} + void webkitWebContextInitializeNotificationPermissions(WebKitWebContext* context) { g_signal_emit(context, signals[INITIALIZE_NOTIFICATION_PERMISSIONS], 0); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in index fa559936ba819..2078cf74a38fe 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in @@ -422,6 +422,10 @@ webkit_web_context_get_use_system_appearance_for_scrollbars (WebKitWebContext WEBKIT_API const gchar* webkit_web_context_get_time_zone_override (WebKitWebContext *context); +WEBKIT_API void +webkit_web_context_garbage_collect_javascript_objects + (WebKitWebContext *context); + G_END_DECLS #endif From 30502204e1ca0e59a71c74a9b5a3e216b16b1d6d Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Thu, 31 Aug 2023 16:31:36 +0200 Subject: [PATCH 09/55] Add did-start-provisional-load-for-frame signal --- .../InjectedBundle/API/glib/WebKitWebPage.cpp | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebPage.cpp b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebPage.cpp index 0c9872072b3bb..60b1e9fd17db9 100644 --- a/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebPage.cpp +++ b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebPage.cpp @@ -86,6 +86,7 @@ enum { FORM_CONTROLS_ASSOCIATED_FOR_FRAME, WILL_SUBMIT_FORM, USER_MESSAGE_RECEIVED, + DID_START_PROVISIONAL_LOAD_FOR_FRAME, LAST_SIGNAL }; @@ -196,10 +197,7 @@ class PageLoaderClient final : public API::InjectedBundle::PageLoaderClient { void didStartProvisionalLoadForFrame(WebPage&, WebFrame& frame, RefPtr&) override { - auto* webKitFrame = webkitFrameGet(&frame); - if (!webKitFrame && !frame.isMainFrame()) - return; - + auto* webKitFrame = webkitFrameGetOrCreate(&frame); const auto uri = getDocumentLoaderURL(frame.coreLocalFrame()->loader().provisionalDocumentLoader()); if (webKitFrame) @@ -207,6 +205,8 @@ class PageLoaderClient final : public API::InjectedBundle::PageLoaderClient { if (frame.isMainFrame()) webkitWebPageSetURI(m_webPage, uri); + + g_signal_emit(m_webPage, signals[DID_START_PROVISIONAL_LOAD_FOR_FRAME], 0, webKitFrame); } void didReceiveServerRedirectForProvisionalLoadForFrame(WebPage&, WebFrame& frame, RefPtr&) override @@ -789,6 +789,21 @@ ALLOW_DEPRECATED_DECLARATIONS_END g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 1, WEBKIT_TYPE_USER_MESSAGE); + + /** + * WebKitWebPage::did-start-provisional-load-for-frame: + * @web_page: the #WebKitWebPage on which the signal is emitted + * @frame: the #WebKitFrame + * + */ + signals[DID_START_PROVISIONAL_LOAD_FOR_FRAME] = g_signal_new( + "did-start-provisional-load-for-frame", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + 0, 0, nullptr, + g_cclosure_marshal_generic, + G_TYPE_NONE, 1, + WEBKIT_TYPE_FRAME); } WebPage* webkitWebPageGetPage(WebKitWebPage *webPage) From 8830313cb4364cc49d863de98ea198158a18d3b3 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Wed, 25 Jan 2023 15:50:59 +0100 Subject: [PATCH 10/55] [Responsiveness] Add API to manually check WebProcess responsiveness --- .../UIProcess/API/glib/WebKitWebView.cpp | 21 +++++++++++++++++++ .../UIProcess/API/glib/WebKitWebView.h.in | 11 ++++++++++ Source/WebKit/UIProcess/WebPageProxy.cpp | 15 +++++++++++++ Source/WebKit/UIProcess/WebPageProxy.h | 1 + 4 files changed, 48 insertions(+) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp index 9edd3e67dd17b..c2ac8e0719835 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -5645,3 +5645,24 @@ webkit_web_view_get_default_content_security_policy(WebKitWebView* webView) return webView->priv->defaultContentSecurityPolicy.data(); } + +void webkit_web_view_is_web_process_responsive_async(WebKitWebView *webView, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + + GRefPtr task = adoptGRef(g_task_new(webView, cancellable, callback, userData)); + getPage(webView).isWebProcessResponsive([task = WTFMove(task)] (bool isWebProcessResponsive) { + if (g_task_return_error_if_cancelled(task.get())) + return; + + g_task_return_boolean(task.get(), isWebProcessResponsive); + }); +} + +gboolean webkit_web_view_is_web_process_responsive_finish(WebKitWebView* webView, GAsyncResult* result, GError** error) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), false); + g_return_val_if_fail(g_task_is_valid(result, webView), false); + + return g_task_propagate_boolean(G_TASK(result), error); +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in b/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in index f385fd67b1074..b1159e2552bf8 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in @@ -1047,6 +1047,17 @@ webkit_web_view_get_default_content_security_policy (WebKitWebView */ #endif +WEBKIT_API void +webkit_web_view_is_web_process_responsive_async (WebKitWebView *web_view, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +WEBKIT_API gboolean +webkit_web_view_is_web_process_responsive_finish (WebKitWebView *web_view, + GAsyncResult *result, + GError **error); + G_END_DECLS #endif diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp index 70538fe2d307d..b700123084b1e 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp @@ -9636,6 +9636,21 @@ void WebPageProxy::didChangeProcessIsResponsive() internals().pageLoadState.didChangeProcessIsResponsive(); } +void WebPageProxy::isWebProcessResponsive(CompletionHandler&& callback) +{ + if (m_isClosed) { + if (callback) { + RunLoop::main().dispatch([callback = WTFMove(callback)]() mutable { + bool isWebProcessResponsive = true; + callback(isWebProcessResponsive); + }); + } + return; + } + + process().isResponsive(WTFMove(callback)); +} + String WebPageProxy::currentURL() const { String url = internals().pageLoadState.activeURL(); diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h index 8647cfcd97633..40ec4e18b09c3 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.h +++ b/Source/WebKit/UIProcess/WebPageProxy.h @@ -1492,6 +1492,7 @@ class WebPageProxy final : public API::ObjectImpl, publ void dispatchProcessDidTerminate(ProcessTerminationReason); void willChangeProcessIsResponsive(); void didChangeProcessIsResponsive(); + void isWebProcessResponsive(CompletionHandler&& callback); #if PLATFORM(IOS_FAMILY) void processWillBecomeSuspended(); From 7bf8a30153b917cae84ad737a430c51bae90c870 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Wed, 25 Jan 2023 15:52:37 +0100 Subject: [PATCH 11/55] [Responsiveness] Add API to get the WebProcess ID --- Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp | 7 +++++++ Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in | 3 +++ 2 files changed, 10 insertions(+) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp index c2ac8e0719835..3016245c8196d 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -5666,3 +5666,10 @@ gboolean webkit_web_view_is_web_process_responsive_finish(WebKitWebView* webView return g_task_propagate_boolean(G_TASK(result), error); } + +pid_t webkit_web_view_get_web_process_identifier(WebKitWebView *webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0); + + return getPage(webView).processID(); +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in b/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in index b1159e2552bf8..f323902daedb2 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in @@ -1058,6 +1058,9 @@ webkit_web_view_is_web_process_responsive_finish (WebKitWebView GAsyncResult *result, GError **error); +WEBKIT_API pid_t +webkit_web_view_get_web_process_identifier (WebKitWebView *web_view); + G_END_DECLS #endif From e846875f66f7aed1afbd09659d32848eb47d09e2 Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Wed, 22 Dec 2021 20:22:31 +0000 Subject: [PATCH 12/55] Expose JSC "C" API Signed-off-by: Eugene Mutavchi --- Source/JavaScriptCore/API/glib/JSCContextPrivate.h | 2 +- Source/JavaScriptCore/PlatformWPE.cmake | 4 ++++ Source/WebKit/webkitglib-symbols.map | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/JavaScriptCore/API/glib/JSCContextPrivate.h b/Source/JavaScriptCore/API/glib/JSCContextPrivate.h index 67fcab69f79e3..8d682aa10ba8d 100644 --- a/Source/JavaScriptCore/API/glib/JSCContextPrivate.h +++ b/Source/JavaScriptCore/API/glib/JSCContextPrivate.h @@ -33,7 +33,7 @@ typedef const struct OpaqueJSValue* JSValueRef; typedef struct OpaqueJSValue* JSObjectRef; JS_EXPORT_PRIVATE GRefPtr jscContextGetOrCreate(JSGlobalContextRef); -JS_EXPORT_PRIVATE JSGlobalContextRef jscContextGetJSContext(JSCContext*); +G_BEGIN_DECLS JSC_API JS_EXPORT_PRIVATE JSGlobalContextRef jscContextGetJSContext(JSCContext*); G_END_DECLS JS_EXPORT_PRIVATE GRefPtr jscContextGetOrCreateValue(JSCContext*, JSValueRef); void jscContextValueDestroyed(JSCContext*, JSValueRef); JSC::JSObject* jscContextGetJSWrapper(JSCContext*, gpointer); diff --git a/Source/JavaScriptCore/PlatformWPE.cmake b/Source/JavaScriptCore/PlatformWPE.cmake index efcc6be161e2e..bab1d184e1584 100644 --- a/Source/JavaScriptCore/PlatformWPE.cmake +++ b/Source/JavaScriptCore/PlatformWPE.cmake @@ -14,6 +14,10 @@ list(APPEND JavaScriptCore_PRIVATE_DEFINITIONS PKGLIBDIR="${CMAKE_INSTALL_FULL_LIBDIR}/wpe-webkit-${WPE_API_VERSION}" ) +install(FILES ${JavaScriptCore_PUBLIC_FRAMEWORK_HEADERS} + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/wpe-webkit-${WPE_API_VERSION}/JavaScriptCore" +) + install(FILES ${JavaScriptCore_INSTALLED_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/wpe-webkit-${WPE_API_VERSION}/jsc" COMPONENT "Development" diff --git a/Source/WebKit/webkitglib-symbols.map b/Source/WebKit/webkitglib-symbols.map index 8b5340f55b9fe..cf28ff13a2248 100644 --- a/Source/WebKit/webkitglib-symbols.map +++ b/Source/WebKit/webkitglib-symbols.map @@ -2,6 +2,8 @@ global: jsc_*; webkit_*; + JS*; + jscContextGetJSContext; extern "C++" { "WebKit::GPUProcessMain(int, char**)"; "WebKit::NetworkProcessMain(int, char**)"; From 75087758cd73197e3e1aa7962cef6d18567c339b Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Wed, 25 Jan 2023 17:46:37 +0100 Subject: [PATCH 13/55] Add a setting to allow closing windows from scripts --- .../Preferences/UnifiedWebPreferences.yaml | 14 +++++ Source/WebCore/page/DOMWindow.cpp | 2 +- .../UIProcess/API/glib/WebKitSettings.cpp | 56 +++++++++++++++++++ .../UIProcess/API/glib/WebKitSettings.h.in | 7 +++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml index 21b4c1aa39dbc..db72e479ca741 100644 --- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml +++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml @@ -291,6 +291,20 @@ AllowRunningOfInsecureContent: WebCore: default: false +AllowScriptsToCloseWindows: + type: bool + status: embedder + humanReadableName: "Allow scripts to close windows" + humanReadableDescription: "Allow scripts to close windows" + condition: PLATFORM(WPE) + defaultValue: + WebKitLegacy: + default: false + WebKit: + default: false + WebCore: + default: false + AllowSettingAnyXHRHeaderFromFileURLs: type: bool status: embedder diff --git a/Source/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp index 85bb921bec67a..05289c8c6ab40 100644 --- a/Source/WebCore/page/DOMWindow.cpp +++ b/Source/WebCore/page/DOMWindow.cpp @@ -112,7 +112,7 @@ void DOMWindow::close() if (!frame->isMainFrame()) return; - if (!(page->openedByDOM() || page->backForward().count() <= 1)) { + if (!(page->openedByDOM() || page->backForward().count() <= 1 || frame->settings().allowScriptsToCloseWindows())) { checkedConsole()->addMessage(MessageSource::JS, MessageLevel::Warning, "Can't close the window since it was not opened by JavaScript"_s); return; } diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp index 197c549be2313..a6ced79aafa10 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp @@ -174,6 +174,7 @@ enum { PROP_MEDIA_CONTENT_TYPES_REQUIRING_HARDWARE_SUPPORT, PROP_ENABLE_WEBRTC, PROP_DISABLE_WEB_SECURITY, + PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS, N_PROPERTIES, }; @@ -409,6 +410,9 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN case PROP_DISABLE_WEB_SECURITY: webkit_settings_set_disable_web_security(settings, g_value_get_boolean(value)); break; + case PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS: + webkit_settings_set_allow_scripts_to_close_windows(settings, g_value_get_boolean(value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); break; @@ -617,6 +621,9 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN case PROP_DISABLE_WEB_SECURITY: g_value_set_boolean(value, webkit_settings_get_disable_web_security(settings)); break; + case PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS: + g_value_set_boolean(value, webkit_settings_get_allow_scripts_to_close_windows(settings)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); break; @@ -1618,6 +1625,19 @@ static void webkit_settings_class_init(WebKitSettingsClass* klass) FALSE, readWriteConstructParamFlags); + /** + * WebKitSettings:allow-scripts-to-close-windows: + * + * Allow scripts to close windows they didn't open. + * + */ + sObjProperties[PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS] = g_param_spec_boolean( + "allow-scripts-to-close-windows", + _("Allow scripts to close windows"), + _("Whether scripts can close windows they didn't open."), + FALSE, + readWriteConstructParamFlags); + g_object_class_install_properties(gObjectClass, N_PROPERTIES, sObjProperties); } @@ -4131,3 +4151,39 @@ WebKitFeatureList* webkit_settings_get_development_features(void) { return webkitFeatureListCreate(WebPreferences::internalDebugFeatures()); } + +/** + * webkit_settings_get_allow_scripts_to_close_windows: + * @settings: a #WebKitSettings + * + * Get the #WebKitSettings:allow-scripts-to-close-windows property. + * + * Returns: %TRUE If script can close windows not opened by them or %FALSE otherwise. + */ +gboolean webkit_settings_get_allow_scripts_to_close_windows (WebKitSettings *settings) +{ + g_return_val_if_fail(WEBKIT_IS_SETTINGS(settings), FALSE); + + return settings->priv->preferences->allowScriptsToCloseWindows(); +} + +/** + * webkit_settings_set_allow_scripts_to_close_windows + * @settings: a #WebKitSettings + * @allowed: Value to be set + * + * Set the #WebKitSettings:allow-scripts-to-close-windows property. + */ +WEBKIT_API void +webkit_settings_set_allow_scripts_to_close_windows(WebKitSettings *settings, gboolean allowed) +{ + g_return_if_fail(WEBKIT_IS_SETTINGS(settings)); + + WebKitSettingsPrivate* priv = settings->priv; + bool currentValue = priv->preferences->allowScriptsToCloseWindows(); + if (currentValue == allowed) + return; + + priv->preferences->setAllowScriptsToCloseWindows(allowed); + g_object_notify(G_OBJECT(settings), "allow-scripts-to-close-windows"); +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in index 6a9bfa6afd95d..e637d233f35fe 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in @@ -562,6 +562,13 @@ webkit_settings_get_experimental_features (void); WEBKIT_API WebKitFeatureList * webkit_settings_get_development_features (void); +WEBKIT_API gboolean +webkit_settings_get_allow_scripts_to_close_windows (WebKitSettings *settings); + +WEBKIT_API void +webkit_settings_set_allow_scripts_to_close_windows (WebKitSettings *settings, + gboolean allowed); + G_END_DECLS #endif /* WebKitSettings_h */ From fb00101ca6f5fa3437e704f977da410ad5d72077 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Fri, 27 Jan 2023 14:07:11 +0100 Subject: [PATCH 14/55] Add setting to enable/disable directory upload --- .../UIProcess/API/glib/WebKitSettings.cpp | 55 +++++++++++++++++++ .../UIProcess/API/glib/WebKitSettings.h.in | 7 +++ 2 files changed, 62 insertions(+) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp index a6ced79aafa10..48e6bddcafe7b 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp @@ -175,6 +175,7 @@ enum { PROP_ENABLE_WEBRTC, PROP_DISABLE_WEB_SECURITY, PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS, + PROP_ENABLE_DIRECTORY_UPLOAD, N_PROPERTIES, }; @@ -413,6 +414,9 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN case PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS: webkit_settings_set_allow_scripts_to_close_windows(settings, g_value_get_boolean(value)); break; + case PROP_ENABLE_DIRECTORY_UPLOAD: + webkit_settings_set_enable_directory_upload(settings, g_value_get_boolean(value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); break; @@ -624,6 +628,9 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN case PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS: g_value_set_boolean(value, webkit_settings_get_allow_scripts_to_close_windows(settings)); break; + case PROP_ENABLE_DIRECTORY_UPLOAD: + g_value_set_boolean(value, webkit_settings_get_enable_directory_upload(settings)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); break; @@ -1638,6 +1645,19 @@ static void webkit_settings_class_init(WebKitSettingsClass* klass) FALSE, readWriteConstructParamFlags); + /** + * WebKitSettings:enable-directory-upload: + * + * Enable or disable directory upload. + * + */ + sObjProperties[PROP_ENABLE_DIRECTORY_UPLOAD] = g_param_spec_boolean( + "enable-directory-upload", + _("Enable directory upload"), + _("Whether directory upload should be enabled."), + TRUE, + readWriteConstructParamFlags); + g_object_class_install_properties(gObjectClass, N_PROPERTIES, sObjProperties); } @@ -4187,3 +4207,38 @@ webkit_settings_set_allow_scripts_to_close_windows(WebKitSettings *settings, gbo priv->preferences->setAllowScriptsToCloseWindows(allowed); g_object_notify(G_OBJECT(settings), "allow-scripts-to-close-windows"); } + +/** + * webkit_settings_get_enable_directory_upload: + * @settings: a #WebKitSettings + * + * Get the #WebKitSettings:enable-directory-upload property. + * + * Returns: %TRUE If Directory Upload is enabled or %FALSE otherwise. + */ +gboolean webkit_settings_get_enable_directory_upload(WebKitSettings* settings) +{ + g_return_val_if_fail(WEBKIT_IS_SETTINGS(settings), FALSE); + + return settings->priv->preferences->directoryUploadEnabled(); +} + +/** + * webkit_settings_set_enable_directory_upload: + * @settings: a #WebKitSettings + * @enabled: Value to be set + * + * Set the #WebKitSettings:enable-directory-upload property. + */ +void webkit_settings_set_enable_directory_upload(WebKitSettings* settings, gboolean enabled) +{ + g_return_if_fail(WEBKIT_IS_SETTINGS(settings)); + + WebKitSettingsPrivate* priv = settings->priv; + bool currentValue = priv->preferences->directoryUploadEnabled(); + if (currentValue == enabled) + return; + + priv->preferences->setDirectoryUploadEnabled(enabled); + g_object_notify(G_OBJECT(settings), "enable-directory-upload"); +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in index e637d233f35fe..35a3bb742c572 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in @@ -569,6 +569,13 @@ WEBKIT_API void webkit_settings_set_allow_scripts_to_close_windows (WebKitSettings *settings, gboolean allowed); +WEBKIT_API gboolean +webkit_settings_get_enable_directory_upload (WebKitSettings *settings); + +WEBKIT_API void +webkit_settings_set_enable_directory_upload (WebKitSettings *settings, + gboolean enabled); + G_END_DECLS #endif /* WebKitSettings_h */ From 7a2e7411fef13ca8b08e279b27045e47a1c4fda2 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Thu, 16 Feb 2023 17:01:42 +0100 Subject: [PATCH 15/55] Add provision to allow insecure content --- .../UIProcess/API/glib/WebKitSettings.cpp | 108 ++++++++++++++++++ .../UIProcess/API/glib/WebKitSettings.h.in | 14 +++ 2 files changed, 122 insertions(+) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp index 48e6bddcafe7b..0e074a12ecd62 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp @@ -174,6 +174,8 @@ enum { PROP_MEDIA_CONTENT_TYPES_REQUIRING_HARDWARE_SUPPORT, PROP_ENABLE_WEBRTC, PROP_DISABLE_WEB_SECURITY, + PROP_ALLOW_RUNNING_OF_INSECURE_CONTENT, + PROP_ALLOW_DISPLAY_OF_INSECURE_CONTENT, PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS, PROP_ENABLE_DIRECTORY_UPLOAD, N_PROPERTIES, @@ -411,6 +413,12 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN case PROP_DISABLE_WEB_SECURITY: webkit_settings_set_disable_web_security(settings, g_value_get_boolean(value)); break; + case PROP_ALLOW_RUNNING_OF_INSECURE_CONTENT: + webkit_settings_set_allow_running_of_insecure_content(settings, g_value_get_boolean(value)); + break; + case PROP_ALLOW_DISPLAY_OF_INSECURE_CONTENT: + webkit_settings_set_allow_display_of_insecure_content(settings, g_value_get_boolean(value)); + break; case PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS: webkit_settings_set_allow_scripts_to_close_windows(settings, g_value_get_boolean(value)); break; @@ -625,6 +633,12 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN case PROP_DISABLE_WEB_SECURITY: g_value_set_boolean(value, webkit_settings_get_disable_web_security(settings)); break; + case PROP_ALLOW_RUNNING_OF_INSECURE_CONTENT: + g_value_set_boolean(value, webkit_settings_get_allow_running_of_insecure_content(settings)); + break; + case PROP_ALLOW_DISPLAY_OF_INSECURE_CONTENT: + g_value_set_boolean(value, webkit_settings_get_allow_display_of_insecure_content(settings)); + break; case PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS: g_value_set_boolean(value, webkit_settings_get_allow_scripts_to_close_windows(settings)); break; @@ -1632,6 +1646,30 @@ static void webkit_settings_class_init(WebKitSettingsClass* klass) FALSE, readWriteConstructParamFlags); + /** + * WebKitSettings:allow-running-of-insecure-content: + * + * Allow running of insecure content on pages + */ + sObjProperties[PROP_ALLOW_RUNNING_OF_INSECURE_CONTENT] = g_param_spec_boolean( + "allow-running-of-insecure-content", + _("Allow running insecure content"), + _("Whether running insecure content should be allowed."), + FALSE, + readWriteConstructParamFlags); + + /** + * WebKitSettings:allow-display-of-insecure-content: + * + * Allow display of insecure content on pages + */ + sObjProperties[PROP_ALLOW_DISPLAY_OF_INSECURE_CONTENT] = g_param_spec_boolean( + "allow-display-of-insecure-content", + _("Allow display insecure content"), + _("Whether display insecure content should be allowed."), + FALSE, + readWriteConstructParamFlags); + /** * WebKitSettings:allow-scripts-to-close-windows: * @@ -4172,6 +4210,76 @@ WebKitFeatureList* webkit_settings_get_development_features(void) return webkitFeatureListCreate(WebPreferences::internalDebugFeatures()); } +/** + * webkit_settings_get_allow_running_of_insecure_content: + * @settings: a #WebKitSettings + * + * Get the #WebKitSettings:allow-running-of-insecure-content property. + * + * Returns: %TRUE If running of insecure content is allowed or %FALSE otherwise. + */ +gboolean webkit_settings_get_allow_running_of_insecure_content(WebKitSettings* settings) +{ + g_return_val_if_fail(WEBKIT_IS_SETTINGS(settings), FALSE); + + return settings->priv->preferences->allowRunningOfInsecureContent(); +} + +/** + * webkit_settings_set_allow_running_of_insecure_content: + * @settings: a #WebKitSettings + * @allowed: Value to be set + * + * Set the #WebKitSettings:allow-running-of-insecure-content property. + */ +void webkit_settings_set_allow_running_of_insecure_content(WebKitSettings* settings, gboolean allowed) +{ + g_return_if_fail(WEBKIT_IS_SETTINGS(settings)); + + WebKitSettingsPrivate* priv = settings->priv; + bool currentValue = priv->preferences->allowRunningOfInsecureContent(); + if (currentValue == allowed) + return; + + priv->preferences->setAllowRunningOfInsecureContent(allowed); + g_object_notify_by_pspec(G_OBJECT(settings), sObjProperties[PROP_ALLOW_RUNNING_OF_INSECURE_CONTENT]); +} + +/** + * webkit_settings_get_allow_display_of_insecure_content: + * @settings: a #WebKitSettings + * + * Get the #WebKitSettings:allow-display-of-insecure-content property. + * + * Returns: %TRUE If display of insecure content is allowed or %FALSE otherwise. + */ +gboolean webkit_settings_get_allow_display_of_insecure_content(WebKitSettings* settings) +{ + g_return_val_if_fail(WEBKIT_IS_SETTINGS(settings), FALSE); + + return settings->priv->preferences->allowDisplayOfInsecureContent(); +} + +/** + * webkit_settings_set_allow_display_of_insecure_content: + * @settings: a #WebKitSettings + * @allowed: Value to be set + * + * Set the #WebKitSettings:allow-display-of-insecure-content property. + */ +void webkit_settings_set_allow_display_of_insecure_content(WebKitSettings* settings, gboolean allowed) +{ + g_return_if_fail(WEBKIT_IS_SETTINGS(settings)); + + WebKitSettingsPrivate* priv = settings->priv; + bool currentValue = priv->preferences->allowDisplayOfInsecureContent(); + if (currentValue == allowed) + return; + + priv->preferences->setAllowDisplayOfInsecureContent(allowed); + g_object_notify_by_pspec(G_OBJECT(settings), sObjProperties[PROP_ALLOW_DISPLAY_OF_INSECURE_CONTENT]); +} + /** * webkit_settings_get_allow_scripts_to_close_windows: * @settings: a #WebKitSettings diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in index 35a3bb742c572..3f5a9f177fe79 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in @@ -562,6 +562,20 @@ webkit_settings_get_experimental_features (void); WEBKIT_API WebKitFeatureList * webkit_settings_get_development_features (void); +WEBKIT_API gboolean +webkit_settings_get_allow_running_of_insecure_content (WebKitSettings *settings); + +WEBKIT_API void +webkit_settings_set_allow_running_of_insecure_content (WebKitSettings *settings, + gboolean allowed); + +WEBKIT_API gboolean +webkit_settings_get_allow_display_of_insecure_content (WebKitSettings *settings); + +WEBKIT_API void +webkit_settings_set_allow_display_of_insecure_content (WebKitSettings *settings, + gboolean allowed); + WEBKIT_API gboolean webkit_settings_get_allow_scripts_to_close_windows (WebKitSettings *settings); From a9798739b7449b0dee568761499b7bb90ee49876 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Thu, 2 Mar 2023 11:52:32 +0100 Subject: [PATCH 16/55] Add a property to WebKitWebsiteDataManager to set the LocalStorage quota. --- Source/WebCore/page/Settings.yaml | 6 +++++ .../storage/StorageNamespaceProvider.cpp | 16 ++++++-------- .../storage/StorageNamespaceProvider.h | 4 ++-- Source/WebCore/testing/Internals.cpp | 2 +- Source/WebKit/NetworkProcess/NetworkProcess.h | 8 +++++++ .../NetworkProcessCreationParameters.h | 1 + ...ProcessCreationParameters.serialization.in | 1 + .../soup/NetworkProcessSoup.cpp | 4 ++++ .../storage/LocalStorageManager.cpp | 5 ++--- .../WebKit/Shared/WebPageCreationParameters.h | 2 ++ ...WebPageCreationParameters.serialization.in | 2 ++ .../API/glib/WebKitWebsiteDataManager.cpp | 22 +++++++++++++++++++ Source/WebKit/UIProcess/WebPageProxy.cpp | 2 ++ Source/WebKit/UIProcess/WebProcessPool.h | 2 ++ .../UIProcess/WebsiteData/WebsiteDataStore.h | 1 + .../WebsiteDataStoreConfiguration.cpp | 1 + .../WebsiteDataStoreConfiguration.h | 4 ++++ .../UIProcess/soup/WebProcessPoolSoup.cpp | 2 ++ Source/WebKit/WebProcess/WebPage/WebPage.cpp | 2 ++ 19 files changed, 72 insertions(+), 15 deletions(-) diff --git a/Source/WebCore/page/Settings.yaml b/Source/WebCore/page/Settings.yaml index ddddf2a5ea7e2..3199bbbee1938 100644 --- a/Source/WebCore/page/Settings.yaml +++ b/Source/WebCore/page/Settings.yaml @@ -263,6 +263,12 @@ LocalStorageDatabasePath: WebCore: default: '{ }' +LocalStorageQuota: + type: uint32_t + defaultValue: + WebCore: + default: 5242880 + MaximumHTMLParserDOMTreeDepth: type: uint32_t defaultValue: diff --git a/Source/WebCore/storage/StorageNamespaceProvider.cpp b/Source/WebCore/storage/StorageNamespaceProvider.cpp index f7466bf89d206..67f2fef254297 100644 --- a/Source/WebCore/storage/StorageNamespaceProvider.cpp +++ b/Source/WebCore/storage/StorageNamespaceProvider.cpp @@ -29,14 +29,12 @@ #include "Document.h" #include "Page.h" #include "SecurityOriginData.h" +#include "Settings.h" #include "StorageArea.h" #include "StorageNamespace.h" namespace WebCore { -// Suggested by the HTML5 spec. -unsigned localStorageDatabaseQuotaInBytes = 5 * 1024 * 1024; - StorageNamespaceProvider::StorageNamespaceProvider() { } @@ -53,9 +51,9 @@ Ref StorageNamespaceProvider::localStorageArea(Document& document) RefPtr storageNamespace; if (document.canAccessResource(ScriptExecutionContext::ResourceType::LocalStorage) == ScriptExecutionContext::HasResourceAccess::DefaultForThirdParty) - storageNamespace = &transientLocalStorageNamespace(document.topOrigin(), document.page()->sessionID()); + storageNamespace = &transientLocalStorageNamespace(document.topOrigin(), document.page()->settings().localStorageQuota(), document.page()->sessionID()); else - storageNamespace = &localStorageNamespace(document.page()->sessionID()); + storageNamespace = &localStorageNamespace(document.page()->settings().localStorageQuota(), document.page()->sessionID()); return storageNamespace->storageArea(document.securityOrigin()); } @@ -69,20 +67,20 @@ Ref StorageNamespaceProvider::sessionStorageArea(Document& document return sessionStorageNamespace(document.topOrigin(), *document.page())->storageArea(document.securityOrigin()); } -StorageNamespace& StorageNamespaceProvider::localStorageNamespace(PAL::SessionID sessionID) +StorageNamespace& StorageNamespaceProvider::localStorageNamespace(unsigned quota, PAL::SessionID sessionID) { if (!m_localStorageNamespace) - m_localStorageNamespace = createLocalStorageNamespace(localStorageDatabaseQuotaInBytes, sessionID); + m_localStorageNamespace = createLocalStorageNamespace(quota, sessionID); ASSERT(m_localStorageNamespace->sessionID() == sessionID); return *m_localStorageNamespace; } -StorageNamespace& StorageNamespaceProvider::transientLocalStorageNamespace(SecurityOrigin& securityOrigin, PAL::SessionID sessionID) +StorageNamespace& StorageNamespaceProvider::transientLocalStorageNamespace(SecurityOrigin& securityOrigin, unsigned quota, PAL::SessionID sessionID) { auto& slot = m_transientLocalStorageNamespaces.add(securityOrigin.data(), nullptr).iterator->value; if (!slot) - slot = createTransientLocalStorageNamespace(securityOrigin, localStorageDatabaseQuotaInBytes, sessionID); + slot = createTransientLocalStorageNamespace(securityOrigin, quota, sessionID); ASSERT(slot->sessionID() == sessionID); return *slot; diff --git a/Source/WebCore/storage/StorageNamespaceProvider.h b/Source/WebCore/storage/StorageNamespaceProvider.h index 057b6e8c70672..e91f6a1c10aef 100644 --- a/Source/WebCore/storage/StorageNamespaceProvider.h +++ b/Source/WebCore/storage/StorageNamespaceProvider.h @@ -63,8 +63,8 @@ class StorageNamespaceProvider : public RefCounted { private: friend class Internals; - WEBCORE_EXPORT StorageNamespace& localStorageNamespace(PAL::SessionID); - StorageNamespace& transientLocalStorageNamespace(SecurityOrigin&, PAL::SessionID); + WEBCORE_EXPORT StorageNamespace& localStorageNamespace(unsigned quota, PAL::SessionID); + StorageNamespace& transientLocalStorageNamespace(SecurityOrigin&, unsigned quota, PAL::SessionID); virtual Ref createLocalStorageNamespace(unsigned quota, PAL::SessionID) = 0; virtual Ref createTransientLocalStorageNamespace(SecurityOrigin&, unsigned quota, PAL::SessionID) = 0; diff --git a/Source/WebCore/testing/Internals.cpp b/Source/WebCore/testing/Internals.cpp index d27a1c7c53284..c27db4042e27c 100644 --- a/Source/WebCore/testing/Internals.cpp +++ b/Source/WebCore/testing/Internals.cpp @@ -3072,7 +3072,7 @@ uint64_t Internals::storageAreaMapCount() const if (!page) return 0; - return page->storageNamespaceProvider().localStorageNamespace(page->sessionID()).storageAreaMapCountForTesting(); + return page->storageNamespaceProvider().localStorageNamespace(page->settings().localStorageQuota(), page->sessionID()).storageAreaMapCountForTesting(); } uint64_t Internals::elementIdentifier(Element& element) const diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.h b/Source/WebKit/NetworkProcess/NetworkProcess.h index 6d41842684f3e..c7f0b886b1986 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkProcess.h @@ -412,6 +412,10 @@ class NetworkProcess final : public AuxiliaryProcess, private DownloadManager::C void setEmulatedConditions(PAL::SessionID, std::optional&& bytesPerSecondLimit); #endif +#if USE(SOUP) + static unsigned localStorageQuota() { return s_localStorageQuota; } +#endif + void deleteWebsiteDataForOrigin(PAL::SessionID, OptionSet, const WebCore::ClientOrigin&, CompletionHandler&&); void deleteWebsiteDataForOrigins(PAL::SessionID, OptionSet, const Vector& origins, const Vector& cookieHostNames, const Vector& HSTSCacheHostnames, const Vector&, CompletionHandler&&); @@ -586,6 +590,10 @@ class NetworkProcess final : public AuxiliaryProcess, private DownloadManager::C int m_mediaStreamingActivitityToken { NOTIFY_TOKEN_INVALID }; bool m_isParentProcessFullWebBrowserOrRunningTest { false }; #endif + +#if USE(SOUP) + static unsigned s_localStorageQuota; +#endif }; #if !PLATFORM(COCOA) diff --git a/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h b/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h index ee1295074b923..dadb6889e7f51 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h +++ b/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h @@ -66,6 +66,7 @@ struct NetworkProcessCreationParameters { WebCore::HTTPCookieAcceptPolicy cookieAcceptPolicy { WebCore::HTTPCookieAcceptPolicy::AlwaysAccept }; Vector languages; std::optional memoryPressureHandlerConfiguration; + uint32_t localStorageQuota; #endif Vector urlSchemesRegisteredAsSecure; diff --git a/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.serialization.in b/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.serialization.in index b4b6807c90340..6e9d46612b7c6 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.serialization.in +++ b/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.serialization.in @@ -44,6 +44,7 @@ headers: "NetworkProcessCreationParameters.h" "AuxiliaryProcessCreationParameter WebCore::HTTPCookieAcceptPolicy cookieAcceptPolicy Vector languages std::optional memoryPressureHandlerConfiguration + uint32_t localStorageQuota #endif Vector urlSchemesRegisteredAsSecure diff --git a/Source/WebKit/NetworkProcess/soup/NetworkProcessSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkProcessSoup.cpp index 0fe1bff291851..0826d2d60930f 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkProcessSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkProcessSoup.cpp @@ -50,6 +50,8 @@ namespace WebKit { using namespace WebCore; +unsigned NetworkProcess::s_localStorageQuota = 5 * MB; + static CString buildAcceptLanguages(const Vector& languages) { size_t languagesCount = languages.size(); @@ -155,6 +157,8 @@ void NetworkProcess::platformInitializeNetworkProcess(const NetworkProcessCreati }); } #endif + + s_localStorageQuota = parameters.localStorageQuota; } void NetworkProcess::setIgnoreTLSErrors(PAL::SessionID sessionID, bool ignoreTLSErrors) diff --git a/Source/WebKit/NetworkProcess/storage/LocalStorageManager.cpp b/Source/WebKit/NetworkProcess/storage/LocalStorageManager.cpp index 2e5cfcdc09962..ba81c7310ce72 100644 --- a/Source/WebKit/NetworkProcess/storage/LocalStorageManager.cpp +++ b/Source/WebKit/NetworkProcess/storage/LocalStorageManager.cpp @@ -27,6 +27,7 @@ #include "LocalStorageManager.h" #include "MemoryStorageArea.h" +#include "NetworkProcess.h" #include "SQLiteStorageArea.h" #include "StorageAreaRegistry.h" #include @@ -34,8 +35,6 @@ namespace WebKit { -// Suggested by https://www.w3.org/TR/webstorage/#disk-space -constexpr unsigned localStorageQuotaInBytes = 5 * MB; constexpr auto s_fileSuffix = ".localstorage"_s; constexpr auto s_fileName = "localstorage.sqlite3"_s; @@ -179,7 +178,7 @@ StorageAreaIdentifier LocalStorageManager::connectToLocalStorageArea(IPC::Connec { if (!m_localStorageArea) { if (!m_path.isEmpty()) - m_localStorageArea = makeUnique(localStorageQuotaInBytes, origin, m_path, WTFMove(workQueue)); + m_localStorageArea = makeUnique(NetworkProcess::localStorageQuota(), origin, m_path, WTFMove(workQueue)); else m_localStorageArea = makeUnique(origin, StorageAreaBase::StorageType::Local); diff --git a/Source/WebKit/Shared/WebPageCreationParameters.h b/Source/WebKit/Shared/WebPageCreationParameters.h index e0f2fcf54bf77..22e91dbf4fbaf 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.h +++ b/Source/WebKit/Shared/WebPageCreationParameters.h @@ -317,6 +317,8 @@ struct WebPageCreationParameters { WebCore::ContentSecurityPolicyModeForExtension contentSecurityPolicyModeForExtension { WebCore::ContentSecurityPolicyModeForExtension::None }; std::optional subframeProcessPageParameters; + uint32_t localStorageQuota; + std::optional openerFrameIdentifier; std::optional mainFrameIdentifier; diff --git a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in index c7c3aac107d2b..d47af9edef41e 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in +++ b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in @@ -245,6 +245,8 @@ enum class WebCore::UserInterfaceLayoutDirection : bool; WebCore::ContentSecurityPolicyModeForExtension contentSecurityPolicyModeForExtension; std::optional subframeProcessPageParameters; + uint32_t localStorageQuota; + std::optional openerFrameIdentifier; std::optional mainFrameIdentifier; diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebsiteDataManager.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebsiteDataManager.cpp index cd66c76412062..2da0d28ea8a0e 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebsiteDataManager.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebsiteDataManager.cpp @@ -86,6 +86,7 @@ enum { PROP_DOM_CACHE_DIRECTORY, #endif PROP_IS_EPHEMERAL, + PROP_LOCAL_STORAGE_QUOTA, PROP_ORIGIN_STORAGE_RATIO, PROP_TOTAL_STORAGE_RATIO }; @@ -118,6 +119,7 @@ struct _WebKitWebsiteDataManagerPrivate { gdouble originStorageRatio; gdouble totalStorageRatio; + unsigned localStorageQuota { 0 }; }; WEBKIT_DEFINE_FINAL_TYPE(WebKitWebsiteDataManager, webkit_website_data_manager, G_TYPE_OBJECT, GObject) @@ -226,6 +228,10 @@ static void webkitWebsiteDataManagerSetProperty(GObject* object, guint propID, c case PROP_TOTAL_STORAGE_RATIO: manager->priv->totalStorageRatio = g_value_get_double(value); break; + case PROP_LOCAL_STORAGE_QUOTA: + manager->priv->localStorageQuota = g_value_get_uint(value); + WebProcessPool::setLocalStorageQuota(manager->priv->localStorageQuota); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec); } @@ -493,6 +499,21 @@ static void webkit_website_data_manager_class_init(WebKitWebsiteDataManagerClass FALSE, static_cast(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY))); + /** + * WebKitWebsiteDataManager:local-storage-quota: + * + * Quota for local storage (in bytes) + * + */ + g_object_class_install_property( + gObjectClass, + PROP_LOCAL_STORAGE_QUOTA, + g_param_spec_uint("local-storage-quota", + _("Local storage quota"), + _("The maximum size of local storage in bytes"), + 1, G_MAXUINT, 5 * 1024 * 1024, + static_cast(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); + /** * WebKitWebsiteDataManager:origin-storage-ratio: * @@ -555,6 +576,7 @@ WebKit::WebsiteDataStore& webkitWebsiteDataManagerGetDataStore(WebKitWebsiteData if (priv->domCacheDirectory) configuration->setCacheStorageDirectory(FileSystem::stringFromFileSystemRepresentation(priv->domCacheDirectory.get())); #endif + configuration->setLocalStorageQuota(priv->localStorageQuota); if (priv->originStorageRatio >= 0.0) configuration->setOriginQuotaRatio(priv->originStorageRatio); diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp index b700123084b1e..ea46cfdc51dad 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp @@ -10345,6 +10345,8 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc parameters.hasResizableWindows = protectedPageClient()->hasResizableWindows(); #endif + parameters.localStorageQuota = m_websiteDataStore->localStorageQuota(); + #if ENABLE(ADVANCED_PRIVACY_PROTECTIONS) parameters.linkDecorationFilteringData = LinkDecorationFilteringController::shared().cachedStrings(); parameters.allowedQueryParametersForAdvancedPrivacyProtections = cachedAllowedQueryParametersForAdvancedPrivacyProtections(); diff --git a/Source/WebKit/UIProcess/WebProcessPool.h b/Source/WebKit/UIProcess/WebProcessPool.h index 579b2bd282f8a..ca4ccec895eeb 100644 --- a/Source/WebKit/UIProcess/WebProcessPool.h +++ b/Source/WebKit/UIProcess/WebProcessPool.h @@ -302,6 +302,7 @@ class WebProcessPool final #if USE(SOUP) static void setNetworkProcessMemoryPressureHandlerConfiguration(const std::optional& configuration) { s_networkProcessMemoryPressureHandlerConfiguration = configuration; } + static void setLocalStorageQuota(unsigned quota) { s_localStorageQuota = quota; } #endif void setEnhancedAccessibility(bool); @@ -734,6 +735,7 @@ class WebProcessPool final #if USE(SOUP) static std::optional s_networkProcessMemoryPressureHandlerConfiguration; + static unsigned s_localStorageQuota; #endif #if PLATFORM(MAC) diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h index 165885137ca03..1011349f89c00 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h @@ -439,6 +439,7 @@ class WebsiteDataStore : public API::ObjectImpl&& bytesPerSecondLimit); #endif + unsigned localStorageQuota() const { return m_configuration->localStorageQuota(); } void addPage(WebPageProxy&); void removePage(WebPageProxy&); diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreConfiguration.cpp b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreConfiguration.cpp index 5906bb08242aa..b49c7e616ffc5 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreConfiguration.cpp +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreConfiguration.cpp @@ -172,6 +172,7 @@ Ref WebsiteDataStoreConfiguration::copy() const #if ENABLE(DECLARATIVE_WEB_PUSH) copy->m_isDeclarativeWebPushEnabled = this->m_isDeclarativeWebPushEnabled; #endif + copy-> m_localStorageQuota = this->m_localStorageQuota; return copy; } diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreConfiguration.h b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreConfiguration.h index 5e72d9a6df703..1e261582412fa 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreConfiguration.h +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreConfiguration.h @@ -277,6 +277,9 @@ class WebsiteDataStoreConfiguration : public API::ObjectImpl create(IsPersistent isPersistent, ShouldInitializePaths shouldInitializePaths) { return adoptRef(*new WebsiteDataStoreConfiguration(isPersistent, shouldInitializePaths)); } @@ -335,6 +338,7 @@ class WebsiteDataStoreConfiguration : public API::ObjectImpl m_proxyConfiguration; #endif + unsigned m_localStorageQuota; Vector m_memoryFootprintNotificationThresholds; std::optional m_defaultTrackingPreventionEnabledOverride; }; diff --git a/Source/WebKit/UIProcess/soup/WebProcessPoolSoup.cpp b/Source/WebKit/UIProcess/soup/WebProcessPoolSoup.cpp index 550ef4e566982..6a9642c8249ea 100644 --- a/Source/WebKit/UIProcess/soup/WebProcessPoolSoup.cpp +++ b/Source/WebKit/UIProcess/soup/WebProcessPoolSoup.cpp @@ -37,11 +37,13 @@ namespace WebKit { std::optional WebProcessPool::s_networkProcessMemoryPressureHandlerConfiguration; +unsigned WebProcessPool::s_localStorageQuota = 0; void WebProcessPool::platformInitializeNetworkProcess(NetworkProcessCreationParameters& parameters) { parameters.languages = overrideLanguages().isEmpty() ? userPreferredLanguages() : overrideLanguages(); parameters.memoryPressureHandlerConfiguration = s_networkProcessMemoryPressureHandlerConfiguration; + parameters.localStorageQuota = s_localStorageQuota; #if OS(LINUX) if (MemoryPressureMonitor::disabled()) diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp index ec4bd58b65341..91df2b76529f9 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp @@ -1042,6 +1042,8 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters) #endif #endif // HAVE(SANDBOX_STATE_FLAGS) + m_page->settings().setLocalStorageQuota(parameters.localStorageQuota); + updateThrottleState(); #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) updateImageAnimationEnabled(); From 7789c4ba14cbdf08b8077f5fbc1cf9cfdf1a835a Mon Sep 17 00:00:00 2001 From: Amanda Falke Date: Wed, 1 Mar 2023 17:44:29 -0500 Subject: [PATCH 17/55] provision wal_autocheckpoint to prevent the log file growing to large size --- Source/WebCore/platform/sql/SQLiteDatabase.cpp | 13 ++++++++++++- .../NetworkProcess/storage/SQLiteStorageArea.cpp | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/WebCore/platform/sql/SQLiteDatabase.cpp b/Source/WebCore/platform/sql/SQLiteDatabase.cpp index a0a0adc83e512..4c9fa4e506ad4 100644 --- a/Source/WebCore/platform/sql/SQLiteDatabase.cpp +++ b/Source/WebCore/platform/sql/SQLiteDatabase.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #if !USE(SYSTEM_MALLOC) #include @@ -205,7 +206,17 @@ static int walAutomaticTruncationHook(void* context, sqlite3* db, const char* db { UNUSED_PARAM(context); - static constexpr int checkpointThreshold = 1000; // matches SQLITE_DEFAULT_WAL_AUTOCHECKPOINT + // prevent -wal file from growing indefinitely w automatic checkpointing: + // set threshold for number of pages after which checkpoint should be run + static constexpr int checkpointThresholdDefault = 1000; // matches SQLITE_DEFAULT_WAL_AUTOCHECKPOINT + static int checkpointThreshold = 0; + + // control threshold w/ to checkpoint more frequently if desired + if (!checkpointThreshold) { + auto envValue = String::fromLatin1(getenv("WPE_WAL_AUTOCHECKPOINT")); + checkpointThreshold = parseInteger(envValue).value_or(checkpointThresholdDefault); + checkpointThreshold = checkpointThreshold < 0 ? checkpointThresholdDefault : checkpointThreshold; + } if (walPageCount >= checkpointThreshold) { int newWalPageCount = 0; diff --git a/Source/WebKit/NetworkProcess/storage/SQLiteStorageArea.cpp b/Source/WebKit/NetworkProcess/storage/SQLiteStorageArea.cpp index 6e821b06e8563..2f843bb6d71c9 100644 --- a/Source/WebKit/NetworkProcess/storage/SQLiteStorageArea.cpp +++ b/Source/WebKit/NetworkProcess/storage/SQLiteStorageArea.cpp @@ -185,6 +185,8 @@ bool SQLiteStorageArea::prepareDatabase(ShouldCreateIfNotExists shouldCreateIfNo // We will never access the database from different threads simultaneously. m_database->disableThreadingChecks(); + m_database->enableAutomaticWALTruncation(); + if (!createTableIfNecessary()) { m_database = nullptr; return false; From 14527e962cf6987fec5161f7096f23fb50c233e2 Mon Sep 17 00:00:00 2001 From: Amanda Falke Date: Mon, 13 Mar 2023 14:35:07 -0400 Subject: [PATCH 18/55] Control on-disk cache size with env var WPE_DISK_CACHE_SIZE --- Source/WebKit/Shared/CacheModel.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Source/WebKit/Shared/CacheModel.cpp b/Source/WebKit/Shared/CacheModel.cpp index 84b8ac8db9830..cecedb0cebd69 100644 --- a/Source/WebKit/Shared/CacheModel.cpp +++ b/Source/WebKit/Shared/CacheModel.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include namespace WebKit { @@ -170,6 +172,21 @@ uint64_t calculateURLCacheDiskCapacity(CacheModel cacheModel, uint64_t diskFreeS ASSERT_NOT_REACHED(); }; + auto s = String::fromLatin1(getenv("WPE_DISK_CACHE_SIZE")); + if (!s.isEmpty()) { + String value = s.trim(deprecatedIsSpaceOrNewline).convertToLowercaseWithoutLocale(); + size_t units = 1; + if (value.endsWith('k')) + units = KB; + else if (value.endsWith('m')) + units = MB; + if (units != 1) + value = value.substring(0, value.length()-1); + + size_t size = size_t(parseInteger(s).value_or(1) * units); + urlCacheDiskCapacity = (unsigned long)(size); + } + return urlCacheDiskCapacity; } From f4aae528aa436c7866e94680bb07bd9b848fd54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Goco=C5=82?= Date: Thu, 29 Jun 2023 10:50:27 +0200 Subject: [PATCH 19/55] Add configuration option to allow moving window to background when window.close is called When allow_scripts_to_close_windows property is set to true, scripts can close windows that are not opened by them. But after window.close API is called, page is in "is closing" and browser expects window to be closed. When integrator wants to hide browser window/suspend browser, instead of closing it, page will be stuck in "is closing" state, where some APIs don't work anymore. This change introduces new property allow_move_to_suspend_on_window_close (disabled by default) which removes setting "is closing" state and just sends notification to browser integration, without any expectations on how it's handled. --- .../Preferences/UnifiedWebPreferences.yaml | 14 +++++ Source/WebCore/page/DOMWindow.cpp | 20 ++++--- .../UIProcess/API/glib/WebKitSettings.cpp | 56 +++++++++++++++++++ .../UIProcess/API/glib/WebKitSettings.h.in | 6 ++ 4 files changed, 87 insertions(+), 9 deletions(-) diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml index db72e479ca741..cf537c7e2cbcc 100644 --- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml +++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml @@ -268,6 +268,20 @@ AllowMediaContentTypesRequiringHardwareSupportAsFallback: WebCore: default: false +AllowMoveToSuspendOnWindowClose: + type: bool + status: embedder + humanReadableName: "Allow move to suspend on window.close()" + humanReadableDescription: "Allow to suspend browser instead of closing window on window.close()" + condition: PLATFORM(WPE) + defaultValue: + WebKitLegacy: + default: false + WebKit: + default: false + WebCore: + default: false + AllowMultiElementImplicitSubmission: type: bool status: embedder diff --git a/Source/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp index 05289c8c6ab40..f41eb22ea8d2a 100644 --- a/Source/WebCore/page/DOMWindow.cpp +++ b/Source/WebCore/page/DOMWindow.cpp @@ -112,18 +112,20 @@ void DOMWindow::close() if (!frame->isMainFrame()) return; - if (!(page->openedByDOM() || page->backForward().count() <= 1 || frame->settings().allowScriptsToCloseWindows())) { - checkedConsole()->addMessage(MessageSource::JS, MessageLevel::Warning, "Can't close the window since it was not opened by JavaScript"_s); - return; - } + if (!frame->settings().allowMoveToSuspendOnWindowClose()) { + if (!(page->openedByDOM() || page->backForward().count() <= 1 || frame->settings().allowScriptsToCloseWindows())) { + checkedConsole()->addMessage(MessageSource::JS, MessageLevel::Warning, "Can't close the window since it was not opened by JavaScript"_s); + return; + } - RefPtr localFrame = dynamicDowncast(frame); - if (localFrame && !localFrame->checkedLoader()->shouldClose()) - return; + RefPtr localFrame = dynamicDowncast(frame); + if (localFrame && !localFrame->checkedLoader()->shouldClose()) + return; - ResourceLoadObserver::shared().updateCentralStatisticsStore([] { }); + ResourceLoadObserver::shared().updateCentralStatisticsStore([] { }); - page->setIsClosing(); + page->setIsClosing(); + } closePage(); } diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp index 0e074a12ecd62..a8ce40c7cfab6 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp @@ -177,6 +177,7 @@ enum { PROP_ALLOW_RUNNING_OF_INSECURE_CONTENT, PROP_ALLOW_DISPLAY_OF_INSECURE_CONTENT, PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS, + PROP_ALLOW_MOVE_TO_SUSPEND_ON_WINDOW_CLOSE, PROP_ENABLE_DIRECTORY_UPLOAD, N_PROPERTIES, }; @@ -422,6 +423,9 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN case PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS: webkit_settings_set_allow_scripts_to_close_windows(settings, g_value_get_boolean(value)); break; + case PROP_ALLOW_MOVE_TO_SUSPEND_ON_WINDOW_CLOSE: + webkit_settings_set_allow_move_to_suspend_on_window_close(settings, g_value_get_boolean(value)); + break; case PROP_ENABLE_DIRECTORY_UPLOAD: webkit_settings_set_enable_directory_upload(settings, g_value_get_boolean(value)); break; @@ -642,6 +646,9 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN case PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS: g_value_set_boolean(value, webkit_settings_get_allow_scripts_to_close_windows(settings)); break; + case PROP_ALLOW_MOVE_TO_SUSPEND_ON_WINDOW_CLOSE: + g_value_set_boolean(value, webkit_settings_get_allow_move_to_suspend_on_window_close(settings)); + break; case PROP_ENABLE_DIRECTORY_UPLOAD: g_value_set_boolean(value, webkit_settings_get_enable_directory_upload(settings)); break; @@ -1683,6 +1690,19 @@ static void webkit_settings_class_init(WebKitSettingsClass* klass) FALSE, readWriteConstructParamFlags); + /** + * WebKitSettings:allow-move-to-suspend-on-window-close: + * + * Allow browser to move to suspend on window close. + * + */ + sObjProperties[PROP_ALLOW_MOVE_TO_SUSPEND_ON_WINDOW_CLOSE] = g_param_spec_boolean( + "allow-move-to-suspend-on-window-close", + _("Allow move to suspend on window.close()"), + _("Allow to suspend browser instead of closing window on window.close()"), + FALSE, + readWriteConstructParamFlags); + /** * WebKitSettings:enable-directory-upload: * @@ -4316,6 +4336,42 @@ webkit_settings_set_allow_scripts_to_close_windows(WebKitSettings *settings, gbo g_object_notify(G_OBJECT(settings), "allow-scripts-to-close-windows"); } +/** + * webkit_settings_get_allow_move_to_suspend_on_window_close: + * @settings: a #WebKitSettings + * + * Get the #WebKitSettings:allow-move-to-suspend-on-window-close property. + * + * Returns: %TRUE If browser can be suspended on window close. + */ +gboolean webkit_settings_get_allow_move_to_suspend_on_window_close (WebKitSettings *settings) +{ + g_return_val_if_fail(WEBKIT_IS_SETTINGS(settings), FALSE); + + return settings->priv->preferences->allowMoveToSuspendOnWindowClose(); +} + +/** + * webkit_settings_set_allow_move_to_suspend_on_window_close + * @settings: a #WebKitSettings + * @allowed: Value to be set + * + * Set the #WebKitSettings:allow-move-to-suspend-on-window-close property. + */ +WEBKIT_API void +webkit_settings_set_allow_move_to_suspend_on_window_close(WebKitSettings *settings, gboolean allowed) +{ + g_return_if_fail(WEBKIT_IS_SETTINGS(settings)); + + WebKitSettingsPrivate* priv = settings->priv; + bool currentValue = priv->preferences->allowMoveToSuspendOnWindowClose(); + if (currentValue == allowed) + return; + + priv->preferences->setAllowMoveToSuspendOnWindowClose(allowed); + g_object_notify(G_OBJECT(settings), "allow-move-to-suspend-on-window-close"); +} + /** * webkit_settings_get_enable_directory_upload: * @settings: a #WebKitSettings diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in index 3f5a9f177fe79..df7858368e7bc 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in @@ -582,6 +582,12 @@ webkit_settings_get_allow_scripts_to_close_windows (WebKitSettings WEBKIT_API void webkit_settings_set_allow_scripts_to_close_windows (WebKitSettings *settings, gboolean allowed); +WEBKIT_API gboolean +webkit_settings_get_allow_move_to_suspend_on_window_close (WebKitSettings *settings); + +WEBKIT_API void +webkit_settings_set_allow_move_to_suspend_on_window_close (WebKitSettings *settings, + gboolean allowed); WEBKIT_API gboolean webkit_settings_get_enable_directory_upload (WebKitSettings *settings); From c6fa54306a2c6ed64281c84637b15138741c0099 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Tue, 10 Jan 2023 15:27:57 +0100 Subject: [PATCH 20/55] Add env var to allow keeping the existent navigation on a fragment load --- Source/WebCore/loader/FrameLoader.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp index 3bf0377208a9d..7aed46ff91292 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp @@ -3542,8 +3542,16 @@ void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequ // frame to be deallocated. Ref frame = m_frame.get(); + static bool keepNavigationOnFragmentLoad = false; + static bool keepNavigationOnFragmentLoadInitialized = false; + + if (!keepNavigationOnFragmentLoadInitialized) { + keepNavigationOnFragmentLoad = !!getenv("WPE_KEEP_NAVIGATION_ON_FRAGMENT_LOAD"); + keepNavigationOnFragmentLoadInitialized = true; + } + // If we have a provisional request for a different document, a fragment scroll should cancel it. - if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url())) { + if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url()) && !keepNavigationOnFragmentLoad) { protectedProvisionalDocumentLoader()->stopLoading(); FRAMELOADER_RELEASE_LOG(ResourceLoading, "continueFragmentScrollAfterNavigationPolicy: Clearing provisional document loader (m_provisionalDocumentLoader=%p)", m_provisionalDocumentLoader.get()); setProvisionalDocumentLoader(nullptr); From c3b13d69b0d522ad952f466dfa52be384aa66840 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Wed, 27 Sep 2023 11:46:28 +0200 Subject: [PATCH 21/55] Add API to send memory pressure events --- Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp | 7 +++++++ Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in | 4 ++++ Source/WebKit/UIProcess/WebPageProxy.cpp | 6 ++++++ Source/WebKit/UIProcess/WebPageProxy.h | 2 ++ 4 files changed, 19 insertions(+) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp index 3016245c8196d..b42daef30598a 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -5673,3 +5673,10 @@ pid_t webkit_web_view_get_web_process_identifier(WebKitWebView *webView) return getPage(webView).processID(); } + +void webkit_web_view_send_memory_pressure_event(WebKitWebView *webView, gboolean critical) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + + getPage(webView).sendMemoryPressureEvent(critical); +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in b/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in index f323902daedb2..3d22af71b0c10 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in @@ -1061,6 +1061,10 @@ webkit_web_view_is_web_process_responsive_finish (WebKitWebView WEBKIT_API pid_t webkit_web_view_get_web_process_identifier (WebKitWebView *web_view); +WEBKIT_API void +webkit_web_view_send_memory_pressure_event (WebKitWebView *web_view, + gboolean critical); + G_END_DECLS #endif diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp index ea46cfdc51dad..28564bab30ff3 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp @@ -14186,6 +14186,12 @@ void WebPageProxy::frameNameChanged(IPC::Connection& connection, WebCore::FrameI }); } +void WebPageProxy::sendMemoryPressureEvent(bool critical) const +{ + for (auto& processPool : WebProcessPool::allProcessPools()) + processPool->sendMemoryPressureEvent(critical); +} + } // namespace WebKit #undef WEBPAGEPROXY_RELEASE_LOG diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h index 40ec4e18b09c3..5a98fb2d5c97c 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.h +++ b/Source/WebKit/UIProcess/WebPageProxy.h @@ -2386,6 +2386,8 @@ class WebPageProxy final : public API::ObjectImpl, publ WebPageProxyMessageReceiverRegistration& messageReceiverRegistration(); + void sendMemoryPressureEvent(bool critical) const; + #if HAVE(ESIM_AUTOFILL_SYSTEM_SUPPORT) bool shouldAllowAutoFillForCellularIdentifiers() const; #endif From 0e9a5f87618ebbb7461aa528bd1a7b4046f351ce Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Tue, 17 Jan 2023 17:12:19 +0100 Subject: [PATCH 22/55] [MemoryPressure] Add WPE_RAM_SIZE env var to define a custom RAM size [MemoryPressure] Handle video memory usage besides normal memory Delete JIT code only on synchronous requests: Tune memory pressure settings for rapid mem usage changes When playing an asset with video, frequent seek/jump operations within a short period may cause rapid memory increases. The current pressure settings may not allow (enough) memory release in time to avoid an app running in a container to be killed due it reaching the memory limits. To allow sufficient, in time, memory release, the release needs to happen with the "synchrounous" flag set to true, allowing full garbage collection cycle when reaching critical limits. Furthermore, the critical threshold needs to be lowered as well considering that the release is not instantaneous and on embedded devices the 95% original threshold does not allow enough room for mem release on apps with lower allowed memory usage limits. [1203][MemoryPressureHandler] Increase default fraction values Do critical and synchonous memory release when limit is exceeded and print log message. Signed-off-by: Andrzej Surdej Improve 'MemoryPressureMonitor' to use cgroup memory measurements within container MemoryPressureMonitor: Fix cgroup memory statistics Fix "memory.memsw.usage_in_bytes" file path so it acounts for swap also --- Source/WTF/wtf/MemoryPressureHandler.cpp | 156 +++++++++++++++--- Source/WTF/wtf/MemoryPressureHandler.h | 23 ++- Source/WTF/wtf/RAMSize.cpp | 29 ++++ .../wtf/unix/MemoryPressureHandlerUnix.cpp | 9 +- Source/WebCore/page/MemoryRelease.cpp | 6 +- .../Shared/WTFArgumentCoders.serialization.in | 1 + .../API/glib/WebKitMemoryPressureSettings.cpp | 36 ++++ .../glib/WebKitMemoryPressureSettings.h.in | 7 + .../UIProcess/linux/MemoryPressureMonitor.cpp | 29 ++++ 9 files changed, 257 insertions(+), 39 deletions(-) diff --git a/Source/WTF/wtf/MemoryPressureHandler.cpp b/Source/WTF/wtf/MemoryPressureHandler.cpp index 8348265e15434..a82885a2dbbd0 100644 --- a/Source/WTF/wtf/MemoryPressureHandler.cpp +++ b/Source/WTF/wtf/MemoryPressureHandler.cpp @@ -28,11 +28,14 @@ #include #include +#include #include +#include #include #include #include #include +#include namespace WTF { @@ -42,14 +45,64 @@ WTF_EXPORT_PRIVATE bool MemoryPressureHandler::ReliefLogger::s_loggingEnabled = static const double s_conservativeThresholdFraction = 0.5; static const double s_strictThresholdFraction = 0.65; #else -static const double s_conservativeThresholdFraction = 0.33; -static const double s_strictThresholdFraction = 0.5; +static const double s_conservativeThresholdFraction = 0.8; +static const double s_strictThresholdFraction = 0.9; #endif static const std::optional s_killThresholdFraction; static const Seconds s_pollInterval = 30_s; static std::atomic s_hasCreatedMemoryPressureHandler; +// This file contains the amount of video memory used, and will be filled by some other +// platform component. It's a text file containing an unsigned integer value. +static String s_GPUMemoryFile; +static ssize_t s_envBaseThresholdVideo = 0; + +static bool isWebProcess() +{ + static bool result = false; + static bool initialized = false; + + if (!initialized) { + initialized = true; + + FILE* file = fopen("/proc/self/cmdline", "r"); + if (!file) + return result; + + char* buffer = nullptr; + size_t size = 0; + if (getline(&buffer, &size, file) != -1) + result = !fnmatch("*WPEWebProcess*", buffer, 0); + + free(buffer); + fclose(file); + } + + return result; +} + +static size_t memoryFootprintVideo() +{ + if (!isWebProcess() || s_GPUMemoryFile.isEmpty()) + return 0; + + FILE* file = fopen(s_GPUMemoryFile.utf8().data(), "r"); + if (!file) + return 0; + + char* buffer = nullptr; + size_t size = 0; + size_t footprint = 0; + if (getline(&buffer, &size, file) != -1) + sscanf(buffer, "%lu", &footprint); + + free(buffer); + fclose(file); + + return footprint; +} + MemoryPressureHandler& MemoryPressureHandler::singleton() { static LazyNeverDestroyed memoryPressureHandler; @@ -76,6 +129,27 @@ MemoryPressureHandler::MemoryPressureHandler() #if PLATFORM(COCOA) setDispatchQueue(dispatch_get_main_queue()); #endif + + // If this is the WebProcess, Check whether the env var WPE_POLL_MAX_MEMORY_GPU_FILE exists, containing the file + // that we need to poll to get the video memory used, and whether WPE_POLL_MAX_MEMORY_GPU exists, overriding the + // limit for video memory set by the API. + if (isWebProcess()) { + s_GPUMemoryFile = String::fromLatin1(getenv("WPE_POLL_MAX_MEMORY_GPU_FILE")); + String s = String::fromLatin1(getenv("WPE_POLL_MAX_MEMORY_GPU")); + if (!s.isEmpty()) { + String value = s.convertToLowercaseWithoutLocale(); + size_t units = 1; + if (value.endsWith('k')) + units = KB; + else if (value.endsWith('m')) + units = MB; + if (units != 1) + value = value.substring(0, value.length() - 1); + s_envBaseThresholdVideo = parseInteger(value).value_or(0) * units; + if (s_envBaseThresholdVideo) + m_configuration.baseThresholdVideo = s_envBaseThresholdVideo; + } + } } void MemoryPressureHandler::setMemoryFootprintPollIntervalForTesting(Seconds pollInterval) @@ -139,10 +213,14 @@ void MemoryPressureHandler::setPageCount(unsigned pageCount) singleton().m_pageCount = pageCount; } -std::optional MemoryPressureHandler::thresholdForMemoryKill() +std::optional MemoryPressureHandler::thresholdForMemoryKill(MemoryType type) { if (m_configuration.killThresholdFraction) - return m_configuration.baseThreshold * (*m_configuration.killThresholdFraction); + return (*m_configuration.killThresholdFraction) * (type == MemoryType::Normal ? m_configuration.baseThreshold : m_configuration.baseThresholdVideo); + else { + // Don't kill the process if no killThreshold was set. + return std::nullopt; + } switch (m_processState) { case WebsamProcessState::Inactive: @@ -153,26 +231,26 @@ std::optional MemoryPressureHandler::thresholdForMemoryKill() return std::nullopt; } -size_t MemoryPressureHandler::thresholdForPolicy(MemoryUsagePolicy policy) +size_t MemoryPressureHandler::thresholdForPolicy(MemoryUsagePolicy policy, MemoryType type) { switch (policy) { case MemoryUsagePolicy::Unrestricted: return 0; case MemoryUsagePolicy::Conservative: - return m_configuration.baseThreshold * m_configuration.conservativeThresholdFraction; + return m_configuration.conservativeThresholdFraction * (type == MemoryType::Normal ? m_configuration.baseThreshold : m_configuration.baseThresholdVideo); case MemoryUsagePolicy::Strict: - return m_configuration.baseThreshold * m_configuration.strictThresholdFraction; + return m_configuration.strictThresholdFraction * (type == MemoryType::Normal ? m_configuration.baseThreshold : m_configuration.baseThresholdVideo); default: ASSERT_NOT_REACHED(); return 0; } } -MemoryUsagePolicy MemoryPressureHandler::policyForFootprint(size_t footprint) +MemoryUsagePolicy MemoryPressureHandler::policyForFootprints(size_t footprint, size_t footprintVideo) { - if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Strict)) + if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Strict, MemoryType::Normal) || footprintVideo >= thresholdForPolicy(MemoryUsagePolicy::Strict, MemoryType::Video)) return MemoryUsagePolicy::Strict; - if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Conservative)) + if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Conservative, MemoryType::Normal) || footprintVideo >= thresholdForPolicy(MemoryUsagePolicy::Conservative, MemoryType::Video)) return MemoryUsagePolicy::Conservative; return MemoryUsagePolicy::Unrestricted; } @@ -183,31 +261,35 @@ MemoryUsagePolicy MemoryPressureHandler::currentMemoryUsagePolicy() return MemoryUsagePolicy::Conservative; if (m_isSimulatingMemoryPressure) return MemoryUsagePolicy::Strict; - return policyForFootprint(memoryFootprint()); + return policyForFootprints(memoryFootprint(), memoryFootprintVideo()); } -void MemoryPressureHandler::shrinkOrDie(size_t killThreshold) +void MemoryPressureHandler::shrinkOrDie(size_t killThreshold, size_t killThresholdVideo) { RELEASE_LOG(MemoryPressure, "Process is above the memory kill threshold. Trying to shrink down."); releaseMemory(Critical::Yes, Synchronous::Yes); size_t footprint = memoryFootprint(); + size_t footprintVideo = memoryFootprintVideo(); RELEASE_LOG(MemoryPressure, "New memory footprint: %zu MB", footprint / MB); - if (footprint < killThreshold) { + if ((footprint < killThreshold) && (footprintVideo < killThresholdVideo)) { RELEASE_LOG(MemoryPressure, "Shrank below memory kill threshold. Process gets to live."); - setMemoryUsagePolicyBasedOnFootprint(footprint); + setMemoryUsagePolicyBasedOnFootprints(footprint, footprintVideo); return; } - WTFLogAlways("Unable to shrink memory footprint of process (%zu MB) below the kill thresold (%zu MB). Killed\n", footprint / MB, killThreshold / MB); + if (footprint >= killThreshold) + WTFLogAlways("Unable to shrink memory footprint of process (%zu MB) below the kill thresold (%zu MB). Killed\n", footprint / MB, killThreshold / MB); + else + WTFLogAlways("Unable to shrink video memory footprint of process (%zu MB) below the kill thresold (%zu MB). Killed\n", footprintVideo / MB, killThresholdVideo / MB); RELEASE_ASSERT(m_memoryKillCallback); m_memoryKillCallback(); } -void MemoryPressureHandler::setMemoryUsagePolicyBasedOnFootprint(size_t footprint) +void MemoryPressureHandler::setMemoryUsagePolicyBasedOnFootprints(size_t footprint, size_t footprintVideo) { - auto newPolicy = policyForFootprint(footprint); + auto newPolicy = policyForFootprints(footprint, footprintVideo); if (newPolicy == m_memoryUsagePolicy) return; @@ -230,6 +312,7 @@ void MemoryPressureHandler::setMemoryFootprintNotificationThresholds(Vector= *killThreshold) { - shrinkOrDie(*killThreshold); + auto killThreshold = thresholdForMemoryKill(MemoryType::Normal); + auto killThresholdVideo = thresholdForMemoryKill(MemoryType::Video); + if ((killThreshold && footprint >= *killThreshold) || (killThresholdVideo && footprintVideo >= *killThresholdVideo)) { + shrinkOrDie(*killThreshold, *killThresholdVideo); return; } - setMemoryUsagePolicyBasedOnFootprint(footprint); + setMemoryUsagePolicyBasedOnFootprints(footprint, footprintVideo); switch (m_memoryUsagePolicy) { case MemoryUsagePolicy::Unrestricted: @@ -254,6 +338,13 @@ void MemoryPressureHandler::measurementTimerFired() releaseMemory(Critical::No, Synchronous::No); break; case MemoryUsagePolicy::Strict: + if (footprint > m_configuration.baseThreshold || footprintVideo > m_configuration.baseThresholdVideo) { + WTFLogAlways("MemoryPressure: Critical memory usage (PID=%d) [MB]: %zu (of %zu), video: %zu (of %zu)\n", + getpid(), footprint / MB, m_configuration.baseThreshold / MB, + footprintVideo / MB, m_configuration.baseThresholdVideo / MB); + releaseMemory(Critical::Yes, Synchronous::Yes); + break; + } releaseMemory(Critical::Yes, Synchronous::No); break; } @@ -313,6 +404,20 @@ void MemoryPressureHandler::endSimulatedMemoryPressure() memoryPressureStatusChanged(); } +void MemoryPressureHandler::setConfiguration(Configuration&& configuration) +{ + m_configuration = WTFMove(configuration); + if (s_envBaseThresholdVideo) + m_configuration.baseThresholdVideo = s_envBaseThresholdVideo; +} + +void MemoryPressureHandler::setConfiguration(const Configuration& configuration) +{ + m_configuration = configuration; + if (s_envBaseThresholdVideo) + m_configuration.baseThresholdVideo = s_envBaseThresholdVideo; +} + void MemoryPressureHandler::releaseMemory(Critical critical, Synchronous synchronous) { if (!m_lowMemoryHandler) @@ -354,14 +459,15 @@ void MemoryPressureHandler::ReliefLogger::logMemoryUsageChange() auto currentMemory = platformMemoryUsage(); if (!currentMemory || !m_initialMemory) { - MEMORYPRESSURE_LOG("Memory pressure relief: %" PUBLIC_LOG_STRING ": (Unable to get dirty memory information for process)", m_logString); + MEMORYPRESSURE_LOG("Memory pressure relief: pid = %d, %" PUBLIC_LOG_STRING ": (Unable to get dirty memory information for process)", getpid(), m_logString); return; } long residentDiff = currentMemory->resident - m_initialMemory->resident; long physicalDiff = currentMemory->physical - m_initialMemory->physical; - MEMORYPRESSURE_LOG("Memory pressure relief: %" PUBLIC_LOG_STRING ": res = %zu/%zu/%ld, res+swap = %zu/%zu/%ld", + MEMORYPRESSURE_LOG("Memory pressure relief: pid = %d, %" PUBLIC_LOG_STRING ": res = %zu/%zu/%ld, res+swap = %zu/%zu/%ld", + getpid(), m_logString, m_initialMemory->resident, currentMemory->resident, residentDiff, m_initialMemory->physical, currentMemory->physical, physicalDiff); @@ -373,6 +479,7 @@ void MemoryPressureHandler::platformInitialize() { } MemoryPressureHandlerConfiguration::MemoryPressureHandlerConfiguration() : baseThreshold(std::min(3 * GB, ramSize())) + , baseThresholdVideo(1 * GB) , conservativeThresholdFraction(s_conservativeThresholdFraction) , strictThresholdFraction(s_strictThresholdFraction) , killThresholdFraction(s_killThresholdFraction) @@ -380,8 +487,9 @@ MemoryPressureHandlerConfiguration::MemoryPressureHandlerConfiguration() { } -MemoryPressureHandlerConfiguration::MemoryPressureHandlerConfiguration(size_t base, double conservative, double strict, std::optional kill, Seconds interval) +MemoryPressureHandlerConfiguration::MemoryPressureHandlerConfiguration(size_t base, size_t baseVideo, double conservative, double strict, std::optional kill, Seconds interval) : baseThreshold(base) + , baseThresholdVideo(baseVideo) , conservativeThresholdFraction(conservative) , strictThresholdFraction(strict) , killThresholdFraction(kill) diff --git a/Source/WTF/wtf/MemoryPressureHandler.h b/Source/WTF/wtf/MemoryPressureHandler.h index 06d4ab7e00a82..97d8e2f892fb9 100644 --- a/Source/WTF/wtf/MemoryPressureHandler.h +++ b/Source/WTF/wtf/MemoryPressureHandler.h @@ -60,6 +60,11 @@ enum class MemoryUsagePolicy : uint8_t { Strict, // Time to start pinching pennies for real }; +enum class MemoryType : uint8_t { + Normal, + Video +}; + enum class WebsamProcessState : uint8_t { Active, Inactive, @@ -73,9 +78,10 @@ typedef WTF::Function LowMemoryHandler; struct MemoryPressureHandlerConfiguration { WTF_MAKE_STRUCT_FAST_ALLOCATED; WTF_EXPORT_PRIVATE MemoryPressureHandlerConfiguration(); - WTF_EXPORT_PRIVATE MemoryPressureHandlerConfiguration(size_t, double, double, std::optional, Seconds); + WTF_EXPORT_PRIVATE MemoryPressureHandlerConfiguration(size_t, size_t, double, double, std::optional, Seconds); size_t baseThreshold; + size_t baseThresholdVideo; double conservativeThresholdFraction; double strictThresholdFraction; std::optional killThresholdFraction; @@ -187,9 +193,8 @@ class MemoryPressureHandler { }; using Configuration = MemoryPressureHandlerConfiguration; - - void setConfiguration(Configuration&& configuration) { m_configuration = WTFMove(configuration); } - void setConfiguration(const Configuration& configuration) { m_configuration = configuration; } + void setConfiguration(Configuration&&); + void setConfiguration(const Configuration&); WTF_EXPORT_PRIVATE void releaseMemory(Critical, Synchronous = Synchronous::No); @@ -212,9 +217,9 @@ class MemoryPressureHandler { WTF_EXPORT_PRIVATE void setMemoryFootprintNotificationThresholds(Vector&& thresholds, WTF::Function&&); private: - std::optional thresholdForMemoryKill(); - size_t thresholdForPolicy(MemoryUsagePolicy); - MemoryUsagePolicy policyForFootprint(size_t); + std::optional thresholdForMemoryKill(MemoryType); + size_t thresholdForPolicy(MemoryUsagePolicy, MemoryType); + MemoryUsagePolicy policyForFootprints(size_t, size_t); void memoryPressureStatusChanged(); @@ -231,8 +236,8 @@ class MemoryPressureHandler { void platformInitialize(); void measurementTimerFired(); - void shrinkOrDie(size_t killThreshold); - void setMemoryUsagePolicyBasedOnFootprint(size_t); + void shrinkOrDie(size_t killThreshold, size_t killThresholdVideo); + void setMemoryUsagePolicyBasedOnFootprints(size_t, size_t); unsigned m_pageCount { 0 }; diff --git a/Source/WTF/wtf/RAMSize.cpp b/Source/WTF/wtf/RAMSize.cpp index 439ec9874b81c..2d1ac58244efa 100644 --- a/Source/WTF/wtf/RAMSize.cpp +++ b/Source/WTF/wtf/RAMSize.cpp @@ -25,6 +25,8 @@ #include "config.h" #include +#include +#include #include @@ -50,8 +52,35 @@ namespace WTF { static constexpr size_t ramSizeGuess = 512 * MB; #endif +static size_t customRAMSize() +{ + // Syntax: Case insensitive, unit multipliers (M=Mb, K=Kb, =bytes). + // Example: WPE_RAM_SIZE='500M' + + size_t customSize = 0; + + String s = String::fromLatin1(getenv("WPE_RAM_SIZE")); + if (!s.isEmpty()) { + String value = s.convertToLowercaseWithoutLocale(); + size_t units = 1; + if (value.endsWith('k')) + units = KB; + else if (value.endsWith('m')) + units = MB; + if (units != 1) + value = value.substring(0, value.length() - 1); + customSize = parseInteger(value).value_or(0) * units; + } + + return customSize; +} + static size_t computeRAMSize() { + size_t custom = customRAMSize(); + if (custom) + return custom; + #if OS(WINDOWS) MEMORYSTATUSEX status; status.dwLength = sizeof(status); diff --git a/Source/WTF/wtf/unix/MemoryPressureHandlerUnix.cpp b/Source/WTF/wtf/unix/MemoryPressureHandlerUnix.cpp index 1c40593000210..598ca31096498 100644 --- a/Source/WTF/wtf/unix/MemoryPressureHandlerUnix.cpp +++ b/Source/WTF/wtf/unix/MemoryPressureHandlerUnix.cpp @@ -56,8 +56,13 @@ namespace WTF { // we wait longer to try again (s_maximumHoldOffTime). // These value seems reasonable and testing verifies that it throttles frequent // low memory events, greatly reducing CPU usage. +#if PLATFORM(WPE) +static const Seconds s_minimumHoldOffTime { 1_s }; +static const Seconds s_maximumHoldOffTime { 1_s }; +#else static const Seconds s_minimumHoldOffTime { 5_s }; static const Seconds s_maximumHoldOffTime { 30_s }; +#endif static const size_t s_minimumBytesFreedToUseMinimumHoldOffTime = 1 * MB; static const unsigned s_holdOffMultiplier = 20; @@ -72,7 +77,9 @@ void MemoryPressureHandler::triggerMemoryPressureEvent(bool isCritical) setMemoryPressureStatus(SystemMemoryPressureStatus::Critical); ensureOnMainThread([this, isCritical] { - respondToMemoryPressure(isCritical ? Critical::Yes : Critical::No); + // When memory usage reaches the critical state, we may not release enough memory in time if we use the + // async mode, so use synchrounous mode in such case + respondToMemoryPressure(isCritical ? Critical::Yes : Critical::No, isCritical ? Synchronous::Yes : Synchronous::No); }); if (ReliefLogger::loggingEnabled() && isUnderMemoryPressure()) diff --git a/Source/WebCore/page/MemoryRelease.cpp b/Source/WebCore/page/MemoryRelease.cpp index b5852fb732e0a..4cc5f74627454 100644 --- a/Source/WebCore/page/MemoryRelease.cpp +++ b/Source/WebCore/page/MemoryRelease.cpp @@ -133,17 +133,13 @@ static void releaseCriticalMemory(Synchronous synchronous, MaintainBackForwardCa document->cachedResourceLoader().garbageCollectDocumentResources(); } - if (synchronous == Synchronous::Yes) - GCController::singleton().deleteAllCode(JSC::PreventCollectionAndDeleteAllCode); - else - GCController::singleton().deleteAllCode(JSC::DeleteAllCodeIfNotCollecting); - #if ENABLE(VIDEO) for (auto& mediaElement : HTMLMediaElement::allMediaElements()) Ref { mediaElement.get() }->purgeBufferedDataIfPossible(); #endif if (synchronous == Synchronous::Yes) { + GCController::singleton().deleteAllCode(JSC::PreventCollectionAndDeleteAllCode); GCController::singleton().garbageCollectNow(); } else { #if PLATFORM(IOS_FAMILY) diff --git a/Source/WebKit/Shared/WTFArgumentCoders.serialization.in b/Source/WebKit/Shared/WTFArgumentCoders.serialization.in index af0a413e8ad76..2dc6747857dbd 100644 --- a/Source/WebKit/Shared/WTFArgumentCoders.serialization.in +++ b/Source/WebKit/Shared/WTFArgumentCoders.serialization.in @@ -213,6 +213,7 @@ using WTF::ProcessID = pid_t; header: [CustomHeader] struct WTF::MemoryPressureHandlerConfiguration { size_t baseThreshold; + size_t baseThresholdVideo; double conservativeThresholdFraction; double strictThresholdFraction; std::optional killThresholdFraction; diff --git a/Source/WebKit/UIProcess/API/glib/WebKitMemoryPressureSettings.cpp b/Source/WebKit/UIProcess/API/glib/WebKitMemoryPressureSettings.cpp index f0cb7b4148b57..08108134338bc 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitMemoryPressureSettings.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitMemoryPressureSettings.cpp @@ -144,6 +144,42 @@ guint webkit_memory_pressure_settings_get_memory_limit(WebKitMemoryPressureSetti return settings->configuration.baseThreshold / MB; } +/** + * webkit_memory_pressure_settings_set_video_memory_limit: + * @settings: a #WebKitMemoryPressureSettings + * @memory_limit: amount of video memory (in MB) that the process is allowed to use. + * + * Sets @memory_limit the video memory limit value to @settings. + * + * The default value is 1GB. + * + * Since: 2.34 + */ +void webkit_memory_pressure_settings_set_video_memory_limit(WebKitMemoryPressureSettings* settings, guint memoryLimit) +{ + g_return_if_fail(settings); + g_return_if_fail(memoryLimit); + + settings->configuration.baseThresholdVideo = memoryLimit * MB; +} + +/** + * webkit_memory_pressure_settings_get_video_memory_limit: + * @settings: a #WebKitMemoryPressureSettings + * + * Gets the video memory usage limit. + * + * Returns: current value, in megabytes. + * + * Since: 2.34 + */ +guint webkit_memory_pressure_settings_get_video_memory_limit(WebKitMemoryPressureSettings* settings) +{ + g_return_val_if_fail(settings, 0); + + return settings->configuration.baseThresholdVideo / MB; +} + /** * webkit_memory_pressure_settings_set_conservative_threshold: * @settings: a #WebKitMemoryPressureSettings diff --git a/Source/WebKit/UIProcess/API/glib/WebKitMemoryPressureSettings.h.in b/Source/WebKit/UIProcess/API/glib/WebKitMemoryPressureSettings.h.in index 0ed86d0300764..0e5f10a13ed7d 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitMemoryPressureSettings.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitMemoryPressureSettings.h.in @@ -50,6 +50,13 @@ webkit_memory_pressure_settings_set_memory_limit (WebKitMemoryPressure WEBKIT_API guint webkit_memory_pressure_settings_get_memory_limit (WebKitMemoryPressureSettings *settings); +WEBKIT_API void +webkit_memory_pressure_settings_set_video_memory_limit (WebKitMemoryPressureSettings *settings, + guint memory_limit); + +WEBKIT_API guint +webkit_memory_pressure_settings_get_video_memory_limit (WebKitMemoryPressureSettings *settings); + WEBKIT_API void webkit_memory_pressure_settings_set_conservative_threshold (WebKitMemoryPressureSettings *settings, gdouble value); diff --git a/Source/WebKit/UIProcess/linux/MemoryPressureMonitor.cpp b/Source/WebKit/UIProcess/linux/MemoryPressureMonitor.cpp index a95ba6be5ef3f..649b09ebbb95f 100644 --- a/Source/WebKit/UIProcess/linux/MemoryPressureMonitor.cpp +++ b/Source/WebKit/UIProcess/linux/MemoryPressureMonitor.cpp @@ -48,8 +48,13 @@ static const Seconds s_minPollingInterval { 1_s }; static const Seconds s_maxPollingInterval { 5_s }; static const double s_minUsedMemoryPercentageForPolling = 50; static const double s_maxUsedMemoryPercentageForPolling = 85; +#if PLATFORM(WPE) +static const int s_memoryPresurePercentageThreshold = 80; +static const int s_memoryPresurePercentageThresholdCritical = 85; +#else static const int s_memoryPresurePercentageThreshold = 90; static const int s_memoryPresurePercentageThresholdCritical = 95; +#endif // cgroups.7: The usual place for such mounts is under a tmpfs(5) // filesystem mounted at /sys/fs/cgroup. static const char* s_cgroupMemoryPath = "/sys/fs/cgroup/%s/%s/%s"; @@ -412,6 +417,30 @@ void CGroupMemoryController::setMemoryControllerPath(CString memoryControllerPat m_cgroupMemoryMemswUsageInBytesFile = getCgroupFile("memory", memoryControllerPath, CString("memory.memsw.usage_in_bytes")); m_cgroupMemoryLimitInBytesFile = getCgroupFile("memory", memoryControllerPath, CString("memory.limit_in_bytes")); m_cgroupMemoryUsageInBytesFile = getCgroupFile("memory", memoryControllerPath, CString("memory.usage_in_bytes")); + + // when ran within (e.g. docker) container, it's possible that will be specified in /proc/self/cgroup + // and yet the paths like /sys/fs/cgroup/memory// will be unavailable + // therefore it's worth falling back to default files so that memory pressure monitor would still work as expected in such cases + const bool shouldFallbackToEmptyPath = isActive() + && m_cgroupMemoryControllerPath != "/" + && !m_cgroupV2MemoryCurrentFile + && !m_cgroupV2MemoryMemswMaxFile + && !m_cgroupV2MemoryMaxFile + && !m_cgroupV2MemoryHighFile + && !m_cgroupMemoryMemswLimitInBytesFile + && !m_cgroupMemoryMemswUsageInBytesFile + && !m_cgroupMemoryLimitInBytesFile + && !m_cgroupMemoryUsageInBytesFile; + if (shouldFallbackToEmptyPath) { + m_cgroupV2MemoryCurrentFile = getCgroupFile("/", "", CString("memory.current")); + m_cgroupV2MemoryMemswMaxFile = getCgroupFile("/", "", CString("memory.memsw.max")); + m_cgroupV2MemoryMaxFile = getCgroupFile("/", "", CString("memory.max")); + m_cgroupV2MemoryHighFile = getCgroupFile("/", "", CString("memory.high")); + m_cgroupMemoryMemswLimitInBytesFile = getCgroupFile("memory", "", CString("memory.memsw.limit_in_bytes")); + m_cgroupMemoryMemswUsageInBytesFile = getCgroupFile("memory", "", CString("memory.memsw.usage_in_bytes")); + m_cgroupMemoryLimitInBytesFile = getCgroupFile("memory", "", CString("memory.limit_in_bytes")); + m_cgroupMemoryUsageInBytesFile = getCgroupFile("memory", "", CString("memory.usage_in_bytes")); + } } void CGroupMemoryController::disposeMemoryController() From 926d99419937cfea71b8153bcbfbc96dd4a17aac Mon Sep 17 00:00:00 2001 From: Amanda Falke Date: Wed, 1 Feb 2023 15:41:22 -0500 Subject: [PATCH 23/55] Disable caching of XHR ArrayBuffer and/or env variable - Disable caching of ArrayBuffer XHR. - Setting the environment variable WPE_DISABLE_XHR_RESPONSE_CACHING disables the memory cache for xhr responses. This is useful to reduce the memory footprint when the responses are quite big and cannot be reused. XMLHttpReques: allow disabling the cache for selected protocols --- Source/WebCore/xml/XMLHttpRequest.cpp | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Source/WebCore/xml/XMLHttpRequest.cpp b/Source/WebCore/xml/XMLHttpRequest.cpp index ef9a30ab0ce87..6451e0f8be91a 100644 --- a/Source/WebCore/xml/XMLHttpRequest.cpp +++ b/Source/WebCore/xml/XMLHttpRequest.cpp @@ -98,6 +98,29 @@ static void logConsoleError(ScriptExecutionContext* context, const String& messa context->addConsoleMessage(MessageSource::JS, MessageLevel::Error, message); } +static bool shouldDisableCacheForRequest(const URL& url) +{ + static Vector s_protocolsNotCached; + static std::once_flag s_onceFlag; + std::call_once(s_onceFlag, + [] { + // The env var contains a comma separated list of protocols that need to disable the cache, + // for example WPE_DISABLE_XHR_RESPONSE_CACHING_FOR_PROTOCOLS="dvb,echo,file" + String s(String::fromLatin1(std::getenv("WPE_DISABLE_XHR_RESPONSE_CACHING_FOR_PROTOCOLS"))); + if (!s.isEmpty()) { + s_protocolsNotCached.appendVector(s.split(',')); + } + }); + + if (getenv("WPE_DISABLE_XHR_RESPONSE_CACHING")) + return true; + + if (s_protocolsNotCached.contains(url.protocol().toString())) + return true; + + return false; +} + Ref XMLHttpRequest::create(ScriptExecutionContext& context) { auto xmlHttpRequest = adoptRef(*new XMLHttpRequest(context)); @@ -627,6 +650,12 @@ ExceptionOr XMLHttpRequest::createRequest() options.filteringPolicy = ResponseFilteringPolicy::Enable; options.contentEncodingSniffingPolicy = ContentEncodingSniffingPolicy::Disable; + if (responseType() == ResponseType::Arraybuffer || shouldDisableCacheForRequest(m_url.url())) { + options.dataBufferingPolicy = DataBufferingPolicy::DoNotBufferData; + options.cachingPolicy = CachingPolicy::DisallowCaching; + request.setCachePolicy(ResourceRequestCachePolicy::DoNotUseAnyCache); + } + if (m_timeoutMilliseconds) { if (!m_async) request.setTimeoutInterval(m_timeoutMilliseconds / 1000.0); From df304d04b256aae13c9536aa85da212d2110535d Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Wed, 15 Feb 2023 10:40:16 +0100 Subject: [PATCH 24/55] Jettison on top level navigation --- Source/WebCore/loader/FrameLoader.cpp | 4 +++- Source/WebCore/page/MemoryRelease.cpp | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp index 7aed46ff91292..dc5db43ba64dd 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp @@ -83,6 +83,7 @@ #include "IgnoreOpensDuringUnloadCountIncrementer.h" #include "InspectorController.h" #include "InspectorInstrumentation.h" +#include "LegacySchemeRegistry.h" #include "LinkLoader.h" #include "LoaderStrategy.h" #include "LocalDOMWindow.h" @@ -2226,7 +2227,8 @@ void FrameLoader::commitProvisionalLoad() // We are doing this here because we know for sure that a new page is about to be loaded. BackForwardCache::singleton().addIfCacheable(*frame->history().protectedCurrentItem(), frame->protectedPage().get()); - WebCore::jettisonExpensiveObjectsOnTopLevelNavigation(); + if (pdl && LegacySchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(pdl->request().url().protocol().toStringWithoutCopying())) + WebCore::jettisonExpensiveObjectsOnTopLevelNavigation(); } if (m_loadType != FrameLoadType::Replace) diff --git a/Source/WebCore/page/MemoryRelease.cpp b/Source/WebCore/page/MemoryRelease.cpp index 4cc5f74627454..610546a45b775 100644 --- a/Source/WebCore/page/MemoryRelease.cpp +++ b/Source/WebCore/page/MemoryRelease.cpp @@ -253,7 +253,24 @@ void logMemoryStatistics(LogMemoryStatisticsReason reason) void platformReleaseMemory(Critical) { } #endif void platformReleaseGraphicsMemory(Critical) { } -void jettisonExpensiveObjectsOnTopLevelNavigation() { } +void jettisonExpensiveObjectsOnTopLevelNavigation() +{ + // based on code from cocoa/MemoryReleaseCocoa.mm + // Protect against doing excessive jettisoning during repeated navigations. + const auto minimumTimeSinceNavigation = std::chrono::seconds(2); + + const auto now = std::chrono::steady_clock::now(); + static auto timeOfLastNavigation = now; + const bool shouldJettison = (timeOfLastNavigation == now) || (std::chrono::duration_cast(now - timeOfLastNavigation) >= minimumTimeSinceNavigation); + timeOfLastNavigation = now; + + if (!shouldJettison) + return; + + RunLoop::main().dispatch([]{ + releaseMemory(Critical::Yes, Synchronous::Yes); + }); +} void registerMemoryReleaseNotifyCallbacks() { } #endif From 627a2f561dc6cab05d50e3ba7fc58a4b760c6daf Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Thu, 31 Aug 2023 17:03:29 +0200 Subject: [PATCH 25/55] [JSC] Enable SharedArrayBuffer feature by default --- Source/JavaScriptCore/runtime/OptionsList.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/JavaScriptCore/runtime/OptionsList.h b/Source/JavaScriptCore/runtime/OptionsList.h index 7b736f59628e3..54c8a4592cd2e 100644 --- a/Source/JavaScriptCore/runtime/OptionsList.h +++ b/Source/JavaScriptCore/runtime/OptionsList.h @@ -594,7 +594,7 @@ bool hasCapacityToUseLargeGigacage(); v(Bool, usePromiseTryMethod, false, Normal, "Expose the Promise.try() method.") \ v(Bool, useRegExpEscape, false, Normal, "Expose RegExp.escape feature.") \ v(Bool, useResizableArrayBuffer, true, Normal, "Expose ResizableArrayBuffer feature.") \ - v(Bool, useSharedArrayBuffer, false, Normal, nullptr) \ + v(Bool, useSharedArrayBuffer, true, Normal, nullptr) \ v(Bool, useShadowRealm, false, Normal, "Expose the ShadowRealm object.") \ v(Bool, useStringWellFormed, true, Normal, "Expose the String well-formed methods.") \ v(Bool, useTemporal, false, Normal, "Expose the Temporal object.") \ From ee25625bc40764a84a2e8f0c0c06aa2ba601d2ea Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Wed, 1 Feb 2023 16:06:09 +0100 Subject: [PATCH 26/55] Do not try to swap navigation as we're not using PSON --- Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp b/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp index 0a1122951e37d..e0c7fc7ed80ad 100644 --- a/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp +++ b/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp @@ -826,6 +826,9 @@ void NetworkResourceLoader::processClearSiteDataHeader(const WebCore::ResourceRe static BrowsingContextGroupSwitchDecision toBrowsingContextGroupSwitchDecision(const std::optional& currentCoopEnforcementResult) { + // PSON is disabled, so return a value that doesn't cause the navigation to be swapped to a new WebProcess. + return BrowsingContextGroupSwitchDecision::StayInGroup; + if (!currentCoopEnforcementResult || !currentCoopEnforcementResult->needsBrowsingContextGroupSwitch) return BrowsingContextGroupSwitchDecision::StayInGroup; if (currentCoopEnforcementResult->crossOriginOpenerPolicy.value == CrossOriginOpenerPolicyValue::SameOriginPlusCOEP) From b77f8229a325f3a2e01ed1dcc07ad6d1617defd2 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Thu, 31 Aug 2023 19:17:10 +0200 Subject: [PATCH 27/55] [JSC] Add option to disable console logging --- Source/JavaScriptCore/runtime/ConsoleObject.cpp | 4 ++++ Source/JavaScriptCore/runtime/OptionsList.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/JavaScriptCore/runtime/ConsoleObject.cpp b/Source/JavaScriptCore/runtime/ConsoleObject.cpp index 599be35f0eb8e..5bc140eec6659 100644 --- a/Source/JavaScriptCore/runtime/ConsoleObject.cpp +++ b/Source/JavaScriptCore/runtime/ConsoleObject.cpp @@ -28,6 +28,7 @@ #include "ConsoleClient.h" #include "JSCInlines.h" +#include "Options.h" #include "ScriptArguments.h" #include "ScriptCallStackFactory.h" @@ -133,6 +134,9 @@ static EncodedJSValue consoleLogWithLevel(JSGlobalObject* globalObject, CallFram if (!client) return JSValue::encode(jsUndefined()); + if (Options::disableConsoleLog()) + return JSValue::encode(jsUndefined()); + client->logWithLevel(globalObject, Inspector::createScriptArguments(globalObject, callFrame, 0), level); return JSValue::encode(jsUndefined()); } diff --git a/Source/JavaScriptCore/runtime/OptionsList.h b/Source/JavaScriptCore/runtime/OptionsList.h index 54c8a4592cd2e..ccc55d72745cb 100644 --- a/Source/JavaScriptCore/runtime/OptionsList.h +++ b/Source/JavaScriptCore/runtime/OptionsList.h @@ -605,7 +605,7 @@ bool hasCapacityToUseLargeGigacage(); v(Bool, useWebAssemblyRelaxedSIMD, false, Normal, "Allow the relaxed simd instructions and types from the wasm relaxed simd spec.") \ v(Bool, useWebAssemblyTailCalls, false, Normal, "Allow the new instructions from the wasm tail calls spec.") \ v(Bool, useWebAssemblyExtendedConstantExpressions, true, Normal, "Allow the use of global, element, and data init expressions from the extended constant expressions proposal.") \ - + v(Bool, disableConsoleLog, false, Normal, "Disable printing of JS console logs.") \ enum OptionEquivalence { From edb2da8ffa3ef31c9329f29ce51894d71588a4f3 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Thu, 15 Dec 2022 12:33:09 +0100 Subject: [PATCH 28/55] [Network] Add TCPKeepAlive option TCPKeepAlive is implemented only for libsoup 3.x --- .../NetworkProcess/soup/NetworkDataTaskSoup.cpp | 15 ++++++++++++--- .../NetworkProcess/soup/NetworkDataTaskSoup.h | 2 -- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp index f0a39b556f7f1..d91a223441e90 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp @@ -223,7 +223,6 @@ void NetworkDataTaskSoup::createRequest(ResourceRequest&& request, WasBlockingCo g_signal_connect(m_soupMessage.get(), "wrote-body-data", G_CALLBACK(wroteBodyDataCallback), this); #if USE(SOUP2) g_signal_connect(static_cast(*m_session).soupSession(), "authenticate", G_CALLBACK(authenticateCallback), this); - g_signal_connect(m_soupMessage.get(), "network-event", G_CALLBACK(networkEventCallback), this); #else g_signal_connect(m_soupMessage.get(), "authenticate", G_CALLBACK(authenticateCallback), this); g_signal_connect(m_soupMessage.get(), "accept-certificate", G_CALLBACK(acceptCertificateCallback), this); @@ -235,6 +234,7 @@ void NetworkDataTaskSoup::createRequest(ResourceRequest&& request, WasBlockingCo g_signal_connect(m_soupMessage.get(), "request-certificate", G_CALLBACK(requestCertificateCallback), this); g_signal_connect(m_soupMessage.get(), "request-certificate-password", G_CALLBACK(requestCertificatePasswordCallback), this); #endif + g_signal_connect(m_soupMessage.get(), "network-event", G_CALLBACK(networkEventCallback), this); g_signal_connect(m_soupMessage.get(), "restarted", G_CALLBACK(restartedCallback), this); g_signal_connect(m_soupMessage.get(), "starting", G_CALLBACK(startingCallback), this); if (m_shouldContentSniff == ContentSniffingPolicy::SniffContent) @@ -1503,7 +1503,6 @@ void NetworkDataTaskSoup::didFail(const ResourceError& error) dispatchDidCompleteWithError(error); } -#if USE(SOUP2) void NetworkDataTaskSoup::networkEventCallback(SoupMessage* soupMessage, GSocketClientEvent event, GIOStream* stream, NetworkDataTaskSoup* task) { if (task->state() == State::Canceling || task->state() == State::Completed || !task->m_client) @@ -1515,6 +1514,16 @@ void NetworkDataTaskSoup::networkEventCallback(SoupMessage* soupMessage, GSocket void NetworkDataTaskSoup::networkEvent(GSocketClientEvent event, GIOStream* stream) { +#if !USE(SOUP2) + if (event == G_SOCKET_CLIENT_CONNECTED) { + const char* enableTCPkeepalive = getenv("WEBKIT_TCP_KEEPALIVE"); + if (enableTCPkeepalive && enableTCPkeepalive[0] != '0') { + RELEASE_ASSERT(G_IS_SOCKET_CONNECTION(stream)); + if (GSocket* socket = g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream))) + g_socket_set_keepalive(socket, TRUE); + } + } +#else auto time = MonotonicTime::now(); switch (event) { case G_SOCKET_CLIENT_RESOLVING: @@ -1556,8 +1565,8 @@ void NetworkDataTaskSoup::networkEvent(GSocketClientEvent event, GIOStream* stre ASSERT_NOT_REACHED(); break; } -} #endif +} void NetworkDataTaskSoup::startingCallback(SoupMessage* soupMessage, NetworkDataTaskSoup* task) { diff --git a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h index 89e46b9be47bf..54b135a30028e 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h +++ b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h @@ -148,10 +148,8 @@ class NetworkDataTaskSoup final : public NetworkDataTask { void didFail(const WebCore::ResourceError&); -#if USE(SOUP2) static void networkEventCallback(SoupMessage*, GSocketClientEvent, GIOStream*, NetworkDataTaskSoup*); void networkEvent(GSocketClientEvent, GIOStream*); -#endif #if SOUP_CHECK_VERSION(2, 49, 91) static void startingCallback(SoupMessage*, NetworkDataTaskSoup*); From 9915aa144471d58ad02805086f9d57b220835f95 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Wed, 26 Jul 2023 16:55:59 +0200 Subject: [PATCH 29/55] [soup] Add env var to allow reusing POST connections --- .../NetworkProcess/soup/NetworkDataTaskSoup.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp index d91a223441e90..4e530ca63f250 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp @@ -183,6 +183,22 @@ void NetworkDataTaskSoup::createRequest(ResourceRequest&& request, WasBlockingCo soup_message_disable_feature(m_soupMessage.get(), SOUP_TYPE_AUTH_MANAGER); #endif } + + static bool enablePostReuse = false; + static std::once_flag onceFlag; + std::call_once(onceFlag, [] { + char* envString = getenv("WPE_POST_CONNECTION_REUSE"); + enablePostReuse = !!envString && envString[0] != '0'; + }); + +#if USE(SOUP2) + const char* method = m_soupMessage->method; +#else + const char* method = soup_message_get_method(m_soupMessage.get()); +#endif + if (method == SOUP_METHOD_POST && enablePostReuse) + messageFlags |= SOUP_MESSAGE_IDEMPOTENT; + soup_message_set_flags(m_soupMessage.get(), static_cast(soup_message_get_flags(m_soupMessage.get()) | messageFlags)); bool shouldBlockCookies = wasBlockingCookies == WasBlockingCookies::Yes ? true : m_storedCredentialsPolicy == StoredCredentialsPolicy::EphemeralStateless; From 74eb1c6930dffbe93315873a7bc6cff9aa123f83 Mon Sep 17 00:00:00 2001 From: Zan Dobersek Date: Tue, 23 May 2017 15:30:01 +0200 Subject: [PATCH 30/55] OptionsWPE: compile with -ffunction-sections -fdata-sections, link with --gc-sections. --- Source/cmake/OptionsWPE.cmake | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 8a921cd25198c..bf73984b9b77f 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -451,3 +451,10 @@ set(WPEWebProcessExtension_Uninstalled_PKGCONFIG_FILE ${CMAKE_BINARY_DIR}/${WPE_ include(BubblewrapSandboxChecks) include(GStreamerChecks) + +# Optimize binary size for release builds by removing dead sections on unix/gcc. +if (CMAKE_COMPILER_IS_GNUCC AND UNIX AND NOT APPLE) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ffunction-sections -fdata-sections") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections -fno-rtti") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--gc-sections") +endif () From 44b1aa55187fb21e7abd94ac6954ca699fe322b1 Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Thu, 8 Jun 2017 17:39:53 +0200 Subject: [PATCH 31/55] Use -ffunction-sections/-fdata-sections/--gc-sections with clang too This saves about 1500 kB on a production build on ARMv7. --- Source/cmake/OptionsWPE.cmake | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index bf73984b9b77f..9ee7ca4b3985c 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -453,8 +453,11 @@ include(BubblewrapSandboxChecks) include(GStreamerChecks) # Optimize binary size for release builds by removing dead sections on unix/gcc. -if (CMAKE_COMPILER_IS_GNUCC AND UNIX AND NOT APPLE) - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ffunction-sections -fdata-sections") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections -fno-rtti") +if (COMPILER_IS_GCC_OR_CLANG AND UNIX AND NOT APPLE) + if (CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_COMPILER_SIZE_OPT_FLAGS " -finline-limit=90 -fsection-anchors") + endif () + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}${CMAKE_COMPILER_SIZE_OPT_FLAGS} -ffunction-sections -fdata-sections") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}${CMAKE_COMPILER_SIZE_OPT_FLAGS} -ffunction-sections -fdata-sections -fno-rtti") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--gc-sections") endif () From ce6e581c9827b41f0ec2780b14d2ae27b6dd9511 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Tue, 14 Feb 2023 13:16:38 +0100 Subject: [PATCH 32/55] OptionWPE: Optimize binary size of debug build This fix helps to build debug version of WPE for 32-bit RPi. Unfortunately the build can be done only with at least -O1 (for 32-bit RPi). --- Source/cmake/OptionsWPE.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 9ee7ca4b3985c..774d4afa3816c 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -460,4 +460,7 @@ if (COMPILER_IS_GCC_OR_CLANG AND UNIX AND NOT APPLE) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}${CMAKE_COMPILER_SIZE_OPT_FLAGS} -ffunction-sections -fdata-sections") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}${CMAKE_COMPILER_SIZE_OPT_FLAGS} -ffunction-sections -fdata-sections -fno-rtti") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--gc-sections") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}${CMAKE_COMPILER_SIZE_OPT_FLAGS} -ffunction-sections -fdata-sections") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}${CMAKE_COMPILER_SIZE_OPT_FLAGS} -ffunction-sections -fdata-sections -fno-rtti") + set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -Wl,--gc-sections") endif () From a606907bcf8c1fc96bece2c8814bf5e5e4e6b3a5 Mon Sep 17 00:00:00 2001 From: Charlie Turner Date: Mon, 5 Mar 2018 16:24:58 +0000 Subject: [PATCH 33/55] Condition section anchoring to ARM/ARM64 platforms Needed for building on a X86-64 desktop, where the linker complains about this option a lot. --- Source/cmake/OptionsWPE.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 774d4afa3816c..837888d10470d 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -454,7 +454,13 @@ include(GStreamerChecks) # Optimize binary size for release builds by removing dead sections on unix/gcc. if (COMPILER_IS_GCC_OR_CLANG AND UNIX AND NOT APPLE) - if (CMAKE_COMPILER_IS_GNUCC) + # Conditioned on ARM/ARM64 since those are the targets we know support section + # anchoring, for builds on X86 and X86-64 target, this option is not supported. + # It may be supported on several others aside from ARM*. + # The GCC documentation is poor in that it says the option is target dependent, + # but fails to decribe on which targets it is supported. I didn't fancy reading + # the source to find out. + if (CMAKE_COMPILER_IS_GNUCC AND (WTF_CPU_ARM64 OR WTF_CPU_ARM)) set(CMAKE_COMPILER_SIZE_OPT_FLAGS " -finline-limit=90 -fsection-anchors") endif () set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}${CMAKE_COMPILER_SIZE_OPT_FLAGS} -ffunction-sections -fdata-sections") From 679f86792f1486f9e779c25489b2d590e4012be3 Mon Sep 17 00:00:00 2001 From: "Vivek.A" Date: Thu, 19 May 2022 10:47:08 +0000 Subject: [PATCH 34/55] Added option to enable logs --- Source/cmake/OptionsWPE.cmake | 6 ++++++ Source/cmake/WebKitFeatures.cmake | 1 + 2 files changed, 7 insertions(+) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 837888d10470d..562b623d7c50e 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -415,6 +415,12 @@ set(DERIVED_SOURCES_WEBKIT_DIR ${DERIVED_SOURCES_DIR}/WebKit) set(DERIVED_SOURCES_WPE_API_DIR ${DERIVED_SOURCES_WEBKIT_DIR}/wpe) set(DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR "${CMAKE_BINARY_DIR}/DerivedSources/WPEToolingBackends") +if (ENABLE_LOGS) + SET_AND_EXPOSE_TO_BUILD(LOG_DISABLED FALSE) + SET_AND_EXPOSE_TO_BUILD(ERROR_DISABLED FALSE) + SET_AND_EXPOSE_TO_BUILD(FATAL_DISABLED FALSE) +endif () + # Using FORWARDING_HEADERS_DIR is deprecated set(FORWARDING_HEADERS_DIR ${DERIVED_SOURCES_DIR}/ForwardingHeaders) set(FORWARDING_HEADERS_WPE_DIR ${FORWARDING_HEADERS_DIR}/wpe) diff --git a/Source/cmake/WebKitFeatures.cmake b/Source/cmake/WebKitFeatures.cmake index dd68e9935bd3f..f5f39357e5f51 100644 --- a/Source/cmake/WebKitFeatures.cmake +++ b/Source/cmake/WebKitFeatures.cmake @@ -182,6 +182,7 @@ macro(WEBKIT_OPTION_BEGIN) WEBKIT_OPTION_DEFINE(ENABLE_LEGACY_CUSTOM_PROTOCOL_MANAGER "Toggle legacy protocol manager support" PRIVATE OFF) WEBKIT_OPTION_DEFINE(ENABLE_LEGACY_ENCRYPTED_MEDIA "Toggle Legacy EME V2 support" PRIVATE OFF) WEBKIT_OPTION_DEFINE(ENABLE_LLVM_PROFILE_GENERATION "Include LLVM's instrumentation to generate profiles for PGO" PRIVATE OFF) + WEBKIT_OPTION_DEFINE(ENABLE_LOGS "Toggle logging support" PRIVATE OFF) WEBKIT_OPTION_DEFINE(ENABLE_MATHML "Toggle MathML support" PRIVATE ON) WEBKIT_OPTION_DEFINE(ENABLE_MEDIA_CAPTURE "Toggle Media Capture support" PRIVATE OFF) WEBKIT_OPTION_DEFINE(ENABLE_MEDIA_CONTROLS_CONTEXT_MENUS "Toggle Media controls context menus." PRIVATE OFF) From 858cbe991e2eab2197eb2125ca44477a77485ad4 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Thu, 9 Feb 2023 14:13:12 +0100 Subject: [PATCH 35/55] Disable systemd logging by default --- Source/cmake/OptionsWPE.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 562b623d7c50e..212aff17e5941 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -88,7 +88,7 @@ endif () # and the option is not relevant to other WebKit ports. WEBKIT_OPTION_DEFINE(ENABLE_DOCUMENTATION "Whether to generate documentation." PUBLIC ON) WEBKIT_OPTION_DEFINE(ENABLE_INTROSPECTION "Whether to enable GObject introspection." PUBLIC ON) -WEBKIT_OPTION_DEFINE(ENABLE_JOURNALD_LOG "Whether to enable journald logging" PUBLIC ON) +WEBKIT_OPTION_DEFINE(ENABLE_JOURNALD_LOG "Whether to enable journald logging" PUBLIC OFF) WEBKIT_OPTION_DEFINE(ENABLE_WPE_PLATFORM_DRM "Whether to enable support for DRM platform" PUBLIC ON) WEBKIT_OPTION_DEFINE(ENABLE_WPE_PLATFORM_HEADLESS "Whether to enable support for headless platform" PUBLIC ON) WEBKIT_OPTION_DEFINE(ENABLE_WPE_PLATFORM_WAYLAND "Whether to enable support for Wayland platform" PUBLIC ON) From b6ebe42127fcd8655f6de4c343a8d759768f8717 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Wed, 22 Jun 2022 18:38:28 +0200 Subject: [PATCH 36/55] [INSPECTOR] Wait a max of 60s before failing on loading libWPEWebInspectorResources.so --- .../remote/glib/RemoteInspectorServer.cpp | 2 +- .../remote/glib/RemoteInspectorUtils.cpp | 24 +++++++-------- .../Inspector/glib/RemoteInspectorClient.cpp | 30 ++++++++++++++++++- .../Inspector/glib/RemoteInspectorClient.h | 3 ++ 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Source/JavaScriptCore/inspector/remote/glib/RemoteInspectorServer.cpp b/Source/JavaScriptCore/inspector/remote/glib/RemoteInspectorServer.cpp index 40bc826178d05..72b7e9071fc63 100644 --- a/Source/JavaScriptCore/inspector/remote/glib/RemoteInspectorServer.cpp +++ b/Source/JavaScriptCore/inspector/remote/glib/RemoteInspectorServer.cpp @@ -241,7 +241,7 @@ GVariant* RemoteInspectorServer::setupInspectorClient(SocketConnection& clientCo m_clientConnection = &clientConnection; GVariant* backendCommands; - if (strcmp(clientBackendCommandsHash, backendCommandsHash().data())) { + if (!backendCommandsHash().isNull() && strcmp(clientBackendCommandsHash, backendCommandsHash().data())) { auto bytes = Inspector::backendCommands(); backendCommands = g_variant_new_bytestring(static_cast(g_bytes_get_data(bytes.get(), nullptr))); } else diff --git a/Source/JavaScriptCore/inspector/remote/glib/RemoteInspectorUtils.cpp b/Source/JavaScriptCore/inspector/remote/glib/RemoteInspectorUtils.cpp index 04a49a2af4b59..ec18fa4416af3 100644 --- a/Source/JavaScriptCore/inspector/remote/glib/RemoteInspectorUtils.cpp +++ b/Source/JavaScriptCore/inspector/remote/glib/RemoteInspectorUtils.cpp @@ -40,25 +40,18 @@ namespace Inspector { GRefPtr backendCommands() { #if PLATFORM(WPE) - static std::once_flag flag; - std::call_once(flag, [] { - const char* libDir = PKGLIBDIR; -#if ENABLE(DEVELOPER_MODE) - // Probably no need for a specific env var here. Assume the inspector resources.so file is - // in the same directory as the injected bundle lib, for developer builds. - const char* path = g_getenv("WEBKIT_INJECTED_BUNDLE_PATH"); - if (path && g_file_test(path, G_FILE_TEST_IS_DIR)) - libDir = path; -#endif - GUniquePtr bundleFilename(g_build_filename(libDir, "libWPEWebInspectorResources.so", nullptr)); - GModule* resourcesModule = g_module_open(bundleFilename.get(), G_MODULE_BIND_LAZY); + static bool moduleLoaded = false; + + if (!moduleLoaded) { + GModule* resourcesModule = g_module_open(PKGLIBDIR G_DIR_SEPARATOR_S "libWPEWebInspectorResources.so", G_MODULE_BIND_LAZY); if (!resourcesModule) { WTFLogAlways("Error loading libWPEWebInspectorResources.so: %s", g_module_error()); - return; + return nullptr; } g_module_make_resident(resourcesModule); - }); + moduleLoaded = true; + } #endif GRefPtr bytes = adoptGRef(g_resources_lookup_data(INSPECTOR_BACKEND_COMMANDS_PATH, G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr)); ASSERT(bytes); @@ -70,6 +63,9 @@ const CString& backendCommandsHash() static CString hexDigest; if (hexDigest.isNull()) { auto bytes = backendCommands(); + if (!bytes) + return hexDigest; + size_t dataSize; gconstpointer data = g_bytes_get_data(bytes.get(), &dataSize); ASSERT(dataSize); diff --git a/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorClient.cpp b/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorClient.cpp index 30e48a5ae5947..718021214e5eb 100644 --- a/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorClient.cpp +++ b/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorClient.cpp @@ -172,6 +172,7 @@ RemoteInspectorClient::RemoteInspectorClient(String&& hostAndPort, RemoteInspect : m_hostAndPort(WTFMove(hostAndPort)) , m_observer(observer) , m_cancellable(adoptGRef(g_cancellable_new())) + , m_setupInspectorClientTimer(*this, &RemoteInspectorClient::setupInspectorClientTimerFired) { GRefPtr socketClient = adoptGRef(g_socket_client_new()); g_socket_client_connect_to_host_async(socketClient.get(), m_hostAndPort.utf8().data(), 0, m_cancellable.get(), @@ -200,7 +201,34 @@ RemoteInspectorClient::~RemoteInspectorClient() void RemoteInspectorClient::setupConnection(Ref&& connection) { m_socketConnection = WTFMove(connection); - m_socketConnection->sendMessage("SetupInspectorClient", g_variant_new("(@ay)", g_variant_new_bytestring(Inspector::backendCommandsHash().data()))); + setupInspectorClientTimerFired(); +} + +void RemoteInspectorClient::setupInspectorClientTimerFired() +{ + // There's an scenario where libWPEWebInspectorResources.so will not be available when the browser is + // launched, but will be downloaded once the network connection is up. To handle this situation we check + // whether the library is present bebore sending the SetupInspectorClient message. We will check for + // the library every 10 seconds to configure the proper commands. After 60 seconds we give up and + // send an empty string of commands, which causes the inspector not to work. + static int numTries = 0; + + if (numTries <= 6 && Inspector::backendCommandsHash().isNull()) { + // Retry every 10 seconds for 60 seconds. + m_setupInspectorClientTimer.startOneShot(10_s); + numTries++; + return; + } + + GVariant* backendCommandsHashString; + if (!Inspector::backendCommandsHash().isNull()) + backendCommandsHashString = g_variant_new_bytestring(Inspector::backendCommandsHash().data()); + else { + WTFLogAlways("Unable to load libWPEWebInspectorResources.so after 60 seconds: WebInspector won't work properly"); + backendCommandsHashString = g_variant_new_bytestring(""); + } + + m_socketConnection->sendMessage("SetupInspectorClient", g_variant_new("(@ay)", backendCommandsHashString)); } void RemoteInspectorClient::setBackendCommands(const char* backendCommands) diff --git a/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorClient.h b/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorClient.h index b299ca08ea100..6d49c57718057 100644 --- a/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorClient.h +++ b/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorClient.h @@ -27,6 +27,7 @@ #if ENABLE(REMOTE_INSPECTOR) +#include #include #include #include @@ -80,6 +81,7 @@ class RemoteInspectorClient { void setBackendCommands(const char*); void setTargetList(uint64_t connectionID, Vector&&); void sendMessageToFrontend(uint64_t connectionID, uint64_t targetID, const char*); + void setupInspectorClientTimerFired(); String m_hostAndPort; String m_backendCommandsURL; @@ -88,6 +90,7 @@ class RemoteInspectorClient { GRefPtr m_cancellable; HashMap> m_targets; HashMap, std::unique_ptr> m_inspectorProxyMap; + WebCore::Timer m_setupInspectorClientTimer; }; } // namespace WebKit From c4b8d7eb245e043f80e67e4fce43aaf39dc4309d Mon Sep 17 00:00:00 2001 From: Andrzej Surdej Date: Wed, 14 Sep 2022 12:45:19 +0200 Subject: [PATCH 37/55] [INSPECTOR] Never destroy RemoteInspectorHTTPServer singleton Destroying RemoteInspectorHTTPServer with on different thread that it was created on causes RELEASE_ASSERT to be triggered (via ~RemoteInspectorClient -> ~TimerBase). Such case happens when main UIProcess loop doesn't run in the main thread (like WPE WebKitBrowser plugin scenario) --- .../UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp b/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp index 89382a72d9c1c..90f6c08252c01 100644 --- a/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp +++ b/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp @@ -31,6 +31,7 @@ #include "RemoteInspectorClient.h" #include #include +#include #include #include @@ -38,7 +39,7 @@ namespace WebKit { RemoteInspectorHTTPServer& RemoteInspectorHTTPServer::singleton() { - static RemoteInspectorHTTPServer server; + static NeverDestroyed server; return server; } From 57c8b7b55296d038fe68f90bfdcdc6870b15760e Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Thu, 19 May 2022 18:43:04 +0000 Subject: [PATCH 38/55] [INSPECTOR] Listen on both ipv4 and ipv6 --- .../UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp b/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp index 90f6c08252c01..49901cd8edbd9 100644 --- a/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp +++ b/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp @@ -47,8 +47,10 @@ bool RemoteInspectorHTTPServer::start(GRefPtr&& socketAddress, u { m_server = adoptGRef(soup_server_new("server-header", "WebKitInspectorHTTPServer ", nullptr)); + guint16 port = g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(socketAddress.get())); + GUniqueOutPtr error; - if (!soup_server_listen(m_server.get(), socketAddress.get(), static_cast(0), &error.outPtr())) { + if (!soup_server_listen_all(m_server.get(), port, static_cast(0), &error.outPtr())) { GUniquePtr address(g_socket_connectable_to_string(G_SOCKET_CONNECTABLE(socketAddress.get()))); g_warning("Failed to start remote inspector HTTP server on %s: %s", address.get(), error->message); return false; From d4efa236f475f271e6dee11f33e6312d3b51d890 Mon Sep 17 00:00:00 2001 From: Jacek Manko Date: Wed, 28 Jun 2023 16:59:43 +0200 Subject: [PATCH 39/55] Use static port for internal webinspector communication With this port being dynamic, it's not possible to add specific iptables rules allowing this traffic - and with restrictive rules this traffic may be blocked. Allow selecting the port - controlled by WEBKIT_INSPECTOR_PORT env --- Source/WebKit/UIProcess/API/glib/WebKitInitialize.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitInitialize.cpp b/Source/WebKit/UIProcess/API/glib/WebKitInitialize.cpp index f781e0d12b9c4..39822615d2f2f 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitInitialize.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitInitialize.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #if USE(SKIA) #include @@ -79,8 +80,11 @@ static void initializeRemoteInspectorServer() auto inspectorHTTPAddress = parseAddress(httpAddress); GRefPtr inspectorAddress; - if (inspectorHTTPAddress) - inspectorAddress = adoptGRef(G_SOCKET_ADDRESS(g_inet_socket_address_new(g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(inspectorHTTPAddress.get())), 0))); + if (inspectorHTTPAddress) { + String envVar = String::fromLatin1(getenv("WEBKIT_INSPECTOR_PORT")); + auto port = parseInteger(envVar).value_or(0); + inspectorAddress = adoptGRef(G_SOCKET_ADDRESS(g_inet_socket_address_new(g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(inspectorHTTPAddress.get())), port))); + } else inspectorAddress = parseAddress(address); if (!inspectorHTTPAddress && !inspectorAddress) { From 932e27e4e84d81c7c40fc700b943843d43c1a4aa Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Thu, 9 Mar 2023 16:23:14 +0100 Subject: [PATCH 40/55] Take into account scaling operations when deciding backingStore scale factor --- .../graphics/nicosia/NicosiaAnimation.cpp | 25 +++++++++++ .../graphics/nicosia/NicosiaAnimation.h | 1 + .../coordinated/CoordinatedGraphicsLayer.cpp | 43 ++++++++++++++++++- .../coordinated/CoordinatedGraphicsLayer.h | 6 +++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.cpp b/Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.cpp index f26d4034ac44b..fc7e66214bd98 100644 --- a/Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.cpp +++ b/Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.cpp @@ -21,6 +21,7 @@ #include "NicosiaAnimation.h" #include "LayoutSize.h" +#include "ScaleTransformOperation.h" #include "TranslateTransformOperation.h" #include @@ -474,4 +475,28 @@ bool Animations::hasRunningTransformAnimations() const }); } +float Animations::maximumScaleFactor() const +{ + // Traverse all the keyframes keeping the max values used for scaling. + double scale = 1; + for (auto& animation : m_animations) { + auto& keyframes = animation.keyframes(); + + if (keyframes.property() != AnimatedProperty::Transform) + continue; + + for (size_t i = 0; i < keyframes.size(); i++) { + const auto& transformOperations = static_cast(keyframes.at(i)).value(); + for (size_t j = 0; j < transformOperations.size(); j++) { + auto* transformOperation = transformOperations.at(j); + if (TransformOperation::isScaleTransformOperationType(transformOperation->type())) { + auto* scaleTransformOperation = static_cast(transformOperation); + scale = std::max(scale, std::max(scaleTransformOperation->x(), scaleTransformOperation->y())); + } + } + } + } + return scale; +} + } // namespace Nicosia diff --git a/Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.h b/Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.h index 88422cf5ee1d3..aaac3e338093c 100644 --- a/Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.h +++ b/Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.h @@ -103,6 +103,7 @@ class Animations { Vector& animations() { return m_animations; } bool hasActiveAnimationsOfType(WebCore::AnimatedProperty type) const; + float maximumScaleFactor() const; bool hasRunningAnimations() const; bool hasRunningTransformAnimations() const; diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp index c0dfd07eb491b..37752d641ab60 100644 --- a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp @@ -864,6 +864,10 @@ void CoordinatedGraphicsLayer::flushCompositingStateForThisLayerOnly() // Determine the backing store presence. Content is painted later, in the updateContentBuffers() traversal. if (shouldHaveBackingStore()) { + // The layer has a backingStore. Check whether we need to apply a concrete scale factor to it + // because of some animation or transformation. If we don't do this, the backingStore will always + // have a factor of 1, which will produce blurry results when the layer is scaled up. + updateAnimationOrTransformScaleFactor(); if (!m_nicosia.backingStore) { m_nicosia.backingStore = Nicosia::BackingStore::create(); m_nicosia.delta.backingStoreChanged = true; @@ -1076,7 +1080,7 @@ void CoordinatedGraphicsLayer::deviceOrPageScaleFactorChanged() float CoordinatedGraphicsLayer::effectiveContentsScale() { - return selfOrAncestorHaveNonAffineTransforms() ? 1 : deviceScaleFactor() * pageScaleFactor(); + return selfOrAncestorHaveNonAffineTransforms() ? 1 : deviceScaleFactor() * pageScaleFactor() * m_animationOrTransformScaleFactor; } IntRect CoordinatedGraphicsLayer::transformedVisibleRect() @@ -1436,6 +1440,12 @@ bool CoordinatedGraphicsLayer::addAnimation(const KeyframeValueList& valueList, m_animations.add(Nicosia::Animation(keyframesName, valueList, boxSize, *anim, m_lastAnimationStartTime, 0_s, Nicosia::Animation::AnimationState::Playing)); m_animationStartedTimer.startOneShot(0_s); didChangeAnimations(); + + // If the animation is of type AnimatedProperty::Transform, it may be a scale animation. Check whether + // we need to update the scale factor due to a new scale animation being added. + if (valueList.property() == AnimatedProperty::Transform) + updateAnimationScaleFactor(); + return true; } @@ -1449,6 +1459,9 @@ void CoordinatedGraphicsLayer::removeAnimation(const String& animationName, std: { m_animations.remove(animationName); didChangeAnimations(); + // An animation has been removed, and it could be a scale animation, so check whether + // we need to update the animation scale factor. + updateAnimationScaleFactor(); } void CoordinatedGraphicsLayer::suspendAnimations(MonotonicTime time) @@ -1491,6 +1504,34 @@ PlatformLayer* CoordinatedGraphicsLayer::platformLayer() const } #endif +void CoordinatedGraphicsLayer::updateAnimationScaleFactor() +{ + m_animationScaleFactor = m_animations.maximumScaleFactor(); +} + +void CoordinatedGraphicsLayer::updateAnimationOrTransformScaleFactor() +{ + TransformationMatrix::Decomposed2Type decomposed2; + + float parentScale = 1.0; + if (parent()) { + if (!downcast(*parent()).m_layerTransform.combinedForChildren().decompose2(decomposed2)) + return; + parentScale = std::max(decomposed2.scaleX, decomposed2.scaleY); + } + + if (!transform().decompose2(decomposed2)) + return; + float localScale = std::max(decomposed2.scaleX, decomposed2.scaleY); + + float newScale = parentScale * std::max(m_animationScaleFactor, localScale); + + if (newScale != m_animationOrTransformScaleFactor) { + m_animationOrTransformScaleFactor = newScale; + m_pendingContentsScaleAdjustment = true; + } +} + static void dumpInnerLayer(TextStream& textStream, const String& label, CoordinatedGraphicsLayer* layer, OptionSet options) { if (!layer) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h index 47ef910ba4460..87944326fd184 100644 --- a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h @@ -230,6 +230,9 @@ class WEBCORE_EXPORT CoordinatedGraphicsLayer : public GraphicsLayer { RefPtr acquireTextureForAcceleratedBuffer(const IntSize&); #endif + void updateAnimationScaleFactor(); + void updateAnimationOrTransformScaleFactor(); + Nicosia::PlatformLayer::LayerID m_id; GraphicsLayerTransform m_layerTransform; TransformationMatrix m_cachedInverseTransform; @@ -279,6 +282,9 @@ class WEBCORE_EXPORT CoordinatedGraphicsLayer : public GraphicsLayer { RefPtr m_animatedBackingStoreHost; RefPtr m_backdropLayer; + + float m_animationScaleFactor { 1.0 }; + float m_animationOrTransformScaleFactor { 1.0 }; }; } // namespace WebCore From 62ba6dbafd00a6f641f288a0bf0b5f04b63f4223 Mon Sep 17 00:00:00 2001 From: Andrzej Surdej Date: Thu, 31 Mar 2022 11:51:04 +0200 Subject: [PATCH 41/55] Handle all types of headers for accessibility read out Fetch the text of sibling node to the grid/table row --- .../accessibility/AccessibilityNodeObject.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Source/WebCore/accessibility/AccessibilityNodeObject.cpp b/Source/WebCore/accessibility/AccessibilityNodeObject.cpp index 8e8ec0f6a19ae..2ea27ca10628e 100644 --- a/Source/WebCore/accessibility/AccessibilityNodeObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityNodeObject.cpp @@ -1930,6 +1930,18 @@ void AccessibilityNodeObject::visibleText(Vector& textOrder) if (!text.isEmpty()) textOrder.append(AccessibilityText(text, AccessibilityTextSource::Children)); } + + if(textOrder.size() == 0 && this->isTableRow()) { + AccessibilityObject* axObject = previousSibling(); + if (axObject && axObject->isHeading()) { + TextUnderElementMode mode; + mode.includeFocusableContent = true; + String text = axObject->textUnderElement(mode); + if (!text.isEmpty()) { + textOrder.append(AccessibilityText(text, AccessibilityTextSource::Children)); + } + } + } } void AccessibilityNodeObject::helpText(Vector& textOrder) const From 9fdc99296e37fff00c9a0ea42f2e3b2d50b06d1e Mon Sep 17 00:00:00 2001 From: Andrzej Surdej Date: Tue, 29 Mar 2022 14:07:51 +0200 Subject: [PATCH 42/55] Add Generic, Cell, GridCell and Caption roles for visibleText computation Allow
or retrieval of 'visibleText' for nested
& elements. --- Source/WebCore/accessibility/AccessibilityObject.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/WebCore/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp index b5062702ee76d..f02b13b57b0e6 100644 --- a/Source/WebCore/accessibility/AccessibilityObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityObject.cpp @@ -1857,6 +1857,10 @@ bool AccessibilityObject::dependsOnTextUnderElement() const case AccessibilityRole::RadioButton: case AccessibilityRole::Switch: case AccessibilityRole::Tab: + case AccessibilityRole::Generic: + case AccessibilityRole::Cell: + case AccessibilityRole::GridCell: + case AccessibilityRole::Caption: return true; default: break; From daa496dd42c3492dddc381dc9ff0d66acb83df30 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Wed, 15 Mar 2023 21:27:46 +0100 Subject: [PATCH 43/55] Voice Guidance reads iframe when added to DOM. Make Voice Guidance to differentiate between an actual page load and an iframe being added to the DOM. --- .../atspi/AccessibilityObjectAtspi.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp b/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp index c0c10b6dcfed2..122bf39e6650b 100644 --- a/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp +++ b/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp @@ -149,9 +149,9 @@ void AccessibilityObjectAtspi::elementDestroyed() AccessibilityAtspi::singleton().unregisterObject(*this); } -static Atspi::Role atspiRole(AccessibilityRole role) +static Atspi::Role atspiRole(AXCoreObject* coreObject) { - switch (role) { + switch (coreObject->roleValue()) { case AccessibilityRole::ApplicationAlert: return Atspi::Role::Notification; case AccessibilityRole::ApplicationAlertDialog: @@ -305,7 +305,16 @@ static Atspi::Role atspiRole(AccessibilityRole role) case AccessibilityRole::UserInterfaceTooltip: return Atspi::Role::ToolTip; case AccessibilityRole::WebArea: + { + RefPtr liveObject = dynamicDowncast(coreObject); + if (liveObject) { + WebCore::Frame *frame = liveObject->frame(); + if (frame) + return frame->WebCore::Frame::isMainFrame() ? Atspi::Role::DocumentWeb : Atspi::Role::DocumentFrame; + } + return Atspi::Role::DocumentWeb; + } case AccessibilityRole::WebApplication: return Atspi::Role::Embedded; case AccessibilityRole::ApplicationLog: @@ -1238,7 +1247,7 @@ Atspi::Role AccessibilityObjectAtspi::role() const if (auto effective = effectiveRole()) return *effective; - return atspiRole(m_coreObject->roleValue()); + return atspiRole(m_coreObject); } String AccessibilityObjectAtspi::effectiveRoleName() const From a8b1182b72fe332c7748a2476bbe07149b3bf8d6 Mon Sep 17 00:00:00 2001 From: Pawel Lampe Date: Tue, 21 Mar 2023 10:06:58 +0100 Subject: [PATCH 44/55] Adapt speech synthesis changes from 2.28 - Add missing functions - Add proper error handling (similar to #823 with optional as in #875) for both UIProcess and WebProcess --- Source/WebCore/Headers.cmake | 10 +++++++++ .../Modules/speech/SpeechSynthesis.cpp | 22 +++++++++---------- .../WebCore/Modules/speech/SpeechSynthesis.h | 6 ++--- .../Modules/speech/SpeechSynthesisErrorCode.h | 2 +- Source/WebCore/page/SpeechSynthesisClient.h | 3 ++- .../platform/PlatformSpeechSynthesizer.h | 5 +++-- .../mock/PlatformSpeechSynthesizerMock.cpp | 2 +- .../WebKit/UIProcess/WebPageProxyInternals.h | 2 +- .../gstreamer/WebPageProxyGStreamer.cpp | 7 ++++-- Source/WebKit/WebProcess/WebPage/WebPage.cpp | 7 ++++-- Source/WebKit/WebProcess/WebPage/WebPage.h | 2 +- .../WebProcess/WebPage/WebPage.messages.in | 2 +- 12 files changed, 44 insertions(+), 26 deletions(-) diff --git a/Source/WebCore/Headers.cmake b/Source/WebCore/Headers.cmake index 0bb80e1d03f9e..8b52262f489da 100644 --- a/Source/WebCore/Headers.cmake +++ b/Source/WebCore/Headers.cmake @@ -550,6 +550,16 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS Modules/reporting/TestReportBody.h Modules/reporting/ViolationReportType.h + Modules/speech/LocalDOMWindowSpeechSynthesis.h + Modules/speech/SpeechSynthesisErrorCode.h + Modules/speech/SpeechSynthesisErrorEvent.h + Modules/speech/SpeechSynthesisErrorEventInit.h + Modules/speech/SpeechSynthesisEvent.h + Modules/speech/SpeechSynthesisEventInit.h + Modules/speech/SpeechSynthesis.h + Modules/speech/SpeechSynthesisUtterance.h + Modules/speech/SpeechSynthesisVoice.h + Modules/speech/SpeechRecognitionCaptureSource.h Modules/speech/SpeechRecognitionCaptureSourceImpl.h Modules/speech/SpeechRecognitionConnection.h diff --git a/Source/WebCore/Modules/speech/SpeechSynthesis.cpp b/Source/WebCore/Modules/speech/SpeechSynthesis.cpp index 6e153e89f3ada..00d2fd5f385f0 100644 --- a/Source/WebCore/Modules/speech/SpeechSynthesis.cpp +++ b/Source/WebCore/Modules/speech/SpeechSynthesis.cpp @@ -83,7 +83,7 @@ void SpeechSynthesis::setPlatformSynthesizer(Ref&& sy m_voiceList = std::nullopt; m_utteranceQueue.clear(); // Finish current utterance. - speakingErrorOccurred(); + speakingErrorOccurred(SpeechSynthesisErrorCode::Canceled); m_isPaused = false; m_speechSynthesisClient = nullptr; } @@ -174,7 +174,7 @@ void SpeechSynthesis::cancel() m_speechSynthesisClient->cancel(); // If we wait for cancel to callback speakingErrorOccurred, then m_currentSpeechUtterance will be null // and the event won't be processed. Instead we process the error immediately. - speakingErrorOccurred(); + speakingErrorOccurred(SpeechSynthesisErrorCode::Canceled); m_currentSpeechUtterance = nullptr; } else if (m_platformSpeechSynthesizer) m_platformSpeechSynthesizer->cancel(); @@ -202,18 +202,18 @@ void SpeechSynthesis::resumeSynthesis() } } -void SpeechSynthesis::handleSpeakingCompleted(SpeechSynthesisUtterance& utterance, bool errorOccurred) +void SpeechSynthesis::handleSpeakingCompleted(SpeechSynthesisUtterance& utterance, std::optional error) { ASSERT(m_currentSpeechUtterance); Ref protect(utterance); m_currentSpeechUtterance = nullptr; - if (errorOccurred) - utterance.errorEventOccurred(eventNames().errorEvent, SpeechSynthesisErrorCode::Canceled); + if (error) + utterance.errorEventOccurred(eventNames().errorEvent, *error); else utterance.eventOccurred(eventNames().endEvent, 0, 0, String()); - + if (m_utteranceQueue.size()) { Ref firstUtterance = m_utteranceQueue.takeFirst(); ASSERT(&utterance == firstUtterance.ptr()); @@ -272,11 +272,11 @@ void SpeechSynthesis::didResumeSpeaking() didResumeSpeaking(*protectedCurrentSpeechUtterance()->platformUtterance()); } -void SpeechSynthesis::speakingErrorOccurred() +void SpeechSynthesis::speakingErrorOccurred(std::optional error) { if (!m_currentSpeechUtterance) return; - speakingErrorOccurred(*protectedCurrentSpeechUtterance()->platformUtterance()); + speakingErrorOccurred(*protectedCurrentSpeechUtterance()->platformUtterance(), error); } void SpeechSynthesis::boundaryEventOccurred(bool wordBoundary, unsigned charIndex, unsigned charLength) @@ -314,13 +314,13 @@ void SpeechSynthesis::didResumeSpeaking(PlatformSpeechSynthesisUtterance& uttera void SpeechSynthesis::didFinishSpeaking(PlatformSpeechSynthesisUtterance& utterance) { if (utterance.client()) - handleSpeakingCompleted(static_cast(*utterance.client()), false); + handleSpeakingCompleted(static_cast(*utterance.client()), std::nullopt); } -void SpeechSynthesis::speakingErrorOccurred(PlatformSpeechSynthesisUtterance& utterance) +void SpeechSynthesis::speakingErrorOccurred(PlatformSpeechSynthesisUtterance& utterance, std::optional error) { if (utterance.client()) - handleSpeakingCompleted(static_cast(*utterance.client()), true); + handleSpeakingCompleted(static_cast(*utterance.client()), error); } RefPtr SpeechSynthesis::protectedCurrentSpeechUtterance() diff --git a/Source/WebCore/Modules/speech/SpeechSynthesis.h b/Source/WebCore/Modules/speech/SpeechSynthesis.h index 84387da61b09e..65be177e4fdd3 100644 --- a/Source/WebCore/Modules/speech/SpeechSynthesis.h +++ b/Source/WebCore/Modules/speech/SpeechSynthesis.h @@ -86,7 +86,7 @@ class SpeechSynthesis : public PlatformSpeechSynthesizerClient, public SpeechSyn void didPauseSpeaking(PlatformSpeechSynthesisUtterance&) override; void didResumeSpeaking(PlatformSpeechSynthesisUtterance&) override; void didFinishSpeaking(PlatformSpeechSynthesisUtterance&) override; - void speakingErrorOccurred(PlatformSpeechSynthesisUtterance&) override; + void speakingErrorOccurred(PlatformSpeechSynthesisUtterance&, std::optional) override; void boundaryEventOccurred(PlatformSpeechSynthesisUtterance&, SpeechBoundary, unsigned charIndex, unsigned charLength) override; // SpeechSynthesisClientObserver @@ -94,7 +94,7 @@ class SpeechSynthesis : public PlatformSpeechSynthesizerClient, public SpeechSyn void didFinishSpeaking() override; void didPauseSpeaking() override; void didResumeSpeaking() override; - void speakingErrorOccurred() override; + void speakingErrorOccurred(std::optional) override; void boundaryEventOccurred(bool wordBoundary, unsigned charIndex, unsigned charLength) override; void voicesChanged() override; @@ -102,7 +102,7 @@ class SpeechSynthesis : public PlatformSpeechSynthesizerClient, public SpeechSyn bool virtualHasPendingActivity() const final; void startSpeakingImmediately(SpeechSynthesisUtterance&); - void handleSpeakingCompleted(SpeechSynthesisUtterance&, bool errorOccurred); + void handleSpeakingCompleted(SpeechSynthesisUtterance&, std::optional); // EventTarget ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); } diff --git a/Source/WebCore/Modules/speech/SpeechSynthesisErrorCode.h b/Source/WebCore/Modules/speech/SpeechSynthesisErrorCode.h index 8c310f88c881b..f5f79bd6ffeec 100644 --- a/Source/WebCore/Modules/speech/SpeechSynthesisErrorCode.h +++ b/Source/WebCore/Modules/speech/SpeechSynthesisErrorCode.h @@ -28,7 +28,7 @@ namespace WebCore { -enum class SpeechSynthesisErrorCode { +enum class SpeechSynthesisErrorCode : uint8_t { Canceled, Interrupted, AudioBusy, diff --git a/Source/WebCore/page/SpeechSynthesisClient.h b/Source/WebCore/page/SpeechSynthesisClient.h index 49f2bbadd2c69..9ab4b22502a46 100644 --- a/Source/WebCore/page/SpeechSynthesisClient.h +++ b/Source/WebCore/page/SpeechSynthesisClient.h @@ -45,6 +45,7 @@ namespace WebCore { class PlatformSpeechSynthesisUtterance; class SpeechSynthesisClientObserver; class PlatformSpeechSynthesisVoice; +enum class SpeechSynthesisErrorCode : uint8_t; class SpeechSynthesisClient : public CanMakeWeakPtr { public: @@ -70,7 +71,7 @@ class SpeechSynthesisClientObserver : public CanMakeWeakPtr) = 0; virtual void boundaryEventOccurred(bool wordBoundary, unsigned charIndex, unsigned charLength) = 0; virtual void voicesChanged() = 0; }; diff --git a/Source/WebCore/platform/PlatformSpeechSynthesizer.h b/Source/WebCore/platform/PlatformSpeechSynthesizer.h index 5d347d3e5cdf4..50a995c027970 100644 --- a/Source/WebCore/platform/PlatformSpeechSynthesizer.h +++ b/Source/WebCore/platform/PlatformSpeechSynthesizer.h @@ -29,7 +29,8 @@ #if ENABLE(SPEECH_SYNTHESIS) #include "PlatformSpeechSynthesisVoice.h" -#include +#include "SpeechSynthesisErrorCode.h" +#include #include #if PLATFORM(COCOA) @@ -55,7 +56,7 @@ class PlatformSpeechSynthesizerClient { virtual void didFinishSpeaking(PlatformSpeechSynthesisUtterance&) = 0; virtual void didPauseSpeaking(PlatformSpeechSynthesisUtterance&) = 0; virtual void didResumeSpeaking(PlatformSpeechSynthesisUtterance&) = 0; - virtual void speakingErrorOccurred(PlatformSpeechSynthesisUtterance&) = 0; + virtual void speakingErrorOccurred(PlatformSpeechSynthesisUtterance&, std::optional) = 0; virtual void boundaryEventOccurred(PlatformSpeechSynthesisUtterance&, SpeechBoundary, unsigned charIndex, unsigned charLength) = 0; virtual void voicesDidChange() = 0; protected: diff --git a/Source/WebCore/platform/mock/PlatformSpeechSynthesizerMock.cpp b/Source/WebCore/platform/mock/PlatformSpeechSynthesizerMock.cpp index 069d8e021810a..094837160fa84 100644 --- a/Source/WebCore/platform/mock/PlatformSpeechSynthesizerMock.cpp +++ b/Source/WebCore/platform/mock/PlatformSpeechSynthesizerMock.cpp @@ -81,7 +81,7 @@ void PlatformSpeechSynthesizerMock::cancel() m_speakingFinishedTimer.stop(); auto utterance = std::exchange(m_utterance, nullptr); - client().speakingErrorOccurred(*utterance); + client().speakingErrorOccurred(*utterance, SpeechSynthesisErrorCode::Canceled); } void PlatformSpeechSynthesizerMock::pause() diff --git a/Source/WebKit/UIProcess/WebPageProxyInternals.h b/Source/WebKit/UIProcess/WebPageProxyInternals.h index de43940ad6514..1f7bfbed2b910 100644 --- a/Source/WebKit/UIProcess/WebPageProxyInternals.h +++ b/Source/WebKit/UIProcess/WebPageProxyInternals.h @@ -373,7 +373,7 @@ struct WebPageProxy::Internals final : WebPopupMenuProxy::Client void didFinishSpeaking(WebCore::PlatformSpeechSynthesisUtterance&) final; void didPauseSpeaking(WebCore::PlatformSpeechSynthesisUtterance&) final; void didResumeSpeaking(WebCore::PlatformSpeechSynthesisUtterance&) final; - void speakingErrorOccurred(WebCore::PlatformSpeechSynthesisUtterance&) final; + void speakingErrorOccurred(WebCore::PlatformSpeechSynthesisUtterance&, std::optional) final; void boundaryEventOccurred(WebCore::PlatformSpeechSynthesisUtterance&, WebCore::SpeechBoundary, unsigned characterIndex, unsigned characterLength) final; // PlatformSpeechSynthesizerClient diff --git a/Source/WebKit/UIProcess/gstreamer/WebPageProxyGStreamer.cpp b/Source/WebKit/UIProcess/gstreamer/WebPageProxyGStreamer.cpp index 4e1a353b422bf..a128088dcf040 100644 --- a/Source/WebKit/UIProcess/gstreamer/WebPageProxyGStreamer.cpp +++ b/Source/WebKit/UIProcess/gstreamer/WebPageProxyGStreamer.cpp @@ -58,9 +58,12 @@ void WebPageProxy::Internals::didResumeSpeaking(WebCore::PlatformSpeechSynthesis handler(); } -void WebPageProxy::Internals::speakingErrorOccurred(WebCore::PlatformSpeechSynthesisUtterance&) +void WebPageProxy::Internals::speakingErrorOccurred(WebCore::PlatformSpeechSynthesisUtterance&, std::optional error) { - page.send(Messages::WebPage::SpeakingErrorOccurred()); + if (!error) + page.send(Messages::WebPage::SpeakingErrorOccurred(std::nullopt)); + else + page.send(Messages::WebPage::SpeakingErrorOccurred(static_cast(*error))); } void WebPageProxy::Internals::boundaryEventOccurred(WebCore::PlatformSpeechSynthesisUtterance&, WebCore::SpeechBoundary speechBoundary, unsigned charIndex, unsigned charLength) diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp index 91df2b76529f9..da5782feb838e 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp @@ -249,6 +249,7 @@ #include #include #include +#include #include #include #include @@ -8316,10 +8317,12 @@ void WebPage::systemPreviewActionTriggered(WebCore::SystemPreviewInfo previewInf #endif #if ENABLE(SPEECH_SYNTHESIS) -void WebPage::speakingErrorOccurred() +void WebPage::speakingErrorOccurred(std::optional error) { if (auto observer = corePage()->speechSynthesisClient()->observer()) - observer->speakingErrorOccurred(); + observer->speakingErrorOccurred(!error + ? std::nullopt + : std::make_optional(static_cast(*error))); } void WebPage::boundaryEventOccurred(bool wordBoundary, unsigned charIndex, unsigned charLength) diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.h b/Source/WebKit/WebProcess/WebPage/WebPage.h index cf7b3214202e4..bd70601b1712b 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.h +++ b/Source/WebKit/WebProcess/WebPage/WebPage.h @@ -2166,7 +2166,7 @@ class WebPage : public API::ObjectImpl, public IP #endif #if ENABLE(SPEECH_SYNTHESIS) - void speakingErrorOccurred(); + void speakingErrorOccurred(std::optional error); void boundaryEventOccurred(bool wordBoundary, unsigned charIndex, unsigned charLength); void voicesDidChange(); #endif diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in index d2cdb4a24b5d8..fd91ddd2add21 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in +++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in @@ -668,7 +668,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType SimulateDeviceOrientationChange(double alpha, double beta, double gamma) #if ENABLE(SPEECH_SYNTHESIS) - SpeakingErrorOccurred() + SpeakingErrorOccurred(std::optional error) BoundaryEventOccurred(bool wordBoundary, unsigned charIndex, unsigned charLength) VoicesDidChange() #endif From fbb355f49ad6782acc9a4ef72d2dbd6801917f00 Mon Sep 17 00:00:00 2001 From: Filipe Norte Date: Tue, 3 Oct 2023 17:46:21 +0100 Subject: [PATCH 45/55] Add support for triggering notifications on WPE Implement registerNotifyCallback via filesystem watch Original from 2.28 pull request: https://github.com/WebPlatformForEmbedded/WPEWebKit/pull/1039 --- Source/WebCore/PAL/pal/Logging.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Source/WebCore/PAL/pal/Logging.cpp b/Source/WebCore/PAL/pal/Logging.cpp index 5107ec3c3d476..752d068cd8a1d 100644 --- a/Source/WebCore/PAL/pal/Logging.cpp +++ b/Source/WebCore/PAL/pal/Logging.cpp @@ -31,6 +31,11 @@ #if PLATFORM(COCOA) #include #include +#elif PLATFORM(WPE) +#include +#include +#include +#include #endif namespace PAL { @@ -42,6 +47,25 @@ void registerNotifyCallback(ASCIILiteral notifyID, Function&& callback) notify_register_dispatch(notifyID.characters(), &token, dispatch_get_main_queue(), makeBlockPtr([callback = WTFMove(callback)](int) { callback(); }).get()); +#elif PLATFORM(WPE) + using namespace FileSystem; + + // Triggers callback with "touch /notify/". + CString notifyFilePath = fileSystemRepresentation(pathByAppendingComponents(StringView::fromLatin1(g_get_user_config_dir()), {"notify"_s, notifyID})); + GRefPtr notifyFile = adoptGRef(g_file_new_for_path(notifyFilePath.data())); + GFileMonitor* monitor = g_file_monitor_file(notifyFile.get(), G_FILE_MONITOR_NONE, nullptr, nullptr); + + g_signal_connect(monitor, "changed", G_CALLBACK(+[](GFileMonitor*, GFile* file, GFile*, GFileMonitorEvent event, WTF::Function *callback) { + const char *path = g_file_get_path(file); + if ((nullptr == path) || !g_file_test(path, G_FILE_TEST_EXISTS)) { + return; + } + if ((G_FILE_MONITOR_EVENT_CREATED == event) || (G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED == event)) { + (*callback)(); + } + // We are not releasing the allocated memory for the Function object, as this code will get called each time the signal is raised + // No "unregisterNotifyCallback" available to do proper cleanup (signal disconnection and memory release) + }), new WTF::Function(WTFMove(callback))); #else UNUSED_PARAM(notifyID); UNUSED_PARAM(callback); From 61b6e2ac6f6452996fd4b1aaae4263d5e00882ce Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Fri, 10 Nov 2023 13:14:34 +0100 Subject: [PATCH 46/55] [OIPF] Add window.KeyEvent interface with VK keys mapping --- Source/WebCore/CMakeLists.txt | 9 ++++ Source/WebCore/page/DOMWindow.cpp | 14 ++++++ Source/WebCore/page/DOMWindow.h | 8 ++++ Source/WebCore/page/DOMWindow.idl | 4 ++ Source/WebCore/page/LocalDOMWindow.cpp | 16 +++++++ Source/WebCore/page/LocalDOMWindow.h | 11 +++++ Source/WebCore/page/VkConsts.cpp | 10 +++++ Source/WebCore/page/VkConsts.h | 19 ++++++++ Source/WebCore/page/VkConsts.idl | 61 ++++++++++++++++++++++++++ Source/cmake/OptionsWPE.cmake | 1 + 10 files changed, 153 insertions(+) create mode 100644 Source/WebCore/page/VkConsts.cpp create mode 100644 Source/WebCore/page/VkConsts.h create mode 100644 Source/WebCore/page/VkConsts.idl diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt index c1453f7dbcb0f..4df5ae890642d 100644 --- a/Source/WebCore/CMakeLists.txt +++ b/Source/WebCore/CMakeLists.txt @@ -2256,6 +2256,15 @@ if (USE_LIBWEBRTC) ) endif () +if (ENABLE_OIPF_VK) + list(APPEND WebCore_IDL_FILES + page/VkConsts.idl + ) + list(APPEND WebCore_SOURCES + page/VkConsts.cpp + ) +endif () + # FIXME: This needs a more scalable solution. See webkit.org/b/267080 for some related discussion. if (HAVE_OS_DARK_MODE_SUPPORT) set(FEATURE_DEFINES_WITH_SPACE_SEPARATOR "${FEATURE_DEFINES_WITH_SPACE_SEPARATOR} HAVE_OS_DARK_MODE_SUPPORT") diff --git a/Source/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp index f41eb22ea8d2a..57d52c6ac3574 100644 --- a/Source/WebCore/page/DOMWindow.cpp +++ b/Source/WebCore/page/DOMWindow.cpp @@ -48,6 +48,10 @@ #include #include +#if ENABLE(OIPF_VK) +#include "VkConsts.h" +#endif + namespace WebCore { WTF_MAKE_ISO_ALLOCATED_IMPL(DOMWindow); @@ -535,6 +539,16 @@ void DOMWindow::blur() RELEASE_ASSERT_NOT_REACHED(); } +#if ENABLE(OIPF_VK) +ExceptionOr> DOMWindow::keyEvent() +{ + auto* localThis = dynamicDowncast(*this); + if (!localThis) + return Exception { ExceptionCode::SecurityError }; + return localThis->keyEvent(); +} +#endif + ExceptionOr DOMWindow::print() { auto* localThis = dynamicDowncast(*this); diff --git a/Source/WebCore/page/DOMWindow.h b/Source/WebCore/page/DOMWindow.h index 10198190e156f..29f52eca91476 100644 --- a/Source/WebCore/page/DOMWindow.h +++ b/Source/WebCore/page/DOMWindow.h @@ -77,6 +77,10 @@ class WebKitNamespace; class WebKitPoint; class WindowProxy; +#if ENABLE(OIPF_VK) +class VkConsts; +#endif + #if ENABLE(DEVICE_ORIENTATION) class DeviceMotionController; class DeviceOrientationController; @@ -130,6 +134,10 @@ class DOMWindow : public RefCounted, public EventTarget { void focus(LocalDOMWindow& incumbentWindow); void blur(); +#if ENABLE(OIPF_VK) + ExceptionOr> keyEvent(); +#endif + ExceptionOr name() const; ExceptionOr setName(const AtomString&); ExceptionOr status() const; diff --git a/Source/WebCore/page/DOMWindow.idl b/Source/WebCore/page/DOMWindow.idl index 2e6130f38f769..86891284c9736 100644 --- a/Source/WebCore/page/DOMWindow.idl +++ b/Source/WebCore/page/DOMWindow.idl @@ -122,6 +122,10 @@ // Internal operations, not exposed to the Web. [EnabledForWorld=shadowRootIsAlwaysOpen] NodeList collectMatchingElementsInFlatTree(Node scope, DOMString selectors); [EnabledForWorld=shadowRootIsAlwaysOpen] Element? matchingElementInFlatTree(Node scope, DOMString selectors); + +#if defined(ENABLE_OIPF_VK) && ENABLE_OIPF_VK + readonly attribute VkConsts KeyEvent; +#endif }; DOMWindow includes AnimationFrameProvider; diff --git a/Source/WebCore/page/LocalDOMWindow.cpp b/Source/WebCore/page/LocalDOMWindow.cpp index 5ff88125ff4bd..420bbd9f596cd 100644 --- a/Source/WebCore/page/LocalDOMWindow.cpp +++ b/Source/WebCore/page/LocalDOMWindow.cpp @@ -161,6 +161,10 @@ #include "PointerLockController.h" #endif +#if ENABLE(OIPF_VK) +#include "VkConsts.h" +#endif + namespace WebCore { using namespace Inspector; @@ -2789,4 +2793,16 @@ CookieStore& LocalDOMWindow::cookieStore() return *m_cookieStore; } +#if ENABLE(OIPF_VK) +RefPtr LocalDOMWindow::keyEvent() +{ + if (!isCurrentlyDisplayedInFrame()) + return nullptr; + if (!m_keyEvent) + m_keyEvent = VkConsts::create(*this); + + return m_keyEvent; +} +#endif + } // namespace WebCore diff --git a/Source/WebCore/page/LocalDOMWindow.h b/Source/WebCore/page/LocalDOMWindow.h index 772dcb200002b..8591f57e0bdc0 100644 --- a/Source/WebCore/page/LocalDOMWindow.h +++ b/Source/WebCore/page/LocalDOMWindow.h @@ -61,6 +61,10 @@ class JSValue; namespace WebCore { +#if ENABLE(OIPF_VK) +class VkConsts; +#endif + enum class IncludeTargetOrigin : bool { No, Yes }; class LocalDOMWindowObserver : public CanMakeWeakPtr { @@ -366,6 +370,10 @@ class LocalDOMWindow final CookieStore& cookieStore(); +#if ENABLE(OIPF_VK) + RefPtr keyEvent(); +#endif + private: explicit LocalDOMWindow(Document&); @@ -415,6 +423,9 @@ class LocalDOMWindow final mutable RefPtr m_toolbar; mutable RefPtr m_visualViewport; mutable RefPtr m_navigation; +#if ENABLE(OIPF_VK) + mutable RefPtr m_keyEvent; +#endif String m_status; diff --git a/Source/WebCore/page/VkConsts.cpp b/Source/WebCore/page/VkConsts.cpp new file mode 100644 index 0000000000000..45dc2c3c1067a --- /dev/null +++ b/Source/WebCore/page/VkConsts.cpp @@ -0,0 +1,10 @@ +#include "VkConsts.h" + +namespace WebCore { + +VkConsts::VkConsts(LocalDOMWindow& window) + : LocalDOMWindowProperty(&window) +{ +} + +} // namespace WebCore \ No newline at end of file diff --git a/Source/WebCore/page/VkConsts.h b/Source/WebCore/page/VkConsts.h new file mode 100644 index 0000000000000..bb20a4f7ab600 --- /dev/null +++ b/Source/WebCore/page/VkConsts.h @@ -0,0 +1,19 @@ +#ifndef VKCONSTS_H +#define VKCONSTS_H + +#include "config.h" +#include "LocalDOMWindowProperty.h" +#include + +namespace WebCore { + +class VkConsts final : public RefCounted, public LocalDOMWindowProperty { +public: + static Ref create(LocalDOMWindow& window) { return adoptRef(*new VkConsts(window)); } + +private: + explicit VkConsts(LocalDOMWindow&); +}; +} // namespace WebCore + +#endif // VKCONSTS_H \ No newline at end of file diff --git a/Source/WebCore/page/VkConsts.idl b/Source/WebCore/page/VkConsts.idl new file mode 100644 index 0000000000000..59c50810d7258 --- /dev/null +++ b/Source/WebCore/page/VkConsts.idl @@ -0,0 +1,61 @@ +[ + Exposed=Window, + DoNotCheckConstants +] interface VkConsts { + const long VK_ENTER = 13; + const long VK_LEFT = 37; + const long VK_UP = 38; + const long VK_RIGHT = 39; + const long VK_DOWN = 40; + const long VK_SPACE = 32; + const long VK_BACK_SPACE = 8; + const long VK_0 = 48; + const long VK_1 = 49; + const long VK_2 = 50; + const long VK_3 = 51; + const long VK_4 = 52; + const long VK_5 = 53; + const long VK_6 = 54; + const long VK_7 = 55; + const long VK_8 = 56; + const long VK_9 = 57; + const long VK_A = 65; + const long VK_B = 66; + const long VK_C = 67; + const long VK_D = 68; + const long VK_E = 69; + const long VK_F = 70; + const long VK_G = 71; + const long VK_H = 72; + const long VK_I = 73; + const long VK_J = 74; + const long VK_K = 75; + const long VK_L = 76; + const long VK_M = 77; + const long VK_N = 78; + const long VK_O = 79; + const long VK_P = 80; + const long VK_Q = 81; + const long VK_R = 82; + const long VK_S = 83; + const long VK_T = 84; + const long VK_U = 85; + const long VK_V = 86; + const long VK_W = 87; + const long VK_X = 88; + const long VK_Y = 89; + const long VK_Z = 90; + const long VK_RED = 403; + const long VK_GREEN = 404; + const long VK_YELLOW = 405; + const long VK_BLUE = 406; + const long VK_HELP = 47; + const long VK_PLAY = 250; + const long VK_PAUSE = 19; + const long VK_PLAY_PAUSE = 179; + const long VK_STOP = 178; + const long VK_FAST_FWD = 228; + const long VK_REWIND = 227; + const long VK_BACK = 27; + const long VK_CONTEXT_MENU = 93; +}; diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 212aff17e5941..1d2d83e8cde7c 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -103,6 +103,7 @@ WEBKIT_OPTION_DEFINE(USE_SOUP2 "Whether to enable usage of Soup 2 instead of Sou # Private options specific to the WPE port. WEBKIT_OPTION_DEFINE(USE_EXTERNAL_HOLEPUNCH "Whether to enable external holepunch" PRIVATE OFF) WEBKIT_OPTION_DEFINE(USE_ANGLE_GBM "Whether to enable ANGLE implementation with GBM" PRIVATE OFF) +WEBKIT_OPTION_DEFINE(ENABLE_OIPF_VK "Whether to enable OIPF keys for DAE applications" PRIVATE OFF) WEBKIT_OPTION_DEPEND(ENABLE_DOCUMENTATION ENABLE_INTROSPECTION) From 039ccfe23636356740b66cb13c650e6f16c6af70 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Thu, 30 Nov 2023 10:44:39 +0100 Subject: [PATCH 47/55] Add logging for loading failures --- .../WebCoreSupport/WebLocalFrameLoaderClient.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp index 9916cdda0f3bf..608d97e9d1ba8 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp @@ -293,6 +293,11 @@ void WebLocalFrameLoaderClient::dispatchDidReceiveResponse(DocumentLoader*, Reso #if PLATFORM(GTK) || PLATFORM(WPE) webPage->send(Messages::WebPageProxy::DidReceiveResponseForResource(identifier, m_frame->frameID(), response)); #endif + + if (response.httpStatusCode() >= 400) { + String message = "Failed to load resource: the server responded with a status of " + String::number(response.httpStatusCode()) + " (" + response.httpStatusText() + ')'; + LOG(Loading,"dispatchDidReceiveResponse->message:%s", message.utf8().data()); + } } void WebLocalFrameLoaderClient::dispatchDidReceiveContentLength(DocumentLoader*, ResourceLoaderIdentifier identifier, int dataLength) @@ -342,6 +347,8 @@ void WebLocalFrameLoaderClient::dispatchDidFailLoading(DocumentLoader*, Resource #endif webPage->removeResourceRequest(identifier); + + LOG(Loading,"dispatchedDidFailLoading: isTimeout=%d, isCancellation=%d, isAccessControl=%d, errorCode=%d description:%s", error.isTimeout(), error.isCancellation(), error.isAccessControl(), error.errorCode(), error.localizedDescription().utf8().data()); } bool WebLocalFrameLoaderClient::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int /*length*/) @@ -712,6 +719,8 @@ void WebLocalFrameLoaderClient::dispatchDidFailLoad(const ResourceError& error) // If we have a load listener, notify it. if (LoadListener* loadListener = m_frame->loadListener()) loadListener->didFailLoad(m_frame.ptr(), error.isCancellation()); + + LOG(Loading,"dispatchDidFailLoad: isTimeout= %d, isCancellation= %d, isAccessControl= %d, errorCode= %d description: %s", error.isTimeout(), error.isCancellation(), error.isAccessControl(), error.errorCode(), error.localizedDescription().utf8().data()); } void WebLocalFrameLoaderClient::dispatchDidFinishDocumentLoad() From 30f29090eb8deb388251e5832092bd54f0cfd281 Mon Sep 17 00:00:00 2001 From: Filipe Norte Date: Thu, 21 Dec 2023 12:09:31 +0000 Subject: [PATCH 48/55] Support unrestricted ports usage for custom URI schemes Some custom URI schemes may assign a different meaning to the port of an URI. Webkit restricts, by default, usage of certain ports. To bypass the check, an env var allows specifying which protocols shall be allowed unrestricted ports usage. Some network based protocols (e.g. http, https, and others) are kept still restricted. --- Source/WTF/wtf/URL.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Source/WTF/wtf/URL.cpp b/Source/WTF/wtf/URL.cpp index 7d92d3d5570cb..4a5a59a213d90 100644 --- a/Source/WTF/wtf/URL.cpp +++ b/Source/WTF/wtf/URL.cpp @@ -988,6 +988,32 @@ const URL& aboutSrcDocURL() return staticSrcDocURL; } +static bool protocolIsWhitelistedForAllPortsAcccess(StringView protocol) +{ + static Vector s_protocolsWhitelisted; + static std::once_flag s_onceFlag; + std::call_once(s_onceFlag, + [] { + // The env var contains a comma separated list of protocols that need to have + // access to all ports. + // Example: WPE_WHITELIST_ALL_PORTS_FOR_PROTOCOLS="dvb,echo,custom" + String s(String::fromLatin1(std::getenv("WPE_WHITELIST_ALL_PORTS_FOR_PROTOCOLS"))); + if (s.isEmpty()) + return; + + s_protocolsWhitelisted.appendVector(s.convertToASCIILowercase().split(',')); + + const Vector excludeFromWhitelist( { "http"_s, "https"_s, "ws"_s, "wss"_s, "ftp"_s, "ftps"_s} ); + + // Ensure reserved protocols are not whitelisted + s_protocolsWhitelisted.removeAllMatching([&](const auto& protocol) { + return excludeFromWhitelist.contains(protocol); + }); + }); + + return s_protocolsWhitelisted.contains(protocol.convertToASCIILowercase()); +} + bool portAllowed(const URL& url) { std::optional port = url.port(); @@ -996,6 +1022,9 @@ bool portAllowed(const URL& url) if (!port) return true; + if (protocolIsWhitelistedForAllPortsAcccess(url.protocol())) + return true; + // This blocked port list matches the port blocking that Mozilla implements. // See http://www.mozilla.org/projects/netlib/PortBanning.html for more information. static const uint16_t blockedPortList[] = { From 903aacce408450ba9439ac9955b1ee927f02e788 Mon Sep 17 00:00:00 2001 From: Filipe Norte Date: Mon, 15 Apr 2024 15:11:28 +0100 Subject: [PATCH 49/55] Add support to enable/disable service workers at runtime --- .../UIProcess/API/glib/WebKitSettings.cpp | 61 +++++++++++++++++++ .../UIProcess/API/glib/WebKitSettings.h.in | 6 ++ 2 files changed, 67 insertions(+) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp index a8ce40c7cfab6..e54824289e46e 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp @@ -179,6 +179,7 @@ enum { PROP_ALLOW_SCRIPTS_TO_CLOSE_WINDOWS, PROP_ALLOW_MOVE_TO_SUSPEND_ON_WINDOW_CLOSE, PROP_ENABLE_DIRECTORY_UPLOAD, + PROP_ENABLE_SERVICE_WORKER, N_PROPERTIES, }; @@ -429,6 +430,9 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN case PROP_ENABLE_DIRECTORY_UPLOAD: webkit_settings_set_enable_directory_upload(settings, g_value_get_boolean(value)); break; + case PROP_ENABLE_SERVICE_WORKER: + webkit_settings_set_enable_service_worker(settings, g_value_get_boolean(value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); break; @@ -652,6 +656,9 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN case PROP_ENABLE_DIRECTORY_UPLOAD: g_value_set_boolean(value, webkit_settings_get_enable_directory_upload(settings)); break; + case PROP_ENABLE_SERVICE_WORKER: + g_value_set_boolean(value, webkit_settings_get_enable_service_worker(settings)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); break; @@ -1716,6 +1723,21 @@ static void webkit_settings_class_init(WebKitSettingsClass* klass) TRUE, readWriteConstructParamFlags); + /** + * WebKitSettings:enable-service-worker: + * + * Enable or disable service worker. + * This property will only work as intended if the ServiceWorker feature is enabled at build time + * with the ENABLE_SERVICE_WORKER flag. + * + */ + sObjProperties[PROP_ENABLE_SERVICE_WORKER] = g_param_spec_boolean( + "enable-service-worker", + _("Enable service worker"), + _("Whether service worker support should be enabled."), + TRUE, + readWriteConstructParamFlags); + g_object_class_install_properties(gObjectClass, N_PROPERTIES, sObjProperties); } @@ -4406,3 +4428,42 @@ void webkit_settings_set_enable_directory_upload(WebKitSettings* settings, gbool priv->preferences->setDirectoryUploadEnabled(enabled); g_object_notify(G_OBJECT(settings), "enable-directory-upload"); } + +/** + * webkit_settings_get_enable_service_worker: + * @settings: a #WebKitSettings + * + * Get the #WebKitSettings:enable-service-worker property. + * + * Returns: %TRUE if Service Worker support is enabled or %FALSE otherwise. + * + * Since: 2.38 + */ +gboolean webkit_settings_get_enable_service_worker(WebKitSettings* settings) +{ + g_return_val_if_fail(WEBKIT_IS_SETTINGS(settings), FALSE); + + return settings->priv->preferences->serviceWorkersEnabled(); +} + +/** + * webkit_settings_set_enable_service_worker: + * @settings: a #WebKitSettings + * @enabled: Value to be set + * + * Set the #WebKitSettings:enable-service-worker property. + * + * Since: 2.38 + */ +void webkit_settings_set_enable_service_worker(WebKitSettings* settings, gboolean enabled) +{ + g_return_if_fail(WEBKIT_IS_SETTINGS(settings)); + + WebKitSettingsPrivate* priv = settings->priv; + bool currentValue = priv->preferences->serviceWorkersEnabled(); + if (currentValue == enabled) + return; + + priv->preferences->setServiceWorkersEnabled(enabled); + g_object_notify_by_pspec(G_OBJECT(settings), sObjProperties[PROP_ENABLE_SERVICE_WORKER]); +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in index df7858368e7bc..e35c6fbcfee29 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in @@ -596,6 +596,12 @@ WEBKIT_API void webkit_settings_set_enable_directory_upload (WebKitSettings *settings, gboolean enabled); +WEBKIT_API gboolean +webkit_settings_get_enable_service_worker (WebKitSettings* settings); +WEBKIT_API void +webkit_settings_set_enable_service_worker (WebKitSettings* settings, + gboolean enabled); + G_END_DECLS #endif /* WebKitSettings_h */ From ac6b407929a1bef91cbae9c79aec91c144811b86 Mon Sep 17 00:00:00 2001 From: Andrzej Surdej Date: Fri, 12 Apr 2024 10:53:38 +0200 Subject: [PATCH 50/55] Enable MemoryPressureHandler for MALLOC_HEAP_BREAKDOWN Enabling MALLOC_HEAP_BREAKDOWN currently disables MemoryPressureHandler. We would like to keep both enabled to be able to track memory related issues. --- Source/WTF/wtf/MemoryPressureHandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/WTF/wtf/MemoryPressureHandler.cpp b/Source/WTF/wtf/MemoryPressureHandler.cpp index a82885a2dbbd0..b57d02f82c9d2 100644 --- a/Source/WTF/wtf/MemoryPressureHandler.cpp +++ b/Source/WTF/wtf/MemoryPressureHandler.cpp @@ -159,11 +159,13 @@ void MemoryPressureHandler::setMemoryFootprintPollIntervalForTesting(Seconds pol void MemoryPressureHandler::setShouldUsePeriodicMemoryMonitor(bool use) { +#if !ENABLE(MALLOC_HEAP_BREAKDOWN) if (!isFastMallocEnabled()) { // If we're running with FastMalloc disabled, some kind of testing or debugging is probably happening. // Let's be nice and not enable the memory kill mechanism. return; } +#endif if (use) { m_measurementTimer = makeUnique(RunLoop::main(), this, &MemoryPressureHandler::measurementTimerFired); From d675935cf878a8cc0c4fcf197ea31bf470bc6720 Mon Sep 17 00:00:00 2001 From: dkolesa Date: Fri, 26 Apr 2024 13:22:43 +0200 Subject: [PATCH 51/55] Fix remaining !ENABLE(VIDEO) build failures https://bugs.webkit.org/show_bug.cgi?id=273314 Reviewed by NOBODY (OOPS!). Recent refactorings introduced the breakages. They were fixed partially in ea2be408f27eb1009bbde7b0a2496018d4ca5e86 but not entirely. Notably, a misplacement of an #endif in WebCoreArgumentCoders resulted in strange IPC errors. * Source/WebCore/Modules/WebGPU/GPUDevice.cpp: * Source/WebCore/Modules/WebGPU/GPUDevice.h: * Source/WebCore/page/InteractionRegion.cpp: (WebCore::interactionRegionForRenderedRegion): * Source/WebCore/page/Page.cpp: (WebCore::Page::shouldBlockLayerTreeFreezingForVideo): * Source/WebCore/platform/graphics/MediaResourceSniffer.cpp: * Source/WebCore/platform/graphics/MediaResourceSniffer.h: * Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in: * Source/WebKit/WebProcess/WebPage/WebPage.cpp: (WebKit::WebPage::startObservingNowPlayingMetadata): (WebKit::WebPage::stopObservingNowPlayingMetadata): --- Source/WebCore/Modules/WebGPU/GPUDevice.cpp | 2 ++ Source/WebCore/Modules/WebGPU/GPUDevice.h | 2 ++ Source/WebCore/page/InteractionRegion.cpp | 3 ++- Source/WebCore/page/Page.cpp | 2 ++ .../platform/graphics/MediaResourceSniffer.cpp | 4 ++++ .../WebCore/platform/graphics/MediaResourceSniffer.h | 4 ++++ .../Shared/WebCoreArgumentCoders.serialization.in | 11 ++++++++--- Source/WebKit/WebProcess/WebPage/WebPage.cpp | 4 ++++ 8 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Source/WebCore/Modules/WebGPU/GPUDevice.cpp b/Source/WebCore/Modules/WebGPU/GPUDevice.cpp index 4057cfd2c0cd4..0b1cb1e160f93 100644 --- a/Source/WebCore/Modules/WebGPU/GPUDevice.cpp +++ b/Source/WebCore/Modules/WebGPU/GPUDevice.cpp @@ -601,9 +601,11 @@ bool GPUDevice::addEventListener(const AtomString& eventType, Ref return result; } +#if ENABLE(VIDEO) WeakPtr GPUDevice::takeExternalTextureForVideoElement(const HTMLVideoElement& element) { return m_videoElementToExternalTextureMap.take(element); } +#endif } diff --git a/Source/WebCore/Modules/WebGPU/GPUDevice.h b/Source/WebCore/Modules/WebGPU/GPUDevice.h index cb4fa7b15a21f..8814a483ed610 100644 --- a/Source/WebCore/Modules/WebGPU/GPUDevice.h +++ b/Source/WebCore/Modules/WebGPU/GPUDevice.h @@ -139,7 +139,9 @@ class GPUDevice : public RefCounted, public ActiveDOMObject, public E using RefCounted::ref; using RefCounted::deref; +#if ENABLE(VIDEO) WeakPtr takeExternalTextureForVideoElement(const HTMLVideoElement&); +#endif private: GPUDevice(ScriptExecutionContext*, Ref&&); diff --git a/Source/WebCore/page/InteractionRegion.cpp b/Source/WebCore/page/InteractionRegion.cpp index 0df7a5105f451..80da18bbaa061 100644 --- a/Source/WebCore/page/InteractionRegion.cpp +++ b/Source/WebCore/page/InteractionRegion.cpp @@ -394,9 +394,10 @@ std::optional interactionRegionForRenderedRegion(RenderObject if (needsContentHint) { if (auto* renderImage = dynamicDowncast(regionRenderer)) { isPhoto = [&]() -> bool { +#if ENABLE(VIDEO) if (is(renderImage)) return true; - +#endif if (!renderImage->cachedImage()) return false; diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp index f941ccf807bda..ed1542184630c 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp @@ -2721,6 +2721,7 @@ void Page::setMuted(MediaProducerMutedStateFlags muted) bool Page::shouldBlockLayerTreeFreezingForVideo() { bool shouldBlockLayerTreeFreezingForVideo = false; +#if ENABLE(VIDEO) forEachMediaElement([&shouldBlockLayerTreeFreezingForVideo] (HTMLMediaElement& element) { // FIXME: Consider only returning true when `element.readyState >= // HTMLMediaElementEnums::HAVE_METADATA` and forcing an update to the layer tree @@ -2729,6 +2730,7 @@ bool Page::shouldBlockLayerTreeFreezingForVideo() if (element.isVideo()) shouldBlockLayerTreeFreezingForVideo = true; }); +#endif return shouldBlockLayerTreeFreezingForVideo; } diff --git a/Source/WebCore/platform/graphics/MediaResourceSniffer.cpp b/Source/WebCore/platform/graphics/MediaResourceSniffer.cpp index b8ef1ef9873c6..8e79ac51fb62f 100644 --- a/Source/WebCore/platform/graphics/MediaResourceSniffer.cpp +++ b/Source/WebCore/platform/graphics/MediaResourceSniffer.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "MediaResourceSniffer.h" +#if ENABLE(VIDEO) + #include "MIMESniffer.h" #include "ResourceRequest.h" #include @@ -106,3 +108,5 @@ void MediaResourceSniffer::loadFinished(PlatformMediaResource&, const NetworkLoa } } // namespace WebCore + +#endif // ENABLE(VIDEO) diff --git a/Source/WebCore/platform/graphics/MediaResourceSniffer.h b/Source/WebCore/platform/graphics/MediaResourceSniffer.h index 40eaa43948221..bf38c602bd2a6 100644 --- a/Source/WebCore/platform/graphics/MediaResourceSniffer.h +++ b/Source/WebCore/platform/graphics/MediaResourceSniffer.h @@ -25,6 +25,8 @@ #pragma once +#if ENABLE(VIDEO) + #include "ContentType.h" #include "MediaPromiseTypes.h" #include "PlatformMediaResourceLoader.h" @@ -58,3 +60,5 @@ class MediaResourceSniffer final : public PlatformMediaResourceClient { }; } // namespace WebCore + +#endif // ENABLE(VIDEO) diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in index 3e5d7230be386..ed0cf0d21d68c 100644 --- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in +++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in @@ -7993,8 +7993,8 @@ class WebCore::SerializedPlatformDataCueValue { RetainPtr locale; std::variant, RetainPtr, RetainPtr, RetainPtr> value; #endif -#endif }; +#endif header: [RefCounted, CustomHeader, CreateUsing=fromIPCData] class WebCore::FragmentedSharedBuffer { @@ -8053,10 +8053,14 @@ using WebCore::DOMCacheEngine::RecordIdentifiersOrError = Expected, WebCore::DOMCacheEngine::Error> using WebCore::DOMCacheEngine::RemoveCacheIdentifierOrError = Expected -using WebCore::MediaPlayerEnums::VideoFullscreenMode = uint32_t using WebCore::SVGFilterExpression = Vector; using WebCore::SandboxFlags = int +#if ENABLE(VIDEO) +using WebCore::MediaPlayerEnums::VideoFullscreenMode = uint32_t +using WebCore::MediaPlayerEnums::VideoFullscreenMode = uint32_t +using WebCore::MediaPlayer::VideoFullscreenMode = uint32_t using WebCore::TrackID = uint64_t +#endif using WebCore::EpochTimeStamp = uint64_t using WebCore::SharedMemory::Handle = WebCore::SharedMemoryHandle using WebCore::ServiceWorkerOrClientIdentifier = std::variant @@ -8092,6 +8096,7 @@ using WebCore::PageOverlay::PageOverlayID = uint64_t SVG_MEETORSLICE_SLICE } +#if ENABLE(VIDEO) enum class WebCore::PlatformMediaError : uint8_t { AppendError, ClientDisconnected, @@ -8106,6 +8111,7 @@ enum class WebCore::PlatformMediaError : uint8_t { NotSupportedError, NetworkError, }; +#endif #if USE(CG) using WebCore::DashArray = Vector; @@ -8137,5 +8143,4 @@ using Inspector::ExtensionTabID = String using WebCore::ArgumentWireBytesMap = HashMap> using WebCore::IDBKeyPath = std::variant>; using WebCore::ServiceWorkerOrClientData = std::variant -using WebCore::MediaPlayer::VideoFullscreenMode = uint32_t enum class WebCore::CrossOriginMode : bool diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp index da5782feb838e..d36d2dde23d5d 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp @@ -9569,6 +9569,7 @@ void WebPage::setDefaultSpatialTrackingLabel(const String& label) void WebPage::startObservingNowPlayingMetadata() { +#if ENABLE(VIDEO) || ENABLE(WEB_AUDIO) if (m_nowPlayingMetadataObserver) return; @@ -9578,15 +9579,18 @@ void WebPage::startObservingNowPlayingMetadata() }); WebCore::PlatformMediaSessionManager::sharedManager().addNowPlayingMetadataObserver(*m_nowPlayingMetadataObserver); +#endif } void WebPage::stopObservingNowPlayingMetadata() { +#if ENABLE(VIDEO) || ENABLE(WEB_AUDIO) auto nowPlayingMetadataObserver = std::exchange(m_nowPlayingMetadataObserver, nullptr); if (!nowPlayingMetadataObserver) return; WebCore::PlatformMediaSessionManager::sharedManager().removeNowPlayingMetadataObserver(*nowPlayingMetadataObserver); +#endif } void WebPage::didAdjustVisibilityWithSelectors(Vector&& selectors) From 7e675fda64ec92978354af8a73642b1453e24164 Mon Sep 17 00:00:00 2001 From: Miguel Gomez Date: Wed, 8 May 2024 19:37:46 +0200 Subject: [PATCH 52/55] [suspend/resume][hide/show] Implement features --- Source/WebCore/html/HTMLMediaElement.cpp | 6 ++ Source/WebCore/html/MediaElementSession.cpp | 2 + .../html/canvas/WebGLRenderingContextBase.cpp | 26 ++++-- .../html/canvas/WebGLRenderingContextBase.h | 1 + .../WebCore/platform/graphics/MediaPlayer.cpp | 5 ++ .../WebCore/platform/graphics/MediaPlayer.h | 1 + .../platform/graphics/MediaPlayerPrivate.h | 1 + .../gstreamer/MediaPlayerPrivateGStreamer.cpp | 80 ++++++++++++++----- .../gstreamer/MediaPlayerPrivateGStreamer.h | 34 +++++++- .../threadedcompositor/ThreadedCompositor.cpp | 43 +++++++++- .../threadedcompositor/ThreadedCompositor.h | 8 ++ .../UIProcess/API/glib/WebKitWebView.cpp | 43 ++++++++++ .../UIProcess/API/glib/WebKitWebView.h.in | 15 ++++ Source/WebKit/UIProcess/API/wpe/WPEWebView.h | 3 +- .../DrawingAreaCoordinatedGraphics.cpp | 44 ++++++++-- .../DrawingAreaCoordinatedGraphics.h | 2 + .../CoordinatedGraphics/LayerTreeHost.cpp | 2 +- 17 files changed, 278 insertions(+), 38 deletions(-) diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp index 9ae6fd1cfb0c6..f8c36658c8611 100644 --- a/Source/WebCore/html/HTMLMediaElement.cpp +++ b/Source/WebCore/html/HTMLMediaElement.cpp @@ -6579,6 +6579,9 @@ void HTMLMediaElement::suspend(ReasonForSuspension reason) m_mediaSession->addBehaviorRestriction(MediaElementSession::RequirePageConsentToResumeMedia); break; case ReasonForSuspension::PageWillBeSuspended: + if (m_player) + m_player->setPageIsSuspended(true); + break; case ReasonForSuspension::JavaScriptDebuggerPaused: case ReasonForSuspension::WillDeferLoading: // Do nothing, we don't pause media playback in these cases. @@ -6590,6 +6593,9 @@ void HTMLMediaElement::resume() { ALWAYS_LOG(LOGIDENTIFIER); + if (m_player) + m_player->setPageIsSuspended(false); + setInActiveDocument(true); if (m_mediaSession && !m_mediaSession->pageAllowsPlaybackAfterResuming()) diff --git a/Source/WebCore/html/MediaElementSession.cpp b/Source/WebCore/html/MediaElementSession.cpp index 4d3591162899a..03e255a37b9c6 100644 --- a/Source/WebCore/html/MediaElementSession.cpp +++ b/Source/WebCore/html/MediaElementSession.cpp @@ -272,6 +272,7 @@ void MediaElementSession::visibilityChanged() else if (m_element.isVisibleInViewport()) m_elementIsHiddenUntilVisibleInViewport = false; +#if !PLATFORM(WPE) bool isPlayingAudio = m_element.isPlaying() && m_element.hasAudio() && !m_element.muted() && m_element.volume(); if (!isPlayingAudio) { if (elementIsHidden) { @@ -283,6 +284,7 @@ void MediaElementSession::visibilityChanged() } return; } +#endif if (hasBehaviorRestriction(RequirePageVisibilityToPlayAudio)) { if (elementIsHidden) { diff --git a/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp b/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp index c4256b064a205..fe7831f195767 100644 --- a/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp +++ b/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp @@ -614,15 +614,15 @@ void WebGLRenderingContextBase::addCompressedTextureFormat(GCGLenum format) void WebGLRenderingContextBase::addActivityStateChangeObserverIfNecessary() { - // We are only interested in visibility changes for contexts - // that are using the high-performance GPU. - if (m_attributes.powerPreference != WebGLPowerPreference::HighPerformance) - return; - auto* canvas = htmlCanvas(); if (!canvas) return; + //m_nonCompositedWebGLEnabled = canvas->document().frame()->settings().nonCompositedWebGLEnabled(); + m_nonCompositedWebGLEnabled = false; + if (m_attributes.powerPreference != WebGLPowerPreference::HighPerformance && !m_nonCompositedWebGLEnabled) + return; + RefPtr page = canvas->document().page(); if (!page) return; @@ -632,6 +632,22 @@ void WebGLRenderingContextBase::addActivityStateChangeObserverIfNecessary() // We won't get a state change right away, so // make sure the context knows if it visible or not. protectedGraphicsContextGL()->setContextVisibility(page->isVisible()); + +#if 0 + if (m_nonCompositedWebGLEnabled) { + if (((changed & ActivityState::IsInWindow) && !(newActivityState & ActivityState::IsInWindow)) || + ((changed & ActivityState::IsVisible) && !(newActivityState & ActivityState::IsVisible))) { + if (m_scissorEnabled) + m_context->disable(GraphicsContextGL::SCISSOR_TEST); + m_context->clearColor(0, 0, 0, 0); + m_context->clear(GraphicsContextGL::COLOR_BUFFER_BIT); + m_context->markContextChanged(); + m_context->prepareForDisplay(); + if (m_scissorEnabled) + m_context->enable(GraphicsContextGL::SCISSOR_TEST); + } + } +#endif } void WebGLRenderingContextBase::removeActivityStateChangeObserver() diff --git a/Source/WebCore/html/canvas/WebGLRenderingContextBase.h b/Source/WebCore/html/canvas/WebGLRenderingContextBase.h index 39017272a3803..2354ef1a7165a 100644 --- a/Source/WebCore/html/canvas/WebGLRenderingContextBase.h +++ b/Source/WebCore/html/canvas/WebGLRenderingContextBase.h @@ -1073,6 +1073,7 @@ class WebGLRenderingContextBase : public GraphicsContextGL::Client, public GPUBa #endif bool m_isSuspended { false }; + bool m_nonCompositedWebGLEnabled { false }; // The ordinal number of when the context was last active (drew, read pixels). uint64_t m_activeOrdinal { 0 }; diff --git a/Source/WebCore/platform/graphics/MediaPlayer.cpp b/Source/WebCore/platform/graphics/MediaPlayer.cpp index 79ceea776d877..cadb627f85d9d 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.cpp +++ b/Source/WebCore/platform/graphics/MediaPlayer.cpp @@ -1098,6 +1098,11 @@ void MediaPlayer::setPageIsVisible(bool visible, String&& sceneIdentifier) m_private->setPageIsVisible(visible, WTFMove(sceneIdentifier)); } +void MediaPlayer::setPageIsSuspended(bool suspended) +{ + m_private->setPageIsSuspended(suspended); +} + void MediaPlayer::setVisibleForCanvas(bool visible) { if (visible == m_visibleForCanvas) diff --git a/Source/WebCore/platform/graphics/MediaPlayer.h b/Source/WebCore/platform/graphics/MediaPlayer.h index 92ac09f54f770..47cb61edc5458 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.h +++ b/Source/WebCore/platform/graphics/MediaPlayer.h @@ -396,6 +396,7 @@ class WEBCORE_EXPORT MediaPlayer : public MediaPlayerEnums, public ThreadSafeRef void cancelLoad(); void setPageIsVisible(bool, String&& sceneIdentifier = ""_s); + void setPageisSuspended(bool); void setVisibleForCanvas(bool); bool isVisibleForCanvas() const { return m_visibleForCanvas; } diff --git a/Source/WebCore/platform/graphics/MediaPlayerPrivate.h b/Source/WebCore/platform/graphics/MediaPlayerPrivate.h index 931f2a74691cf..83d8cbfc2a225 100644 --- a/Source/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/Source/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -120,6 +120,7 @@ class MediaPlayerPrivateInterface { virtual bool hasAudio() const = 0; virtual void setPageIsVisible(bool, String&& sceneIdentifier = ""_s) = 0; + virtual void setPageIsSuspended(bool) { } virtual void setVisibleForCanvas(bool visible) { setPageIsVisible(visible); } virtual void setVisibleInViewport(bool) { } diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index 91167d1a89e59..7dd173b2d2078 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -200,6 +200,11 @@ MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer() GST_DEBUG_OBJECT(pipeline(), "Disposing player"); m_isPlayerShuttingDown.store(true); +#if USE(GSTREAMER_HOLEPUNCH) + if (m_gstreamerHolePunchHost) + m_gstreamerHolePunchHost->playerPrivateWillBeDestroyed(); +#endif + m_sinkTaskQueue.startAborting(); for (auto& track : m_audioTracks.values()) @@ -4121,27 +4126,10 @@ GstElement* MediaPlayerPrivateGStreamer::createVideoSinkGL() class GStreamerHolePunchClient : public TextureMapperPlatformLayerBuffer::HolePunchClient { public: - GStreamerHolePunchClient(GRefPtr&& videoSink, RefPtr&& quirksManagerForTesting) - : m_videoSink(WTFMove(videoSink)) - , m_quirksManagerForTesting(WTFMove(quirksManagerForTesting)) - { }; - void setVideoRectangle(const IntRect& rect) final - { - if (!m_videoSink) - return; - - if (m_quirksManagerForTesting) { - m_quirksManagerForTesting->setHolePunchVideoRectangle(m_videoSink.get(), rect); - return; - } - - auto& quirksManager = GStreamerQuirksManager::singleton(); - quirksManager.setHolePunchVideoRectangle(m_videoSink.get(), rect); - } - + GStreamerHolePunchClient(RefPtr&& host) : m_host(WTFMove(host)) { }; + void setVideoRectangle(const IntRect& rect) final { m_host->setVideoRectangle(rect); } private: - GRefPtr m_videoSink; - RefPtr m_quirksManagerForTesting; + RefPtr m_host; }; bool MediaPlayerPrivateGStreamer::isHolePunchRenderingEnabled() const @@ -4176,12 +4164,15 @@ GstElement* MediaPlayerPrivateGStreamer::createHolePunchVideoSink() void MediaPlayerPrivateGStreamer::pushNextHolePunchBuffer() { + if (!m_gstreamerHolePunchHost) + m_gstreamerHolePunchHost = GStreamerHolePunchHost::create(*this); + auto proxyOperation = [this](TextureMapperPlatformLayerProxyGL& proxy) { Locker locker { proxy.lock() }; std::unique_ptr layerBuffer = makeUnique(0, m_size, TextureMapperFlags::ShouldNotBlend, GL_DONT_CARE); - std::unique_ptr holePunchClient = makeUnique(m_videoSink.get(), RefPtr { m_quirksManagerForTesting }); + std::unique_ptr holePunchClient = makeUnique(m_gstreamerHolePunchHost.copyRef()); layerBuffer->setHolePunchClient(WTFMove(holePunchClient)); proxy.pushNextBuffer(WTFMove(layerBuffer)); }; @@ -4196,6 +4187,22 @@ void MediaPlayerPrivateGStreamer::pushNextHolePunchBuffer() #endif } +void MediaPlayerPrivateGStreamer::setVideoRectangle(const IntRect& rect) +{ + Locker locker { m_holePunchLock }; + + if (!m_visible || m_suspended || !m_videoSink) + return; + + if (m_quirksManagerForTesting) { + m_quirksManagerForTesting->setHolePunchVideoRectangle(m_videoSink.get(), rect); + return; + } + + auto& quirksManager = GStreamerQuirksManager::singleton(); + quirksManager.setHolePunchVideoRectangle(m_videoSink.get(), rect); +} + bool MediaPlayerPrivateGStreamer::shouldIgnoreIntrinsicSize() { return isHolePunchRenderingEnabled(); @@ -4589,6 +4596,37 @@ String MediaPlayerPrivateGStreamer::codecForStreamId(const String& streamId) return m_codecs.get(streamId); } +void MediaPlayerPrivateGStreamer::setPageIsVisible(bool visible, String &&) +{ + + if (m_visible != visible) { +#if USE(GSTREAMER_HOLEPUNCH) + Locker locker { m_holePunchLock }; +#endif + m_visible = visible; + +#if USE(GSTREAMER_HOLEPUNCH) + //if (!m_visible) + // setRectangleToVideoSink(m_videoSink.get(), IntRect()); +#endif + } +} + +void MediaPlayerPrivateGStreamer::setPageIsSuspended(bool suspended) +{ + if (m_suspended != suspended) { +#if USE(GSTREAMER_HOLEPUNCH) + Locker locker { m_holePunchLock }; +#endif + m_suspended = suspended; + +#if USE(GSTREAMER_HOLEPUNCH) + //if (m_suspended) + // setRectangleToVideoSink(m_videoSink.get(), IntRect()); +#endif + } +} + #undef GST_CAT_DEFAULT } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h index 6178772f7027b..ddde800a2c88c 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h @@ -162,7 +162,8 @@ class MediaPlayerPrivateGStreamer void setMuted(bool) final; MediaPlayer::NetworkState networkState() const final; MediaPlayer::ReadyState readyState() const final; - void setPageIsVisible(bool visible, String&&) final { m_visible = visible; } + void setPageIsVisible(bool visible, String&&) final; + void setPageIsSuspended(bool suspended) final; void setVisibleInViewport(bool isVisible) final; void setPresentationSize(const IntSize&) final; MediaTime duration() const override; @@ -248,6 +249,31 @@ class MediaPlayerPrivateGStreamer String codecForStreamId(const String& streamId); +#if USE(GSTREAMER_HOLEPUNCH) + class GStreamerHolePunchHost : public ThreadSafeRefCounted { + public: + static Ref create(MediaPlayerPrivateGStreamer& playerPrivate) + { + return adoptRef(*new GStreamerHolePunchHost(playerPrivate)); + } + + void setVideoRectangle(const IntRect& rect) + { + if (m_playerPrivate) + m_playerPrivate->setVideoRectangle(rect); + } + + void playerPrivateWillBeDestroyed() { m_playerPrivate = nullptr; } + private: + explicit GStreamerHolePunchHost(MediaPlayerPrivateGStreamer& playerPrivate) + : m_playerPrivate(&playerPrivate) + { } + + MediaPlayerPrivateGStreamer* m_playerPrivate; + }; + void setVideoRectangle(const IntRect& rect); +#endif + protected: enum MainThreadNotification { VideoChanged = 1 << 0, @@ -577,6 +603,7 @@ class MediaPlayerPrivateGStreamer bool m_isMuted { false }; bool m_visible { false }; + bool m_suspended { false }; // playbin3 only: bool m_waitingForStreamsSelectedEvent { true }; @@ -653,6 +680,11 @@ class MediaPlayerPrivateGStreamer RefPtr m_loader; RefPtr m_quirksManagerForTesting; + +#if USE(GSTREAMER_HOLEPUNCH) + RefPtr m_gstreamerHolePunchHost; + Lock m_holePunchLock; +#endif }; } diff --git a/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp b/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp index 43e0aafa5d419..b85d85a5fc98c 100644 --- a/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp +++ b/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp @@ -175,6 +175,29 @@ void ThreadedCompositor::suspend() }); } +void ThreadedCompositor::suspendToTransparent() +{ +#if 0 + // If we're in nonCompositedWebGL mode, the WebGLRenderingContext will have painted the + // transparent background. We don't need to do anything besides suspending. + if (m_nonCompositedWebGLEnabled) { + suspend(); + return; + } +#endif + + // When not in nonCompositedWebGL, we need to request a redraw to paint the transparent + // background, and when the scene is completed, suspend. + if (++m_suspendedCount > 1) + return; + + // Set the flag for transparent and request a redraw. + m_compositingRunLoop->performTaskSync([this, protectedThis = Ref { *this }] { + m_suspendToTransparentState = SuspendToTransparentState::Requested; + }); + m_compositingRunLoop->scheduleUpdate(); +} + void ThreadedCompositor::resume() { ASSERT(m_suspendedCount > 0); @@ -183,8 +206,10 @@ void ThreadedCompositor::resume() m_compositingRunLoop->performTaskSync([this, protectedThis = Ref { *this }] { m_scene->setActive(true); + m_suspendToTransparentState = SuspendToTransparentState::None; }); m_compositingRunLoop->resume(); + m_compositingRunLoop->scheduleUpdate(); } void ThreadedCompositor::setScrollPosition(const IntPoint& scrollPosition, float scale) @@ -273,7 +298,10 @@ void ThreadedCompositor::renderLayerTree() m_client.clearIfNeeded(); m_scene->applyStateChanges(states); - m_scene->paintToCurrentGLContext(viewportTransform, FloatRect { FloatPoint { }, viewportSize }, m_flipY); + if (m_suspendToTransparentState != SuspendToTransparentState::Requested) + m_scene->paintToCurrentGLContext(viewportTransform, FloatRect { FloatPoint { }, viewportSize }, m_flipY); + else + m_suspendToTransparentState = SuspendToTransparentState::WaitingForFrameComplete; m_context->swapBuffers(); @@ -298,6 +326,12 @@ void ThreadedCompositor::sceneUpdateFinished() } #endif + if (m_suspendToTransparentState == SuspendToTransparentState::WaitingForFrameComplete) { + m_compositingRunLoop->suspend(); + m_scene->setActive(false); + m_suspendToTransparentState = SuspendToTransparentState::None; + } + Locker stateLocker { m_compositingRunLoop->stateLock() }; #if !HAVE(DISPLAY_LINK) @@ -354,11 +388,12 @@ void ThreadedCompositor::frameComplete() #if !HAVE(DISPLAY_LINK) void ThreadedCompositor::displayUpdateFired() { - m_display.displayUpdate = m_display.displayUpdate.nextUpdate(); + // The displayRefresh timer breaks the capability to suspend and resume, so disable it. + // m_display.displayUpdate = m_display.displayUpdate.nextUpdate(); - m_client.displayDidRefresh(m_display.displayID); + // m_client.displayDidRefresh(m_display.displayID); - m_display.updateTimer->startOneShot(Seconds { 1.0 / m_display.displayUpdate.updatesPerSecond }); + // m_display.updateTimer->startOneShot(Seconds { 1.0 / m_display.displayUpdate.updatesPerSecond }); } #endif diff --git a/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h b/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h index 07e0dca9c3033..1c13abd0fa3b4 100644 --- a/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h +++ b/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h @@ -86,6 +86,7 @@ class ThreadedCompositor : public CoordinatedGraphicsSceneClient, public ThreadS void frameComplete(); void suspend(); + void suspendToTransparent(); void resume(); RunLoop& compositingRunLoop() const { return m_compositingRunLoop->runLoop(); } @@ -139,6 +140,13 @@ class ThreadedCompositor : public CoordinatedGraphicsSceneClient, public ThreadS Ref m_displayRefreshMonitor; #endif + + enum class SuspendToTransparentState { + None, + Requested, + WaitingForFrameComplete + }; + SuspendToTransparentState m_suspendToTransparentState { SuspendToTransparentState::None }; }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp index b42daef30598a..7e289784925ab 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -5646,6 +5646,49 @@ webkit_web_view_get_default_content_security_policy(WebKitWebView* webView) return webView->priv->defaultContentSecurityPolicy.data(); } +void webkit_web_view_suspend(WebKitWebView *webView) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + + auto viewStateFlags = webView->priv->view->viewState(); + viewStateFlags.remove(WebCore::ActivityState::IsInWindow); + webView->priv->view->setViewState(viewStateFlags); +} + +void webkit_web_view_resume(WebKitWebView *webView) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + + auto viewStateFlags = webView->priv->view->viewState(); + viewStateFlags.add(WebCore::ActivityState::IsInWindow); + webView->priv->view->setViewState(viewStateFlags); +} + +gboolean webkit_web_view_is_suspended(WebKitWebView *webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE); + + return !webView->priv->view->viewState().contains(WebCore::ActivityState::IsInWindow); +} + +void webkit_web_view_hide(WebKitWebView *webView) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + + auto viewStateFlags = webView->priv->view->viewState(); + viewStateFlags.remove(WebCore::ActivityState::IsVisible); + webView->priv->view->setViewState(viewStateFlags); +} + +void webkit_web_view_show(WebKitWebView *webView) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + + auto viewStateFlags = webView->priv->view->viewState(); + viewStateFlags.add(WebCore::ActivityState::IsVisible); + webView->priv->view->setViewState(viewStateFlags); +} + void webkit_web_view_is_web_process_responsive_async(WebKitWebView *webView, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData) { g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in b/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in index 3d22af71b0c10..936f63150c32e 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.h.in @@ -905,6 +905,21 @@ webkit_web_view_get_web_extension_mode (WebKitWebView WEBKIT_API const gchar* webkit_web_view_get_default_content_security_policy (WebKitWebView *web_view); +WEBKIT_API void +webkit_web_view_suspend (WebKitWebView *web_view); + +WEBKIT_API void +webkit_web_view_resume (WebKitWebView *web_view); + +WEBKIT_API gboolean +webkit_web_view_is_suspended (WebKitWebView *web_view); + +WEBKIT_API void +webkit_web_view_hide (WebKitWebView *web_view); + +WEBKIT_API void +webkit_web_view_show (WebKitWebView *web_view); + #if USE(GI_FINISH_FUNC_ANNOTATION) /** * webkit_web_view_run_async_javascript_function_in_world: (finish-func webkit_web_view_run_javascript_in_world_finish) diff --git a/Source/WebKit/UIProcess/API/wpe/WPEWebView.h b/Source/WebKit/UIProcess/API/wpe/WPEWebView.h index 359cfdb2c8363..6e17c4eddce83 100644 --- a/Source/WebKit/UIProcess/API/wpe/WPEWebView.h +++ b/Source/WebKit/UIProcess/API/wpe/WPEWebView.h @@ -141,6 +141,8 @@ class View : public API::ObjectImpl { static WebKit::WebPageProxy* platformWebPageProxyForGamepadInput(); #endif + void setViewState(OptionSet); + #if ENABLE(WPE_PLATFORM) void updateAcceleratedSurface(uint64_t); WebKit::RendererBufferFormat renderBufferFormat() const; @@ -158,7 +160,6 @@ class View : public API::ObjectImpl { #endif void setSize(const WebCore::IntSize&); - void setViewState(OptionSet); void handleKeyboardEvent(struct wpe_input_keyboard_event*); #if ENABLE(WPE_PLATFORM) diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp index 6780fb04b9424..d6f4d07701408 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp @@ -64,6 +64,14 @@ DrawingAreaCoordinatedGraphics::DrawingAreaCoordinatedGraphics(WebPage& webPage, #if USE(GLIB_EVENT_LOOP) && !PLATFORM(WPE) m_displayTimer.setPriority(RunLoopSourcePriority::NonAcceleratedDrawingTimer); #endif + + // If ActivityState::IsInWindow is not on we need to trigger suspend immediately. + if (!(parameters.activityState & ActivityState::IsInWindow)) { + suspendPainting(); + m_webPage->corePage()->suspendAllMediaPlayback(); + m_webPage->corePage()->suspendActiveDOMObjectsAndAnimations(); + m_isViewSuspended = true; + } } DrawingAreaCoordinatedGraphics::~DrawingAreaCoordinatedGraphics() = default; @@ -356,12 +364,37 @@ RefPtr DrawingAreaCoordinatedGraphics::createDisplayRefre void DrawingAreaCoordinatedGraphics::activityStateDidChange(OptionSet changed, ActivityStateChangeID, CompletionHandler&& completionHandler) { - if (changed & ActivityState::IsVisible) { - if (m_webPage->isVisible()) - resumePainting(); - else + // We use calls to suspendPainting() and resumePainting() to stop the compositor loop and paint the content transparent + // so nothing gets rendered. There are 2 exceptions to this that need to be handled separately: + // - WebGL in nonCompositedWebGL: we're not using the compositor in this case. WebGLRenderingContextBase will observe the activity + // state changes and paint the content transparent when the view is suspended or hidden. + // - MediaPlayer videoSink window when using the GStreamer holepunch: HTMLMediaElement will perform calls to the MediaPlayer + // to set an empty rectangle when it detects that the view has become hidden or suspended. + + // Handle hide/show functionality. + if (changed & ActivityState::IsVisible && !m_isViewSuspended) { + if (m_webPage->corePage()->isVisible()) + resumePainting(); + else + suspendPainting(); + } + + // Handle suspend/resume functionality. Besides stopping the rendering, we stop active DOM objects and media playback. + if (changed & ActivityState::IsInWindow) { + if (m_isViewSuspended) { + m_webPage->corePage()->resumeActiveDOMObjectsAndAnimations(); + m_webPage->corePage()->resumeAllMediaPlayback(); + if (m_webPage->corePage()->isVisible()) + resumePainting(); + m_isViewSuspended = false; + } else { suspendPainting(); + m_webPage->corePage()->suspendAllMediaPlayback(); + m_webPage->corePage()->suspendActiveDOMObjectsAndAnimations(); + m_isViewSuspended = true; + } } + completionHandler(); } @@ -482,7 +515,8 @@ void DrawingAreaCoordinatedGraphics::exitAcceleratedCompositingModeSoon() void DrawingAreaCoordinatedGraphics::suspendPainting() { - ASSERT(!m_isPaintingSuspended); + if (m_isPaintingSuspended) + return; if (m_layerTreeHost) m_layerTreeHost->pauseRendering(); diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.h b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.h index 6033c425ce637..d0da278bea05e 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.h +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.h @@ -127,6 +127,8 @@ class DrawingAreaCoordinatedGraphics final : public DrawingArea { // won't paint until painting has resumed again. bool m_isPaintingSuspended { false }; + bool m_isViewSuspended { false }; + RunLoop::Timer m_exitCompositingTimer; // The layer tree host that handles accelerated compositing. diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp index d453fc33b2a36..ea7cb82eaea8e 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp @@ -254,7 +254,7 @@ void LayerTreeHost::pauseRendering() { m_isSuspended = true; m_surface->visibilityDidChange(false); - m_compositor->suspend(); + m_compositor->suspendToTransparent(); } void LayerTreeHost::resumeRendering() From 2e6058cb524287b580a2d616f1965c3cc4a6180d Mon Sep 17 00:00:00 2001 From: "Vivek.A" Date: Wed, 8 May 2024 20:08:30 +0200 Subject: [PATCH 53/55] Add a provision in WebKitURIResponse to check if the response is from a main frame resource --- .../Shared/API/glib/WebKitURIResponse.cpp | 41 ++++++++++++++++++- .../API/glib/WebKitURIResponsePrivate.h | 1 + .../API/glib/WebKitResponsePolicyDecision.cpp | 4 +- .../UIProcess/API/glib/WebKitURIResponse.h.in | 3 ++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/Source/WebKit/Shared/API/glib/WebKitURIResponse.cpp b/Source/WebKit/Shared/API/glib/WebKitURIResponse.cpp index 5f91cde5a3be9..6f7007c8af082 100644 --- a/Source/WebKit/Shared/API/glib/WebKitURIResponse.cpp +++ b/Source/WebKit/Shared/API/glib/WebKitURIResponse.cpp @@ -46,7 +46,8 @@ enum { PROP_CONTENT_LENGTH, PROP_MIME_TYPE, PROP_SUGGESTED_FILENAME, - PROP_HTTP_HEADERS + PROP_HTTP_HEADERS, + PROP_IS_MAIN_FRAME }; struct _WebKitURIResponsePrivate { @@ -55,6 +56,7 @@ struct _WebKitURIResponsePrivate { CString mimeType; CString suggestedFilename; GUniquePtr httpHeaders; + gboolean isMainFrame; }; WEBKIT_DEFINE_FINAL_TYPE(WebKitURIResponse, webkit_uri_response, G_TYPE_OBJECT, GObject) @@ -82,6 +84,9 @@ static void webkitURIResponseGetProperty(GObject* object, guint propId, GValue* case PROP_HTTP_HEADERS: g_value_set_boxed(value, webkit_uri_response_get_http_headers(response)); break; + case PROP_IS_MAIN_FRAME: + g_value_set_boolean(value, webkit_uri_response_is_main_frame(response)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); } @@ -166,6 +171,22 @@ static void webkit_uri_response_class_init(WebKitURIResponseClass* responseClass nullptr, nullptr, SOUP_TYPE_MESSAGE_HEADERS, WEBKIT_PARAM_READABLE)); + + /** + * WebKitURIResponse:is-main-frame: + * + * Indication of the origin of the response, TRUE if the response is for main frame, FALSE otherwise + * + */ + g_object_class_install_property( + objectClass, + PROP_IS_MAIN_FRAME, + g_param_spec_boolean( + "is-main-frame", + _("Is main frame response"), + _("Whether the response is for the main frame"), + FALSE, + WEBKIT_PARAM_READABLE)); } /** @@ -286,6 +307,18 @@ SoupMessageHeaders* webkit_uri_response_get_http_headers(WebKitURIResponse* resp return response->priv->httpHeaders.get(); } +/** + * webkit_uri_response_is_main_frame: + * @response: a #WebKitURIResponse + * + * Returns: (transfer none): TRUE if the response is for a request from main frame or FALSE + */ +gboolean webkit_uri_response_is_main_frame(WebKitURIResponse* response) +{ + g_return_val_if_fail(WEBKIT_IS_URI_RESPONSE(response), false); + return response->priv->isMainFrame; +} + WebKitURIResponse* webkitURIResponseCreateForResourceResponse(const WebCore::ResourceResponse& resourceResponse) { WebKitURIResponse* uriResponse = WEBKIT_URI_RESPONSE(g_object_new(WEBKIT_TYPE_URI_RESPONSE, NULL)); @@ -293,6 +326,12 @@ WebKitURIResponse* webkitURIResponseCreateForResourceResponse(const WebCore::Res return uriResponse; } +void webkitURIResponseSetIsMainFrame(WebKitURIResponse* response, gboolean isMainFrame) +{ + g_return_if_fail(WEBKIT_IS_URI_RESPONSE(response)); + response->priv->isMainFrame = isMainFrame; +} + const WebCore::ResourceResponse& webkitURIResponseGetResourceResponse(WebKitURIResponse* uriResponse) { return uriResponse->priv->resourceResponse; diff --git a/Source/WebKit/Shared/API/glib/WebKitURIResponsePrivate.h b/Source/WebKit/Shared/API/glib/WebKitURIResponsePrivate.h index c2dc49c177989..0317570e7041f 100644 --- a/Source/WebKit/Shared/API/glib/WebKitURIResponsePrivate.h +++ b/Source/WebKit/Shared/API/glib/WebKitURIResponsePrivate.h @@ -30,6 +30,7 @@ #include WebKitURIResponse* webkitURIResponseCreateForResourceResponse(const WebCore::ResourceResponse&); +void webkitURIResponseSetIsMainFrame(WebKitURIResponse* response, gboolean isMainFrame); const WebCore::ResourceResponse& webkitURIResponseGetResourceResponse(WebKitURIResponse*); #endif // WebKitURIResponsePrivate_h diff --git a/Source/WebKit/UIProcess/API/glib/WebKitResponsePolicyDecision.cpp b/Source/WebKit/UIProcess/API/glib/WebKitResponsePolicyDecision.cpp index 1c9c271fce62e..08c01a930a82e 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitResponsePolicyDecision.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitResponsePolicyDecision.cpp @@ -141,8 +141,10 @@ WebKitURIRequest* webkit_response_policy_decision_get_request(WebKitResponsePoli WebKitURIResponse* webkit_response_policy_decision_get_response(WebKitResponsePolicyDecision* decision) { g_return_val_if_fail(WEBKIT_IS_RESPONSE_POLICY_DECISION(decision), nullptr); - if (!decision->priv->response) + if (!decision->priv->response) { decision->priv->response = adoptGRef(webkitURIResponseCreateForResourceResponse(decision->priv->navigationResponse->response())); + webkitURIResponseSetIsMainFrame(decision->priv->response.get(), decision->priv->navigationResponse->frame().isMainFrame()); + } return decision->priv->response.get(); } diff --git a/Source/WebKit/UIProcess/API/glib/WebKitURIResponse.h.in b/Source/WebKit/UIProcess/API/glib/WebKitURIResponse.h.in index f17b0cc4d160d..b425ec35791d5 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitURIResponse.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitURIResponse.h.in @@ -67,6 +67,9 @@ webkit_uri_response_get_suggested_filename (WebKitURIResponse *response); WEBKIT_API SoupMessageHeaders * webkit_uri_response_get_http_headers (WebKitURIResponse *response); +WEBKIT_API gboolean +webkit_uri_response_is_main_frame (WebKitURIResponse *response); + G_END_DECLS #endif From ca63a1cde1dc4527045b02f721921b35d798324e Mon Sep 17 00:00:00 2001 From: dkolesa Date: Wed, 22 May 2024 11:06:51 +0200 Subject: [PATCH 54/55] Remove unneeded this captures causing build fail --- Source/WebCore/Modules/mediastream/ImageCapture.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/WebCore/Modules/mediastream/ImageCapture.cpp b/Source/WebCore/Modules/mediastream/ImageCapture.cpp index 09f945ecdba38..4f0c7659e60f3 100644 --- a/Source/WebCore/Modules/mediastream/ImageCapture.cpp +++ b/Source/WebCore/Modules/mediastream/ImageCapture.cpp @@ -80,7 +80,7 @@ void ImageCapture::takePhoto(PhotoSettings&& settings, DOMPromiseDeferredtakePhoto(WTFMove(settings))->whenSettled(RunLoop::main(), [this, protectedThis = Ref { *this }, promise = WTFMove(promise), identifier = WTFMove(identifier)] (auto&& result) mutable { - queueTaskKeepingObjectAlive(*this, TaskSource::ImageCapture, [this, promise = WTFMove(promise), result = WTFMove(result), identifier = WTFMove(identifier)] () mutable { + queueTaskKeepingObjectAlive(*this, TaskSource::ImageCapture, [promise = WTFMove(promise), result = WTFMove(result), identifier = WTFMove(identifier)] () mutable { if (!result) { ERROR_LOG(identifier, "rejecting promise: ", result.error().message()); promise.reject(WTFMove(result.error())); @@ -109,7 +109,7 @@ void ImageCapture::getPhotoCapabilities(DOMPromiseDeferredgetPhotoCapabilities()->whenSettled(RunLoop::main(), [this, protectedThis = Ref { *this }, promise = WTFMove(promise), identifier = WTFMove(identifier)] (auto&& result) mutable { - queueTaskKeepingObjectAlive(*this, TaskSource::ImageCapture, [this, promise = WTFMove(promise), result = WTFMove(result), identifier = WTFMove(identifier)] () mutable { + queueTaskKeepingObjectAlive(*this, TaskSource::ImageCapture, [promise = WTFMove(promise), result = WTFMove(result), identifier = WTFMove(identifier)] () mutable { if (!result) { ERROR_LOG(identifier, "rejecting promise: ", result.error().message()); promise.reject(WTFMove(result.error())); @@ -138,7 +138,7 @@ void ImageCapture::getPhotoSettings(DOMPromiseDeferredgetPhotoSettings()->whenSettled(RunLoop::main(), [this, protectedThis = Ref { *this }, promise = WTFMove(promise), identifier = WTFMove(identifier)] (auto&& result) mutable { - queueTaskKeepingObjectAlive(*this, TaskSource::ImageCapture, [this, promise = WTFMove(promise), result = WTFMove(result), identifier = WTFMove(identifier)] () mutable { + queueTaskKeepingObjectAlive(*this, TaskSource::ImageCapture, [promise = WTFMove(promise), result = WTFMove(result), identifier = WTFMove(identifier)] () mutable { if (!result) { ERROR_LOG(identifier, "rejecting promise: ", result.error().message()); promise.reject(WTFMove(result.error())); From 36c6ef61349c5c01dc36849d399a12dc075c1b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=BDan=20Dober=C5=A1ek?= Date: Wed, 22 May 2024 11:16:34 +0200 Subject: [PATCH 55/55] Implement Broadcom Nexus API for ANGLE WebGL Co-authored-by: dkolesa --- .../ThirdParty/ANGLE/src/common/utilities.cpp | 1 + .../libANGLE/renderer/gl/egl/DisplayEGL.cpp | 6 +- .../renderer/gl/egl/DmaBufImageSiblingEGL.cpp | 62 ++++ .../renderer/gl/egl/DmaBufImageSiblingEGL.h | 28 ++ .../ANGLE/src/libANGLE/validationEGL.cpp | 21 +- Source/WebCore/PlatformWPE.cmake | 5 + Source/WebCore/SourcesWPE.txt | 3 + Source/WebCore/platform/TextureMapper.cmake | 6 + .../graphics/nexus/GraphicsContextGLNexus.cpp | 271 ++++++++++++++++++ .../graphics/nexus/GraphicsContextGLNexus.h | 60 ++++ .../platform/graphics/nexus/NexusSurface.cpp | 22 ++ .../platform/graphics/nexus/NexusSurface.h | 26 ++ .../nicosia/NicosiaGCGLANGLELayer.cpp | 31 ++ .../graphics/nicosia/NicosiaGCGLANGLELayer.h | 6 + .../GraphicsContextGLTextureMapperANGLE.cpp | 8 + .../texmap/TextureMapperPlatformLayerProxy.h | 1 + .../TextureMapperPlatformLayerProxyNexus.cpp | 144 ++++++++++ .../TextureMapperPlatformLayerProxyNexus.h | 61 ++++ Source/cmake/OptionsWPE.cmake | 9 + 19 files changed, 768 insertions(+), 3 deletions(-) create mode 100644 Source/WebCore/platform/graphics/nexus/GraphicsContextGLNexus.cpp create mode 100644 Source/WebCore/platform/graphics/nexus/GraphicsContextGLNexus.h create mode 100644 Source/WebCore/platform/graphics/nexus/NexusSurface.cpp create mode 100644 Source/WebCore/platform/graphics/nexus/NexusSurface.h create mode 100644 Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyNexus.cpp create mode 100644 Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyNexus.h diff --git a/Source/ThirdParty/ANGLE/src/common/utilities.cpp b/Source/ThirdParty/ANGLE/src/common/utilities.cpp index 2e03a110de26a..23e2f0377ab5f 100644 --- a/Source/ThirdParty/ANGLE/src/common/utilities.cpp +++ b/Source/ThirdParty/ANGLE/src/common/utilities.cpp @@ -1305,6 +1305,7 @@ bool IsExternalImageTarget(EGLenum target) case EGL_LINUX_DMA_BUF_EXT: case EGL_METAL_TEXTURE_ANGLE: case EGL_VULKAN_IMAGE_ANGLE: + case EGL_NATIVE_PIXMAP_KHR: return true; default: diff --git a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp b/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp index 4ccf19a92c208..1a8f226fe02bf 100644 --- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp +++ b/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp @@ -842,8 +842,7 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const outExtensions->image = mEGL->hasExtension("EGL_KHR_image"); outExtensions->imageBase = mEGL->hasExtension("EGL_KHR_image_base"); - // Pixmaps are not supported in ANGLE's EGL implementation. - // outExtensions->imagePixmap = mEGL->hasExtension("EGL_KHR_image_pixmap"); + outExtensions->imagePixmap = mEGL->hasExtension("EGL_KHR_image_pixmap"); outExtensions->glTexture2DImage = mEGL->hasExtension("EGL_KHR_gl_texture_2D_image"); outExtensions->glTextureCubemapImage = mEGL->hasExtension("EGL_KHR_gl_texture_cubemap_image"); outExtensions->glTexture3DImage = mEGL->hasExtension("EGL_KHR_gl_texture_3D_image"); @@ -1023,6 +1022,9 @@ ExternalImageSiblingImpl *DisplayEGL::createExternalImageSibling(const gl::Conte ASSERT(buffer == nullptr); return new DmaBufImageSiblingEGL(attribs); + case EGL_NATIVE_PIXMAP_KHR: + return new PixmapImageSiblingEGL(buffer, attribs); + default: return DisplayGL::createExternalImageSibling(context, target, buffer, attribs); } diff --git a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DmaBufImageSiblingEGL.cpp b/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DmaBufImageSiblingEGL.cpp index 2d770f0be4c21..8a549a8fe056b 100644 --- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DmaBufImageSiblingEGL.cpp +++ b/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DmaBufImageSiblingEGL.cpp @@ -122,4 +122,66 @@ void DmaBufImageSiblingEGL::getImageCreationAttributes(std::vector *outA } } +PixmapImageSiblingEGL::PixmapImageSiblingEGL(EGLClientBuffer buffer, const egl::AttributeMap &attribs) + : mBuffer(buffer), mAttribs(attribs), mFormat(GL_NONE) +{ + ASSERT(mAttribs.contains(EGL_WIDTH)); + mSize.width = mAttribs.getAsInt(EGL_WIDTH); + ASSERT(mAttribs.contains(EGL_HEIGHT)); + mSize.height = mAttribs.getAsInt(EGL_HEIGHT); + + mFormat = gl::Format(GL_RGBA8); +} + +PixmapImageSiblingEGL::~PixmapImageSiblingEGL() {} + +egl::Error PixmapImageSiblingEGL::initialize(const egl::Display *display) +{ + return egl::NoError(); +} + +gl::Format PixmapImageSiblingEGL::getFormat() const +{ + return mFormat; +} + +bool PixmapImageSiblingEGL::isRenderable(const gl::Context *context) const +{ + return true; +} + +bool PixmapImageSiblingEGL::isTexturable(const gl::Context *context) const +{ + return true; +} + +bool PixmapImageSiblingEGL::isYUV() const +{ + return false; +} + +bool PixmapImageSiblingEGL::hasProtectedContent() const +{ + return false; +} + +gl::Extents PixmapImageSiblingEGL::getSize() const +{ + return mSize; +} + +size_t PixmapImageSiblingEGL::getSamples() const +{ + return 0; +} + +EGLClientBuffer PixmapImageSiblingEGL::getBuffer() const +{ + return mBuffer; +} + +void PixmapImageSiblingEGL::getImageCreationAttributes(std::vector *outAttributes) const +{ +} + } // namespace rx diff --git a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DmaBufImageSiblingEGL.h b/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DmaBufImageSiblingEGL.h index f367f6b3095e4..cc3594a369105 100644 --- a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DmaBufImageSiblingEGL.h +++ b/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/egl/DmaBufImageSiblingEGL.h @@ -44,6 +44,34 @@ class DmaBufImageSiblingEGL : public ExternalImageSiblingEGL bool mHasProtectedContent; }; +class PixmapImageSiblingEGL : public ExternalImageSiblingEGL +{ + public: + PixmapImageSiblingEGL(EGLClientBuffer buffer, const egl::AttributeMap &attribs); + ~PixmapImageSiblingEGL() override; + + egl::Error initialize(const egl::Display *display) override; + + // ExternalImageSiblingImpl interface + gl::Format getFormat() const override; + bool isRenderable(const gl::Context *context) const override; + bool isTexturable(const gl::Context *context) const override; + bool isYUV() const override; + bool hasProtectedContent() const override; + gl::Extents getSize() const override; + size_t getSamples() const override; + + // ExternalImageSiblingEGL interface + EGLClientBuffer getBuffer() const override; + void getImageCreationAttributes(std::vector *outAttributes) const override; + + private: + EGLClientBuffer mBuffer; + egl::AttributeMap mAttribs; + gl::Extents mSize; + gl::Format mFormat; +}; + } // namespace rx #endif // LIBANGLE_RENDERER_GL_EGL_DMABUFIMAGESIBLINGEGL_H_ diff --git a/Source/ThirdParty/ANGLE/src/libANGLE/validationEGL.cpp b/Source/ThirdParty/ANGLE/src/libANGLE/validationEGL.cpp index f56f90d32b8cb..1812037c832d2 100644 --- a/Source/ThirdParty/ANGLE/src/libANGLE/validationEGL.cpp +++ b/Source/ThirdParty/ANGLE/src/libANGLE/validationEGL.cpp @@ -3525,7 +3525,7 @@ bool ValidateCreateImage(const ValidationContext *val, case EGL_WIDTH: case EGL_HEIGHT: - if (target != EGL_LINUX_DMA_BUF_EXT) + if (target != EGL_LINUX_DMA_BUF_EXT && target != EGL_NATIVE_PIXMAP_KHR) { val->setError( EGL_BAD_PARAMETER, @@ -4080,6 +4080,25 @@ bool ValidateCreateImage(const ValidationContext *val, display->validateImageClientBuffer(context, target, buffer, attributes), val->entryPoint, val->labeledObject, false); break; + case EGL_NATIVE_PIXMAP_KHR: + if (!displayExtensions.imagePixmap) + { + val->setError(EGL_BAD_PARAMETER, "EGL_KHR_image_pixmap not supported."); + return false; + } + + if (context != nullptr) + { + val->setError(EGL_BAD_PARAMETER, "ctx must be EGL_NO_CONTEXT."); + return false; + } + + if (buffer == nullptr) + { + val->setError(EGL_BAD_PARAMETER, "buffer must not be NULL."); + return false; + } + break; default: val->setError(EGL_BAD_PARAMETER, "invalid target: 0x%X", target); return false; diff --git a/Source/WebCore/PlatformWPE.cmake b/Source/WebCore/PlatformWPE.cmake index c6a03b56d8358..7aff6974adf57 100644 --- a/Source/WebCore/PlatformWPE.cmake +++ b/Source/WebCore/PlatformWPE.cmake @@ -35,6 +35,7 @@ list(APPEND WebCore_PRIVATE_INCLUDE_DIRECTORIES "${WEBCORE_DIR}/platform/graphics/opengl" "${WEBCORE_DIR}/platform/graphics/opentype" "${WEBCORE_DIR}/platform/graphics/libwpe" + "${WEBCORE_DIR}/platform/graphics/nexus" "${WEBCORE_DIR}/platform/graphics/wayland" "${WEBCORE_DIR}/platform/mock/mediasource" "${WEBCORE_DIR}/platform/mediacapabilities" @@ -76,6 +77,10 @@ list(APPEND WebCore_LIBRARIES ${UPOWERGLIB_LIBRARIES} ) +if (USE_NEXUS) + list(APPEND WebCore_LIBRARIES nexus) +endif () + list(APPEND WebCore_SYSTEM_INCLUDE_DIRECTORIES ${GIO_UNIX_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} diff --git a/Source/WebCore/SourcesWPE.txt b/Source/WebCore/SourcesWPE.txt index 92f1879df295f..f743474f6e7e5 100644 --- a/Source/WebCore/SourcesWPE.txt +++ b/Source/WebCore/SourcesWPE.txt @@ -75,6 +75,9 @@ platform/graphics/gbm/PlatformDisplayGBM.cpp @no-unify platform/graphics/libwpe/PlatformDisplayLibWPE.cpp +platform/graphics/nexus/GraphicsContextGLNexus.cpp @no-unify +platform/graphics/nexus/NexusSurface.cpp @no-unify + platform/graphics/opentype/OpenTypeVerticalData.cpp platform/libwpe/PasteboardLibWPE.cpp diff --git a/Source/WebCore/platform/TextureMapper.cmake b/Source/WebCore/platform/TextureMapper.cmake index d27b08a45f0c8..17bf343b4618c 100644 --- a/Source/WebCore/platform/TextureMapper.cmake +++ b/Source/WebCore/platform/TextureMapper.cmake @@ -69,6 +69,12 @@ if (USE_COORDINATED_GRAPHICS) platform/graphics/texmap/coordinated/TiledBackingStoreClient.h ) + if (USE_NEXUS) + list(APPEND WebCore_SOURCES + platform/graphics/texmap/TextureMapperPlatformLayerProxyNexus.cpp + ) + endif () + if (USE_CAIRO) list(APPEND WebCore_SOURCES platform/graphics/texmap/coordinated/CoordinatedGraphicsLayerCairo.cpp diff --git a/Source/WebCore/platform/graphics/nexus/GraphicsContextGLNexus.cpp b/Source/WebCore/platform/graphics/nexus/GraphicsContextGLNexus.cpp new file mode 100644 index 0000000000000..9f624abed1a38 --- /dev/null +++ b/Source/WebCore/platform/graphics/nexus/GraphicsContextGLNexus.cpp @@ -0,0 +1,271 @@ +#include "config.h" +#include "GraphicsContextGLNexus.h" + +#if ENABLE(WEBGL) && USE(TEXTURE_MAPPER) && USE(NEXUS) + +#include "ANGLEHeaders.h" +#include "Logging.h" +#include "NicosiaGCGLANGLELayer.h" +#include "PlatformLayerDisplayDelegate.h" +#include "PixelBuffer.h" + +#if ENABLE(MEDIA_STREAM) || ENABLE(WEB_CODECS) +#include "VideoFrame.h" +#endif + +#include + +namespace WebCore { + +RefPtr GraphicsContextGLNexus::create(GraphicsContextGLAttributes&& attributes) +{ + auto context = adoptRef(*new GraphicsContextGLNexus(WTFMove(attributes))); + if (!context->initialize()) + return nullptr; + LOG(WebGL, "Successfully initialized Nexus context %p", context.ptr()); + return context; +} + +GraphicsContextGLNexus::GraphicsContextGLNexus(GraphicsContextGLAttributes&& attributes) + : GraphicsContextGLANGLE(WTFMove(attributes)) +{ +} + +GraphicsContextGLNexus::~GraphicsContextGLNexus() +{ +} + +RefPtr GraphicsContextGLNexus::layerContentsDisplayDelegate() +{ + return m_layerContentsDisplayDelegate.copyRef(); +} + +#if ENABLE(MEDIA_STREAM) || ENABLE(WEB_CODECS) +RefPtr GraphicsContextGLGBM::surfaceBufferToVideoFrame(SurfaceBuffer) +{ + return { }; +} +#endif // ENABLE(MEDIA_STREAM) || ENABLE(WEB_CODECS) + +#if ENABLE(VIDEO) +bool GraphicsContextGLNexus::copyTextureFromMedia(MediaPlayer&, PlatformGLObject, GCGLenum, GCGLint, GCGLenum, GCGLenum, GCGLenum, bool, bool) +{ + return false; +} +#endif // ENABLE(VIDEO) + +RefPtr GraphicsContextGLNexus::readCompositedResults() +{ + return { }; +} + +void GraphicsContextGLNexus::setContextVisibility(bool) +{ +} + +void GraphicsContextGLNexus::prepareForDisplay() +{ + if (!makeContextCurrent()) + return; + + prepareTexture(); + GL_Flush(); +} + +bool GraphicsContextGLNexus::platformInitializeContext() +{ + m_isForWebGL2 = contextAttributes().isWebGL2; + + const char* clientExtensions = EGL_QueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + LOG(WebGL, "clientExtensions: %s\n", clientExtensions); + + Vector displayAttributes { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, + EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE, + EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE, /* EGL_PLATFORM_NEXUS_BRCM */ 0x32F0, + EGL_NONE, + }; + + m_displayObj = EGL_GetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes.data()); + if (m_displayObj == EGL_NO_DISPLAY) + return false; + + EGLint majorVersion, minorVersion; + if (EGL_Initialize(m_displayObj, &majorVersion, &minorVersion) == EGL_FALSE) { + LOG(WebGL, "EGLDisplay Initialization failed."); + return false; + } + LOG(WebGL, "ANGLE initialised Major: %d Minor: %d", majorVersion, minorVersion); + + const char* displayExtensions = EGL_QueryString(m_displayObj, EGL_EXTENSIONS); + LOG(WebGL, "Extensions: %s\n", displayExtensions); + + EGLint configAttributes[] = { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_NONE + }; + EGLint numberConfigsReturned = 0; + EGL_ChooseConfig(m_displayObj, configAttributes, &m_configObj, 1, &numberConfigsReturned); + if (numberConfigsReturned != 1) { + LOG(WebGL, "EGLConfig Initialization failed."); + return false; + } + LOG(WebGL, "Got EGLConfig"); + + EGL_BindAPI(EGL_OPENGL_ES_API); + if (EGL_GetError() != EGL_SUCCESS) { + LOG(WebGL, "Unable to bind to OPENGL_ES_API"); + return false; + } + + Vector eglContextAttributes; + if (m_isForWebGL2) { + eglContextAttributes.append(EGL_CONTEXT_CLIENT_VERSION); + eglContextAttributes.append(3); + } else { + eglContextAttributes.append(EGL_CONTEXT_CLIENT_VERSION); + eglContextAttributes.append(2); + // ANGLE will upgrade the context to ES3 automatically unless this is specified. + eglContextAttributes.append(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE); + eglContextAttributes.append(EGL_FALSE); + } + eglContextAttributes.append(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE); + eglContextAttributes.append(EGL_TRUE); + // WebGL requires that all resources are cleared at creation. + eglContextAttributes.append(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE); + eglContextAttributes.append(EGL_TRUE); + // WebGL doesn't allow client arrays. + eglContextAttributes.append(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE); + eglContextAttributes.append(EGL_FALSE); + // WebGL doesn't allow implicit creation of objects on bind. + eglContextAttributes.append(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM); + eglContextAttributes.append(EGL_FALSE); + + if (strstr(displayExtensions, "EGL_ANGLE_power_preference")) { + eglContextAttributes.append(EGL_POWER_PREFERENCE_ANGLE); + // EGL_LOW_POWER_ANGLE is the default. Change to + // EGL_HIGH_POWER_ANGLE if desired. + eglContextAttributes.append(EGL_LOW_POWER_ANGLE); + } + eglContextAttributes.append(EGL_NONE); + + auto sharingContext = EGL_NO_CONTEXT; + + m_contextObj = EGL_CreateContext(m_displayObj, m_configObj, sharingContext, eglContextAttributes.data()); + if (m_contextObj == EGL_NO_CONTEXT) { + LOG(WebGL, "EGLContext Initialization failed."); + return false; + } + if (!makeContextCurrent()) { + LOG(WebGL, "ANGLE makeContextCurrent failed."); + return false; + } + LOG(WebGL, "Got EGLContext"); + return true; +} + +bool GraphicsContextGLNexus::platformInitialize() +{ + m_nicosiaLayer = makeUnique(*this); + m_layerContentsDisplayDelegate = PlatformLayerDisplayDelegate::create(&m_nicosiaLayer->contentLayer()); + + bool success = makeContextCurrent(); + ASSERT_UNUSED(success, success); + + // We require this extension to render into the dmabuf-backed EGLImage. + RELEASE_ASSERT(supportsExtension("GL_OES_EGL_image"_s)); + GL_RequestExtensionANGLE("GL_OES_EGL_image"); + + validateAttributes(); + auto attributes = contextAttributes(); // They may have changed during validation. + + GLenum textureTarget = drawingBufferTextureTarget(); + // Create a texture to render into. + GL_GenTextures(1, &m_texture); + GL_BindTexture(textureTarget, m_texture); + GL_TexParameterf(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + GL_TexParameterf(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + GL_TexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + GL_TexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + GL_BindTexture(textureTarget, 0); + + // Create an FBO. + GL_GenFramebuffers(1, &m_fbo); + GL_BindFramebuffer(GL_FRAMEBUFFER, m_fbo); + + // Create a multisample FBO. + ASSERT(m_state.boundReadFBO == m_state.boundDrawFBO); + if (attributes.antialias) { + GL_GenFramebuffers(1, &m_multisampleFBO); + GL_BindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); + m_state.boundDrawFBO = m_state.boundReadFBO = m_multisampleFBO; + GL_GenRenderbuffers(1, &m_multisampleColorBuffer); + if (attributes.stencil || attributes.depth) + GL_GenRenderbuffers(1, &m_multisampleDepthStencilBuffer); + } else { + // Bind canvas FBO. + GL_BindFramebuffer(GL_FRAMEBUFFER, m_fbo); + m_state.boundDrawFBO = m_state.boundReadFBO = m_fbo; + if (attributes.stencil || attributes.depth) + GL_GenRenderbuffers(1, &m_depthStencilBuffer); + } + + return GraphicsContextGLANGLE::platformInitialize(); +} + +bool GraphicsContextGLNexus::reshapeDrawingBuffer() +{ + auto size = getInternalFramebufferSize(); + + NEXUS_SurfaceCreateSettings surfSettings; + NEXUS_Surface_GetDefaultCreateSettings(&surfSettings); + surfSettings.compatibility.graphicsv3d = true; + surfSettings.width = size.width(); + surfSettings.height = size.height(); + surfSettings.pixelFormat = NEXUS_PixelFormat_eA8_B8_G8_R8; + surfSettings.heap = NEXUS_Platform_GetFramebufferHeap(NEXUS_OFFSCREEN_SURFACE); + + NEXUS_SurfaceHandle surfaceHandle = NEXUS_Surface_Create(&surfSettings); + + m_nexusSurface = adoptRef(*new NexusSurface(surfaceHandle, size)); + + std::array attributes { + EGL_WIDTH, EGLint(size.width()), + EGL_HEIGHT, EGLint(size.height()), + EGL_NONE + }; + EGLImageKHR image = EGL_CreateImageKHR(platformDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, m_nexusSurface->handle(), attributes.data()); + + auto [textureTarget, textureBinding] = drawingBufferTextureBindingPoint(); + ScopedRestoreTextureBinding restoreBinding(textureBinding, textureTarget, textureTarget != TEXTURE_RECTANGLE_ARB); + + GL_BindTexture(textureTarget, m_texture); + GL_EGLImageTargetTexture2DOES(textureTarget, image); + GL_FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, m_texture, 0); + + return true; +} + +#if ENABLE(WEBXR) +bool GraphicsContextGLNexus::createFoveation(IntSize, IntSize, IntSize, std::span, std::span, std::span) +{ + return false; +} +void GraphicsContextGLNexus::enableFoveation(GCGLuint) +{ +} +void GraphicsContextGLNexus::disableFoveation() +{ +} +#endif + +} // namespace WebCore + +#endif // ENABLE(WEBGL) && USE(TEXTURE_MAPPER) && USE(NEXUS) diff --git a/Source/WebCore/platform/graphics/nexus/GraphicsContextGLNexus.h b/Source/WebCore/platform/graphics/nexus/GraphicsContextGLNexus.h new file mode 100644 index 0000000000000..7b3ca9227f240 --- /dev/null +++ b/Source/WebCore/platform/graphics/nexus/GraphicsContextGLNexus.h @@ -0,0 +1,60 @@ + +#pragma once + +#if ENABLE(WEBGL) && USE(TEXTURE_MAPPER) && USE(NEXUS) + +#include "GraphicsContextGLANGLE.h" +#include "NexusSurface.h" +#include + +namespace Nicosia { +class GCGLANGLELayer; +} + +namespace WebCore { + +class GraphicsContextGLNexus : public GraphicsContextGLANGLE { +public: + static RefPtr create(GraphicsContextGLAttributes&&); + virtual ~GraphicsContextGLNexus(); + + // GraphicsContextGL overrides + RefPtr layerContentsDisplayDelegate() final; + +#if ENABLE(MEDIA_STREAM) || ENABLE(WEB_CODECS) + RefPtr surfaceBufferToVideoFrame(SurfaceBuffer) override; +#endif +#if ENABLE(VIDEO) + bool copyTextureFromMedia(MediaPlayer&, PlatformGLObject texture, GCGLenum target, GCGLint level, GCGLenum internalFormat, GCGLenum format, GCGLenum type, bool premultiplyAlpha, bool flipY) override; +#endif + RefPtr readCompositedResults() final; + + void setContextVisibility(bool) override; + void prepareForDisplay() override; + + // GraphicsContextGLANGLE overrides + bool platformInitializeContext() override; + bool platformInitialize() override; + + bool reshapeDrawingBuffer() override; +#if ENABLE(WEBXR) + bool createFoveation(IntSize, IntSize, IntSize, std::span, std::span, std::span) override; + void enableFoveation(GCGLuint) override; + void disableFoveation() override; +#endif + + const RefPtr& nexusSurface() const { return m_nexusSurface; } + +protected: + explicit GraphicsContextGLNexus(GraphicsContextGLAttributes&&); + +private: + std::unique_ptr m_nicosiaLayer; + RefPtr m_layerContentsDisplayDelegate; + + RefPtr m_nexusSurface; +}; + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/platform/graphics/nexus/NexusSurface.cpp b/Source/WebCore/platform/graphics/nexus/NexusSurface.cpp new file mode 100644 index 0000000000000..30e54537f384c --- /dev/null +++ b/Source/WebCore/platform/graphics/nexus/NexusSurface.cpp @@ -0,0 +1,22 @@ +#include "config.h" +#include "NexusSurface.h" + +#if USE(NEXUS) + +namespace WebCore { + +NexusSurface::NexusSurface(NEXUS_SurfaceHandle handle, const IntSize& size) + : m_handle(handle) + , m_size(size) +{ } + +NexusSurface::~NexusSurface() +{ + if (m_handle) + NEXUS_Surface_Destroy(m_handle); + m_handle = nullptr; +} + +} // namespace WebCore + +#endif // USE(NEXUS) diff --git a/Source/WebCore/platform/graphics/nexus/NexusSurface.h b/Source/WebCore/platform/graphics/nexus/NexusSurface.h new file mode 100644 index 0000000000000..509b7ce24ae02 --- /dev/null +++ b/Source/WebCore/platform/graphics/nexus/NexusSurface.h @@ -0,0 +1,26 @@ +#pragma once + +#if USE(NEXUS) + +#include "IntSize.h" +#include +#include + +namespace WebCore { + +class NexusSurface : public ThreadSafeRefCounted { +public: + NexusSurface(NEXUS_SurfaceHandle, const IntSize&); + ~NexusSurface(); + + NEXUS_SurfaceHandle handle() const { return m_handle; } + const IntSize& size() const { return m_size; } + +private: + NEXUS_SurfaceHandle m_handle; + IntSize m_size; +}; + +} // namespace WebCore + +#endif // USE(NEXUS) diff --git a/Source/WebCore/platform/graphics/nicosia/NicosiaGCGLANGLELayer.cpp b/Source/WebCore/platform/graphics/nicosia/NicosiaGCGLANGLELayer.cpp index 5590667878d55..ea5e50df99429 100644 --- a/Source/WebCore/platform/graphics/nicosia/NicosiaGCGLANGLELayer.cpp +++ b/Source/WebCore/platform/graphics/nicosia/NicosiaGCGLANGLELayer.cpp @@ -42,6 +42,11 @@ #include "TextureMapperPlatformLayerProxyDMABuf.h" #endif +#if USE(NEXUS) +#include "GraphicsContextGLNexus.h" +#include "TextureMapperPlatformLayerProxyNexus.h" +#endif + namespace Nicosia { using namespace WebCore; @@ -72,6 +77,24 @@ void GCGLANGLELayer::swapBuffersIfNeeded() ASSERT(is(proxy)); #endif +#if USE(NEXUS) + if (is(proxy)) { + auto& context = static_cast(m_context); + auto size = context.getInternalFramebufferSize(); + + { + Locker locker { proxy.lock() }; + + OptionSet flags = TextureMapperFlags::ShouldFlipTexture; + if (m_context.contextAttributes().alpha) + flags.add(TextureMapperFlags::ShouldBlend); + + downcast(proxy).presentSurface(context.nexusSurface().copyRef(), flags); + } + return; + } +#endif + OptionSet flags = TextureMapperFlags::ShouldFlipTexture; GLint colorFormat; if (m_context.contextAttributes().alpha) { @@ -103,6 +126,14 @@ GCGLANGLELayer::GCGLANGLELayer(GraphicsContextGLGBM& context) } #endif +#if USE(NEXUS) +GCGLANGLELayer::GCGLANGLELayer(GraphicsContextGLNexus& context) + : m_context(context) + , m_contentLayer(Nicosia::ContentLayer::create(*this, adoptRef(*new TextureMapperPlatformLayerProxyNexus(TextureMapperPlatformLayerProxy::ContentType::WebGL)))) +{ +} +#endif + GCGLANGLELayer::~GCGLANGLELayer() { m_contentLayer->invalidateClient(); diff --git a/Source/WebCore/platform/graphics/nicosia/NicosiaGCGLANGLELayer.h b/Source/WebCore/platform/graphics/nicosia/NicosiaGCGLANGLELayer.h index d06e7786bca2c..2aa3aecb9919c 100644 --- a/Source/WebCore/platform/graphics/nicosia/NicosiaGCGLANGLELayer.h +++ b/Source/WebCore/platform/graphics/nicosia/NicosiaGCGLANGLELayer.h @@ -38,6 +38,9 @@ class GraphicsContextGLTextureMapperANGLE; #if USE(ANGLE_GBM) class GraphicsContextGLGBM; #endif +#if USE(NEXUS) +class GraphicsContextGLNexus; +#endif } namespace Nicosia { @@ -49,6 +52,9 @@ class GCGLANGLELayer final : public ContentLayer::Client { #if USE(ANGLE_GBM) GCGLANGLELayer(WebCore::GraphicsContextGLGBM&); #endif +#if USE(NEXUS) + GCGLANGLELayer(WebCore::GraphicsContextGLNexus&); +#endif virtual ~GCGLANGLELayer(); diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsContextGLTextureMapperANGLE.cpp b/Source/WebCore/platform/graphics/texmap/GraphicsContextGLTextureMapperANGLE.cpp index d12ad0da5e556..fe8e75cd52fae 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsContextGLTextureMapperANGLE.cpp +++ b/Source/WebCore/platform/graphics/texmap/GraphicsContextGLTextureMapperANGLE.cpp @@ -54,6 +54,10 @@ #include "GraphicsContextGLGBMTextureMapper.h" #endif +#if USE(NEXUS) +#include "GraphicsContextGLNexus.h" +#endif + #if PLATFORM(GTK) || PLATFORM(WPE) #include "GLFence.h" #endif @@ -131,7 +135,11 @@ RefPtr createWebProcessGraphicsContextGL(const GraphicsContex if (eglExtensions.KHR_image_base && eglExtensions.EXT_image_dma_buf_import) return GraphicsContextGLGBMTextureMapper::create(GraphicsContextGLAttributes { attributes }); #endif +#if USE(NEXUS) + return GraphicsContextGLNexus::create(GraphicsContextGLAttributes(attributes)); +#else return GraphicsContextGLTextureMapperANGLE::create(GraphicsContextGLAttributes { attributes }); +#endif } RefPtr GraphicsContextGLTextureMapperANGLE::create(GraphicsContextGLAttributes&& attributes) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxy.h b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxy.h index 82a74ae7e5a91..ce05d60ba558b 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxy.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxy.h @@ -56,6 +56,7 @@ class TextureMapperPlatformLayerProxy : public ThreadSafeRefCounted +#else +#include +#include +#endif + +namespace WebCore { + +struct TextureMapperPlatformLayerProxyNexus::NexusSurfaceLayer::GLData { + WTF_MAKE_STRUCT_FAST_ALLOCATED; + + GLData(NEXUS_SurfaceHandle); + ~GLData(); + + EGLImageKHR image { EGL_NO_IMAGE_KHR }; + GLuint texture { 0 }; +}; + +TextureMapperPlatformLayerProxyNexus::NexusSurfaceLayer::GLData::GLData(NEXUS_SurfaceHandle surface) +{ + auto& platformDisplay = PlatformDisplay::sharedDisplayForCompositing(); + + std::array attributes { EGL_NONE }; + image = eglCreateImageKHR(platformDisplay.eglDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)surface, attributes.data()); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); + glBindTexture(GL_TEXTURE_2D, 0); +} + +TextureMapperPlatformLayerProxyNexus::NexusSurfaceLayer::GLData::~GLData() +{ + auto& platformDisplay = PlatformDisplay::sharedDisplayForCompositing(); + if (image != EGL_NO_IMAGE_KHR) + eglDestroyImageKHR(platformDisplay.eglDisplay(), image); + image = EGL_NO_IMAGE_KHR; + + if (texture) + glDeleteTextures(1, &texture); + texture = 0; +} + +TextureMapperPlatformLayerProxyNexus::TextureMapperPlatformLayerProxyNexus(ContentType contentType) + : TextureMapperPlatformLayerProxy(contentType) +{ +} + +TextureMapperPlatformLayerProxyNexus::~TextureMapperPlatformLayerProxyNexus() +{ +} + +void TextureMapperPlatformLayerProxyNexus::activateOnCompositingThread(Compositor* compositor, TextureMapperLayer* targetLayer) +{ +#if ASSERT_ENABLED + if (!m_compositorThread) + m_compositorThread = &Thread::current(); +#endif + ASSERT(m_compositorThread == &Thread::current()); + ASSERT(compositor); + ASSERT(targetLayer); + + { + Locker locker { m_lock }; + m_compositor = compositor; + m_targetLayer = targetLayer; + } +} + +void TextureMapperPlatformLayerProxyNexus::invalidate() +{ + ASSERT(m_compositorThread == &Thread::current()); +#if ASSERT_ENABLED + m_compositorThread = nullptr; +#endif + + Locker locker { m_lock }; + + m_pendingLayer = nullptr; + m_committedLayer = nullptr; + + m_compositor = nullptr; + m_targetLayer = nullptr; +} + +void TextureMapperPlatformLayerProxyNexus::swapBuffer() +{ + Locker locker { m_lock }; + if (!m_targetLayer || !m_pendingLayer) + return; + + auto previousLayer = WTFMove(m_committedLayer); + m_committedLayer = WTFMove(m_pendingLayer); + m_targetLayer->setContentsLayer(m_committedLayer.get()); + + previousLayer = nullptr; + + if (!m_committedLayer->m_glData) + m_committedLayer->m_glData = makeUnique(m_committedLayer->m_nexusSurface->handle()); +} + +void TextureMapperPlatformLayerProxyNexus::presentSurface(RefPtr&& surface, OptionSet flags) +{ + ASSERT(m_lock.isHeld()); + + if (m_committedLayer && m_committedLayer->nexusSurface() == surface) + m_pendingLayer = m_committedLayer.copyRef(); + else + m_pendingLayer = adoptRef(*new NexusSurfaceLayer(WTFMove(surface), flags)); + + if (m_compositor) + m_compositor->onNewBufferAvailable(); +} + +TextureMapperPlatformLayerProxyNexus::NexusSurfaceLayer::NexusSurfaceLayer(RefPtr&& surface, OptionSet flags) + : m_nexusSurface(surface) + , m_flags(flags) +{ +} + +void TextureMapperPlatformLayerProxyNexus::NexusSurfaceLayer::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity) +{ + if (!m_glData || m_glData->image == EGL_NO_IMAGE_KHR) + return; + + textureMapper.drawTexture(m_glData->texture, m_flags, targetRect, modelViewMatrix, opacity); +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyNexus.h b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyNexus.h new file mode 100644 index 0000000000000..d4eeddae67ef2 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyNexus.h @@ -0,0 +1,61 @@ +#pragma once + +#include "TextureMapperPlatformLayerProxy.h" + +#if USE(COORDINATED_GRAPHICS) + +#include "NexusSurface.h" +#include "TextureMapperFlags.h" +#include "TextureMapperGLHeaders.h" +#include "TextureMapperPlatformLayer.h" +#include + +namespace WebCore { + +class TextureMapperPlatformLayerProxyNexus final : public TextureMapperPlatformLayerProxy { + WTF_MAKE_FAST_ALLOCATED; +public: + explicit TextureMapperPlatformLayerProxyNexus(ContentType); + virtual ~TextureMapperPlatformLayerProxyNexus(); + + bool isNexusBased() const override { return true; } + + void activateOnCompositingThread(Compositor*, TextureMapperLayer*) override; + void invalidate() override; + void swapBuffer() override; + + void presentSurface(RefPtr&&, OptionSet); + + struct NexusSurfaceLayer : public ThreadSafeRefCounted, public TextureMapperPlatformLayer { + WTF_MAKE_FAST_ALLOCATED; + public: + NexusSurfaceLayer(RefPtr&&, OptionSet); + + void paintToTextureMapper(TextureMapper&, const FloatRect&, const TransformationMatrix& modelViewMatrix = { }, float opacity = 1.0) final; + + const RefPtr& nexusSurface() const { return m_nexusSurface; } + + private: + friend class TextureMapperPlatformLayerProxyNexus; + + RefPtr m_nexusSurface; + OptionSet m_flags; + + struct GLData; + std::unique_ptr m_glData; + }; + +private: +#if ASSERT_ENABLED + RefPtr m_compositorThread; +#endif + + RefPtr m_pendingLayer; + RefPtr m_committedLayer; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_TEXTUREMAPPER_PLATFORMLAYERPROXY(TextureMapperPlatformLayerProxyNexus, isNexusBased()); + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 1d2d83e8cde7c..03341e391a464 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -92,10 +92,12 @@ WEBKIT_OPTION_DEFINE(ENABLE_JOURNALD_LOG "Whether to enable journald logging" PU WEBKIT_OPTION_DEFINE(ENABLE_WPE_PLATFORM_DRM "Whether to enable support for DRM platform" PUBLIC ON) WEBKIT_OPTION_DEFINE(ENABLE_WPE_PLATFORM_HEADLESS "Whether to enable support for headless platform" PUBLIC ON) WEBKIT_OPTION_DEFINE(ENABLE_WPE_PLATFORM_WAYLAND "Whether to enable support for Wayland platform" PUBLIC ON) +WEBKIT_OPTION_DEFINE(ENABLE_WPE_PLATFORM_BROADCOM_NEXUS "Whether to enable suppot for Broadcom Nexus platform" PUBLIC ON) WEBKIT_OPTION_DEFINE(ENABLE_WPE_QT_API "Whether to enable support for the Qt5/QML plugin" PUBLIC ${ENABLE_DEVELOPER_MODE}) WEBKIT_OPTION_DEFINE(ENABLE_WPE_1_1_API "Whether to build WPE 1.1 instead of WPE 2.0" PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_ATK "Whether to enable usage of ATK." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_GBM "Whether to enable usage of GBM." PUBLIC ON) +WEBKIT_OPTION_DEFINE(USE_NEXUS "Whether to enable usage of Broadcom Nexus." PUBLIC OFF) WEBKIT_OPTION_DEFINE(USE_LIBBACKTRACE "Whether to enable usage of libbacktrace." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_LIBDRM "Whether to enable usage of libdrm." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_SOUP2 "Whether to enable usage of Soup 2 instead of Soup 3." PUBLIC OFF) @@ -127,7 +129,9 @@ if (ENABLE_DEVELOPER_MODE) endif () WEBKIT_OPTION_DEPEND(ENABLE_WPE_PLATFORM_DRM USE_GBM) +WEBKIT_OPTION_DEPEND(ENABLE_WPE_PLATFORM_BROADCOM_NEXUS USE_NEXUS) WEBKIT_OPTION_DEPEND(USE_GBM USE_LIBDRM) +WEBKIT_OPTION_DEPEND(USE_NEXUS USE_LIBDRM) WEBKIT_OPTION_DEPEND(USE_EXTERNAL_HOLEPUNCH ENABLE_VIDEO) include(GStreamerDependencies) @@ -285,6 +289,11 @@ if (ENABLE_WPE_PLATFORM) SET_AND_EXPOSE_TO_BUILD(ENABLE_WPE_PLATFORM_WAYLAND ON) set(WPE_PLATFORM_WAYLAND ON) endif () + + if (ENABLE_WPE_PLATFORM_BROADCOM_NEXUS) + SET_AND_EXPOSE_TO_BUILD(ENABLE_WPE_PLATFORM_BROADCOM_NEXUS ON) + set(WPE_PLATFORM_BROADCOM_NEXUS ON) + endif () endif () if (ENABLE_WPE_QT_API)