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/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/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 7b736f59628e3..ccc55d72745cb 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.") \ @@ -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 { 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/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml index 21b4c1aa39dbc..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 @@ -291,6 +305,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/WTF/wtf/MemoryPressureHandler.cpp b/Source/WTF/wtf/MemoryPressureHandler.cpp index 8348265e15434..b57d02f82c9d2 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) @@ -85,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); @@ -139,10 +215,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 +233,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 +263,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 +314,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 +340,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 +406,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 +461,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 +481,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 +489,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/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[] = { 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/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/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/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/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())); 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/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); 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/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 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; 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 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/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp index 3bf0377208a9d..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) @@ -3542,8 +3544,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); 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/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp index 85bb921bec67a..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); @@ -112,18 +116,20 @@ void DOMWindow::close() if (!frame->isMainFrame()) return; - if (!(page->openedByDOM() || page->backForward().count() <= 1)) { - 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(); } @@ -533,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/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/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/MemoryRelease.cpp b/Source/WebCore/page/MemoryRelease.cpp index b5852fb732e0a..610546a45b775 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) @@ -257,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 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/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/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/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/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/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/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/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/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/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/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/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/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/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 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/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/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/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); 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/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/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) diff --git a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp index f0a39b556f7f1..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; @@ -223,7 +239,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 +250,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 +1519,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 +1530,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 +1581,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*); 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/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; 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/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/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; } 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/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/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/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/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)); } 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) { 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/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/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/UIProcess/API/glib/WebKitSettings.cpp b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp index b8d3249532dee..e54824289e46e 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp @@ -174,6 +174,12 @@ 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_ALLOW_MOVE_TO_SUSPEND_ON_WINDOW_CLOSE, + PROP_ENABLE_DIRECTORY_UPLOAD, + PROP_ENABLE_SERVICE_WORKER, N_PROPERTIES, }; @@ -409,6 +415,24 @@ 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; + 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; + 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; @@ -617,6 +641,24 @@ 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; + 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; + 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; @@ -1618,6 +1660,84 @@ 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: + * + * 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); + + /** + * 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: + * + * 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); + + /** + * 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); } @@ -3147,7 +3267,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()); @@ -4131,3 +4251,219 @@ 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 + * + * 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"); +} + +/** + * 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 + * + * 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"); +} + +/** + * 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 6a9bfa6afd95d..e35c6fbcfee29 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.h.in @@ -562,6 +562,46 @@ 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); + +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); + +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 */ 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 diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp index 14c655bdd47bf..ba7d0cc7ff959 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; @@ -430,8 +428,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)); @@ -1994,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 diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp index 9edd3e67dd17b..7e289784925ab 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -5645,3 +5645,81 @@ 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)); + + 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); +} + +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(); +} + +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 f385fd67b1074..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) @@ -1047,6 +1062,24 @@ 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); + +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/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/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/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 diff --git a/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp b/Source/WebKit/UIProcess/Inspector/glib/RemoteInspectorHTTPServer.cpp index 89382a72d9c1c..49901cd8edbd9 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; } @@ -46,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; diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp index 70538fe2d307d..28564bab30ff3 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(); @@ -10330,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(); @@ -14169,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 8647cfcd97633..5a98fb2d5c97c 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(); @@ -2385,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 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/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/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/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() 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/InjectedBundle/API/glib/WebKitWebExtension.cpp b/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.cpp index cefd10c2d8b22..c568945fa8884 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,52 @@ 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(); +} + +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 1238fc3300927..948eefc4108a5 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,36 @@ 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_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/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) 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); 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() 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() diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp index 00d770be33c78..d36d2dde23d5d 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 @@ -1042,6 +1043,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(); @@ -8115,6 +8118,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) @@ -8313,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) @@ -9563,6 +9569,7 @@ void WebPage::setDefaultSpatialTrackingLabel(const String& label) void WebPage::startObservingNowPlayingMetadata() { +#if ENABLE(VIDEO) || ENABLE(WEB_AUDIO) if (m_nowPlayingMetadataObserver) return; @@ -9572,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) 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 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**)"; diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index e0c8dc92717c3..03341e391a464 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -88,14 +88,16 @@ 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) +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 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_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) @@ -103,6 +105,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) @@ -126,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) @@ -284,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) @@ -415,6 +425,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) @@ -451,3 +467,22 @@ 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 (COMPILER_IS_GCC_OR_CLANG AND UNIX AND NOT APPLE) + # 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") + 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 () 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)