Update on what happened in WebKit in the week from July 28 to August 10.
Quite a packed pair of weeks this time! The range of updates is big, but some highlights are the handful of Layer-Based SVG Engine updates, performance improvements, and the new WPE APIs. Finally, the Web Engines Hackfest recordings are now published!
Cross-Port 🐱
Fixed webkit_website_data_get_size() looking up sizes for localStorage, indexedDB, and the DOM Cache.
Enabled support for the File System and Storage APIs.
Added WEBKIT_WEBSITE_DATA_FILE_SYSTEM API to enable fetching/clearing File System data sites use.
Multimedia 🎥
GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.
Landed a follow-up fix for the h264 edit list support to prevent regressions on YouTube MSE Conformance Tests 2019 when using older versions of GStreamer.
Avoided a spurious seek to zero when seeking to the end of an audio/video when playback starts.
Graphics 🖼️
Recovered a MotionMark compositing regression in the Skia backend, where respecting damage information during compositing cost about 20% on the composition suite and more than 50% on two of its tests. Restricting a draw to the damaged area means splitting it into source-rect-to-destination-rect pieces or drawing it under a device-space clip, and neither is needed when the damage already covers the whole draw, which is the common case in those tests because a composited layer is much smaller than a damage grid cell. Those draws are now issued exactly as they would be with damage turned off, avoiding a clip path that flushed the image set batch and left it an order of magnitude smaller, and with the regressions gone, using damage information for compositing was enabled again along with unifying damaged regions that are sent to the system compositor.
Skipped a per-frame visual overflow recomputation in the container paint cull of the Layer-Based SVG Engine (LBSE). The cull used a cached overflow rect that was recomputed by unioning all descendant bounds on a miss, which happened every frame for containers with an animated transform. It now only runs when the rect is already cached.
Skipped the outline paint pass for SVG renderers without an outline in the Layer-Based SVG Engine (LBSE). Every shape used to be painted twice per frame, the second pass being a no-op in the common outline-free case, so guarding it behind hasOutline() removes a redundant traversal from every frame.
Fixed masked SVG content being cut off at the edges in the Layer-Based SVG Engine (LBSE), where the mask image was sized over the enclosing integer rect of the mask content bounds in device space while the transparency layer clip was computed differently, losing the outermost pixels. An SVG renderer that is a box (<text>, <foreignObject>) also used the CSS mask clip rect derived from the border box, which leaves out SVG content spilling outside it, and now uses the visual overflow rect instead
Fixed most of the remaining <mask> issues in the Layer-Based SVG Engine (LBSE): masks were displaced on targets whose children carry transforms, the mask region given by x, y, width and height was ignored so content reaching past it was not cut off, and the cached mask image was never dropped on layout, leaving a resized viewport masking with an image rasterized for the old size.
Stopped rebuilding objectBoundingBox gradients on every layout size change in the Layer-Based SVG Engine (LBSE), which used to discard the cached gradient and re-collect its attributes (serializing every animated property back to a string, including gradientTransform) on the next paint. That work is wasted for objectBoundingBox units, whose coordinates resolve against the object bounding box with the userspace transform recomputed on every paint anyway, so only the clients are repainted now, while userSpaceOnUse gradients resolve against the viewport and are still invalidated as before.
Cached the SVG fill and stroke paint server directly on the renderer in the Layer-Based SVG Engine (LBSE), instead of in the shared referenced-resources table living in a renderer's rar data, where every fill and every stroke paid the cost of a hash map lookup just to reach the cache, which gives a small win on the MotionMark/Suits performance test. It also fixed a shape referencing a paint server that does not exist yet, which kept painting unfilled once an element finally took that id, because the shape registered itself as a pending resource under the full resolved URL while the lookups used the bare fragment identifier.
Sped up mapping the paint dirty rect through transforms in the Layer-Based SVG Engine (LBSE). Transformed SVG paints inverted the full 4x4 matrix on every paint, and now use the cheaper inverse of the 2x3 affine transform whenever the transform is affine, falling back to the 4x4 inverse only for 3D transforms.
Made SVG clip-path no longer force a RenderLayer in the Layer-Based SVG Engine (LBSE). A bare clip is now applied during painting through a shared ClipPathPaintScope, a scope object that sets up the clip in its constructor and tears it down afterwards, handling CSS basic-shape and box clips as well as SVG clipper resources so both regular CSS boxes and SVG content share one path. This is a further step in removing the intrinsic need for layers on SVG renderers, continuing the effort to close the performance gap between LBSE and the legacy SVG engine.
Fixed dynamic x and y updates on SVG <foreignObject> elements, which stopped taking effect after the viewport geometry started being derived from the resolved style. The x, y, width and height attributes are presentation attributes mapped to the CSS x, y, width and height properties, but only width and height marked the presentational hint style as dirty when they changed, so a style recalc never ran for x and y and layout kept reading stale values. All four geometry attributes now invalidate the presentational hint style, matching how <rect> handles its geometry, so setting x.baseVal.value from script repositions the <foreignObject> as expected.
Added support for external and data: URL references to clip-path, markers and paint servers (gradients and patterns) in the Layer-Based SVG Engine (LBSE). Until now the LBSE resource resolvers only looked for the referenced fragment inside the local document, so markup like url(file.svg#id) silently resolved to nothing, while filters already worked and the legacy SVG engine handled all of these since a few weeks.
Fixed SVG filters vanishing on elements with a very large bounding box in the Layer-Based SVG Engine (LBSE). The filter region was seeded with the element's object bounding box and then united with each referenced <filter> region, but a referenced <filter> brings its own region, and that region alone decides where the filter paints, so the union could grow far past the image buffer limits and get clamped down to scale that made the output disappear. When every function in the chain is a <filter> reference the bounding box is now dropped and only the referenced regions are kept, matching what the legacy SVG engine does, while objectBoundingBox filter units still resolve exactly as before and HTML/CSS filters are untouched.
WPE WebKit 📟
Add the WebView::run-color-chooser API to WPE to allow applications to show color choosers, similar to WebKitGTK's API.
The WPE port can now use libsecret for persistent credential storage, reusing the implementation from the WebKitGTK port. This is disabled by default and can be toggled passing -DUSE_LIBSECRET=ON to CMake when configuring the build.
Add the WebKitClipboardPermissionRequest API to WPE, allowing support for the clipboard permission similar to WebKItGTK.
Community & Events 🤝
The videos of the Web Engines Hackfest 2026 talks have been published, including the sessions from the new WPE WebKit track. This year the following WebKit-related talks have been recorded:
-
From libwpe to WPEPlatform: Building Embedded Browser on RPi with New WPE API, by Kate Lee, about new embedding API that is planned to be deemed stable for the 2.54 release series.
-
Refactoring composition in WPE with Skia, by Carlos García Campos, about the new Skia-based compositor currently in development that has been recently featured in our weekly dispatches.
-
Techniques for reducing GPU usage in WPE, by Paweł Lampe, which is exactly what reads in the tin and how to balance CPU and GPU usage.
-
Speeding up WPEWebKit and WebKitGTK with Profile-Guided Optimization, by Lauro Moura, because everybody likes to squeeze performance out of an existing codebase without rewriting it thanks to compiler techniques.
-
No QA, No WPE: Catch Regressions Before You Do, by Claudio Saavedra and Nikolas Zimmermann, about how continuous integration and quality assurance has been improved (and continues to) to improve stability and performance in the GTK and WPE WebKit ports.
-
WPEPlatform API for Android, by Alejandro G. Castro, which is not only this year's update on WPE Android but also covers how the platform-dependent components have been partially rewritten and migrated to the WPEPlatform API.
That’s all for this week!